diff --git a/examples/snowbox/index.js b/examples/snowbox/index.js
index ac13fea773..ca694b2d29 100644
--- a/examples/snowbox/index.js
+++ b/examples/snowbox/index.js
@@ -204,6 +204,7 @@ const map = await createMap(
services
)
+const additionalMaps = []
document.getElementById('secondMap').addEventListener('click', async () => {
const secondMap = createMapElement(
{
@@ -227,9 +228,14 @@ document.getElementById('secondMap').addEventListener('click', async () => {
layoutTag: 'TOP_RIGHT',
})
)
+ additionalMaps.push(secondMap)
})
document.getElementById('secondMapClean').addEventListener('click', () => {
- document.getElementById('secondMapContainer').innerText = ''
+ additionalMaps.forEach((map, i) => {
+ map.remove()
+ delete additionalMaps[i]
+ })
+ additionalMaps.length = 0
})
addPlugin(
diff --git a/src/core/components/PolarContainer.ce.vue b/src/core/components/PolarContainer.ce.vue
index ffc3493fe0..1ecf23a094 100644
--- a/src/core/components/PolarContainer.ce.vue
+++ b/src/core/components/PolarContainer.ce.vue
@@ -22,8 +22,9 @@
diff --git a/src/core/components/PolarMap.ce.vue b/src/core/components/PolarMap.ce.vue
index 035057dc6a..f5085e4b9b 100644
--- a/src/core/components/PolarMap.ce.vue
+++ b/src/core/components/PolarMap.ce.vue
@@ -19,7 +19,14 @@ import { t } from 'i18next'
import { easeOut } from 'ol/easing'
import { defaults } from 'ol/interaction'
import { storeToRefs } from 'pinia'
-import { computed, onMounted, useTemplateRef, watch } from 'vue'
+import {
+ computed,
+ markRaw,
+ onBeforeUnmount,
+ onMounted,
+ useTemplateRef,
+ watch,
+} from 'vue'
import { useT } from '../composables/useT'
import { useMainStore } from '../stores/main'
@@ -42,26 +49,28 @@ function onMove() {
}
function createMap() {
- mainStore.map = api.map.createMap(
- {
- target: polarMapContainer.value,
- extent: undefined,
- ...mainStore.configuration,
- layerConf: mainStore.serviceRegister,
- },
- '2D',
- {
- mapParams: {
- interactions: defaults({
- altShiftDragRotate: false,
- pinchRotate: false,
- dragPan: false,
- mouseWheelZoom: false,
- keyboard: false,
- }),
+ mainStore.map = markRaw(
+ api.map.createMap(
+ {
+ target: polarMapContainer.value,
+ extent: undefined,
+ ...mainStore.configuration,
+ layerConf: mainStore.serviceRegister,
},
- }
- ) as Map
+ '2D',
+ {
+ mapParams: {
+ interactions: defaults({
+ altShiftDragRotate: false,
+ pinchRotate: false,
+ dragPan: false,
+ mouseWheelZoom: false,
+ keyboard: false,
+ }),
+ },
+ }
+ ) as Map
+ )
mainStore.map.on('moveend', onMove)
updateDragAndZoomInteractions(
@@ -126,17 +135,24 @@ onMounted(async () => {
mainStore.serviceRegister
)
})
+onBeforeUnmount(() => {
+ mainStore.map.un('moveend', onMove)
+ hammer?.destroy()
+ hammer = null
+})
const oneFingerPan = useT(() =>
t(($) => $.overlay.oneFingerPan, { ns: 'core' })
)
+let hammer: { destroy: () => void } | null = null
function updateListeners() {
if (
!hasWindowSize.value &&
polarMapContainer.value &&
mainStore.hasSmallDisplay
) {
- new Hammer(polarMapContainer.value).on('pan', (e) => {
+ hammer?.destroy()
+ hammer = new Hammer(polarMapContainer.value).on('pan', (e) => {
if (
overlay.value &&
e.maxPointers === 1 &&
diff --git a/src/core/stores/main.ts b/src/core/stores/main.ts
index 4ca1203531..1a3d628d6a 100644
--- a/src/core/stores/main.ts
+++ b/src/core/stores/main.ts
@@ -6,6 +6,9 @@ import { toMerged } from 'es-toolkit'
import { acceptHMRUpdate, defineStore } from 'pinia'
import { computed, ref, shallowRef, watch } from 'vue'
+import { teardownMarkers } from '@/core/utils/map/setupMarkers.ts'
+import { teardownInteractions } from '@/core/utils/map/updateDragAndZoomInteractions.ts'
+
import type {
ColorScheme,
MapConfigurationIncludingDefaults,
@@ -85,6 +88,10 @@ export const useMainStore = defineStore('main', () => {
function teardown() {
removeEventListener('resize', updateHasSmallDisplay)
+ teardownInteractions()
+ if (configuration.value.markers) {
+ teardownMarkers(map.value)
+ }
}
return {
diff --git a/src/core/stores/marker.ts b/src/core/stores/marker.ts
index 46c238f869..aefdfde9fc 100644
--- a/src/core/stores/marker.ts
+++ b/src/core/stores/marker.ts
@@ -1,7 +1,7 @@
import { Feature } from 'ol'
import { Point } from 'ol/geom'
import { acceptHMRUpdate, defineStore } from 'pinia'
-import { computed, ref } from 'vue'
+import { computed, shallowRef } from 'vue'
import type { CallOnMapSelect } from '../types'
@@ -20,8 +20,8 @@ export const useMarkerStore = defineStore('marker', () => {
() => (configuration.value?.clusterClickZoom as boolean) || false
)
- const hovered = ref(null)
- const selected = ref(null)
+ const hovered = shallowRef(null)
+ const selected = shallowRef(null)
const selectedCoordinates = computed(() =>
selected.value === null
? null
diff --git a/src/core/utils/map/setupMarkers.ts b/src/core/utils/map/setupMarkers.ts
index 9c64d54098..ab237ed8dd 100644
--- a/src/core/utils/map/setupMarkers.ts
+++ b/src/core/utils/map/setupMarkers.ts
@@ -19,6 +19,8 @@ import type { MarkerLayer, MarkerStyle, PluginId } from '../../types'
import { useMainStore } from '../../stores/main'
import { getMarkerStyle } from '../../utils/markers'
+let stopWatcher: (() => void) | null = null
+
// these have been measured to fit once and influence marker size
const imgSize: [number, number] = [26, 36]
const imgSizeMulti: [number, number] = [40, 36]
@@ -121,7 +123,7 @@ function updateSelection(
store.selected = markRaw(selectedCluster)
if (centerOnFeature) {
const mainStore = useMainStore()
- mainStore.centerOnFeature(store.selected as Feature)
+ mainStore.centerOnFeature(store.selected)
}
}
@@ -205,7 +207,7 @@ export function setupMarkers(map: Map) {
// // // STORE EVENT HANDLING
- watch(
+ stopWatcher = watch(
() => store.hovered,
(feature) => {
if (feature !== null && feature !== toRaw(store.selected)) {
@@ -236,6 +238,19 @@ export function setupMarkers(map: Map) {
map.on('singleclick', mapSingleClick)
}
+export function teardownMarkers(map: Map) {
+ stopWatcher?.()
+ stopWatcher = null
+ layers = []
+ lastClickEvent = null
+
+ map.un('moveend', mapMoveEnd)
+ map.un('pointermove', mapPointerMove)
+ map.un('click', mapClick)
+
+ map.un('singleclick', mapSingleClick)
+}
+
// // // MAP EVENT HANDLING
let lastClickEvent: MapBrowserEvent | null = null
diff --git a/src/core/utils/map/updateDragAndZoomInteractions.ts b/src/core/utils/map/updateDragAndZoomInteractions.ts
index 1ce5bfdc9a..4cfbac1de9 100644
--- a/src/core/utils/map/updateDragAndZoomInteractions.ts
+++ b/src/core/utils/map/updateDragAndZoomInteractions.ts
@@ -18,3 +18,7 @@ export function updateDragAndZoomInteractions(
map.addInteraction(interaction)
}
}
+
+export function teardownInteractions() {
+ interactions = []
+}
diff --git a/src/plugins/pins/store.ts b/src/plugins/pins/store.ts
index 981c207710..504891c8e4 100644
--- a/src/plugins/pins/store.ts
+++ b/src/plugins/pins/store.ts
@@ -5,6 +5,7 @@
/* eslint-enable tsdoc/syntax */
import type { GeoJsonGeometryTypes, Point as GeoJsonPoint } from 'geojson'
+import type { MapBrowserEvent } from 'ol'
import type { Coordinate } from 'ol/coordinate'
import { toMerged } from 'es-toolkit'
@@ -82,9 +83,7 @@ export const usePinsStore = defineStore('plugins/pins', () => {
function setupPlugin() {
coreStore.map.addLayer(pinLayer)
pinLayer.setZIndex(100)
- coreStore.map.on('singleclick', async ({ coordinate }) => {
- await click(coordinate)
- })
+ coreStore.map.on('singleclick', onSingleClick)
setupCoordinateSource()
setupInitial()
setupInteractions()
@@ -92,9 +91,7 @@ export const usePinsStore = defineStore('plugins/pins', () => {
function teardownPlugin() {
const { map } = coreStore
- map.un('singleclick', async ({ coordinate }) => {
- await click(coordinate)
- })
+ map.un('singleclick', onSingleClick)
removePin()
map.removeLayer(pinLayer)
map.removeInteraction(move)
@@ -185,6 +182,10 @@ export const usePinsStore = defineStore('plugins/pins', () => {
coreStore.map.addInteraction(translate)
}
+ async function onSingleClick({ coordinate }: MapBrowserEvent) {
+ await click(coordinate)
+ }
+
async function click(coordinate: Coordinate) {
const isDrawing = coreStore.map
.getInteractions()