@dative-gpi/foundation-shared-components 1.0.155 → 1.0.156
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/map/FSMap.vue +86 -82
- package/components/map/FSMapFeatureGroup.vue +7 -1
- package/components/map/FSMapLayerButton.vue +1 -0
- package/components/map/FSMapMarker.vue +18 -3
- package/components/map/FSMapMarkerClusterGroup.vue +30 -8
- package/components/map/FSMapPolygon.vue +14 -2
- package/components/map/FSMapTileLayer.vue +12 -1
- package/components/map/layers.ts +0 -0
- package/composables/index.ts +1 -0
- package/composables/useMapLayers.ts +62 -0
- package/package.json +4 -4
package/components/map/FSMap.vue
CHANGED
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
|
|
29
29
|
<FSMapLayerButton
|
|
30
30
|
v-if="$props.allowedLayers?.length && $props.allowedLayers.length > 1"
|
|
31
|
-
:
|
|
31
|
+
:disabled="$props.disabled"
|
|
32
|
+
:layers="layers.filter((layer) => $props.allowedLayers?.includes(layer.name) ?? true)"
|
|
32
33
|
:modelValue="$props.currentLayer"
|
|
33
34
|
@update:model-value="$emit('update:currentLayer', $event)"
|
|
34
35
|
/>
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
>
|
|
40
41
|
<FSButton
|
|
41
42
|
v-if="$props.showMyLocation"
|
|
43
|
+
:disabled="$props.disabled"
|
|
42
44
|
icon="mdi-crosshairs-gps"
|
|
43
45
|
color="primary"
|
|
44
46
|
variant="full"
|
|
@@ -53,12 +55,14 @@
|
|
|
53
55
|
gap="0"
|
|
54
56
|
>
|
|
55
57
|
<FSButton
|
|
58
|
+
:disabled="$props.disabled"
|
|
56
59
|
class="fs-map-zoom-plus-button"
|
|
57
60
|
icon="mdi-plus"
|
|
58
61
|
@click="() => map!.zoomIn()"
|
|
59
62
|
:border="false"
|
|
60
63
|
/>
|
|
61
64
|
<FSButton
|
|
65
|
+
:disabled="$props.disabled"
|
|
62
66
|
class="fs-map-zoom-minus-button"
|
|
63
67
|
icon="mdi-minus"
|
|
64
68
|
@click="() => map!.zoomOut()"
|
|
@@ -92,12 +96,10 @@
|
|
|
92
96
|
import { computed, defineComponent, onMounted, type Ref, provide, type PropType, ref, type StyleValue, watch, onUnmounted, markRaw } from "vue";
|
|
93
97
|
|
|
94
98
|
import type {} from "leaflet.markercluster";
|
|
95
|
-
import { map as createMap, control,
|
|
99
|
+
import { map as createMap, control, latLngBounds, latLng, type LatLng, type FitBoundsOptions, type ZoomPanOptions, type LatLngBounds } from "leaflet";
|
|
96
100
|
|
|
97
|
-
import {
|
|
98
|
-
|
|
99
|
-
import { useBreakpoints, useColors, useSlots } from "../../composables";
|
|
100
|
-
import { ColorEnum, MapLayers, MapOverlayPositions, type MapLayer } from "../../models";
|
|
101
|
+
import { useBreakpoints, useColors, useMapLayers, useSlots } from "../../composables";
|
|
102
|
+
import { ColorEnum, MapLayers, MapOverlayPositions } from "../../models";
|
|
101
103
|
|
|
102
104
|
import FSMapLayerButton from "./FSMapLayerButton.vue";
|
|
103
105
|
import FSMapOverlay from "./FSMapOverlay.vue";
|
|
@@ -130,6 +132,11 @@ export default defineComponent({
|
|
|
130
132
|
required: false,
|
|
131
133
|
default: '100%'
|
|
132
134
|
},
|
|
135
|
+
disabled: {
|
|
136
|
+
type: Boolean,
|
|
137
|
+
required: false,
|
|
138
|
+
default: false
|
|
139
|
+
},
|
|
133
140
|
grayscale: {
|
|
134
141
|
type: Boolean,
|
|
135
142
|
required: false,
|
|
@@ -175,22 +182,20 @@ export default defineComponent({
|
|
|
175
182
|
required: false,
|
|
176
183
|
default: () => [MapLayers.Map, MapLayers.Imagery]
|
|
177
184
|
},
|
|
178
|
-
|
|
185
|
+
zoom: {
|
|
179
186
|
type: Number,
|
|
180
187
|
required: false,
|
|
181
188
|
default: 16
|
|
182
189
|
}
|
|
183
190
|
},
|
|
184
|
-
emits: [
|
|
191
|
+
emits: ['update:overlayMode', 'update:currentLayer', "click:latlng", "update:zoom", "update:center"],
|
|
185
192
|
setup(props, { emit }) {
|
|
186
|
-
const {
|
|
193
|
+
const { layers } = useMapLayers();
|
|
187
194
|
const { isExtraSmall } = useBreakpoints();
|
|
188
195
|
const { getColors } = useColors();
|
|
189
196
|
const { slots } = useSlots();
|
|
190
197
|
|
|
191
198
|
const leafletContainer = ref<HTMLElement>();
|
|
192
|
-
const locationGroupBounds = ref<LatLngBounds>();
|
|
193
|
-
const areaGroupBounds = ref<LatLngBounds>();
|
|
194
199
|
const gpsPosition : Ref<LatLng | null> = ref(null);
|
|
195
200
|
const map: Ref<L.Map | null> = ref(null);
|
|
196
201
|
const overlayHeight = ref<number>();
|
|
@@ -198,7 +203,6 @@ export default defineComponent({
|
|
|
198
203
|
|
|
199
204
|
provide('map', map);
|
|
200
205
|
|
|
201
|
-
const defaultZoom = ref(props.dirtyZoom);
|
|
202
206
|
const mapResizeObserver = new ResizeObserver(() => {
|
|
203
207
|
if(!map.value) {
|
|
204
208
|
return;
|
|
@@ -206,53 +210,6 @@ export default defineComponent({
|
|
|
206
210
|
map.value.invalidateSize();
|
|
207
211
|
});
|
|
208
212
|
|
|
209
|
-
const mapLayers: MapLayer[] = [
|
|
210
|
-
{
|
|
211
|
-
name: MapLayers.Map,
|
|
212
|
-
label: $tr("ui.map-layer.map", "Map"),
|
|
213
|
-
image: new URL("../../assets/images/map/map.png", import.meta.url).href,
|
|
214
|
-
layers: [
|
|
215
|
-
tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
|
|
216
|
-
maxZoom: 22,
|
|
217
|
-
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
218
|
-
attribution: '© Google Map Data',
|
|
219
|
-
className: 'fs-map-tile-base-layer'
|
|
220
|
-
})
|
|
221
|
-
]
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
name: MapLayers.Imagery,
|
|
225
|
-
label: $tr("ui.map-layer.imagery", "Imagery"),
|
|
226
|
-
image: new URL("../../assets/images/map/imagery.png", import.meta.url).href,
|
|
227
|
-
layers: [
|
|
228
|
-
tileLayer(`https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
|
|
229
|
-
maxZoom: 22,
|
|
230
|
-
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
231
|
-
attribution: '© Google Map Data',
|
|
232
|
-
className: 'fs-map-tile-base-layer'
|
|
233
|
-
})
|
|
234
|
-
]
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
name: MapLayers.Snow,
|
|
238
|
-
label: $tr("ui.map-layer.snow", "Snow ski map"),
|
|
239
|
-
image: new URL("../../assets/images/map/snow.png", import.meta.url).href,
|
|
240
|
-
layers: [
|
|
241
|
-
tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
|
|
242
|
-
maxZoom: 22,
|
|
243
|
-
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
244
|
-
attribution: '© Google Map Data',
|
|
245
|
-
className: 'fs-map-tile-base-layer fs-map-tile-grayscale-layer'
|
|
246
|
-
}),
|
|
247
|
-
tileLayer(`https://tiles.opensnowmap.org/pistes/{z}/{x}/{y}.png`, {
|
|
248
|
-
maxZoom: 18,
|
|
249
|
-
attribution: 'Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors & ODbL, © <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
|
|
250
|
-
className: 'fs-map-tile-base-layer'
|
|
251
|
-
})
|
|
252
|
-
]
|
|
253
|
-
}
|
|
254
|
-
];
|
|
255
|
-
|
|
256
213
|
const bottomOffset = computed(() => {
|
|
257
214
|
if (props.overlayMode !== MapOverlayPositions.Expand && overlayHeight.value && isExtraSmall.value) {
|
|
258
215
|
return overlayHeight.value;
|
|
@@ -276,7 +233,7 @@ export default defineComponent({
|
|
|
276
233
|
}));
|
|
277
234
|
|
|
278
235
|
const actualLayer = computed(() => {
|
|
279
|
-
return
|
|
236
|
+
return layers.find((mapLayer) => mapLayer.name === props.currentLayer)?.layers ?? layers[0].layers;
|
|
280
237
|
});
|
|
281
238
|
|
|
282
239
|
const overlaySlots = computed(() => {
|
|
@@ -295,7 +252,7 @@ export default defineComponent({
|
|
|
295
252
|
return map.value.unproject(targetPoint, zoom);
|
|
296
253
|
}
|
|
297
254
|
|
|
298
|
-
const flyTo = (lat: number, lng: number, zoom: number
|
|
255
|
+
const flyTo = (lat: number, lng: number, zoom: number, options?: ZoomPanOptions) => {
|
|
299
256
|
if(!map.value) {
|
|
300
257
|
return;
|
|
301
258
|
}
|
|
@@ -316,7 +273,6 @@ export default defineComponent({
|
|
|
316
273
|
} else {
|
|
317
274
|
map.value.flyTo(calculateTargetPosition(latLng(lat, lng), zoom), zoom, options);
|
|
318
275
|
}
|
|
319
|
-
|
|
320
276
|
}
|
|
321
277
|
|
|
322
278
|
const setView = (lat: number, lng: number, zoom: number) => {
|
|
@@ -329,13 +285,13 @@ export default defineComponent({
|
|
|
329
285
|
const fitBounds = (bounds: LatLngBounds, options?: FitBoundsOptions) => {
|
|
330
286
|
if (!map.value) {return;}
|
|
331
287
|
const paddingTopLeft: [number, number] = [
|
|
332
|
-
leftOffset.value,
|
|
333
|
-
|
|
288
|
+
leftOffset.value + 24,
|
|
289
|
+
24
|
|
334
290
|
];
|
|
335
291
|
|
|
336
292
|
const paddingBottomRight: [number, number] = [
|
|
337
|
-
|
|
338
|
-
bottomOffset.value
|
|
293
|
+
24,
|
|
294
|
+
bottomOffset.value + 24
|
|
339
295
|
];
|
|
340
296
|
const paddingOptions = {
|
|
341
297
|
paddingTopLeft,
|
|
@@ -353,14 +309,16 @@ export default defineComponent({
|
|
|
353
309
|
|
|
354
310
|
const mapOptions = {
|
|
355
311
|
zoomControl: false,
|
|
356
|
-
scrollWheelZoom: props.enableScrollWheelZoom,
|
|
312
|
+
scrollWheelZoom: props.enableScrollWheelZoom && !props.disabled,
|
|
313
|
+
dragging: !props.disabled,
|
|
314
|
+
doubleClickZoom: false,
|
|
357
315
|
minZoom: 2,
|
|
358
316
|
maxZoom: 22,
|
|
359
317
|
maxBounds: latLngBounds(latLng(-90, -180), latLng(90, 180)),
|
|
360
318
|
maxBoundsViscosity: 1.0,
|
|
361
|
-
zoom:
|
|
319
|
+
zoom: props.zoom,
|
|
362
320
|
center: props.center ? latLng(props.center[0], props.center[1]) : latLng(48.85782, 2.29521)
|
|
363
|
-
};
|
|
321
|
+
} satisfies L.MapOptions;
|
|
364
322
|
|
|
365
323
|
map.value = markRaw(createMap(leafletContainer.value, mapOptions));
|
|
366
324
|
|
|
@@ -368,6 +326,21 @@ export default defineComponent({
|
|
|
368
326
|
emit('click:latlng', e.latlng);
|
|
369
327
|
});
|
|
370
328
|
|
|
329
|
+
map.value.on('zoomend', () => {
|
|
330
|
+
if(!map.value) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
emit('update:zoom', map.value.getZoom());
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
map.value.on('moveend', () => {
|
|
337
|
+
if(!map.value) {
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const center = map.value.getCenter();
|
|
341
|
+
emit('update:center', [center.lat, center.lng]);
|
|
342
|
+
});
|
|
343
|
+
|
|
371
344
|
map.value.attributionControl.remove();
|
|
372
345
|
control.attribution({ position: 'bottomleft' }).addTo(map.value);
|
|
373
346
|
|
|
@@ -382,7 +355,7 @@ export default defineComponent({
|
|
|
382
355
|
return;
|
|
383
356
|
}
|
|
384
357
|
|
|
385
|
-
flyTo(e.latlng.lat, e.latlng.lng);
|
|
358
|
+
flyTo(e.latlng.lat, e.latlng.lng, 14);
|
|
386
359
|
});
|
|
387
360
|
|
|
388
361
|
mapResizeObserver.observe(leafletContainer.value);
|
|
@@ -392,38 +365,69 @@ export default defineComponent({
|
|
|
392
365
|
mapResizeObserver.disconnect();
|
|
393
366
|
});
|
|
394
367
|
|
|
395
|
-
watch ([() => props.center, () =>
|
|
396
|
-
if(!map.value || !props.center) {
|
|
368
|
+
watch ([() => props.center, () => props.zoom], ([newCenter, newZoom], [oldCenter, oldZoom]) => {
|
|
369
|
+
if(!map.value || !props.center || !newCenter) {
|
|
397
370
|
return;
|
|
398
371
|
}
|
|
399
|
-
|
|
372
|
+
|
|
373
|
+
if(map.value.getZoom() === newZoom && map.value.getCenter().equals(latLng(newCenter[0], newCenter[1]))) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if((newCenter[0] !== oldCenter?.[0] || newCenter[1] !== oldCenter?.[1]) && newZoom !== oldZoom) {
|
|
378
|
+
setView(newCenter[0], newCenter[1], newZoom);
|
|
379
|
+
}
|
|
380
|
+
else if ((newCenter[0] !== oldCenter?.[0] || newCenter[1] !== oldCenter?.[1])) {
|
|
381
|
+
setView(newCenter[0], newCenter[1], map.value.getZoom());
|
|
382
|
+
}
|
|
383
|
+
else if(newZoom !== oldZoom) {
|
|
384
|
+
map.value.setZoom(newZoom);
|
|
385
|
+
}
|
|
400
386
|
}, { immediate: true });
|
|
401
387
|
|
|
402
388
|
watch([() => props.bounds, () => map.value], () => {
|
|
403
389
|
if(!map.value || !props.bounds) {
|
|
404
390
|
return;
|
|
405
391
|
}
|
|
406
|
-
|
|
392
|
+
|
|
393
|
+
//console.log("Bounds changed", props.bounds);
|
|
394
|
+
fitBounds(props.bounds, { maxZoom: 14 });
|
|
407
395
|
});
|
|
408
396
|
|
|
409
|
-
watch(() => props.
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
397
|
+
watch(() => props.enableScrollWheelZoom, (newValue) => {
|
|
398
|
+
if(!map.value) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if(newValue) {
|
|
402
|
+
map.value.scrollWheelZoom.enable();
|
|
403
|
+
} else {
|
|
404
|
+
map.value.scrollWheelZoom.disable();
|
|
405
|
+
}
|
|
406
|
+
}, { immediate: true });
|
|
407
|
+
|
|
408
|
+
watch(() => props.disabled, (newValue) => {
|
|
409
|
+
if(!map.value) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
if(newValue) {
|
|
413
|
+
map.value.dragging.disable();
|
|
414
|
+
map.value.scrollWheelZoom.disable();
|
|
415
|
+
} else {
|
|
416
|
+
map.value.dragging.enable();
|
|
417
|
+
if(props.enableScrollWheelZoom) {
|
|
418
|
+
map.value.scrollWheelZoom.enable();
|
|
419
|
+
}
|
|
413
420
|
}
|
|
414
421
|
}, { immediate: true });
|
|
415
422
|
|
|
416
423
|
return {
|
|
417
424
|
ColorEnum,
|
|
418
|
-
defaultZoom,
|
|
419
425
|
leafletContainer,
|
|
420
|
-
locationGroupBounds,
|
|
421
426
|
overlayHeight,
|
|
422
427
|
overlayWidth,
|
|
423
|
-
areaGroupBounds,
|
|
424
428
|
map,
|
|
425
429
|
actualLayer,
|
|
426
|
-
|
|
430
|
+
layers,
|
|
427
431
|
gpsPosition,
|
|
428
432
|
style,
|
|
429
433
|
overlaySlots
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
-
import { inject, provide, ref, type Ref } from 'vue';
|
|
6
|
+
import { inject, provide, ref, type Ref, onUnmounted } from 'vue';
|
|
7
7
|
|
|
8
8
|
import { type Map, FeatureGroup } from 'leaflet';
|
|
9
9
|
import { MAP } from './keys';
|
|
@@ -46,6 +46,12 @@ export default {
|
|
|
46
46
|
emit("update:bounds", featureGroup.value.getBounds());
|
|
47
47
|
}
|
|
48
48
|
});
|
|
49
|
+
|
|
50
|
+
onUnmounted(() => {
|
|
51
|
+
if (map.value && map.value.hasLayer(featureGroup.value as unknown as FeatureGroup)) {
|
|
52
|
+
map.value.removeLayer(featureGroup.value as unknown as FeatureGroup);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
49
55
|
}
|
|
50
56
|
};
|
|
51
57
|
</script>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
-
import { inject, type PropType, onMounted, type Ref, watch, ref } from 'vue';
|
|
6
|
+
import { inject, type PropType, onMounted, type Ref, watch, ref, onUnmounted } from 'vue';
|
|
7
7
|
|
|
8
8
|
import { type Map, type DivIcon, divIcon, type LatLng, marker, type Marker, type MarkerClusterGroup } from 'leaflet';
|
|
9
9
|
|
|
@@ -112,9 +112,24 @@ export default {
|
|
|
112
112
|
}
|
|
113
113
|
};
|
|
114
114
|
|
|
115
|
-
onMounted(
|
|
115
|
+
onMounted(() => {
|
|
116
|
+
updateMarker();
|
|
117
|
+
});
|
|
116
118
|
|
|
117
|
-
|
|
119
|
+
onUnmounted(() => {
|
|
120
|
+
if(lastMarker.value && map.value) {
|
|
121
|
+
if(markerClusterGroup && markerClusterGroup.value) {
|
|
122
|
+
markerClusterGroup.value.removeLayer(lastMarker.value as Marker);
|
|
123
|
+
} else {
|
|
124
|
+
map.value.removeLayer(lastMarker.value as Marker);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
lastMarker.value = null;
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
watch([() => props.variant, () => props.color, () => props.latlng?.lat, () => props.latlng?.lng, () => props.selected],
|
|
131
|
+
updateMarker,
|
|
132
|
+
);
|
|
118
133
|
}
|
|
119
134
|
};
|
|
120
135
|
</script>
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
-
import { inject, provide, ref, type Ref } from 'vue';
|
|
6
|
+
import { inject, provide, ref, type Ref, onUnmounted } from 'vue';
|
|
7
7
|
|
|
8
|
-
import { type Map, MarkerClusterGroup, divIcon } from 'leaflet';
|
|
8
|
+
import { LatLngBounds, type Map, MarkerClusterGroup, divIcon } from 'leaflet';
|
|
9
9
|
|
|
10
10
|
import { clusterMarkerHtml } from '../../utils/leafletMarkers';
|
|
11
11
|
import { MAP } from './keys';
|
|
@@ -54,17 +54,39 @@ export default {
|
|
|
54
54
|
|
|
55
55
|
provide('markerClusterGroup', markerClusterGroup);
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
if(!map.value) {
|
|
57
|
+
const handleLayerChange = () => {
|
|
58
|
+
if (!map.value) {
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
-
|
|
62
61
|
const layers = markerClusterGroup.value.getLayers();
|
|
63
|
-
|
|
64
|
-
if(layers.length === props.expectedLayers && !added) {
|
|
62
|
+
if (layers.length === props.expectedLayers && !added) {
|
|
65
63
|
markerClusterGroup.value.addTo(map.value);
|
|
66
64
|
added = true;
|
|
67
|
-
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (layers.length === 0 && added) {
|
|
68
|
+
map.value.removeLayer(markerClusterGroup.value as unknown as L.Layer);
|
|
69
|
+
added = false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const bounds = new LatLngBounds([]);
|
|
73
|
+
for (const layer of layers as any[]) {
|
|
74
|
+
if (layer.getBounds) {
|
|
75
|
+
bounds.extend(layer.getBounds());
|
|
76
|
+
} else if (layer.getLatLng) {
|
|
77
|
+
bounds.extend(layer.getLatLng());
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
emit("update:bounds", layers.length > 0 ? bounds : null);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
markerClusterGroup.value.on("layeradd", handleLayerChange);
|
|
85
|
+
markerClusterGroup.value.on("layerremove", handleLayerChange);
|
|
86
|
+
|
|
87
|
+
onUnmounted(() => {
|
|
88
|
+
if (map.value && map.value.hasLayer(markerClusterGroup.value as unknown as L.Layer)) {
|
|
89
|
+
map.value.removeLayer(markerClusterGroup.value as unknown as L.Layer);
|
|
68
90
|
}
|
|
69
91
|
});
|
|
70
92
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
-
import { inject, type PropType, onMounted, type Ref, watch, ref } from 'vue';
|
|
6
|
+
import { inject, type PropType, onMounted, type Ref, watch, ref, onUnmounted } from 'vue';
|
|
7
7
|
|
|
8
8
|
import { type Map, type LatLng, type Polygon, type FeatureGroup, polygon } from 'leaflet';
|
|
9
9
|
|
|
@@ -75,7 +75,19 @@ export default {
|
|
|
75
75
|
|
|
76
76
|
onMounted(updatePolygon);
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
onUnmounted(() => {
|
|
79
|
+
if (lastPolygon.value) {
|
|
80
|
+
if (featureGroup?.value) {
|
|
81
|
+
featureGroup.value.removeLayer(lastPolygon.value);
|
|
82
|
+
} else if (map.value?.hasLayer(lastPolygon.value)) {
|
|
83
|
+
map.value.removeLayer(lastPolygon.value);
|
|
84
|
+
}
|
|
85
|
+
lastPolygon.value = null;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
watch([() => props.color, () => props.latlngs], updatePolygon);
|
|
79
91
|
}
|
|
80
92
|
};
|
|
81
93
|
</script>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
</template>
|
|
4
4
|
|
|
5
5
|
<script lang="ts">
|
|
6
|
-
import { inject, type PropType, onMounted, type Ref, watch } from 'vue';
|
|
6
|
+
import { inject, type PropType, onMounted, type Ref, watch, onUnmounted } from 'vue';
|
|
7
7
|
|
|
8
8
|
import type { Map, Layer } from 'leaflet';
|
|
9
9
|
|
|
@@ -50,6 +50,17 @@ export default {
|
|
|
50
50
|
|
|
51
51
|
onMounted(updateLayer);
|
|
52
52
|
|
|
53
|
+
onUnmounted(() => {
|
|
54
|
+
if (lastLayers && map.value) {
|
|
55
|
+
lastLayers.forEach(layer => {
|
|
56
|
+
if (map.value.hasLayer(layer)) {
|
|
57
|
+
map.value.removeLayer(layer);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
lastLayers = [];
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
53
64
|
watch(() => props.layers, updateLayer);
|
|
54
65
|
}
|
|
55
66
|
};
|
|
File without changes
|
package/composables/index.ts
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { tileLayer } from 'leaflet';
|
|
2
|
+
|
|
3
|
+
import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
|
|
4
|
+
|
|
5
|
+
import { MapLayers } from '@dative-gpi/foundation-shared-components/models';
|
|
6
|
+
|
|
7
|
+
export const useMapLayers = () => {
|
|
8
|
+
const { $tr } = useTranslationsProvider();
|
|
9
|
+
|
|
10
|
+
const apiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? "";
|
|
11
|
+
|
|
12
|
+
const layers = [
|
|
13
|
+
{
|
|
14
|
+
name: MapLayers.Map,
|
|
15
|
+
label: $tr("ui.map-layer.map", "Map"),
|
|
16
|
+
image: new URL("../../assets/images/map/map.png", import.meta.url).href,
|
|
17
|
+
layers: [
|
|
18
|
+
tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${apiKey}`, {
|
|
19
|
+
maxZoom: 22,
|
|
20
|
+
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
21
|
+
attribution: '© Google Map Data',
|
|
22
|
+
className: 'fs-map-tile-base-layer'
|
|
23
|
+
})
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: MapLayers.Imagery,
|
|
28
|
+
label: $tr("ui.map-layer.imagery", "Imagery"),
|
|
29
|
+
image: new URL("../../assets/images/map/imagery.png", import.meta.url).href,
|
|
30
|
+
layers: [
|
|
31
|
+
tileLayer(`https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}&key=${apiKey}`, {
|
|
32
|
+
maxZoom: 22,
|
|
33
|
+
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
34
|
+
attribution: '© Google Map Data',
|
|
35
|
+
className: 'fs-map-tile-base-layer'
|
|
36
|
+
})
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: MapLayers.Snow,
|
|
41
|
+
label: $tr("ui.map-layer.snow", "Snow ski map"),
|
|
42
|
+
image: new URL("../../assets/images/map/snow.png", import.meta.url).href,
|
|
43
|
+
layers: [
|
|
44
|
+
tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${apiKey}`, {
|
|
45
|
+
maxZoom: 22,
|
|
46
|
+
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
47
|
+
attribution: '© Google Map Data',
|
|
48
|
+
className: 'fs-map-tile-base-layer fs-map-tile-grayscale-layer'
|
|
49
|
+
}),
|
|
50
|
+
tileLayer(`https://tiles.opensnowmap.org/pistes/{z}/{x}/{y}.png`, {
|
|
51
|
+
maxZoom: 18,
|
|
52
|
+
attribution: 'Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors & ODbL, © <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>',
|
|
53
|
+
className: 'fs-map-tile-base-layer'
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
layers
|
|
61
|
+
};
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dative-gpi/foundation-shared-components",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.156",
|
|
5
5
|
"description": "",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"author": "",
|
|
11
11
|
"license": "ISC",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@dative-gpi/foundation-shared-domain": "1.0.
|
|
14
|
-
"@dative-gpi/foundation-shared-services": "1.0.
|
|
13
|
+
"@dative-gpi/foundation-shared-domain": "1.0.156",
|
|
14
|
+
"@dative-gpi/foundation-shared-services": "1.0.156"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
17
|
"@dative-gpi/bones-ui": "^1.0.0",
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"sass": "1.71.1",
|
|
36
36
|
"sass-loader": "13.3.2"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "d67f90e266b8ae583f46c82aec2dbd381c5d3629"
|
|
39
39
|
}
|