alessandro trinca tornidor commited on
Commit
c92d24c
1 Parent(s): 7d48fbe

[feat] add support for locking map during ML inference

Browse files
static/package.json CHANGED
@@ -1,10 +1,8 @@
1
  {
2
- "name": "ml-trinca",
3
- "version": "1.1.0",
4
- "license": "Apache-2.0",
5
  "scripts": {
6
  "dev": "vite",
7
- "dev_4040": "vite --host 0.0.0.0 --port 4040",
8
  "build": "vite build",
9
  "preview": "vite preview --port 5173",
10
  "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
@@ -12,27 +10,24 @@
12
  "type": "module",
13
  "dependencies": {
14
  "@geoman-io/leaflet-geoman-free": "^2.16.0",
15
- "driver.js": "github:trincadev/driver.js",
16
  "leaflet": "^1.9.4",
17
  "leaflet-providers": "^2.0.0",
18
- "vue": "^3.4.21",
19
- "vue-router": "^4.3.0"
20
  },
21
  "devDependencies": {
22
- "@headlessui/vue": "^1.7.19",
23
- "@heroicons/vue": "^2.1.3",
24
  "@tsconfig/node20": "^20.1.4",
25
- "@types/leaflet": "^1.9.9",
26
- "@types/node": "^20.12.5",
27
  "@vitejs/plugin-vue": "^5.0.4",
28
  "@vue/tsconfig": "^0.5.1",
29
  "autoprefixer": "^10.4.19",
30
- "eslint": "^9.0.0",
31
- "eslint-plugin-vue": "^9.24.0",
32
  "postcss": "^8.4.38",
33
  "postcss-import": "^16.1.0",
34
  "prettier": "^3.2.5",
35
  "tailwindcss": "^3.4.3",
36
- "vite": "^5.2.8"
37
  }
38
  }
 
1
  {
2
+ "name": "samgis-fe",
3
+ "private": true,
 
4
  "scripts": {
5
  "dev": "vite",
 
6
  "build": "vite build",
7
  "preview": "vite preview --port 5173",
8
  "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
 
10
  "type": "module",
11
  "dependencies": {
12
  "@geoman-io/leaflet-geoman-free": "^2.16.0",
13
+ "@trincadev/driver.js": "https://github.com/trincadev/driver.js/archive/refs/tags/1.3.1.1-trincadev.tar.gz",
14
  "leaflet": "^1.9.4",
15
  "leaflet-providers": "^2.0.0",
16
+ "vue": "^3.4.23"
 
17
  },
18
  "devDependencies": {
 
 
19
  "@tsconfig/node20": "^20.1.4",
20
+ "@types/leaflet": "^1.9.11",
21
+ "@types/node": "^20.12.7",
22
  "@vitejs/plugin-vue": "^5.0.4",
23
  "@vue/tsconfig": "^0.5.1",
24
  "autoprefixer": "^10.4.19",
25
+ "eslint": "^9.1.0",
26
+ "eslint-plugin-vue": "^9.25.0",
27
  "postcss": "^8.4.38",
28
  "postcss-import": "^16.1.0",
29
  "prettier": "^3.2.5",
30
  "tailwindcss": "^3.4.3",
31
+ "vite": "^5.2.10"
32
  }
33
  }
static/pnpm-lock.yaml CHANGED
The diff for this file is too large to render. See raw diff
 
static/src/AppLisa.vue CHANGED
@@ -1,7 +1,7 @@
1
  <template>
2
  <PageLayout pageTitle="SamGIS with LISA - Inference map page">
3
  <div>
4
- <div id="map-container-md">
5
  <PageLisaMap :mapName="mapName"
6
  :mapBounds='[
7
  { "lat": 46.172594687922256, "lng": 10.079248798586057 },
@@ -21,4 +21,5 @@ import PageLayout from '@/components/PageLayout.vue'
21
 
22
  const mapName = ref('lisa-map')
23
  const description = ref("This page displays predictions made with LISA VLM.")
 
24
  </script>
 
1
  <template>
2
  <PageLayout pageTitle="SamGIS with LISA - Inference map page">
3
  <div>
4
+ <div id="map-container-md-lisa">
5
  <PageLisaMap :mapName="mapName"
6
  :mapBounds='[
7
  { "lat": 46.172594687922256, "lng": 10.079248798586057 },
 
21
 
22
  const mapName = ref('lisa-map')
23
  const description = ref("This page displays predictions made with LISA VLM.")
24
+ console.log("lisa")
25
  </script>
static/src/AppMain.vue CHANGED
@@ -1,7 +1,7 @@
1
  <template>
2
  <PageLayout pageTitle="SamGIS - Inference map page">
3
  <div>
4
- <div id="map-container-md">
5
  <PredictionMap
6
  :mapName="mapName"
7
  :mapBounds='[{
 
1
  <template>
2
  <PageLayout pageTitle="SamGIS - Inference map page">
3
  <div>
4
+ <div id="map-container-md-main">
5
  <PredictionMap
6
  :mapName="mapName"
7
  :mapBounds='[{
static/src/components/NavBar/NavBar.vue CHANGED
@@ -1,8 +1,8 @@
1
  <template>
2
  <div class="fixed top-2 right-5 mr-2 items-center">
3
  <TabComponent description="About SamGIS" href="https://trinca.tornidor.com/projects/samgis-segment-anything-applied-to-GIS" />
4
- <TabComponent description="My blog" href="https://trinca.tornidor.com/" />
5
- <TabComponent description="SamGIS docs" href="https://docs.ml-trinca.tornidor.com/" />
6
  </div>
7
  </template>
8
 
 
1
  <template>
2
  <div class="fixed top-2 right-5 mr-2 items-center">
3
  <TabComponent description="About SamGIS" href="https://trinca.tornidor.com/projects/samgis-segment-anything-applied-to-GIS" />
4
+ <TabComponent description="blog" href="https://trinca.tornidor.com/" />
5
+ <TabComponent description="docs" href="https://docs.ml-trinca.tornidor.com/" />
6
  </div>
7
  </template>
8
 
static/src/components/PageLisaMap.vue CHANGED
@@ -5,39 +5,40 @@
5
 
6
  <div class="lg:border-r lg:col-span-3">
7
  <div id="id-map-cont" class="">
8
-
9
- <details id="detail-prompt-examples-array" :open="detailIsOpenRef">
10
-
11
- <summary><i>Expand this detail element for some prompt examples</i></summary>
12
- <div class="grid grid-cols-1 md:grid-cols-3" id="prompt-examples-array">
13
- <div class="text-xs font-extralight flex bg-green-200">
14
- <textarea
15
- id="prompt-text-placeholder"
16
- v-model="promptTextPlaceholderRef"
17
- class="p-2 border-2 border-indigo-500/100 w-full"
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  />
19
  </div>
20
- <StringArray
21
- :string-array="promptTextArray"
22
- :string-prefix="promptTextPlaceholderRef"
23
- @set-prompt="(stringPrompt: string) => promptTextRef = stringPrompt"
24
- />
25
- </div>
26
 
27
- </details>
 
28
 
29
- <div class="flex">
30
- <textarea
31
- id="prompt-text-llm-ref"
32
- v-model="promptTextRef"
33
- :placeholder=promptTextPlaceholderRef
34
- rows="2"
35
- class="w-full md:pt-1 md:pb-1 flex border-2 mt-2 mb-2 mr-2 border-indigo-500/100"
36
- ></textarea>
37
- <div class="w-full md:pt-1 md:pb-1 flex">
38
  <ButtonMapSendStringRequest
39
  id="id-button-submit"
40
- class="h-8 mt-2 text-sm font-extralight min-w-[180px] max-w-[180px]"
41
  :current-base-map-name="currentBaseMapNameRef"
42
  :map="map"
43
  :promptText="promptTextRef"
@@ -46,7 +47,13 @@
46
  :waiting-string="waitingString"
47
  />
48
  </div>
49
-
 
 
 
 
 
 
50
  </div>
51
 
52
  <div id="map" class="map-predictions"/>
@@ -96,11 +103,14 @@ import {
96
  TileLayer as LTileLayer
97
  } from 'leaflet'
98
  import 'leaflet-providers'
99
- import {onMounted, ref, type Ref} from 'vue'
100
- import {driver} from "../../node_modules/driver.js/src/driver"
 
101
 
102
  import {
103
  durationRef,
 
 
104
  numberOfPolygonsRef,
105
  numberOfPredictedMasksRef,
106
  OpenStreetMap,
@@ -197,6 +207,7 @@ const currentZoomRef = ref()
197
  const promptTextRef: Ref<string> = ref("")
198
  const promptTextPlaceholderRef: Ref<string> = ref(promptPlaceHolder)
199
  const detailIsOpenRef: Ref<boolean> = ref(false)
 
200
  let map: LMap
201
  type ServiceTiles = {
202
  [key: SourceTileType]: LTileLayer;
@@ -224,6 +235,7 @@ const getPopupContentPoint = (leafletEvent: LEvented, label: number): HTMLDivEle
224
  }
225
 
226
  const sendMLStringRequest = async (leafletMap: LMap, promptRequest: string, sourceType: SourceTileType = OpenStreetMap) => {
 
227
  const bodyRequest: IBodyLatLngWithStringPoints = {
228
  bbox: getExtentCurrentViewMapBBox(leafletMap),
229
  string_prompt: promptRequest,
@@ -277,7 +289,9 @@ onMounted(async () => {
277
  currentBaseMapNameRef.value = OpenStreetMap
278
 
279
  map = LeafletMap('map', {
280
- layers: [osmTile]
 
 
281
  })
282
  map.fitBounds(props.mapBounds)
283
  map.attributionControl.setPrefix(prefix)
@@ -301,5 +315,23 @@ onMounted(async () => {
301
 
302
  lisaDriverObj.drive();
303
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  </script>
305
 
 
5
 
6
  <div class="lg:border-r lg:col-span-3">
7
  <div id="id-map-cont" class="">
8
+ <div class="flex">
9
+ <span class="ml-2">
10
+ <input type="checkbox" id="checkboxMapNavigationLocked" v-model="mapNavigationLocked" />
11
+ <span class="ml-2">
12
+ <label class="text-red-600" for="checkboxMapNavigationLocked" v-if="mapNavigationLocked">locked map navigation!</label>
13
+ <label class="text-blue-600" for="checkboxMapNavigationLocked" v-else>map navigation unlocked</label>
14
+ </span>
15
+ </span>
16
+ <details id="detail-prompt-examples-array" :open="detailIsOpenRef" class="ml-2">
17
+
18
+ <summary><i>prompt examples here</i></summary>
19
+ <div class="grid grid-cols-1 md:grid-cols-3" id="prompt-examples-array">
20
+ <div class="text-xs font-extralight flex bg-green-200">
21
+ <textarea
22
+ id="prompt-text-placeholder"
23
+ v-model="promptTextPlaceholderRef"
24
+ class="p-2 border-2 border-indigo-500/100 w-full"
25
+ />
26
+ </div>
27
+ <StringArray
28
+ :string-array="promptTextArray"
29
+ :string-prefix="promptTextPlaceholderRef"
30
+ @set-prompt="(stringPrompt: string) => promptTextRef = stringPrompt"
31
  />
32
  </div>
 
 
 
 
 
 
33
 
34
+ </details>
35
+ </div>
36
 
37
+ <div class="flex w-full lg:w-2/3">
38
+ <div class="md:pt-1 md:pb-1 md:mr-1 mr-2">
 
 
 
 
 
 
 
39
  <ButtonMapSendStringRequest
40
  id="id-button-submit"
41
+ class="w-full h-8 mt-2 text-sm font-extralight min-w-[180px] max-w-[180px]"
42
  :current-base-map-name="currentBaseMapNameRef"
43
  :map="map"
44
  :promptText="promptTextRef"
 
47
  :waiting-string="waitingString"
48
  />
49
  </div>
50
+ <textarea
51
+ id="prompt-text-llm-ref"
52
+ v-model="promptTextRef"
53
+ :placeholder=promptTextPlaceholderRef
54
+ rows="2"
55
+ class="w-full md:pt-1 md:pb-1 border-2 mt-2 mb-2 mr-2 border-indigo-500/100"
56
+ ></textarea>
57
  </div>
58
 
59
  <div id="map" class="map-predictions"/>
 
103
  TileLayer as LTileLayer
104
  } from 'leaflet'
105
  import 'leaflet-providers'
106
+ import { onMounted, onUpdated, ref, type Ref } from 'vue'
107
+ // workaround because of dist/ content not included in @trincadev/driver.js tag release tarball
108
+ import { driver } from "../../node_modules/@trincadev/driver.js/src/driver"
109
 
110
  import {
111
  durationRef,
112
+ maxZoom,
113
+ minZoom,
114
  numberOfPolygonsRef,
115
  numberOfPredictedMasksRef,
116
  OpenStreetMap,
 
207
  const promptTextRef: Ref<string> = ref("")
208
  const promptTextPlaceholderRef: Ref<string> = ref(promptPlaceHolder)
209
  const detailIsOpenRef: Ref<boolean> = ref(false)
210
+ const mapNavigationLocked = ref(false)
211
  let map: LMap
212
  type ServiceTiles = {
213
  [key: SourceTileType]: LTileLayer;
 
235
  }
236
 
237
  const sendMLStringRequest = async (leafletMap: LMap, promptRequest: string, sourceType: SourceTileType = OpenStreetMap) => {
238
+ mapNavigationLocked.value = true
239
  const bodyRequest: IBodyLatLngWithStringPoints = {
240
  bbox: getExtentCurrentViewMapBBox(leafletMap),
241
  string_prompt: promptRequest,
 
289
  currentBaseMapNameRef.value = OpenStreetMap
290
 
291
  map = LeafletMap('map', {
292
+ layers: [osmTile],
293
+ minZoom: minZoom,
294
+ maxZoom: maxZoom
295
  })
296
  map.fitBounds(props.mapBounds)
297
  map.attributionControl.setPrefix(prefix)
 
315
 
316
  lisaDriverObj.drive();
317
  })
318
+
319
+ onUpdated(() => {
320
+ if (mapNavigationLocked.value) {
321
+ map.setMaxZoom(currentZoomRef.value)
322
+ map.setMinZoom(currentZoomRef.value)
323
+ map.options.maxBoundsViscosity = 1.0
324
+ map.setMaxBounds(map.getBounds())
325
+ }
326
+ if (!mapNavigationLocked.value) {
327
+ map.setMaxZoom(maxZoom)
328
+ map.setMinZoom(minZoom)
329
+ map.options.maxBoundsViscosity = 0.0
330
+ map.setMaxBounds([
331
+ [90, 180],
332
+ [-90, -180]
333
+ ])
334
+ }
335
+ })
336
  </script>
337
 
static/src/components/PagePredictionMap.vue CHANGED
@@ -14,9 +14,16 @@
14
  :map="map"
15
  :prompts-array="promptsArrayRef"
16
  :response-message="responseMessageRef"
17
- :send-m-l-request="sendMLLatLngArrayRequest"
18
  :waiting-string="waitingString"
19
  />
 
 
 
 
 
 
 
20
  </div>
21
  <div id="map" class="map-predictions" />
22
  <ButtonMapSendArrayRequest
@@ -26,10 +33,16 @@
26
  :map="map"
27
  :prompts-array="promptsArrayRef"
28
  :response-message="responseMessageRef"
29
- :send-m-l-request="sendMLLatLngArrayRequest"
30
  :waiting-string="waitingString"
31
  />
32
-
 
 
 
 
 
 
33
  </div>
34
  </div>
35
 
@@ -44,7 +57,6 @@
44
  {statName: 'prompt: points/rectangles number', statValue: promptsArrayRef.length},
45
  ]" />
46
  </div>
47
-
48
  <div v-if="responseMessageRef === waitingString" />
49
  <h2 v-else-if="responseMessageRef || responseMessageRef == '-'" class="text-lg text-red-600">{{ responseMessageRef }}</h2>
50
  <div v-else>
@@ -97,11 +109,14 @@ import {
97
  } from 'leaflet'
98
  import 'leaflet-providers'
99
  import '@geoman-io/leaflet-geoman-free'
100
- import { onMounted, ref, type Ref } from 'vue'
101
- import { driver } from "../../node_modules/driver.js/src/driver"
 
102
 
103
  import {
104
  durationRef,
 
 
105
  numberOfPolygonsRef,
106
  numberOfPredictedMasksRef,
107
  OpenStreetMap,
@@ -128,7 +143,7 @@ const driverObj = driver({
128
  showProgress: true,
129
  steps: [
130
  { element: 'id-prediction-map-container', popover: { title: 'SamGIS', description: 'A quick tour about SamGIS functionality' } },
131
- { element: '#map', popover: { title: 'Webmap for ML prompt', description: 'Add here your machine learning prompt' } },
132
  { element: '.leaflet-pm-icon-marker-include', popover: { title: '"Include" point prompt', description: 'add "include" points prompt (label 1) for machine learning request' } },
133
  { element: '.leaflet-pm-icon-marker-exclude', popover: { title: '"Exclude" point prompt', description: 'add "exclude" points prompt (label 0) for machine learning request' } },
134
  { element: '.leaflet-pm-icon-rectangle', popover: { title: '"Include" rectangle prompt', description: 'add "include" rectangles prompt for machine learning request' } },
@@ -143,6 +158,8 @@ const currentBaseMapNameRef = ref("")
143
  const currentMapBBoxRef = ref()
144
  const currentZoomRef = ref()
145
  const promptsArrayRef: Ref<Array<IPointPrompt | IRectanglePrompt>> = ref([])
 
 
146
  let map: LMap
147
  type ServiceTiles = {
148
  [key: SourceTileType]: LTileLayer;
@@ -169,13 +186,14 @@ const getPopupContentPoint = (leafletEvent: LEvented, label: number): HTMLDivEle
169
  return popupDiv
170
  }
171
 
172
- const sendMLLatLngArrayRequest = async (leafletMap: LMap, promptRequest: Array<IPointPrompt | IRectanglePrompt>, sourceType: SourceTileType = OpenStreetMap) => {
173
  if (map.pm.globalDragModeEnabled()) {
174
  map.pm.disableGlobalDragMode()
175
  }
176
  if (map.pm.globalEditModeEnabled()) {
177
  map.pm.disableGlobalEditMode()
178
  }
 
179
  const bodyRequest: IBodyLatLngPoints = {
180
  bbox: getExtentCurrentViewMapBBox(leafletMap),
181
  prompt: promptRequest,
@@ -222,14 +240,15 @@ onMounted(async () => {
222
  "<a href='https://github.com/tilezen/joerd/blob/master/docs/attribution.md'>Mapzen Source Attributions</a>."
223
  }
224
  )
225
-
226
  let baseMaps: ServiceTiles = { OpenStreetMap: osmTile }
227
  baseMaps[localVarSatellite] = satelliteTile
228
  baseMaps[localVarTerrain] = terrainTile
229
  currentBaseMapNameRef.value = OpenStreetMap
230
 
231
  map = LeafletMap('map', {
232
- layers: [osmTile]
 
 
233
  })
234
  map.fitBounds(props.mapBounds)
235
  map.attributionControl.setPrefix(prefix)
@@ -238,6 +257,7 @@ onMounted(async () => {
238
  LeafletControl.layers(baseMaps).addTo(map)
239
  setGeomanControls(map)
240
  updateZoomBboxMap(map)
 
241
 
242
  map.on('zoomend', (e: LEvented) => {
243
  updateZoomBboxMap(map)
@@ -254,5 +274,23 @@ onMounted(async () => {
254
 
255
  driverObj.drive();
256
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  </script>
258
 
 
14
  :map="map"
15
  :prompts-array="promptsArrayRef"
16
  :response-message="responseMessageRef"
17
+ :send-m-l-request="sendMLArrayRequest"
18
  :waiting-string="waitingString"
19
  />
20
+ <span class="ml-2 lg:hidden">
21
+ <input type="checkbox" id="checkboxMapNavigationLocked" v-model="mapNavigationLocked" />
22
+ <span class="ml-2">
23
+ <label class="text-red-600" for="checkboxMapNavigationLocked" v-if="mapNavigationLocked">locked map navigation!</label>
24
+ <label class="text-blue-600" for="checkboxMapNavigationLocked" v-else>map navigation unlocked</label>
25
+ </span>
26
+ </span>
27
  </div>
28
  <div id="map" class="map-predictions" />
29
  <ButtonMapSendArrayRequest
 
33
  :map="map"
34
  :prompts-array="promptsArrayRef"
35
  :response-message="responseMessageRef"
36
+ :send-m-l-request="sendMLArrayRequest"
37
  :waiting-string="waitingString"
38
  />
39
+ <span class="hidden lg:block lg:ml-2">
40
+ <input type="checkbox" id="checkboxMapNavigationLocked" v-model="mapNavigationLocked" />
41
+ <span class="ml-2">
42
+ <label class="text-red-600" for="checkboxMapNavigationLocked" v-if="mapNavigationLocked">locked map navigation!</label>
43
+ <label class="text-blue-600" for="checkboxMapNavigationLocked" v-else>map navigation unlocked</label>
44
+ </span>
45
+ </span>
46
  </div>
47
  </div>
48
 
 
57
  {statName: 'prompt: points/rectangles number', statValue: promptsArrayRef.length},
58
  ]" />
59
  </div>
 
60
  <div v-if="responseMessageRef === waitingString" />
61
  <h2 v-else-if="responseMessageRef || responseMessageRef == '-'" class="text-lg text-red-600">{{ responseMessageRef }}</h2>
62
  <div v-else>
 
109
  } from 'leaflet'
110
  import 'leaflet-providers'
111
  import '@geoman-io/leaflet-geoman-free'
112
+ import { onMounted, onUpdated, ref, type Ref } from 'vue'
113
+ // workaround because of dist/ content not included in @trincadev/driver.js tag release tarball
114
+ import { driver } from "../../node_modules/@trincadev/driver.js/src/driver"
115
 
116
  import {
117
  durationRef,
118
+ maxZoom,
119
+ minZoom,
120
  numberOfPolygonsRef,
121
  numberOfPredictedMasksRef,
122
  OpenStreetMap,
 
143
  showProgress: true,
144
  steps: [
145
  { element: 'id-prediction-map-container', popover: { title: 'SamGIS', description: 'A quick tour about SamGIS functionality' } },
146
+ { element: '#map', popover: { title: 'Webmap for ML prompt', description: 'Add here your machine learning prompt. Pay attention about markers and polygons outside the map bounds: you could get unexpected results' } },
147
  { element: '.leaflet-pm-icon-marker-include', popover: { title: '"Include" point prompt', description: 'add "include" points prompt (label 1) for machine learning request' } },
148
  { element: '.leaflet-pm-icon-marker-exclude', popover: { title: '"Exclude" point prompt', description: 'add "exclude" points prompt (label 0) for machine learning request' } },
149
  { element: '.leaflet-pm-icon-rectangle', popover: { title: '"Include" rectangle prompt', description: 'add "include" rectangles prompt for machine learning request' } },
 
158
  const currentMapBBoxRef = ref()
159
  const currentZoomRef = ref()
160
  const promptsArrayRef: Ref<Array<IPointPrompt | IRectanglePrompt>> = ref([])
161
+ const mapNavigationLocked = ref(false)
162
+ const mapOptionsDefaultRef = ref()
163
  let map: LMap
164
  type ServiceTiles = {
165
  [key: SourceTileType]: LTileLayer;
 
186
  return popupDiv
187
  }
188
 
189
+ const sendMLArrayRequest = async (leafletMap: LMap, promptRequest: Array<IPointPrompt | IRectanglePrompt>, sourceType: SourceTileType = OpenStreetMap) => {
190
  if (map.pm.globalDragModeEnabled()) {
191
  map.pm.disableGlobalDragMode()
192
  }
193
  if (map.pm.globalEditModeEnabled()) {
194
  map.pm.disableGlobalEditMode()
195
  }
196
+ mapNavigationLocked.value = true
197
  const bodyRequest: IBodyLatLngPoints = {
198
  bbox: getExtentCurrentViewMapBBox(leafletMap),
199
  prompt: promptRequest,
 
240
  "<a href='https://github.com/tilezen/joerd/blob/master/docs/attribution.md'>Mapzen Source Attributions</a>."
241
  }
242
  )
 
243
  let baseMaps: ServiceTiles = { OpenStreetMap: osmTile }
244
  baseMaps[localVarSatellite] = satelliteTile
245
  baseMaps[localVarTerrain] = terrainTile
246
  currentBaseMapNameRef.value = OpenStreetMap
247
 
248
  map = LeafletMap('map', {
249
+ layers: [osmTile],
250
+ minZoom: minZoom,
251
+ maxZoom: maxZoom
252
  })
253
  map.fitBounds(props.mapBounds)
254
  map.attributionControl.setPrefix(prefix)
 
257
  LeafletControl.layers(baseMaps).addTo(map)
258
  setGeomanControls(map)
259
  updateZoomBboxMap(map)
260
+ mapOptionsDefaultRef.value = {...map.options}
261
 
262
  map.on('zoomend', (e: LEvented) => {
263
  updateZoomBboxMap(map)
 
274
 
275
  driverObj.drive();
276
  })
277
+
278
+ onUpdated(() => {
279
+ if (mapNavigationLocked.value) {
280
+ map.setMaxZoom(currentZoomRef.value)
281
+ map.setMinZoom(currentZoomRef.value)
282
+ map.options.maxBoundsViscosity = 1.0
283
+ map.setMaxBounds(map.getBounds())
284
+ }
285
+ if (!mapNavigationLocked.value) {
286
+ map.setMaxZoom(maxZoom)
287
+ map.setMinZoom(minZoom)
288
+ map.options.maxBoundsViscosity = 0.0
289
+ map.setMaxBounds([
290
+ [90, 180],
291
+ [-90, -180]
292
+ ])
293
+ }
294
+ })
295
  </script>
296
 
static/src/components/constants.ts CHANGED
@@ -4,7 +4,7 @@ export const prefix = " &copy; <a target=\"_blank\" href=\"https://leafletjs.com
4
  export const OpenStreetMap = "OpenStreetMap"
5
  export const Satellite = "OpenStreetMap.HOT"
6
  export const maxZoom = 20
7
- export const minZoom = 3
8
  export const waitingString = "waiting..."
9
  export const durationRef = ref(0)
10
  export const numberOfPolygonsRef = ref(0)
 
4
  export const OpenStreetMap = "OpenStreetMap"
5
  export const Satellite = "OpenStreetMap.HOT"
6
  export const maxZoom = 20
7
+ export const minZoom = 2
8
  export const waitingString = "waiting..."
9
  export const durationRef = ref(0)
10
  export const numberOfPolygonsRef = ref(0)
static/src/input.css CHANGED
@@ -1,7 +1,8 @@
1
  @import "leaflet/dist/leaflet.css";
2
  @import "leaflet-custom.css";
3
  @import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
4
- @import "../node_modules/driver.js/src/driver.css";
 
5
 
6
  @tailwind base;
7
 
 
1
  @import "leaflet/dist/leaflet.css";
2
  @import "leaflet-custom.css";
3
  @import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
4
+ /* workaround because of dist/ content not included in @trincadev/driver.js tag release tarball */
5
+ @import "../node_modules/@trincadev/driver.js/src/driver.css";
6
 
7
  @tailwind base;
8