Skip to content

Commit 820937a

Browse files
calebrob6m-mohr
andauthored
Added checkbox to show/hide boundaries when zoomed in past render threshold (#255)
* Added checkbox to show/hide boundaries when zoomed in past render threshold * Ran prettier * Persist checkbox state in URL * Fix race condition for zoom level listener --------- Co-authored-by: Matthias Mohr <m.mohr@moregeo.it>
1 parent f9a54e5 commit 820937a

4 files changed

Lines changed: 68 additions & 4 deletions

File tree

src/components/GlobalDataPanel.vue

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script setup lang="ts">
2-
import useSettings from '../composables/useSettings'
2+
import { computed, onUnmounted, ref, watch } from 'vue'
3+
import useSettings, { GLOBAL_DATA_MAP_FIELD_START_ZOOM_LEVEL } from '../composables/useSettings'
34
import useMap from '../composables/useMap'
45
import useAreaOfInterest from '../composables/useAreaOfInterest'
56
import type { PlaceResult } from '../composables/useAreaOfInterest'
@@ -13,6 +14,34 @@ const { map } = useMap()
1314
const { fitToExtent } = useAreaOfInterest()
1415
const { showError } = useNotifier()
1516
17+
const zoom = ref(0)
18+
const onZoomChange = () => {
19+
zoom.value = map.value?.getView()?.getZoom() ?? 0
20+
}
21+
22+
// Watch map and attach zoom listener when map becomes available
23+
watch(
24+
map,
25+
(newMap, oldMap) => {
26+
// Clean up previous listener
27+
if (oldMap) {
28+
oldMap.getView()?.un('change:resolution', onZoomChange)
29+
}
30+
31+
// Attach new listener if map is available
32+
if (newMap) {
33+
onZoomChange()
34+
newMap.getView().on('change:resolution', onZoomChange)
35+
}
36+
},
37+
{ immediate: true },
38+
)
39+
40+
onUnmounted(() => {
41+
map.value?.getView()?.un('change:resolution', onZoomChange)
42+
})
43+
const fieldBoundariesDisabled = computed(() => zoom.value < GLOBAL_DATA_MAP_FIELD_START_ZOOM_LEVEL)
44+
1645
const handleLocationSelected = (place: PlaceResult) => {
1746
if (!map.value) return
1847
if (!place.boundingbox) {
@@ -52,6 +81,15 @@ const handleLocationSelected = (place: PlaceResult) => {
5281
thumb-color="teal"
5382
hide-details
5483
/>
84+
<v-checkbox
85+
v-model="settings.showFieldBoundaries"
86+
label="Show field boundaries"
87+
density="compact"
88+
hide-details
89+
color="teal"
90+
class="mt-2"
91+
:disabled="fieldBoundariesDisabled"
92+
/>
5593
<h3 class="group legend">Legend</h3>
5694
<MapLegend />
5795
</v-col>

src/composables/useMap.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,27 @@ watch(
8585
// Insert at index 0 to keep it as the base layer
8686
map.value.getLayers().insertAt(0, cloudlessLayer.value)
8787

88-
if (settings.value.mode === 'global' && globalPredictionsController.value) {
89-
removeGlobalPredictionsLayer()
90-
updateLayers()
88+
if (settings.value.mode === 'global') {
89+
if (globalPredictionsController.value) {
90+
map.value.removeLayer(globalPredictionsController.value.layer)
91+
globalPredictionsController.value.dispose()
92+
globalPredictionsController.value = null
93+
}
94+
95+
globalPredictionsController.value = createGlobalPredictionsLayer(settings.value)
96+
globalPredictionsController.value.layer.setVisible(settings.value.showFieldBoundaries)
97+
map.value.addLayer(globalPredictionsController.value.layer)
9198
}
9299
},
93100
)
94101

102+
watch(
103+
() => settings.value.showFieldBoundaries,
104+
(visible) => {
105+
globalPredictionsController.value?.layer.setVisible(visible)
106+
},
107+
)
108+
95109
const initCloudlessLayer = () => {
96110
if (!map.value) {
97111
return
@@ -143,6 +157,7 @@ const updateLayers = () => {
143157
if (!globalPredictionsController.value) {
144158
// Only handle first initialization here, year changes are handled by a watcher on year above
145159
globalPredictionsController.value = createGlobalPredictionsLayer(settings.value)
160+
globalPredictionsController.value.layer.setVisible(settings.value.showFieldBoundaries)
146161
map.value.addLayer(globalPredictionsController.value.layer)
147162
}
148163
if (!globalOverviewLayer.value) {

src/composables/usePermalink.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface PermalinkStateInference extends PermalinkState {
3030

3131
export interface PermalinkStateGlobal extends PermalinkState {
3232
threshold: number
33+
showFieldBoundaries: boolean
3334
}
3435

3536
export default function usePermalink() {
@@ -58,6 +59,7 @@ export default function usePermalink() {
5859
center: [0, 0],
5960
year: 2025,
6061
threshold: 0.4,
62+
showFieldBoundaries: true,
6163
}
6264

6365
const getDefaultState = (mode: string): PermalinkStateInference | PermalinkStateGlobal => {
@@ -173,6 +175,7 @@ export default function usePermalink() {
173175
zoom,
174176
center,
175177
threshold: defaultGlobalState.threshold,
178+
showFieldBoundaries: defaultGlobalState.showFieldBoundaries,
176179
}
177180

178181
for (const part of keyValueParts) {
@@ -182,6 +185,8 @@ export default function usePermalink() {
182185
} else if (part.startsWith('year:')) {
183186
const year = parseInt(part.substring(5), 10)
184187
if (!isNaN(year)) result.year = year
188+
} else if (part.startsWith('field_boundaries:')) {
189+
result.showFieldBoundaries = part.substring(17) === '1'
185190
}
186191
}
187192

@@ -284,13 +289,15 @@ export default function usePermalink() {
284289
if (settings.value.year) {
285290
hashParts.push(`year:${settings.value.year}`)
286291
}
292+
hashParts.push(`field_boundaries:${settings.value.showFieldBoundaries ? 1 : 0}`)
287293

288294
state = {
289295
mode,
290296
zoom,
291297
center,
292298
threshold: settings.value.threshold,
293299
year: settings.value.year,
300+
showFieldBoundaries: settings.value.showFieldBoundaries,
294301
}
295302
}
296303

@@ -327,6 +334,7 @@ export default function usePermalink() {
327334

328335
function restoreGlobalState(state: PermalinkStateGlobal) {
329336
settings.value.threshold = state.threshold
337+
settings.value.showFieldBoundaries = state.showFieldBoundaries
330338
if (state.year) {
331339
settings.value.year = state.year
332340
}
@@ -358,6 +366,7 @@ export default function usePermalink() {
358366
settings.value.areaCoverage,
359367
settings.value.buffer,
360368
settings.value.threshold,
369+
settings.value.showFieldBoundaries,
361370
],
362371
() => {
363372
if (!map.value) {

src/composables/useSettings.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export interface Settings {
1212
expertMode: boolean
1313
mode: string
1414
threshold: number
15+
showFieldBoundaries: boolean
1516
}
1617

1718
export interface ModelInfo {
@@ -57,6 +58,7 @@ const defaultSettings: Settings = {
5758
expertMode: false,
5859
mode: defaultMode,
5960
threshold: 0.4,
61+
showFieldBoundaries: true,
6062
}
6163

6264
const defaultModel = computed(() => {

0 commit comments

Comments
 (0)