@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.
Binary file
@@ -14,7 +14,7 @@
14
14
  v-if="map"
15
15
  >
16
16
  <FSMapTileLayer
17
- :layer="actualLayer"
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<'collapse' | 'half' | 'expand'>,
138
+ type: String as PropType<MapOverlayPositions>,
139
139
  required: false,
140
- default: 'collapse'
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<"map" | "imagery">,
168
+ type: String as PropType<MapLayers>,
169
169
  required: false,
170
- default: "map"
170
+ default: MapLayers.Map
171
171
  },
172
172
  allowedLayers: {
173
- type: Array as PropType<string[]>,
173
+ type: Array as PropType<MapLayers[]>,
174
174
  required: false,
175
- default: () => ["map", "imagery"]
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 = 16;
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: "map",
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
- layer: tileLayer(`https://{s}.google.com/vt/lyrs=m&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
209
- maxZoom: 22,
210
- subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
211
- attribution: '© Google Map Data'
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: "imagery",
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
- layer: tileLayer(`https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}&key=${import.meta.env.VITE_GOOGLE_MAPS_API_KEY ?? ""}`, {
219
- maxZoom: 22,
220
- subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
221
- attribution: '© Google Map Data'
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: &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors & ODbL, &copy; <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 !== 'expand' && overlayHeight.value && isExtraSmall.value) {
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((layer) => layer.name === props.currentLayer)?.layer ?? mapLayers[0].layer;
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: 5,
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 === 'expand'"
4
+ :modelValue="$props.mode === MapOverlayPositions.Expand"
5
5
  :contained="true"
6
- @click="$emit('update:mode', 'collapse')"
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 === 'expand' ? '90%' : ($props.mode === 'half' ? '60%' : 'auto') }"
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 === 'expand' ? 'mdi-chevron-down' : 'mdi-chevron-up' }}
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 === 'collapse'"
36
+ v-if="$props.mode === MapOverlayPositions.Collapse"
37
37
  name="collapsed"
38
38
  />
39
39
  <FSCol
40
- v-if="$props.mode !== 'collapse'"
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<"collapse" | "half" | "expand">,
90
+ type: String as PropType<MapOverlayPositions>,
89
91
  required: false,
90
- default: "collapse"
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 === "expand") {
105
- emit("update:mode", "collapse");
106
+ if (props.mode === MapOverlayPositions.Expand) {
107
+ emit("update:mode", MapOverlayPositions.Collapse);
106
108
  return;
107
109
  }
108
- emit("update:mode", "expand");
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
- layer: {
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
- const lastLayer = props.layer;
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.layer || !map.value) {
34
+ if (!props.layers || !map.value) {
35
35
  return;
36
36
  }
37
37
 
38
- if(lastLayer) {
39
- map.value.removeLayer(lastLayer);
38
+ if(lastLayers) {
39
+ lastLayers.forEach(layer => {
40
+ layer.removeFrom(map.value!);
41
+ });
40
42
  }
41
43
 
42
- props.layer.addTo(map.value);
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.layer, updateLayer);
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 : string;
4
+ name : MapLayers;
5
5
  label: string;
6
6
  image: string;
7
- layer: Layer;
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-maps2",
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-maps2",
14
- "@dative-gpi/foundation-shared-services": "1.0.137-maps2"
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": "0e9da9645c2c83684220f99135cf12e4c339897c"
38
+ "gitHead": "006cf58fb01a31192c9511ba0910b023d5ce060e"
39
39
  }
@@ -6,7 +6,15 @@
6
6
  .fs-leaflet-container {
7
7
  width: 100%;
8
8
  height: 100%;
9
- filter: grayscale(var(--fs-map-container-grayscale));
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 {