diff --git a/package.json b/package.json index 2bb8ea5..f50a45a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vue-maplibre-gl", - "version": "2.0.4", + "version": "2.0.5", "description": "Vue 3 plugin for maplibre-gl", "keywords": [ "vue", diff --git a/src/lib/components/controls/attribution.control.ts b/src/lib/components/controls/attribution.control.ts index 0de1d9d..e66d9d7 100644 --- a/src/lib/components/controls/attribution.control.ts +++ b/src/lib/components/controls/attribution.control.ts @@ -1,7 +1,7 @@ import { defineComponent, inject, onBeforeUnmount, PropType, toRef } from 'vue'; import { AttributionControl } from 'maplibre-gl'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; -import { mapSymbol } from '@/lib/types'; +import { isInitializedSymbol, mapSymbol } from '@/lib/types'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; @@ -19,11 +19,12 @@ export default /*#__PURE__*/ defineComponent({ }, setup(props) { - const map = inject(mapSymbol)!, - control = new AttributionControl({ compact: props.compact, customAttribution: props.customAttribution }); + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + control = new AttributionControl({ compact: props.compact, customAttribution: props.customAttribution }); usePositionWatcher(toRef(props, 'position'), map, control); - onBeforeUnmount(() => map.value!.removeControl(control)); + onBeforeUnmount(() => isInitialized.value && map.value!.removeControl(control)); }, render() { diff --git a/src/lib/components/controls/custom.control.ts b/src/lib/components/controls/custom.control.ts index 5997a23..5477f57 100644 --- a/src/lib/components/controls/custom.control.ts +++ b/src/lib/components/controls/custom.control.ts @@ -1,7 +1,7 @@ import { createCommentVNode, defineComponent, h, inject, nextTick, onBeforeUnmount, PropType, ref, Ref, Teleport, toRef, watch } from 'vue'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; import { ControlPosition, IControl } from 'maplibre-gl'; -import { mapSymbol } from '@/lib/types'; +import { isInitializedSymbol, mapSymbol } from '@/lib/types'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; @@ -59,15 +59,14 @@ export default /*#__PURE__*/ defineComponent({ }, setup(props) { - const map = inject(mapSymbol)!, - isAdded = ref(false), - control = new CustomControl(isAdded, props.noClasses!); + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + isAdded = ref(false), + control = new CustomControl(isAdded, props.noClasses!); usePositionWatcher(toRef(props, 'position'), map, control); watch(toRef(props, 'noClasses'), v => control.setClasses(v!)); - onBeforeUnmount(() => { - map.value?.removeControl(control); - }); + onBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control)); return { isAdded, container: control.container }; diff --git a/src/lib/components/controls/frameRate.control.ts b/src/lib/components/controls/frameRate.control.ts index 20433ca..e2c627b 100644 --- a/src/lib/components/controls/frameRate.control.ts +++ b/src/lib/components/controls/frameRate.control.ts @@ -1,7 +1,7 @@ import { defineComponent, inject, onBeforeUnmount, PropType, toRef } from 'vue'; import { IControl, Map as MMap } from 'maplibre-gl'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; -import { mapSymbol } from '@/lib/types'; +import { isInitializedSymbol, mapSymbol } from '@/lib/types'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; export class FrameRateControl implements IControl { @@ -195,8 +195,9 @@ export default /*#__PURE__*/ defineComponent({ }, setup(props) { - const map = inject(mapSymbol)!, - control = new FrameRateControl( + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + control = new FrameRateControl( props.background, props.barWidth, props.color, @@ -209,7 +210,7 @@ export default /*#__PURE__*/ defineComponent({ ); usePositionWatcher(toRef(props, 'position'), map, control); - onBeforeUnmount(() => map.value?.removeControl(control)); + onBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control)); }, render() { diff --git a/src/lib/components/controls/fullscreen.control.ts b/src/lib/components/controls/fullscreen.control.ts index f393ddd..79636f4 100644 --- a/src/lib/components/controls/fullscreen.control.ts +++ b/src/lib/components/controls/fullscreen.control.ts @@ -1,6 +1,6 @@ import { defineComponent, inject, onBeforeUnmount, PropType, toRef } from 'vue'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; -import { mapSymbol } from '@/lib/types'; +import { isInitializedSymbol, mapSymbol } from '@/lib/types'; import { FullscreenControl } from 'maplibre-gl'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; @@ -21,11 +21,12 @@ export default /*#__PURE__*/ defineComponent({ }, setup(props) { - const map = inject(mapSymbol)!, - control = new FullscreenControl({ container: props.container || undefined }); + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + control = new FullscreenControl({ container: props.container || undefined }); usePositionWatcher(toRef(props, 'position'), map, control); - onBeforeUnmount(() => map.value?.removeControl(control)); + onBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control)); }, render() { diff --git a/src/lib/components/controls/geolocation.control.ts b/src/lib/components/controls/geolocation.control.ts index 4bb1293..fa4212b 100644 --- a/src/lib/components/controls/geolocation.control.ts +++ b/src/lib/components/controls/geolocation.control.ts @@ -1,6 +1,6 @@ import { defineComponent, inject, onBeforeUnmount, PropType, toRef } from 'vue'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; -import { mapSymbol } from '@/lib/types'; +import { isInitializedSymbol, mapSymbol } from '@/lib/types'; import { FitBoundsOptions, GeolocateControl } from 'maplibre-gl'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; @@ -37,8 +37,9 @@ export default /*#__PURE__*/ defineComponent({ }, setup(props) { - const map = inject(mapSymbol)!, - control = new GeolocateControl({ + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + control = new GeolocateControl({ positionOptions : props.positionOptions, fitBoundsOptions : props.fitBoundsOptions, trackUserLocation : props.trackUserLocation, @@ -47,7 +48,7 @@ export default /*#__PURE__*/ defineComponent({ }); usePositionWatcher(toRef(props, 'position'), map, control); - onBeforeUnmount(() => map.value?.removeControl(control)); + onBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control)); }, render() { diff --git a/src/lib/components/controls/navigation.control.ts b/src/lib/components/controls/navigation.control.ts index e660c13..743ecea 100644 --- a/src/lib/components/controls/navigation.control.ts +++ b/src/lib/components/controls/navigation.control.ts @@ -1,6 +1,6 @@ import { defineComponent, inject, onBeforeUnmount, PropType, toRef } from 'vue'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; -import { mapSymbol } from '@/lib/types'; +import { isInitializedSymbol, mapSymbol } from '@/lib/types'; import { NavigationControl } from 'maplibre-gl'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; @@ -20,11 +20,12 @@ export default /*#__PURE__*/ defineComponent({ }, setup(props) { - const map = inject(mapSymbol)!, - control = new NavigationControl({ showCompass: props.showCompass, showZoom: props.showZoom, visualizePitch: props.visualizePitch }); + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + control = new NavigationControl({ showCompass: props.showCompass, showZoom: props.showZoom, visualizePitch: props.visualizePitch }); usePositionWatcher(toRef(props, 'position'), map, control); - onBeforeUnmount(() => map.value?.removeControl(control)); + onBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control)); }, render() { diff --git a/src/lib/components/controls/scale.control.ts b/src/lib/components/controls/scale.control.ts index 68ec1f7..effb000 100644 --- a/src/lib/components/controls/scale.control.ts +++ b/src/lib/components/controls/scale.control.ts @@ -1,6 +1,6 @@ import { defineComponent, inject, onBeforeUnmount, PropType, toRef } from 'vue'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; -import { mapSymbol } from '@/lib/types'; +import { isInitializedSymbol, mapSymbol } from '@/lib/types'; import { ScaleControl } from 'maplibre-gl'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; @@ -34,11 +34,12 @@ export default /*#__PURE__*/ defineComponent({ }, setup(props) { - const map = inject(mapSymbol)!, - control = new ScaleControl({ maxWidth: props.maxWidth, unit: props.unit }); + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + control = new ScaleControl({ maxWidth: props.maxWidth, unit: props.unit }); usePositionWatcher(toRef(props, 'position'), map, control); - onBeforeUnmount(() => map.value?.removeControl(control)); + onBeforeUnmount(() => isInitialized.value && map.value?.removeControl(control)); }, render() { diff --git a/src/lib/components/controls/styleSwitch.control.ts b/src/lib/components/controls/styleSwitch.control.ts index e4cd71b..c8151db 100644 --- a/src/lib/components/controls/styleSwitch.control.ts +++ b/src/lib/components/controls/styleSwitch.control.ts @@ -1,6 +1,6 @@ import { createCommentVNode, createTextVNode, defineComponent, h, inject, onBeforeUnmount, PropType, ref, shallowRef, Teleport, toRef, watch } from 'vue'; import { Position, PositionProp, PositionValues } from '@/lib/components/controls/position.enum'; -import { emitterSymbol, isLoadedSymbol, mapSymbol, StyleSwitchItem } from '@/lib/types'; +import { emitterSymbol, isInitializedSymbol, isLoadedSymbol, mapSymbol, StyleSwitchItem } from '@/lib/types'; import { CustomControl } from '@/lib/components/controls/custom.control'; import { usePositionWatcher } from '@/lib/composable/usePositionWatcher'; import { MglButton } from '@/lib/components'; @@ -35,14 +35,15 @@ export default /*#__PURE__*/ defineComponent({ emits: [ 'update:modelValue', 'update:isOpen' ], setup(props, { emit }) { - const map = inject(mapSymbol)!, - isMapLoaded = inject(isLoadedSymbol)!, - emitter = inject(emitterSymbol)!, - isAdded = ref(false), - isOpen = ref(props.isOpen === undefined ? false : props.isOpen), - modelValue = shallowRef(props.modelValue === undefined ? (props.mapStyles.length ? props.mapStyles[ 0 ] : null) : props.modelValue), - control = new CustomControl(isAdded, false), - closer = toggleOpen.bind(null, false); + const map = inject(mapSymbol)!, + isInitialized = inject(isInitializedSymbol)!, + isMapLoaded = inject(isLoadedSymbol)!, + emitter = inject(emitterSymbol)!, + isAdded = ref(false), + isOpen = ref(props.isOpen === undefined ? false : props.isOpen), + modelValue = shallowRef(props.modelValue === undefined ? (props.mapStyles.length ? props.mapStyles[ 0 ] : null) : props.modelValue), + control = new CustomControl(isAdded, false), + closer = toggleOpen.bind(null, false); function setStyleByMap() { const name = map.value!.getStyle().name; @@ -75,8 +76,10 @@ export default /*#__PURE__*/ defineComponent({ } onBeforeUnmount(() => { - map.value!.removeControl(control); - map.value!.off('style.load', setStyleByMap); + if (isInitialized.value) { + map.value!.removeControl(control); + map.value!.off('style.load', setStyleByMap); + } document.removeEventListener('click', closer); }); diff --git a/src/lib/components/map.component.ts b/src/lib/components/map.component.ts index 8320f99..8fb23b4 100644 --- a/src/lib/components/map.component.ts +++ b/src/lib/components/map.component.ts @@ -24,7 +24,7 @@ import { RequestTransformFunction, StyleSpecification } from 'maplibre-gl'; -import { componentIdSymbol, emitterSymbol, isLoadedSymbol, mapSymbol, MglEvents, sourceIdSymbol } from '@/lib/types'; +import { componentIdSymbol, emitterSymbol, isInitializedSymbol, isLoadedSymbol, mapSymbol, MglEvents, sourceIdSymbol } from '@/lib/types'; import { defaults } from '@/lib/defaults'; import { MapLib } from '@/lib/lib/map.lib'; import { Position } from '@/lib/components/controls/position.enum'; @@ -111,6 +111,7 @@ export default /*#__PURE__*/ defineComponent({ provide(mapSymbol, map); provide(isLoadedSymbol, isLoaded); + provide(isInitializedSymbol, isInitialized); provide(componentIdSymbol, component.uid); provide(sourceIdSymbol, ''); provide(emitterSymbol, emitter); @@ -224,19 +225,23 @@ export default /*#__PURE__*/ defineComponent({ } - function dispose() { + async function dispose() { registryItem.isMounted = false; registryItem.isLoaded = false; - isLoaded.value = false; + isLoaded.value = false; - // unbind events if (map.value) { + // unbind events map.value.getCanvas().removeEventListener('webglcontextlost', restart); + map.value._controls.forEach((control) => { + map.value!.removeControl(control); + }); isInitialized.value = false; boundMapEvents.forEach((func, en) => { map.value!.off(en.startsWith('__') ? en.substring(2) : en, func as any); }); + // destroy map map.value.remove(); } diff --git a/src/lib/types.ts b/src/lib/types.ts index 17d76e1..bc85415 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -6,6 +6,7 @@ import { SourceLayerRegistry } from '@/lib/lib/sourceLayer.registry'; export const mapSymbol = Symbol('map') as InjectionKey>, isLoadedSymbol = Symbol('isLoaded') as InjectionKey>, + isInitializedSymbol = Symbol('isInitialized') as InjectionKey>, componentIdSymbol = Symbol('componentId') as InjectionKey, sourceIdSymbol = Symbol('sourceId') as InjectionKey, sourceLayerRegistry = Symbol('sourceLayerRegistry') as InjectionKey,