|
|
@@ -22,7 +22,6 @@ import {
|
|
22
|
22
|
buildTownshipInfo,
|
|
23
|
23
|
flyToTownship,
|
|
24
|
24
|
getTownshipLabelPoints,
|
|
25
|
|
- getTownshipPoiSearchCenter,
|
|
26
|
25
|
removeTownshipBoundaryLayers
|
|
27
|
26
|
} from '@/utils/gisTownshipBoundary'
|
|
28
|
27
|
import { getTownshipLivestockStats } from '@/constants/townshipLivestock'
|
|
|
@@ -48,7 +47,7 @@ const props = defineProps({
|
|
48
|
47
|
type: Boolean,
|
|
49
|
48
|
default: false
|
|
50
|
49
|
},
|
|
51
|
|
- /** 点击乡镇后是否展示该乡镇中心点周边 POI(默认不加载,点击后才查) */
|
|
|
50
|
+ /** 是否展示地图中心点周边 POI(移动地图后防抖查询) */
|
|
52
|
51
|
showPoiMarkers: {
|
|
53
|
52
|
type: Boolean,
|
|
54
|
53
|
default: true
|
|
|
@@ -87,6 +86,10 @@ let unbindWheelZoom = null
|
|
87
|
86
|
/** 滚轮缩放防抖:停止滚动后再合并应用,减少瓦片 canceled */
|
|
88
|
87
|
const WHEEL_ZOOM_DEBOUNCE_MS = 150
|
|
89
|
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
|
94
|
let wheelDeltaAccum = 0
|
|
92
|
95
|
let wheelDebounceTimer = null
|
|
|
@@ -94,8 +97,68 @@ let lastWheelAround = null
|
|
94
|
97
|
let poiMarkers = []
|
|
95
|
98
|
let townshipMarkers = []
|
|
96
|
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
|
163
|
function logClickCoordinate(lngLat) {
|
|
101
|
164
|
if (!lngLat) {
|
|
|
@@ -176,16 +239,6 @@ function bindTownshipDrillDown() {
|
|
176
|
239
|
zoom: props.townshipDrillMaxZoom
|
|
177
|
240
|
})
|
|
178
|
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
|
340
|
async function renderPoiMarkers() {
|
|
288
|
|
- if (!props.showPoiMarkers || !map || !cmmapglRef || !poiSearchCenter) {
|
|
|
341
|
+ if (!props.showPoiMarkers || !map || !cmmapglRef) {
|
|
289
|
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
|
354
|
clearPoiMarkers()
|
|
292
|
355
|
|
|
293
|
356
|
let pois = []
|
|
294
|
357
|
try {
|
|
295
|
|
- pois = await searchNearbyPois({
|
|
296
|
|
- center: poiSearchCenter
|
|
297
|
|
- })
|
|
|
358
|
+ pois = await searchNearbyPois({ center })
|
|
298
|
359
|
} catch {
|
|
299
|
360
|
return
|
|
300
|
361
|
}
|
|
|
@@ -328,6 +389,10 @@ async function renderPoiMarkers() {
|
|
328
|
389
|
}
|
|
329
|
390
|
|
|
330
|
391
|
function destroyMap() {
|
|
|
392
|
+ if (typeof unbindPoiSearch === 'function') {
|
|
|
393
|
+ unbindPoiSearch()
|
|
|
394
|
+ unbindPoiSearch = null
|
|
|
395
|
+ }
|
|
331
|
396
|
if (typeof unbindWheelZoom === 'function') {
|
|
332
|
397
|
unbindWheelZoom()
|
|
333
|
398
|
unbindWheelZoom = null
|
|
|
@@ -335,7 +400,6 @@ function destroyMap() {
|
|
335
|
400
|
wheelDeltaAccum = 0
|
|
336
|
401
|
lastWheelAround = null
|
|
337
|
402
|
clampingZoom = false
|
|
338
|
|
- poiSearchCenter = null
|
|
339
|
403
|
clearPoiMarkers()
|
|
340
|
404
|
teardownTownshipBoundary()
|
|
341
|
405
|
if (map) {
|
|
|
@@ -569,6 +633,7 @@ async function initMap() {
|
|
569
|
633
|
bindMapListeners()
|
|
570
|
634
|
bindZoomClampListener()
|
|
571
|
635
|
unbindWheelZoom = bindDebouncedWheelZoom()
|
|
|
636
|
+ unbindPoiSearch = bindPoiSearchListener()
|
|
572
|
637
|
configureScrollZoom()
|
|
573
|
638
|
map.on('load', () => {
|
|
574
|
639
|
applyMapLimits()
|
|
|
@@ -577,6 +642,7 @@ async function initMap() {
|
|
577
|
642
|
syncWmtsLayerVisibility(map)
|
|
578
|
643
|
resizeMap()
|
|
579
|
644
|
renderTownshipBoundary()
|
|
|
645
|
+ schedulePoiSearch()
|
|
580
|
646
|
emit('ready', map)
|
|
581
|
647
|
})
|
|
582
|
648
|
// 瓦片/遥测等非致命错误不向页面报错
|
|
|
@@ -602,9 +668,13 @@ watch(
|
|
602
|
668
|
() => props.showPoiMarkers,
|
|
603
|
669
|
(show) => {
|
|
604
|
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
|
678
|
clearPoiMarkers()
|
|
609
|
679
|
}
|
|
610
|
680
|
}
|