@dative-gpi/foundation-shared-components 1.0.137-maps2 → 1.0.137-maps3
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 +63 -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"
|
|
@@ -96,7 +96,7 @@ import { map as createMap, control, tileLayer, latLngBounds, latLng, type LatLng
|
|
|
96
96
|
import { useTranslations as useTranslationsProvider } from "@dative-gpi/bones-ui/composables";
|
|
97
97
|
|
|
98
98
|
import { useBreakpoints, useColors, useSlots } from "../../composables";
|
|
99
|
-
import { ColorEnum, type MapLayer } from "../../models";
|
|
99
|
+
import { ColorEnum, MapLayers, MapOverlayPositions, type MapLayer } from "../../models";
|
|
100
100
|
|
|
101
101
|
import FSMapLayerButton from "./FSMapLayerButton.vue";
|
|
102
102
|
import FSMapOverlay from "./FSMapOverlay.vue";
|
|
@@ -135,9 +135,9 @@ export default defineComponent({
|
|
|
135
135
|
default: false
|
|
136
136
|
},
|
|
137
137
|
overlayMode: {
|
|
138
|
-
type: String as PropType<
|
|
138
|
+
type: String as PropType<MapOverlayPositions>,
|
|
139
139
|
required: false,
|
|
140
|
-
default:
|
|
140
|
+
default: MapOverlayPositions.Collapse
|
|
141
141
|
},
|
|
142
142
|
showMyLocation: {
|
|
143
143
|
type: Boolean,
|
|
@@ -165,14 +165,19 @@ export default defineComponent({
|
|
|
165
165
|
default: null
|
|
166
166
|
},
|
|
167
167
|
currentLayer: {
|
|
168
|
-
type: String as PropType<
|
|
168
|
+
type: String as PropType<MapLayers>,
|
|
169
169
|
required: false,
|
|
170
|
-
default:
|
|
170
|
+
default: MapLayers.Map
|
|
171
171
|
},
|
|
172
172
|
allowedLayers: {
|
|
173
|
-
type: Array as PropType<
|
|
173
|
+
type: Array as PropType<MapLayers[]>,
|
|
174
174
|
required: false,
|
|
175
|
-
default: () => [
|
|
175
|
+
default: () => [MapLayers.Map, MapLayers.Imagery]
|
|
176
|
+
},
|
|
177
|
+
dirtyZoom: {
|
|
178
|
+
type: Number,
|
|
179
|
+
required: false,
|
|
180
|
+
default: 16
|
|
176
181
|
}
|
|
177
182
|
},
|
|
178
183
|
emits: ["update:modelValue", "update:selectedLocationId", "update:selectedAreaId", 'update:overlayMode', 'update:currentLayer', "click:latlng"],
|
|
@@ -192,7 +197,7 @@ export default defineComponent({
|
|
|
192
197
|
|
|
193
198
|
provide('map', map);
|
|
194
199
|
|
|
195
|
-
const defaultZoom =
|
|
200
|
+
const defaultZoom = ref(props.dirtyZoom);
|
|
196
201
|
const mapResizeObserver = new ResizeObserver(() => {
|
|
197
202
|
if(!map.value) {
|
|
198
203
|
return;
|
|
@@ -202,29 +207,53 @@ export default defineComponent({
|
|
|
202
207
|
|
|
203
208
|
const mapLayers: MapLayer[] = [
|
|
204
209
|
{
|
|
205
|
-
name:
|
|
210
|
+
name: MapLayers.Map,
|
|
206
211
|
label: $tr("ui.map-layer.map", "Map"),
|
|
207
212
|
image: new URL("../../assets/images/map/map.png", import.meta.url).href,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
+
layers: [
|
|
214
|
+
tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
|
|
215
|
+
maxZoom: 22,
|
|
216
|
+
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
217
|
+
attribution: '© Google Map Data',
|
|
218
|
+
className: 'fs-map-tile-base-layer'
|
|
219
|
+
})
|
|
220
|
+
]
|
|
213
221
|
},
|
|
214
222
|
{
|
|
215
|
-
name:
|
|
223
|
+
name: MapLayers.Imagery,
|
|
216
224
|
label: $tr("ui.map-layer.imagery", "Imagery"),
|
|
217
225
|
image: new URL("../../assets/images/map/imagery.png", import.meta.url).href,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
layers: [
|
|
227
|
+
tileLayer(`https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
|
|
228
|
+
maxZoom: 22,
|
|
229
|
+
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
230
|
+
attribution: '© Google Map Data',
|
|
231
|
+
className: 'fs-map-tile-base-layer'
|
|
232
|
+
})
|
|
233
|
+
]
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: MapLayers.Snow,
|
|
237
|
+
label: $tr("ui.map-layer.snow", "Snow ski map"),
|
|
238
|
+
image: new URL("../../assets/images/map/snow.png", import.meta.url).href,
|
|
239
|
+
layers: [
|
|
240
|
+
tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
|
|
241
|
+
maxZoom: 22,
|
|
242
|
+
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
|
243
|
+
attribution: '© Google Map Data',
|
|
244
|
+
className: 'fs-map-tile-base-layer fs-map-tile-grayscale-layer'
|
|
245
|
+
}),
|
|
246
|
+
tileLayer(`https://tiles.opensnowmap.org/pistes/{z}/{x}/{y}.png`, {
|
|
247
|
+
maxZoom: 18,
|
|
248
|
+
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>',
|
|
249
|
+
className: 'fs-map-tile-base-layer'
|
|
250
|
+
})
|
|
251
|
+
]
|
|
223
252
|
}
|
|
224
253
|
];
|
|
225
254
|
|
|
226
255
|
const bottomOffset = computed(() => {
|
|
227
|
-
if (props.overlayMode !==
|
|
256
|
+
if (props.overlayMode !== MapOverlayPositions.Expand && overlayHeight.value && isExtraSmall.value) {
|
|
228
257
|
return overlayHeight.value;
|
|
229
258
|
}
|
|
230
259
|
return 0;
|
|
@@ -246,7 +275,7 @@ export default defineComponent({
|
|
|
246
275
|
}));
|
|
247
276
|
|
|
248
277
|
const actualLayer = computed(() => {
|
|
249
|
-
return mapLayers.find((
|
|
278
|
+
return mapLayers.find((mapLayer) => mapLayer.name === props.currentLayer)?.layers ?? mapLayers[0].layers;
|
|
250
279
|
});
|
|
251
280
|
|
|
252
281
|
const overlaySlots = computed(() => {
|
|
@@ -265,7 +294,7 @@ export default defineComponent({
|
|
|
265
294
|
return map.value.unproject(targetPoint, zoom);
|
|
266
295
|
}
|
|
267
296
|
|
|
268
|
-
const flyTo = (lat: number, lng: number, zoom: number = defaultZoom, options?: ZoomPanOptions) => {
|
|
297
|
+
const flyTo = (lat: number, lng: number, zoom: number = defaultZoom.value, options?: ZoomPanOptions) => {
|
|
269
298
|
if(!map.value) {
|
|
270
299
|
return;
|
|
271
300
|
}
|
|
@@ -328,7 +357,7 @@ export default defineComponent({
|
|
|
328
357
|
maxZoom: 22,
|
|
329
358
|
maxBounds: latLngBounds(latLng(-90, -180), latLng(90, 180)),
|
|
330
359
|
maxBoundsViscosity: 1.0,
|
|
331
|
-
zoom:
|
|
360
|
+
zoom: defaultZoom.value,
|
|
332
361
|
center: props.center ? latLng(props.center[0], props.center[1]) : latLng(48.85782, 2.29521)
|
|
333
362
|
};
|
|
334
363
|
|
|
@@ -366,16 +395,23 @@ export default defineComponent({
|
|
|
366
395
|
if(!map.value || !props.center) {
|
|
367
396
|
return;
|
|
368
397
|
}
|
|
369
|
-
setView(props.center[0], props.center[1], defaultZoom);
|
|
398
|
+
setView(props.center[0], props.center[1], defaultZoom.value);
|
|
370
399
|
}, { immediate: true });
|
|
371
400
|
|
|
372
401
|
watch([() => props.bounds, () => map.value], () => {
|
|
373
402
|
if(!map.value || !props.bounds) {
|
|
374
403
|
return;
|
|
375
404
|
}
|
|
376
|
-
fitBounds(props.bounds, { maxZoom: defaultZoom });
|
|
405
|
+
fitBounds(props.bounds, { maxZoom: defaultZoom.value });
|
|
377
406
|
});
|
|
378
407
|
|
|
408
|
+
watch(() => props.dirtyZoom, (newZoom) => {
|
|
409
|
+
defaultZoom.value = newZoom;
|
|
410
|
+
if(map.value) {
|
|
411
|
+
map.value.setZoom(newZoom);
|
|
412
|
+
}
|
|
413
|
+
}, { immediate: true });
|
|
414
|
+
|
|
379
415
|
return {
|
|
380
416
|
ColorEnum,
|
|
381
417
|
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-maps3",
|
|
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-maps3",
|
|
14
|
+
"@dative-gpi/foundation-shared-services": "1.0.137-maps3"
|
|
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": "006cf58fb01a31192c9511ba0910b023d5ce060e"
|
|
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 {
|