@dative-gpi/foundation-shared-components 1.0.137-maps2 → 1.0.137-maps4
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/assets/images/map/snow.png +0 -0
- package/components/map/FSMap.vue +64 -27
- package/components/map/FSMapOverlay.vue +14 -11
- package/components/map/FSMapTileLayer.vue +14 -8
- package/components/selects/FSSelectMapLayer.vue +68 -0
- package/models/map.ts +14 -2
- package/package.json +4 -4
- package/styles/components/fs_map.scss +9 -1
|
Binary file
|
package/components/map/FSMap.vue
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
v-if="map"
|
|
15
15
|
>
|
|
16
16
|
<FSMapTileLayer
|
|
17
|
-
:
|
|
17
|
+
:layers="actualLayer"
|
|
18
18
|
/>
|
|
19
19
|
<FSMapMarker
|
|
20
20
|
v-if="gpsPosition"
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
</FSCol>
|
|
70
70
|
|
|
71
71
|
<FSMapOverlay
|
|
72
|
+
v-if="overlaySlots && Object.keys(overlaySlots).length"
|
|
72
73
|
:mode="$props.overlayMode"
|
|
73
74
|
@update:mode="$emit('update:overlayMode', $event)"
|
|
74
75
|
@update:height="(height) => overlayHeight = height"
|
|
@@ -96,7 +97,7 @@ import { map as createMap, control, tileLayer, latLngBounds, latLng, type LatLng
|
|
|
96
97
|
import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
|
|
97
98
|
|
|
98
99
|
import { useBreakpoints, useColors, useSlots } from "../../composables";
|
|
99
|
-
import { ColorEnum, type MapLayer } from "../../models";
|
|
100
|
+
import { ColorEnum, MapLayers, MapOverlayPositions, type MapLayer } from "../../models";
|
|
100
101
|
|
|
101
102
|
import FSMapLayerButton from "./FSMapLayerButton.vue";
|
|
102
103
|
import FSMapOverlay from "./FSMapOverlay.vue";
|
|
@@ -135,9 +136,9 @@ export default defineComponent({
|
|
|
135
136
|
default: false
|
|
136
137
|
},
|
|
137
138
|
overlayMode: {
|
|
138
|
-
type: String as PropType<
|
|
139
|
+
type: String as PropType<MapOverlayPositions>,
|
|
139
140
|
required: false,
|
|
140
|
-
default:
|
|
141
|
+
default: MapOverlayPositions.Collapse
|
|
141
142
|
},
|
|
142
143
|
showMyLocation: {
|
|
143
144
|
type: Boolean,
|
|
@@ -165,14 +166,19 @@ export default defineComponent({
|
|
|
165
166
|
default: null
|
|
166
167
|
},
|
|
167
168
|
currentLayer: {
|
|
168
|
-
type: String as PropType<
|
|
169
|
+
type: String as PropType<MapLayers>,
|
|
169
170
|
required: false,
|
|
170
|
-
default:
|
|
171
|
+
default: MapLayers.Map
|
|
171
172
|
},
|
|
172
173
|
allowedLayers: {
|
|
173
|
-
type: Array as PropType<
|
|
174
|
+
type: Array as PropType<MapLayers[]>,
|
|
174
175
|
required: false,
|
|
175
|
-
default: () => [
|
|
176
|
+
default: () => [MapLayers.Map, MapLayers.Imagery]
|
|
177
|
+
},
|
|
178
|
+
dirtyZoom: {
|
|
179
|
+
type: Number,
|
|
180
|
+
required: false,
|
|
181
|
+
default: 16
|
|
176
182
|
}
|
|
177
183
|
},
|
|
178
184
|
emits: ["update:modelValue", "update:selectedLocationId", "update:selectedAreaId", 'update:overlayMode', 'update:currentLayer', "click:latlng"],
|
|
@@ -192,7 +198,7 @@ export default defineComponent({
|
|
|
192
198
|
|
|
193
199
|
provide('map', map);
|
|
194
200
|
|
|
195
|
-
const defaultZoom =
|
|
201
|
+
const defaultZoom = ref(props.dirtyZoom);
|
|
196
202
|
const mapResizeObserver = new ResizeObserver(() => {
|
|
197
203
|
if(!map.value) {
|
|
198
204
|
return;
|
|
@@ -202,29 +208,53 @@ export default defineComponent({
|
|
|
202
208
|
|
|
203
209
|
const mapLayers: MapLayer[] = [
|
|
204
210
|
{
|
|
205
|
-
name:
|
|
211
|
+
name: MapLayers.Map,
|
|
206
212
|
label: $tr("ui.map-layer.map", "Map"),
|
|
207
213
|
image: new URL("../../assets/images/map/map.png", import.meta.url).href,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
+
]
|
|
213
222
|
},
|
|
214
223
|
{
|
|
215
|
-
name:
|
|
224
|
+
name: MapLayers.Imagery,
|
|
216
225
|
label: $tr("ui.map-layer.imagery", "Imagery"),
|
|
217
226
|
image: new URL("../../assets/images/map/imagery.png", import.meta.url).href,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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
|
+
]
|
|
223
253
|
}
|
|
224
254
|
];
|
|
225
255
|
|
|
226
256
|
const bottomOffset = computed(() => {
|
|
227
|
-
if (props.overlayMode !==
|
|
257
|
+
if (props.overlayMode !== MapOverlayPositions.Expand && overlayHeight.value && isExtraSmall.value) {
|
|
228
258
|
return overlayHeight.value;
|
|
229
259
|
}
|
|
230
260
|
return 0;
|
|
@@ -246,7 +276,7 @@ export default defineComponent({
|
|
|
246
276
|
}));
|
|
247
277
|
|
|
248
278
|
const actualLayer = computed(() => {
|
|
249
|
-
return mapLayers.find((
|
|
279
|
+
return mapLayers.find((mapLayer) => mapLayer.name === props.currentLayer)?.layers ?? mapLayers[0].layers;
|
|
250
280
|
});
|
|
251
281
|
|
|
252
282
|
const overlaySlots = computed(() => {
|
|
@@ -265,7 +295,7 @@ export default defineComponent({
|
|
|
265
295
|
return map.value.unproject(targetPoint, zoom);
|
|
266
296
|
}
|
|
267
297
|
|
|
268
|
-
const flyTo = (lat: number, lng: number, zoom: number = defaultZoom, options?: ZoomPanOptions) => {
|
|
298
|
+
const flyTo = (lat: number, lng: number, zoom: number = defaultZoom.value, options?: ZoomPanOptions) => {
|
|
269
299
|
if(!map.value) {
|
|
270
300
|
return;
|
|
271
301
|
}
|
|
@@ -328,7 +358,7 @@ export default defineComponent({
|
|
|
328
358
|
maxZoom: 22,
|
|
329
359
|
maxBounds: latLngBounds(latLng(-90, -180), latLng(90, 180)),
|
|
330
360
|
maxBoundsViscosity: 1.0,
|
|
331
|
-
zoom:
|
|
361
|
+
zoom: defaultZoom.value,
|
|
332
362
|
center: props.center ? latLng(props.center[0], props.center[1]) : latLng(48.85782, 2.29521)
|
|
333
363
|
};
|
|
334
364
|
|
|
@@ -366,16 +396,23 @@ export default defineComponent({
|
|
|
366
396
|
if(!map.value || !props.center) {
|
|
367
397
|
return;
|
|
368
398
|
}
|
|
369
|
-
setView(props.center[0], props.center[1], defaultZoom);
|
|
399
|
+
setView(props.center[0], props.center[1], defaultZoom.value);
|
|
370
400
|
}, { immediate: true });
|
|
371
401
|
|
|
372
402
|
watch([() => props.bounds, () => map.value], () => {
|
|
373
403
|
if(!map.value || !props.bounds) {
|
|
374
404
|
return;
|
|
375
405
|
}
|
|
376
|
-
fitBounds(props.bounds, { maxZoom: defaultZoom });
|
|
406
|
+
fitBounds(props.bounds, { maxZoom: defaultZoom.value });
|
|
377
407
|
});
|
|
378
408
|
|
|
409
|
+
watch(() => props.dirtyZoom, (newZoom) => {
|
|
410
|
+
defaultZoom.value = newZoom;
|
|
411
|
+
if(map.value) {
|
|
412
|
+
map.value.setZoom(newZoom);
|
|
413
|
+
}
|
|
414
|
+
}, { immediate: true });
|
|
415
|
+
|
|
379
416
|
return {
|
|
380
417
|
ColorEnum,
|
|
381
418
|
defaultZoom,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-overlay
|
|
3
3
|
v-if="isExtraSmall"
|
|
4
|
-
:modelValue="$props.mode ===
|
|
4
|
+
:modelValue="$props.mode === MapOverlayPositions.Expand"
|
|
5
5
|
:contained="true"
|
|
6
|
-
@click="$emit('update:mode',
|
|
6
|
+
@click="$emit('update:mode', MapOverlayPositions.Collapse)"
|
|
7
7
|
zIndex="0"
|
|
8
8
|
/>
|
|
9
9
|
<div
|
|
10
10
|
v-show="isExtraSmall"
|
|
11
11
|
ref="mobileOverlayWrapper"
|
|
12
12
|
class="fs-map-overlay-mobile"
|
|
13
|
-
:style="{ height: $props.mode ===
|
|
13
|
+
:style="{ height: $props.mode === MapOverlayPositions.Expand ? '90%' : ($props.mode === MapOverlayPositions.Half ? '60%' : 'auto') }"
|
|
14
14
|
>
|
|
15
15
|
<FSCard
|
|
16
16
|
width="100%"
|
|
@@ -29,15 +29,15 @@
|
|
|
29
29
|
@mousedown="onClick"
|
|
30
30
|
>
|
|
31
31
|
<FSIcon>
|
|
32
|
-
{{ $props.mode ===
|
|
32
|
+
{{ $props.mode === MapOverlayPositions.Expand ? 'mdi-chevron-down' : 'mdi-chevron-up' }}
|
|
33
33
|
</FSIcon>
|
|
34
34
|
</FSRow>
|
|
35
35
|
<slot
|
|
36
|
-
v-if="$props.mode ===
|
|
36
|
+
v-if="$props.mode === MapOverlayPositions.Collapse"
|
|
37
37
|
name="collapsed"
|
|
38
38
|
/>
|
|
39
39
|
<FSCol
|
|
40
|
-
v-if="$props.mode !==
|
|
40
|
+
v-if="$props.mode !== MapOverlayPositions.Collapse"
|
|
41
41
|
height="fill"
|
|
42
42
|
style="min-height: 0;"
|
|
43
43
|
>
|
|
@@ -70,6 +70,8 @@ import { defineComponent, type PropType, onUnmounted, onMounted, ref } from "vue
|
|
|
70
70
|
|
|
71
71
|
import { useBreakpoints } from "../../composables";
|
|
72
72
|
|
|
73
|
+
import { MapOverlayPositions } from '@dative-gpi/foundation-shared-components/models';
|
|
74
|
+
|
|
73
75
|
import FSCard from "../FSCard.vue";
|
|
74
76
|
import FSIcon from "../FSIcon.vue";
|
|
75
77
|
import FSCol from "../FSCol.vue";
|
|
@@ -85,9 +87,9 @@ export default defineComponent({
|
|
|
85
87
|
},
|
|
86
88
|
props: {
|
|
87
89
|
mode: {
|
|
88
|
-
type: String as PropType<
|
|
90
|
+
type: String as PropType<MapOverlayPositions>,
|
|
89
91
|
required: false,
|
|
90
|
-
default:
|
|
92
|
+
default: MapOverlayPositions.Collapse
|
|
91
93
|
}
|
|
92
94
|
},
|
|
93
95
|
emits: ["update:mode", "update:height", "update:width"],
|
|
@@ -101,11 +103,11 @@ export default defineComponent({
|
|
|
101
103
|
const desktopResizeObserver = ref<ResizeObserver | null>(null);
|
|
102
104
|
|
|
103
105
|
const onClick = (): void => {
|
|
104
|
-
if (props.mode ===
|
|
105
|
-
emit("update:mode",
|
|
106
|
+
if (props.mode === MapOverlayPositions.Expand) {
|
|
107
|
+
emit("update:mode", MapOverlayPositions.Collapse);
|
|
106
108
|
return;
|
|
107
109
|
}
|
|
108
|
-
emit("update:mode",
|
|
110
|
+
emit("update:mode", MapOverlayPositions.Expand);
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
onMounted(() => {
|
|
@@ -144,6 +146,7 @@ export default defineComponent({
|
|
|
144
146
|
return {
|
|
145
147
|
mobileOverlayWrapper,
|
|
146
148
|
isTouchScreenEnabled,
|
|
149
|
+
MapOverlayPositions,
|
|
147
150
|
desktopOverlay,
|
|
148
151
|
isExtraSmall,
|
|
149
152
|
onClick
|
|
@@ -12,15 +12,15 @@ import { MAP } from './keys';
|
|
|
12
12
|
export default {
|
|
13
13
|
name: 'FSMapTileLayer',
|
|
14
14
|
props: {
|
|
15
|
-
|
|
16
|
-
type: Object as PropType<Layer>,
|
|
15
|
+
layers: {
|
|
16
|
+
type: Object as PropType<Layer[]>,
|
|
17
17
|
required: false
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
setup(props) {
|
|
21
21
|
const map = inject<Ref<Map | null>>(MAP);
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
let lastLayers = props.layers;
|
|
24
24
|
|
|
25
25
|
if(!map) {
|
|
26
26
|
throw new Error('FSMapTileLayer must be used inside a FSMap component');
|
|
@@ -31,20 +31,26 @@ export default {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const updateLayer = () => {
|
|
34
|
-
if (!props.
|
|
34
|
+
if (!props.layers || !map.value) {
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
if(
|
|
39
|
-
|
|
38
|
+
if(lastLayers) {
|
|
39
|
+
lastLayers.forEach(layer => {
|
|
40
|
+
layer.removeFrom(map.value!);
|
|
41
|
+
});
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
lastLayers = [];
|
|
45
|
+
|
|
46
|
+
props.layers.forEach(layer => {
|
|
47
|
+
lastLayers?.push(layer.addTo(map.value!));
|
|
48
|
+
});
|
|
43
49
|
};
|
|
44
50
|
|
|
45
51
|
onMounted(updateLayer);
|
|
46
52
|
|
|
47
|
-
watch(() => props.
|
|
53
|
+
watch(() => props.layers, updateLayer);
|
|
48
54
|
}
|
|
49
55
|
};
|
|
50
56
|
</script>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<FSSelectField
|
|
3
|
+
:items="items"
|
|
4
|
+
:modelValue="$props.modelValue"
|
|
5
|
+
@update:modelValue="$emit('update:modelValue', $event)"
|
|
6
|
+
v-bind="$attrs"
|
|
7
|
+
>
|
|
8
|
+
<template
|
|
9
|
+
#item-prepend="{ item }"
|
|
10
|
+
>
|
|
11
|
+
<FSIcon
|
|
12
|
+
:icon="item.icon"
|
|
13
|
+
/>
|
|
14
|
+
</template>
|
|
15
|
+
</FSSelectField>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script lang="ts">
|
|
19
|
+
import type { PropType} from "vue";
|
|
20
|
+
import { defineComponent } from "vue";
|
|
21
|
+
|
|
22
|
+
import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
|
|
23
|
+
|
|
24
|
+
import { MapLayers } from '@dative-gpi/foundation-shared-components/models';
|
|
25
|
+
|
|
26
|
+
import FSSelectField from "../fields/FSSelectField.vue";
|
|
27
|
+
import FSIcon from '@dative-gpi/foundation-shared-components/components/FSIcon.vue';
|
|
28
|
+
|
|
29
|
+
export default defineComponent({
|
|
30
|
+
name: "FSSelectMapLayer",
|
|
31
|
+
components: {
|
|
32
|
+
FSIcon,
|
|
33
|
+
FSSelectField
|
|
34
|
+
},
|
|
35
|
+
props: {
|
|
36
|
+
modelValue: {
|
|
37
|
+
type: [String, Array] as PropType<MapLayers | MapLayers[]>,
|
|
38
|
+
required: false
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
emits: ["update:modelValue"],
|
|
42
|
+
setup() {
|
|
43
|
+
const { $tr } = useTranslationsProvider();
|
|
44
|
+
|
|
45
|
+
const items = [
|
|
46
|
+
{
|
|
47
|
+
id: MapLayers.Map,
|
|
48
|
+
icon: 'mdi-map',
|
|
49
|
+
label: $tr("ui.map-layer.map", "Map")
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: MapLayers.Imagery,
|
|
53
|
+
icon: 'mdi-satellite',
|
|
54
|
+
label: $tr("ui.map-layer.imagery", "Imagery")
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: MapLayers.Snow,
|
|
58
|
+
icon: 'mdi-snowflake',
|
|
59
|
+
label: $tr("ui.map-layer.snow", "Snow ski map")
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
items
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
</script>
|
package/models/map.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
import { type Layer } from "leaflet";
|
|
2
2
|
|
|
3
3
|
export interface MapLayer {
|
|
4
|
-
name :
|
|
4
|
+
name : MapLayers;
|
|
5
5
|
label: string;
|
|
6
6
|
image: string;
|
|
7
|
-
|
|
7
|
+
layers: Layer[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum MapLayers {
|
|
11
|
+
Map = "map",
|
|
12
|
+
Imagery = "imagery",
|
|
13
|
+
Snow= "snow"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum MapOverlayPositions {
|
|
17
|
+
Expand = "expand",
|
|
18
|
+
Half = "half",
|
|
19
|
+
Collapse = "collapse",
|
|
8
20
|
}
|
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.137-
|
|
4
|
+
"version": "1.0.137-maps4",
|
|
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.137-
|
|
14
|
-
"@dative-gpi/foundation-shared-services": "1.0.137-
|
|
13
|
+
"@dative-gpi/foundation-shared-domain": "1.0.137-maps4",
|
|
14
|
+
"@dative-gpi/foundation-shared-services": "1.0.137-maps4"
|
|
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": "2ff4d8aa1783b9f845daae1e8e6c9b9d23820b72"
|
|
39
39
|
}
|
|
@@ -6,7 +6,15 @@
|
|
|
6
6
|
.fs-leaflet-container {
|
|
7
7
|
width: 100%;
|
|
8
8
|
height: 100%;
|
|
9
|
-
|
|
9
|
+
z-index: 0;
|
|
10
|
+
|
|
11
|
+
.fs-map-tile-base-layer {
|
|
12
|
+
filter: grayscale(var(--fs-map-container-grayscale));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.fs-map-tile-grayscale-layer {
|
|
16
|
+
filter: grayscale(100%);
|
|
17
|
+
}
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
.fs-map-overlay-mobile {
|