Przeglądaj źródła

根据移动地图更新点位

xsh_1997 1 miesiąc temu
rodzic
commit
ee7100c511

+ 92 - 22
ruoyi-screen/src/components/GisMap.vue

@@ -22,7 +22,6 @@ import {
22
   buildTownshipInfo,
22
   buildTownshipInfo,
23
   flyToTownship,
23
   flyToTownship,
24
   getTownshipLabelPoints,
24
   getTownshipLabelPoints,
25
-  getTownshipPoiSearchCenter,
26
   removeTownshipBoundaryLayers
25
   removeTownshipBoundaryLayers
27
 } from '@/utils/gisTownshipBoundary'
26
 } from '@/utils/gisTownshipBoundary'
28
 import { getTownshipLivestockStats } from '@/constants/townshipLivestock'
27
 import { getTownshipLivestockStats } from '@/constants/townshipLivestock'
@@ -48,7 +47,7 @@ const props = defineProps({
48
     type: Boolean,
47
     type: Boolean,
49
     default: false
48
     default: false
50
   },
49
   },
51
-  /** 点击乡镇后是否展示该乡镇中心点周边 POI(默认不加载,点击后才查) */
50
+  /** 是否展示地图中心点周边 POI(移动地图后防抖查询) */
52
   showPoiMarkers: {
51
   showPoiMarkers: {
53
     type: Boolean,
52
     type: Boolean,
54
     default: true
53
     default: true
@@ -87,6 +86,10 @@ let unbindWheelZoom = null
87
 /** 滚轮缩放防抖:停止滚动后再合并应用,减少瓦片 canceled */
86
 /** 滚轮缩放防抖:停止滚动后再合并应用,减少瓦片 canceled */
88
 const WHEEL_ZOOM_DEBOUNCE_MS = 150
87
 const WHEEL_ZOOM_DEBOUNCE_MS = 150
89
 const WHEEL_ZOOM_RATE = 0.0022
88
 const WHEEL_ZOOM_RATE = 0.0022
89
+/** 地图移动结束后防抖再查 POI,避免拖拽过程中频繁请求 */
90
+const POI_SEARCH_DEBOUNCE_MS = 400
91
+/** 仅 zoom >= 16 时查询并展示 POI */
92
+const POI_SEARCH_MIN_ZOOM = 16
90
 
93
 
91
 let wheelDeltaAccum = 0
94
 let wheelDeltaAccum = 0
92
 let wheelDebounceTimer = null
95
 let wheelDebounceTimer = null
@@ -94,8 +97,68 @@ let lastWheelAround = null
94
 let poiMarkers = []
97
 let poiMarkers = []
95
 let townshipMarkers = []
98
 let townshipMarkers = []
96
 let unbindTownshipClick = null
99
 let unbindTownshipClick = null
97
-/** 当前 POI 查询中心,仅点击乡镇后赋值 */
98
-let poiSearchCenter = null
100
+let unbindPoiSearch = null
101
+let poiSearchDebounceTimer = null
102
+
103
+function getMapViewCenter() {
104
+  if (!map || typeof map.getCenter !== 'function') {
105
+    return null
106
+  }
107
+  const center = map.getCenter()
108
+  const lng = Number(center?.lng ?? center?.[0])
109
+  const lat = Number(center?.lat ?? center?.[1])
110
+  if (!Number.isFinite(lng) || !Number.isFinite(lat)) {
111
+    return null
112
+  }
113
+  return [lng, lat]
114
+}
115
+
116
+function getMapZoom() {
117
+  if (!map || typeof map.getZoom !== 'function') {
118
+    return null
119
+  }
120
+  const zoom = map.getZoom()
121
+  return Number.isFinite(zoom) ? zoom : null
122
+}
123
+
124
+function shouldSearchPoiAtCurrentZoom() {
125
+  const zoom = getMapZoom()
126
+  return zoom != null && zoom >= POI_SEARCH_MIN_ZOOM
127
+}
128
+
129
+function schedulePoiSearch() {
130
+  if (!props.showPoiMarkers || !map) {
131
+    return
132
+  }
133
+  if (poiSearchDebounceTimer) {
134
+    clearTimeout(poiSearchDebounceTimer)
135
+  }
136
+  poiSearchDebounceTimer = setTimeout(() => {
137
+    poiSearchDebounceTimer = null
138
+    if (!shouldSearchPoiAtCurrentZoom()) {
139
+      clearPoiMarkers()
140
+      return
141
+    }
142
+    renderPoiMarkers()
143
+  }, POI_SEARCH_DEBOUNCE_MS)
144
+}
145
+
146
+function bindPoiSearchListener() {
147
+  if (!map || typeof map.on !== 'function') {
148
+    return () => {}
149
+  }
150
+  const onMoveEnd = () => {
151
+    schedulePoiSearch()
152
+  }
153
+  map.on('moveend', onMoveEnd)
154
+  return () => {
155
+    if (poiSearchDebounceTimer) {
156
+      clearTimeout(poiSearchDebounceTimer)
157
+      poiSearchDebounceTimer = null
158
+    }
159
+    map.off('moveend', onMoveEnd)
160
+  }
161
+}
99
 
162
 
100
 function logClickCoordinate(lngLat) {
163
 function logClickCoordinate(lngLat) {
101
   if (!lngLat) {
164
   if (!lngLat) {
@@ -176,16 +239,6 @@ function bindTownshipDrillDown() {
176
       zoom: props.townshipDrillMaxZoom
239
       zoom: props.townshipDrillMaxZoom
177
     })
240
     })
178
     emit('township-click', info)
241
     emit('township-click', info)
179
-
180
-    if (props.showPoiMarkers) {
181
-      const searchCenter = getTownshipPoiSearchCenter(feature)
182
-      if (searchCenter) {
183
-        poiSearchCenter = searchCenter
184
-        map.once('moveend', () => {
185
-          renderPoiMarkers()
186
-        })
187
-      }
188
-    }
189
   })
242
   })
190
 }
243
 }
191
 
244
 
@@ -285,16 +338,24 @@ function createPoiMarkerElement(name) {
285
 }
338
 }
286
 
339
 
287
 async function renderPoiMarkers() {
340
 async function renderPoiMarkers() {
288
-  if (!props.showPoiMarkers || !map || !cmmapglRef || !poiSearchCenter) {
341
+  if (!props.showPoiMarkers || !map || !cmmapglRef) {
289
     return
342
     return
290
   }
343
   }
344
+  if (!shouldSearchPoiAtCurrentZoom()) {
345
+    clearPoiMarkers()
346
+    return
347
+  }
348
+
349
+  const center = getMapViewCenter()
350
+  if (!center) {
351
+    return
352
+  }
353
+
291
   clearPoiMarkers()
354
   clearPoiMarkers()
292
 
355
 
293
   let pois = []
356
   let pois = []
294
   try {
357
   try {
295
-    pois = await searchNearbyPois({
296
-      center: poiSearchCenter
297
-    })
358
+    pois = await searchNearbyPois({ center })
298
   } catch {
359
   } catch {
299
     return
360
     return
300
   }
361
   }
@@ -328,6 +389,10 @@ async function renderPoiMarkers() {
328
 }
389
 }
329
 
390
 
330
 function destroyMap() {
391
 function destroyMap() {
392
+  if (typeof unbindPoiSearch === 'function') {
393
+    unbindPoiSearch()
394
+    unbindPoiSearch = null
395
+  }
331
   if (typeof unbindWheelZoom === 'function') {
396
   if (typeof unbindWheelZoom === 'function') {
332
     unbindWheelZoom()
397
     unbindWheelZoom()
333
     unbindWheelZoom = null
398
     unbindWheelZoom = null
@@ -335,7 +400,6 @@ function destroyMap() {
335
   wheelDeltaAccum = 0
400
   wheelDeltaAccum = 0
336
   lastWheelAround = null
401
   lastWheelAround = null
337
   clampingZoom = false
402
   clampingZoom = false
338
-  poiSearchCenter = null
339
   clearPoiMarkers()
403
   clearPoiMarkers()
340
   teardownTownshipBoundary()
404
   teardownTownshipBoundary()
341
   if (map) {
405
   if (map) {
@@ -569,6 +633,7 @@ async function initMap() {
569
     bindMapListeners()
633
     bindMapListeners()
570
     bindZoomClampListener()
634
     bindZoomClampListener()
571
     unbindWheelZoom = bindDebouncedWheelZoom()
635
     unbindWheelZoom = bindDebouncedWheelZoom()
636
+    unbindPoiSearch = bindPoiSearchListener()
572
     configureScrollZoom()
637
     configureScrollZoom()
573
     map.on('load', () => {
638
     map.on('load', () => {
574
       applyMapLimits()
639
       applyMapLimits()
@@ -577,6 +642,7 @@ async function initMap() {
577
       syncWmtsLayerVisibility(map)
642
       syncWmtsLayerVisibility(map)
578
       resizeMap()
643
       resizeMap()
579
       renderTownshipBoundary()
644
       renderTownshipBoundary()
645
+      schedulePoiSearch()
580
       emit('ready', map)
646
       emit('ready', map)
581
     })
647
     })
582
     // 瓦片/遥测等非致命错误不向页面报错
648
     // 瓦片/遥测等非致命错误不向页面报错
@@ -602,9 +668,13 @@ watch(
602
   () => props.showPoiMarkers,
668
   () => props.showPoiMarkers,
603
   (show) => {
669
   (show) => {
604
     if (!map || !cmmapglRef) return
670
     if (!map || !cmmapglRef) return
605
-    if (show && poiSearchCenter) {
606
-      renderPoiMarkers()
607
-    } else if (!show) {
671
+    if (show) {
672
+      schedulePoiSearch()
673
+    } else {
674
+      if (poiSearchDebounceTimer) {
675
+        clearTimeout(poiSearchDebounceTimer)
676
+        poiSearchDebounceTimer = null
677
+      }
608
       clearPoiMarkers()
678
       clearPoiMarkers()
609
     }
679
     }
610
   }
680
   }

+ 9 - 0
ruoyi-screen/src/utils/gisTownshipBoundary.js

@@ -70,6 +70,15 @@ export function getTownshipPoiSearchCenter(feature) {
70
   return null
70
   return null
71
 }
71
 }
72
 
72
 
73
+/** POI 多边形搜索范围:取乡镇边界外环 [经度, 纬度][] */
74
+export function getTownshipPoiSearchPolygon(feature) {
75
+  const ring = getPolygonOuterRing(feature)
76
+  if (!Array.isArray(ring) || ring.length < 3) {
77
+    return null
78
+  }
79
+  return ring.map(([lng, lat]) => [Number(lng), Number(lat)])
80
+}
81
+
73
 export function getTownshipGeoJson() {
82
 export function getTownshipGeoJson() {
74
   return townshipGeoJson
83
   return townshipGeoJson
75
 }
84
 }