huweili-cesium 1.2.3 → 1.2.4
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.
- package/index.vue +385 -474
- package/js/basis.js +75 -32
- package/js/customToolbarButtons.js +3 -0
- package/js/index.js +6 -0
- package/js/utils/cameraInteraction.js +101 -0
- package/js/utils/orthographicCameraZoom.js +28 -0
- package/package.json +20 -2
package/index.vue
CHANGED
|
@@ -1,474 +1,385 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="cesium-map-wrapper">
|
|
3
|
-
<div class="cesium-container" ref="cesiumContainer" />
|
|
4
|
-
<WsIndicator />
|
|
5
|
-
</div>
|
|
6
|
-
</template>
|
|
7
|
-
|
|
8
|
-
<script setup>
|
|
9
|
-
import * as Cesium from 'cesium'
|
|
10
|
-
import { ref, onMounted, onUnmounted, onActivated, onDeactivated, nextTick, toRaw } from 'vue'
|
|
11
|
-
import { MapConfig, DroneConfig } from './
|
|
12
|
-
import WsIndicator from './components/wsIndicator/wsIndicator.vue'
|
|
13
|
-
import { objectUtils } from './
|
|
14
|
-
import { basicConfig } from './
|
|
15
|
-
import { useMapStore, MapLoadStatus } from './
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
let
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
baseLayerPicker: mapOptions.control.baseLayerPicker,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
mapStore.setCurrentMapId(props.mapId)
|
|
387
|
-
setupActivityListeners()
|
|
388
|
-
initCesium()
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* keep-alive 组件激活钩子(从缓存中恢复时触发)
|
|
393
|
-
*
|
|
394
|
-
* 触发时机:
|
|
395
|
-
* - 当前组件被 keep-alive 包裹,用户导航回到该页面时
|
|
396
|
-
* - 组件从缓存状态恢复到活动状态
|
|
397
|
-
*
|
|
398
|
-
* 功能说明:
|
|
399
|
-
* - 重新设置当前地图 ID
|
|
400
|
-
* - 如果地图已销毁,重新初始化地图
|
|
401
|
-
* - 如果地图还在缓存中,恢复地图渲染
|
|
402
|
-
*/
|
|
403
|
-
onActivated(() => {
|
|
404
|
-
mapStore.setCurrentMapId(props.mapId)
|
|
405
|
-
if (!map || map.isDestroyed?.()) {
|
|
406
|
-
isMapActive = true
|
|
407
|
-
initCesium()
|
|
408
|
-
return
|
|
409
|
-
}
|
|
410
|
-
resumeMapAfterCache()
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* keep-alive 组件失活钩子(页面被缓存时触发)
|
|
415
|
-
*
|
|
416
|
-
* 触发时机:
|
|
417
|
-
* - 当前组件被 keep-alive 包裹,用户导航离开该页面时
|
|
418
|
-
* - 组件进入缓存状态,但不会被销毁
|
|
419
|
-
*
|
|
420
|
-
* 功能说明:
|
|
421
|
-
* - 标记地图为非活跃状态
|
|
422
|
-
* - 停止持续渲染循环,节省 CPU 资源
|
|
423
|
-
*
|
|
424
|
-
* 与 onUnmounted 的区别:
|
|
425
|
-
* - onDeactivated:组件被缓存,可通过 onActivated 恢复
|
|
426
|
-
* - onUnmounted:组件被销毁,需要完全清理资源
|
|
427
|
-
*/
|
|
428
|
-
onDeactivated(() => {
|
|
429
|
-
isMapActive = false
|
|
430
|
-
stopRenderLoop()
|
|
431
|
-
})
|
|
432
|
-
|
|
433
|
-
/**
|
|
434
|
-
* 组件卸载钩子(完全销毁时触发)
|
|
435
|
-
*
|
|
436
|
-
* 触发时机:
|
|
437
|
-
* - 组件被完全移除时
|
|
438
|
-
* - 路由切换且未使用 keep-alive 缓存时
|
|
439
|
-
*
|
|
440
|
-
* 功能说明:
|
|
441
|
-
* - 停止渲染循环
|
|
442
|
-
* - 移除自定义工具栏按钮
|
|
443
|
-
* - 销毁 Cesium Viewer 实例释放内存
|
|
444
|
-
* - 从 store 中移除地图实例
|
|
445
|
-
*/
|
|
446
|
-
onUnmounted(() => {
|
|
447
|
-
isMapActive = false
|
|
448
|
-
stopRenderLoop()
|
|
449
|
-
removeToolbarButtons(customButtons)
|
|
450
|
-
customButtons = []
|
|
451
|
-
if (map) {
|
|
452
|
-
map.destroy()
|
|
453
|
-
map = null
|
|
454
|
-
}
|
|
455
|
-
mapStore.removeMapInstance(props.mapId)
|
|
456
|
-
})
|
|
457
|
-
|
|
458
|
-
</script>
|
|
459
|
-
|
|
460
|
-
<style scoped lang="less">
|
|
461
|
-
.cesium-map-wrapper {
|
|
462
|
-
width: 100%;
|
|
463
|
-
height: 100%;
|
|
464
|
-
position: relative;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
.cesium-container {
|
|
468
|
-
width: 100%;
|
|
469
|
-
height: 100%;
|
|
470
|
-
position: relative;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
<div class="cesium-map-wrapper" @pointerdown="handleMapPointerDown">
|
|
3
|
+
<div class="cesium-container" ref="cesiumContainer" />
|
|
4
|
+
<WsIndicator />
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script setup>
|
|
9
|
+
import * as Cesium from 'cesium'
|
|
10
|
+
import { ref, watch, onMounted, onUnmounted, onActivated, onDeactivated, nextTick, toRaw } from 'vue'
|
|
11
|
+
import { MapConfig, DroneConfig } from './config'
|
|
12
|
+
import WsIndicator from './components/wsIndicator/wsIndicator.vue'
|
|
13
|
+
import { objectUtils } from './utils/cesium/object'
|
|
14
|
+
import { basicConfig, teardownOrthographicWheelZoom } from './basis'
|
|
15
|
+
import { useMapStore, MapLoadStatus } from './stores/mapStore'
|
|
16
|
+
import { useEventBus } from './utils/useEventBus'
|
|
17
|
+
import { processMapConfigColors } from './tileProviders'
|
|
18
|
+
import { applyImageryLayers, resolveOnlineBasemap } from './utils/mapImagery'
|
|
19
|
+
import { createCustomToolbarButtons } from './customToolbarButtons'
|
|
20
|
+
import { ensureMapFocus } from './utils/cameraInteraction'
|
|
21
|
+
|
|
22
|
+
const { merge } = objectUtils()
|
|
23
|
+
const { mouseController, setInitialCameraView, syncCameraInteractionMode } = basicConfig()
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
addToolbarButton,
|
|
27
|
+
addToolbarButtons,
|
|
28
|
+
removeToolbarButtons,
|
|
29
|
+
createDefaultToolbarButtons,
|
|
30
|
+
} = createCustomToolbarButtons()
|
|
31
|
+
|
|
32
|
+
const mapStore = useMapStore()
|
|
33
|
+
const { on: onEvent, off: offEvent } = useEventBus()
|
|
34
|
+
|
|
35
|
+
const emit = defineEmits(['onload'])
|
|
36
|
+
|
|
37
|
+
const props = defineProps({
|
|
38
|
+
options: {
|
|
39
|
+
type: Object,
|
|
40
|
+
default: undefined,
|
|
41
|
+
},
|
|
42
|
+
mapId: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: 'default',
|
|
45
|
+
},
|
|
46
|
+
showDefaultToolbar: {
|
|
47
|
+
type: Boolean,
|
|
48
|
+
default: true,
|
|
49
|
+
},
|
|
50
|
+
toolbarButtons: {
|
|
51
|
+
type: Array,
|
|
52
|
+
default: undefined,
|
|
53
|
+
},
|
|
54
|
+
extraToolbarButtons: {
|
|
55
|
+
type: Array,
|
|
56
|
+
default: () => [],
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
function resolveToolbarButtonConfigs() {
|
|
61
|
+
if (props.toolbarButtons?.length) {
|
|
62
|
+
return props.toolbarButtons
|
|
63
|
+
}
|
|
64
|
+
const configs = []
|
|
65
|
+
if (props.showDefaultToolbar) {
|
|
66
|
+
configs.push(...createDefaultToolbarButtons({ mapId: props.mapId }))
|
|
67
|
+
}
|
|
68
|
+
if (props.extraToolbarButtons?.length) {
|
|
69
|
+
configs.push(...props.extraToolbarButtons)
|
|
70
|
+
}
|
|
71
|
+
return configs
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const handleSceneModeChange = ({ mapId, sceneMode }) => {
|
|
75
|
+
if (mapId !== props.mapId || !map || map.isDestroyed?.()) return
|
|
76
|
+
syncCameraInteractionMode(map, mapId, sceneMode)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const handleMapPointerDown = () => {
|
|
80
|
+
if (map && !map.isDestroyed?.()) {
|
|
81
|
+
ensureMapFocus(map)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const cesiumContainer = ref(null)
|
|
86
|
+
let map = null
|
|
87
|
+
let customButtons = []
|
|
88
|
+
let isMapActive = true
|
|
89
|
+
|
|
90
|
+
function mountToolbarButtons(viewer) {
|
|
91
|
+
if (!viewer || viewer.isDestroyed?.()) return
|
|
92
|
+
removeToolbarButtons(customButtons)
|
|
93
|
+
customButtons = []
|
|
94
|
+
const toolbarConfigs = resolveToolbarButtonConfigs()
|
|
95
|
+
if (toolbarConfigs.length) {
|
|
96
|
+
customButtons = addToolbarButtons(viewer, toolbarConfigs)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const initCesium = async () => {
|
|
101
|
+
if (!cesiumContainer.value) return
|
|
102
|
+
mapStore.setMapLoadSta(MapLoadStatus.LOADING, props.mapId)
|
|
103
|
+
|
|
104
|
+
let mapOptions
|
|
105
|
+
if (MapConfig) {
|
|
106
|
+
mapOptions = MapConfig
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (DroneConfig) {
|
|
110
|
+
mapStore.setTrailTime(DroneConfig.trailTime, props.mapId)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (props.options) {
|
|
114
|
+
let exOptions
|
|
115
|
+
if (props.options.then) {
|
|
116
|
+
exOptions = toRaw(await props.options)
|
|
117
|
+
} else {
|
|
118
|
+
exOptions = toRaw(props.options)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (mapOptions) {
|
|
122
|
+
mapOptions = merge(mapOptions, exOptions)
|
|
123
|
+
} else {
|
|
124
|
+
mapOptions = exOptions
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (mapOptions) {
|
|
129
|
+
mapOptions = processMapConfigColors(mapOptions)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const viewerOptions = {
|
|
134
|
+
sceneMode: Cesium.SceneMode.SCENE3D,
|
|
135
|
+
useDefaultRenderLoop: false,
|
|
136
|
+
baseLayer: mapOptions.control.imageryProvider === false ? false : undefined,
|
|
137
|
+
baseLayerPicker: mapOptions.control.baseLayerPicker,
|
|
138
|
+
geocoder: mapOptions.control.geocoder,
|
|
139
|
+
homeButton: mapOptions.control.homeButton,
|
|
140
|
+
sceneModePicker: mapOptions.control.sceneModePicker,
|
|
141
|
+
navigationHelpButton: mapOptions.control.navigationHelpButton,
|
|
142
|
+
animation: mapOptions.control.animation,
|
|
143
|
+
timeline: mapOptions.control.timeline,
|
|
144
|
+
infoBox: mapOptions.control.infoBox,
|
|
145
|
+
fullscreenButton: mapOptions.control.fullscreenButton,
|
|
146
|
+
vrButton: mapOptions.control.vrButton,
|
|
147
|
+
terrainProvider: mapOptions.terrain.show
|
|
148
|
+
? await Cesium.CesiumTerrainProvider.fromUrl(mapOptions.terrain.url, {
|
|
149
|
+
requestWaterMask: mapOptions.terrain.coastlineData,
|
|
150
|
+
requestVertexNormals: mapOptions.terrain.lightingData,
|
|
151
|
+
})
|
|
152
|
+
: undefined,
|
|
153
|
+
terrainShadows: Cesium.ShadowMode.RECEIVE_ONLY,
|
|
154
|
+
creditContainer: document.createElement('div'),
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const contextOptions = {
|
|
158
|
+
webgl: {
|
|
159
|
+
alpha: false,
|
|
160
|
+
depth: true,
|
|
161
|
+
stencil: false,
|
|
162
|
+
antialias: true,
|
|
163
|
+
premultipliedAlpha: true,
|
|
164
|
+
preserveDrawingBuffer: false,
|
|
165
|
+
failIfMajorPerformanceCaveat: false,
|
|
166
|
+
},
|
|
167
|
+
requestWebGl2: true,
|
|
168
|
+
powerPreference: 'high-performance',
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const sceneRenderOptions = {
|
|
172
|
+
debugShowFramesPerSecond: mapOptions.scene.debugShowFramesPerSecond,
|
|
173
|
+
enableLighting: mapOptions.scene.globe.enableLighting,
|
|
174
|
+
depthTestAgainstTerrain: mapOptions.scene.globe.depthTestAgainstTerrain,
|
|
175
|
+
fogEnabled: mapOptions.scene.fog.enabled,
|
|
176
|
+
skyAtmosphereShow: mapOptions.scene.skyAtmosphere.show,
|
|
177
|
+
dynamicAtmosphereLighting: mapOptions.scene.globe.dynamicAtmosphereLighting,
|
|
178
|
+
dynamicAtmosphereLightingFromSun: mapOptions.scene.globe.dynamicAtmosphereLightingFromSun,
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
map = new Cesium.Viewer(cesiumContainer.value, {
|
|
182
|
+
...viewerOptions,
|
|
183
|
+
contextOptions,
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
map.scene.debugShowFramesPerSecond = sceneRenderOptions.debugShowFramesPerSecond
|
|
187
|
+
map.scene.globe.enableLighting = sceneRenderOptions.enableLighting
|
|
188
|
+
map.scene.globe.depthTestAgainstTerrain = sceneRenderOptions.depthTestAgainstTerrain
|
|
189
|
+
map.scene.fog.enabled = sceneRenderOptions.fogEnabled
|
|
190
|
+
map.scene.skyAtmosphere.show = sceneRenderOptions.skyAtmosphereShow
|
|
191
|
+
map.scene.globe.dynamicAtmosphereLighting = sceneRenderOptions.dynamicAtmosphereLighting
|
|
192
|
+
map.scene.globe.dynamicAtmosphereLightingFromSun =
|
|
193
|
+
sceneRenderOptions.dynamicAtmosphereLightingFromSun
|
|
194
|
+
|
|
195
|
+
const sceneMode = mapOptions.scene.sceneMode || '3D'
|
|
196
|
+
|
|
197
|
+
const activeBasemap = resolveOnlineBasemap(mapOptions)
|
|
198
|
+
if (activeBasemap) {
|
|
199
|
+
applyImageryLayers(map, mapOptions, activeBasemap)
|
|
200
|
+
console.log(`加载在线底图:${activeBasemap.name},URL:${activeBasemap.url}`)
|
|
201
|
+
window._currentBasemapId = activeBasemap.id
|
|
202
|
+
} else {
|
|
203
|
+
console.warn('未找到可用底图,Cesium 将使用默认底图或空底图显示')
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (map.screenSpaceEventHandler && mapOptions.control.disableDoubleClick) {
|
|
207
|
+
map.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (mapOptions.control.disableEntityClick) {
|
|
211
|
+
map.selectedEntityChanged.addEventListener(() => {
|
|
212
|
+
map.selectedEntity = undefined
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
mouseController(map, props.mapId)
|
|
217
|
+
|
|
218
|
+
mapStore.setMapInfo(
|
|
219
|
+
'center',
|
|
220
|
+
{
|
|
221
|
+
lng: mapOptions.scene.center.lng,
|
|
222
|
+
lat: mapOptions.scene.center.lat,
|
|
223
|
+
heading: mapOptions.scene.center.heading,
|
|
224
|
+
pitch: mapOptions.scene.center.pitch,
|
|
225
|
+
roll: mapOptions.scene.center.roll,
|
|
226
|
+
duration: mapOptions.scene.center.duration,
|
|
227
|
+
alt: mapOptions.scene.center.alt,
|
|
228
|
+
},
|
|
229
|
+
props.mapId,
|
|
230
|
+
)
|
|
231
|
+
mapStore.setMap(map, props.mapId)
|
|
232
|
+
mapStore.setSceneMode(sceneMode, props.mapId)
|
|
233
|
+
|
|
234
|
+
const center = mapOptions.scene.center || {}
|
|
235
|
+
|
|
236
|
+
mountToolbarButtons(map)
|
|
237
|
+
mapStore.setMapLoadSta(MapLoadStatus.LOADED, props.mapId)
|
|
238
|
+
|
|
239
|
+
console.log(`Cesium 地图加载成功,mapId: ${props.mapId}`)
|
|
240
|
+
emit('onload', {
|
|
241
|
+
map,
|
|
242
|
+
center,
|
|
243
|
+
mapId: props.mapId,
|
|
244
|
+
toolbar: {
|
|
245
|
+
addToolbarButton: (opt) => addToolbarButton(map, opt),
|
|
246
|
+
addToolbarButtons: (opts) => addToolbarButtons(map, opts),
|
|
247
|
+
removeToolbarButtons,
|
|
248
|
+
},
|
|
249
|
+
syncCameraInteractionMode: (mode) => syncCameraInteractionMode(map, props.mapId, mode),
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
map.resize()
|
|
253
|
+
setInitialCameraView(map, mapOptions.scene.center, sceneMode, props.mapId)
|
|
254
|
+
map.render()
|
|
255
|
+
|
|
256
|
+
if (sceneMode === '2D') {
|
|
257
|
+
nextTick(() => {
|
|
258
|
+
if (!map || map.isDestroyed?.()) return
|
|
259
|
+
syncCameraInteractionMode(map, props.mapId, '2D')
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
startContinuousRendering(map)
|
|
264
|
+
} catch (error) {
|
|
265
|
+
mapStore.setMapLoadSta(MapLoadStatus.FAILED, props.mapId)
|
|
266
|
+
console.error('Cesium 地图加载失败:', error)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let animationId = null
|
|
271
|
+
let lastActiveTime = Date.now()
|
|
272
|
+
const IDLE_TIMEOUT = 30000
|
|
273
|
+
|
|
274
|
+
function startContinuousRendering(viewer) {
|
|
275
|
+
if (animationId) return
|
|
276
|
+
function animate() {
|
|
277
|
+
const now = Date.now()
|
|
278
|
+
if (
|
|
279
|
+
isMapActive &&
|
|
280
|
+
!document.hidden &&
|
|
281
|
+
map &&
|
|
282
|
+
!map.isDestroyed?.() &&
|
|
283
|
+
now - lastActiveTime < IDLE_TIMEOUT
|
|
284
|
+
) {
|
|
285
|
+
viewer.render()
|
|
286
|
+
}
|
|
287
|
+
animationId = requestAnimationFrame(animate)
|
|
288
|
+
}
|
|
289
|
+
animate()
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function stopRenderLoop() {
|
|
293
|
+
if (animationId) {
|
|
294
|
+
cancelAnimationFrame(animationId)
|
|
295
|
+
animationId = null
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function setupActivityListeners() {
|
|
300
|
+
const activities = ['mousemove', 'keydown', 'touchmove', 'wheel', 'click']
|
|
301
|
+
activities.forEach((event) => {
|
|
302
|
+
document.addEventListener(event, () => {
|
|
303
|
+
lastActiveTime = Date.now()
|
|
304
|
+
})
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function resumeMapAfterCache() {
|
|
309
|
+
if (!map || map.isDestroyed?.()) return
|
|
310
|
+
mapStore.setCurrentMapId(props.mapId)
|
|
311
|
+
isMapActive = true
|
|
312
|
+
lastActiveTime = Date.now()
|
|
313
|
+
nextTick(() => {
|
|
314
|
+
if (!map || map.isDestroyed?.()) return
|
|
315
|
+
map.resize()
|
|
316
|
+
const mode = mapStore.getSceneMode(props.mapId)
|
|
317
|
+
syncCameraInteractionMode(map, props.mapId, mode === '2D' ? '2D' : '3D')
|
|
318
|
+
map.render()
|
|
319
|
+
if (!animationId) startContinuousRendering(map)
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
watch(
|
|
324
|
+
() => props.toolbarButtons,
|
|
325
|
+
() => {
|
|
326
|
+
if (map && !map.isDestroyed?.()) {
|
|
327
|
+
mountToolbarButtons(map)
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
{ deep: true },
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
onMounted(() => {
|
|
334
|
+
mapStore.setCurrentMapId(props.mapId)
|
|
335
|
+
setupActivityListeners()
|
|
336
|
+
onEvent('map-scene-mode-changed', handleSceneModeChange)
|
|
337
|
+
initCesium()
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
onActivated(() => {
|
|
341
|
+
mapStore.setCurrentMapId(props.mapId)
|
|
342
|
+
if (!map || map.isDestroyed?.()) {
|
|
343
|
+
isMapActive = true
|
|
344
|
+
initCesium()
|
|
345
|
+
return
|
|
346
|
+
}
|
|
347
|
+
resumeMapAfterCache()
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
onDeactivated(() => {
|
|
351
|
+
isMapActive = false
|
|
352
|
+
stopRenderLoop()
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
onUnmounted(() => {
|
|
356
|
+
isMapActive = false
|
|
357
|
+
stopRenderLoop()
|
|
358
|
+
offEvent('map-scene-mode-changed', handleSceneModeChange)
|
|
359
|
+
if (map) {
|
|
360
|
+
teardownOrthographicWheelZoom(map)
|
|
361
|
+
}
|
|
362
|
+
removeToolbarButtons(customButtons)
|
|
363
|
+
customButtons = []
|
|
364
|
+
if (map) {
|
|
365
|
+
map.destroy()
|
|
366
|
+
map = null
|
|
367
|
+
}
|
|
368
|
+
mapStore.removeMapInstance(props.mapId)
|
|
369
|
+
})
|
|
370
|
+
</script>
|
|
371
|
+
|
|
372
|
+
<style scoped lang="less">
|
|
373
|
+
.cesium-map-wrapper {
|
|
374
|
+
width: 100%;
|
|
375
|
+
height: 100%;
|
|
376
|
+
position: relative;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.cesium-container {
|
|
380
|
+
width: 100%;
|
|
381
|
+
height: 100%;
|
|
382
|
+
position: relative;
|
|
383
|
+
}
|
|
384
|
+
</style>
|
|
385
|
+
|
package/js/basis.js
CHANGED
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import * as Cesium from 'cesium'
|
|
12
12
|
import { useMapStore } from './stores/mapStore.js'
|
|
13
|
+
import {
|
|
14
|
+
syncCameraInteractionMode,
|
|
15
|
+
teardownOrthographicWheelZoom,
|
|
16
|
+
restorePerspectiveControllerState,
|
|
17
|
+
} from './utils/cameraInteraction.js'
|
|
13
18
|
|
|
14
19
|
export function basicConfig() {
|
|
15
20
|
|
|
@@ -71,29 +76,42 @@ export function basicConfig() {
|
|
|
71
76
|
* roll: 0 // 不翻滚
|
|
72
77
|
* })
|
|
73
78
|
*/
|
|
74
|
-
const
|
|
75
|
-
|
|
79
|
+
const orthoViewHelpers = () => ({
|
|
80
|
+
applyOrthographicFrustum,
|
|
81
|
+
getEffective2DOrthoWidth,
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 设置 Cesium 地图初始相机视角(支持 2D 正交 / 3D 透视)
|
|
86
|
+
* @param {Cesium.Viewer} viewer
|
|
87
|
+
* @param {Object} center
|
|
88
|
+
* @param {'2D'|'3D'} sceneMode
|
|
89
|
+
* @param {string=} mapId
|
|
90
|
+
*/
|
|
91
|
+
const setInitialCameraView = (viewer, center = {}, sceneMode = '3D', mapId) => {
|
|
76
92
|
if (!viewer?.camera) return
|
|
77
93
|
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
94
|
+
const lng = Number(center.lng) || 0
|
|
95
|
+
const lat = Number(center.lat) || 0
|
|
96
|
+
const alt = Number(center.alt) || 10000
|
|
97
|
+
const heading = Cesium.Math.toRadians(Number(center.heading) || 0)
|
|
98
|
+
const pitch = Cesium.Math.toRadians(Number(center.pitch) ?? -90)
|
|
99
|
+
const roll = Cesium.Math.toRadians(Number(center.roll) || 0)
|
|
100
|
+
|
|
101
|
+
if (sceneMode === '2D') {
|
|
102
|
+
const orthoWidth = computeOrthoWidthFromHeight(viewer, alt)
|
|
103
|
+
if (mapId && orthoWidth > 0) {
|
|
104
|
+
mapStore.setViewOrthoWidth(orthoWidth, mapId)
|
|
105
|
+
}
|
|
106
|
+
set2DView(viewer, lng, lat, alt, orthoWidth, mapId)
|
|
107
|
+
return
|
|
108
|
+
}
|
|
85
109
|
|
|
86
|
-
// 设置相机视角
|
|
87
110
|
viewer.camera.setView({
|
|
88
|
-
// 相机目标位置:使用经纬度坐标和高度创建 Cartesian3 坐标
|
|
89
111
|
destination: Cesium.Cartesian3.fromDegrees(lng, lat, alt),
|
|
90
|
-
|
|
91
|
-
orientation: {
|
|
92
|
-
heading, // 航向角:绕垂直轴旋转(0=北,90=东,180=南,270=西)
|
|
93
|
-
pitch, // 俯仰角:绕水平轴旋转(-90=正下方,0=水平,90=正上方)
|
|
94
|
-
roll, // 翻滚角:绕相机朝向轴旋转
|
|
95
|
-
},
|
|
112
|
+
orientation: { heading, pitch, roll },
|
|
96
113
|
})
|
|
114
|
+
syncCameraInteractionMode(viewer, mapId, '3D', orthoViewHelpers())
|
|
97
115
|
}
|
|
98
116
|
|
|
99
117
|
/**
|
|
@@ -102,7 +120,7 @@ export function basicConfig() {
|
|
|
102
120
|
* 处理地图上的鼠标事件,包括点击、拖动、缩放等、
|
|
103
121
|
* @param map - 地图实例
|
|
104
122
|
*/
|
|
105
|
-
const mouseController = (map) => {
|
|
123
|
+
const mouseController = (map, _mapId) => {
|
|
106
124
|
// 添加右键点击事件监听
|
|
107
125
|
map.screenSpaceEventHandler.setInputAction((click) => {
|
|
108
126
|
// 获取点击位置的笛卡尔坐标
|
|
@@ -181,7 +199,7 @@ export function basicConfig() {
|
|
|
181
199
|
if (mapId && orthoWidth > 0) {
|
|
182
200
|
mapStore.setViewOrthoWidth(orthoWidth, mapId)
|
|
183
201
|
}
|
|
184
|
-
set2DView(map, lng, lat, finalAltitude, orthoWidth)
|
|
202
|
+
set2DView(map, lng, lat, finalAltitude, orthoWidth, mapId)
|
|
185
203
|
} else {
|
|
186
204
|
if (mapId) {
|
|
187
205
|
const pitchDeg = Math.abs(centerInfo.pitch ?? -35)
|
|
@@ -189,7 +207,7 @@ export function basicConfig() {
|
|
|
189
207
|
const range = Math.max(finalAltitude / Math.max(Math.sin(pitchRad), 0.1), 100)
|
|
190
208
|
mapStore.setViewOrthoWidth(rangeToOrthoWidth(map, range), mapId)
|
|
191
209
|
}
|
|
192
|
-
set3DView(map, lng, lat, centerInfo, finalAltitude, finalTargetAlt)
|
|
210
|
+
set3DView(map, lng, lat, centerInfo, finalAltitude, finalTargetAlt, undefined, mapId)
|
|
193
211
|
}
|
|
194
212
|
}
|
|
195
213
|
|
|
@@ -240,6 +258,8 @@ export function basicConfig() {
|
|
|
240
258
|
const restorePerspectiveFrustum = (map) => {
|
|
241
259
|
if (!map) return
|
|
242
260
|
|
|
261
|
+
if (map.camera.frustum instanceof Cesium.PerspectiveFrustum) return
|
|
262
|
+
|
|
243
263
|
const currentFrustum = map.camera.frustum
|
|
244
264
|
const perspectiveFrustum = new Cesium.PerspectiveFrustum()
|
|
245
265
|
perspectiveFrustum.fov = getPerspectiveVerticalFovRadians()
|
|
@@ -291,7 +311,6 @@ export function basicConfig() {
|
|
|
291
311
|
if (!map) return
|
|
292
312
|
|
|
293
313
|
const canvas = map.canvas
|
|
294
|
-
const frustum = new Cesium.OrthographicFrustum()
|
|
295
314
|
const width = canvas.clientWidth
|
|
296
315
|
const height = canvas.clientHeight
|
|
297
316
|
|
|
@@ -303,10 +322,22 @@ export function basicConfig() {
|
|
|
303
322
|
} else if (map.scene.camera.frustum instanceof Cesium.PerspectiveFrustum) {
|
|
304
323
|
const cameraHeight = map.scene.camera.positionCartographic?.height ?? 10000
|
|
305
324
|
widthValue = computeOrthoWidthFromHeight(map, cameraHeight)
|
|
325
|
+
} else if (map.scene.camera.frustum instanceof Cesium.OrthographicFrustum) {
|
|
326
|
+
widthValue = map.scene.camera.frustum.width || getEffective2DOrthoWidth(map) || 20000
|
|
306
327
|
} else {
|
|
307
|
-
widthValue =
|
|
328
|
+
widthValue = 20000
|
|
308
329
|
}
|
|
309
330
|
|
|
331
|
+
const currentFrustum = map.scene.camera.frustum
|
|
332
|
+
if (currentFrustum instanceof Cesium.OrthographicFrustum) {
|
|
333
|
+
currentFrustum.width = widthValue
|
|
334
|
+
currentFrustum.aspectRatio = width / height
|
|
335
|
+
currentFrustum.near = 0.1
|
|
336
|
+
currentFrustum.far = 10000000.0
|
|
337
|
+
return
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const frustum = new Cesium.OrthographicFrustum()
|
|
310
341
|
frustum.width = widthValue
|
|
311
342
|
frustum.aspectRatio = width / height
|
|
312
343
|
frustum.near = 0.1
|
|
@@ -322,7 +353,7 @@ export function basicConfig() {
|
|
|
322
353
|
* @param {number=} height 相机高度
|
|
323
354
|
* @param {number=} orthoWidth 正交可视宽度(米),切换 2D/3D 时传入以保持缩放不变
|
|
324
355
|
*/
|
|
325
|
-
const set2DView = (map, lng, lat, height, orthoWidth) => {
|
|
356
|
+
const set2DView = (map, lng, lat, height, orthoWidth, mapId) => {
|
|
326
357
|
if (!map) return
|
|
327
358
|
|
|
328
359
|
const resolvedWidth = Number.isFinite(orthoWidth) && orthoWidth > 0
|
|
@@ -337,15 +368,17 @@ export function basicConfig() {
|
|
|
337
368
|
cameraController.enableTilt = false
|
|
338
369
|
cameraController.enableLook = false
|
|
339
370
|
}
|
|
371
|
+
|
|
340
372
|
map.camera.setView({
|
|
341
373
|
destination: Cesium.Cartesian3.fromDegrees(lng, lat, resolvedHeight),
|
|
342
374
|
orientation: {
|
|
343
375
|
heading: Cesium.Math.toRadians(0),
|
|
344
376
|
pitch: Cesium.Math.toRadians(-90),
|
|
345
|
-
roll: Cesium.Math.toRadians(0)
|
|
346
|
-
}
|
|
377
|
+
roll: Cesium.Math.toRadians(0),
|
|
378
|
+
},
|
|
347
379
|
})
|
|
348
380
|
applyOrthographicFrustum(map, undefined, resolvedWidth)
|
|
381
|
+
syncCameraInteractionMode(map, mapId, '2D', orthoViewHelpers())
|
|
349
382
|
}
|
|
350
383
|
|
|
351
384
|
/**
|
|
@@ -366,7 +399,7 @@ export function basicConfig() {
|
|
|
366
399
|
* @param {number=} targetAlt 目标点的高度(比如无人机的飞行高度,默认0)
|
|
367
400
|
* @param {number=} slantRange 可选,相机到目标点的直线距离(米);传入时优先于 altitude 换算
|
|
368
401
|
*/
|
|
369
|
-
const set3DView = (map, lng, lat, centerInfo = {}, altitude = 10000, targetAlt = 0, slantRange) => {
|
|
402
|
+
const set3DView = (map, lng, lat, centerInfo = {}, altitude = 10000, targetAlt = 0, slantRange, mapId) => {
|
|
370
403
|
// 1. 检查地图实例是否存在,不存在就直接返回
|
|
371
404
|
if (!map) return
|
|
372
405
|
|
|
@@ -418,8 +451,14 @@ export function basicConfig() {
|
|
|
418
451
|
)
|
|
419
452
|
)
|
|
420
453
|
|
|
421
|
-
// 9. 重置相机变换(确保lookAt生效后恢复正常状态)
|
|
422
454
|
map.camera.lookAtTransform(Cesium.Matrix4.IDENTITY)
|
|
455
|
+
|
|
456
|
+
if (mapId) {
|
|
457
|
+
syncCameraInteractionMode(map, mapId, '3D', orthoViewHelpers())
|
|
458
|
+
} else {
|
|
459
|
+
teardownOrthographicWheelZoom(map)
|
|
460
|
+
restorePerspectiveControllerState(map)
|
|
461
|
+
}
|
|
423
462
|
}
|
|
424
463
|
|
|
425
464
|
/**
|
|
@@ -508,14 +547,14 @@ export function basicConfig() {
|
|
|
508
547
|
if (Number.isFinite(slantRange) && slantRange > 0) {
|
|
509
548
|
const orthoWidth = Math.max(rangeToOrthoWidth(map, slantRange), 100)
|
|
510
549
|
mapStore.setViewOrthoWidth(orthoWidth, mapId)
|
|
511
|
-
set3DView(map, lng, lat, centerInfo, undefined, 0, slantRange)
|
|
550
|
+
set3DView(map, lng, lat, centerInfo, undefined, 0, slantRange, mapId)
|
|
512
551
|
return
|
|
513
552
|
}
|
|
514
553
|
|
|
515
554
|
const orthoWidth = getEffective2DOrthoWidth(map) || resolveViewOrthoWidth(map, mapId, centerInfo)
|
|
516
555
|
mapStore.setViewOrthoWidth(orthoWidth, mapId)
|
|
517
556
|
const range = Math.max(orthoWidthToRange(map, orthoWidth), 100)
|
|
518
|
-
set3DView(map, lng, lat, centerInfo, undefined, 0, range)
|
|
557
|
+
set3DView(map, lng, lat, centerInfo, undefined, 0, range, mapId)
|
|
519
558
|
}
|
|
520
559
|
|
|
521
560
|
/**
|
|
@@ -541,7 +580,7 @@ export function basicConfig() {
|
|
|
541
580
|
}
|
|
542
581
|
}
|
|
543
582
|
|
|
544
|
-
set2DView(map, lng, lat, undefined, orthoWidth)
|
|
583
|
+
set2DView(map, lng, lat, undefined, orthoWidth, mapId)
|
|
545
584
|
}
|
|
546
585
|
|
|
547
586
|
/**
|
|
@@ -670,6 +709,10 @@ export function basicConfig() {
|
|
|
670
709
|
set3DView,
|
|
671
710
|
applyOrthographicFrustum,
|
|
672
711
|
restorePerspectiveFrustum,
|
|
673
|
-
setInitialCameraView
|
|
712
|
+
setInitialCameraView,
|
|
713
|
+
syncCameraInteractionMode: (map, mapId, sceneMode) =>
|
|
714
|
+
syncCameraInteractionMode(map, mapId, sceneMode, orthoViewHelpers()),
|
|
674
715
|
}
|
|
675
|
-
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
export { teardownOrthographicWheelZoom, ensureMapFocus } from './utils/cameraInteraction.js'
|
|
@@ -129,6 +129,9 @@ export function createCustomToolbarButtons() {
|
|
|
129
129
|
const result = toggleViewToRtk(mapId)
|
|
130
130
|
if (result.success && btn) btn.innerText = result.currentMode
|
|
131
131
|
mapStore.setSceneMode(result.currentMode, mapId)
|
|
132
|
+
if (result.success) {
|
|
133
|
+
emit('map-scene-mode-changed', { mapId, sceneMode: result.currentMode })
|
|
134
|
+
}
|
|
132
135
|
}
|
|
133
136
|
},
|
|
134
137
|
{
|
package/js/index.js
CHANGED
|
@@ -30,6 +30,12 @@ export { default as eventBus } from './utils/eventBus.js'
|
|
|
30
30
|
export { useEventBus } from './utils/useEventBus.js'
|
|
31
31
|
export { getMapCenterPosition } from './utils/getMapCenterPosition.js'
|
|
32
32
|
export { selectDrone, deselectDrone } from './utils/droneSelection.js'
|
|
33
|
+
export { applyOrthographicZoomFactor } from './utils/orthographicCameraZoom.js'
|
|
34
|
+
export {
|
|
35
|
+
ensureMapFocus,
|
|
36
|
+
teardownOrthographicWheelZoom,
|
|
37
|
+
syncCameraInteractionMode,
|
|
38
|
+
} from './utils/cameraInteraction.js'
|
|
33
39
|
|
|
34
40
|
export {
|
|
35
41
|
BaseConfig,
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 2D 正交 / 3D 透视下的相机交互(滚轮缩放、控制器开关)
|
|
3
|
+
*/
|
|
4
|
+
import * as Cesium from 'cesium'
|
|
5
|
+
import { useMapStore } from '../stores/mapStore.js'
|
|
6
|
+
import { applyOrthographicZoomFactor } from './orthographicCameraZoom.js'
|
|
7
|
+
|
|
8
|
+
const ORTHO_WHEEL_ZOOM_RATE = 1.1
|
|
9
|
+
const orthoWheelCleanups = new WeakMap()
|
|
10
|
+
|
|
11
|
+
export function ensureMapFocus(map) {
|
|
12
|
+
const canvas = map?.canvas
|
|
13
|
+
if (!canvas) return
|
|
14
|
+
if (!canvas.hasAttribute('tabindex')) {
|
|
15
|
+
canvas.setAttribute('tabindex', '0')
|
|
16
|
+
}
|
|
17
|
+
canvas.focus({ preventScroll: true })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 2D:禁用内置缩放,由自定义滚轮接管 */
|
|
21
|
+
export function syncOrthographicControllerState(map) {
|
|
22
|
+
const controller = map.scene?.screenSpaceCameraController
|
|
23
|
+
if (!controller) return
|
|
24
|
+
controller.enableTilt = false
|
|
25
|
+
controller.enableLook = false
|
|
26
|
+
controller.enableZoom = false
|
|
27
|
+
controller.enableCollisionDetection = false
|
|
28
|
+
controller.inertiaZoom = 0
|
|
29
|
+
map.camera.cancelFlight()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** 3D:恢复 Cesium 默认相机交互(含滚轮缩放) */
|
|
33
|
+
export function restorePerspectiveControllerState(map) {
|
|
34
|
+
const controller = map.scene?.screenSpaceCameraController
|
|
35
|
+
if (!controller) return
|
|
36
|
+
controller.enableTilt = true
|
|
37
|
+
controller.enableLook = true
|
|
38
|
+
controller.enableZoom = true
|
|
39
|
+
controller.enableCollisionDetection = true
|
|
40
|
+
controller.inertiaZoom = 0.8
|
|
41
|
+
controller.minimumZoomDistance = 1.0
|
|
42
|
+
controller.maximumZoomDistance = Number.POSITIVE_INFINITY
|
|
43
|
+
map.camera.cancelFlight()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function applyOrthographicZoom(map, mapId, delta) {
|
|
47
|
+
const factor = Math.pow(ORTHO_WHEEL_ZOOM_RATE, -delta / 120)
|
|
48
|
+
applyOrthographicZoomFactor(map, mapId, factor)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 在 canvas capture 阶段拦截滚轮,绕过 ScreenSpaceCameraController 默认缩放
|
|
53
|
+
*/
|
|
54
|
+
export function setupOrthographicWheelZoom(map, mapId) {
|
|
55
|
+
if (!map?.canvas) return
|
|
56
|
+
teardownOrthographicWheelZoom(map)
|
|
57
|
+
syncOrthographicControllerState(map)
|
|
58
|
+
|
|
59
|
+
const onWheel = (event) => {
|
|
60
|
+
if (!(map.camera.frustum instanceof Cesium.OrthographicFrustum)) return
|
|
61
|
+
event.preventDefault()
|
|
62
|
+
event.stopImmediatePropagation()
|
|
63
|
+
const delta = -(event.deltaY || event.wheelDelta || 0)
|
|
64
|
+
applyOrthographicZoom(map, mapId, delta)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
map.canvas.addEventListener('wheel', onWheel, { passive: false, capture: true })
|
|
68
|
+
orthoWheelCleanups.set(map, () => {
|
|
69
|
+
map.canvas.removeEventListener('wheel', onWheel, { capture: true })
|
|
70
|
+
orthoWheelCleanups.delete(map)
|
|
71
|
+
})
|
|
72
|
+
ensureMapFocus(map)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function teardownOrthographicWheelZoom(map) {
|
|
76
|
+
if (!map || map.isDestroyed?.()) return
|
|
77
|
+
orthoWheelCleanups.get(map)?.()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 按 2D/3D 切换相机交互
|
|
82
|
+
* @param {object} helpers.applyOrthographicFrustum
|
|
83
|
+
* @param {object} helpers.getEffective2DOrthoWidth
|
|
84
|
+
*/
|
|
85
|
+
export function syncCameraInteractionMode(map, mapId, sceneMode, helpers) {
|
|
86
|
+
if (!map || map.isDestroyed?.()) return
|
|
87
|
+
const { applyOrthographicFrustum, getEffective2DOrthoWidth } = helpers
|
|
88
|
+
const mapStore = useMapStore()
|
|
89
|
+
|
|
90
|
+
if (sceneMode === '2D') {
|
|
91
|
+
const orthoWidth = mapStore.getViewOrthoWidth(mapId) || getEffective2DOrthoWidth(map)
|
|
92
|
+
if (orthoWidth > 0) {
|
|
93
|
+
applyOrthographicFrustum(map, undefined, orthoWidth)
|
|
94
|
+
}
|
|
95
|
+
setupOrthographicWheelZoom(map, mapId)
|
|
96
|
+
} else {
|
|
97
|
+
teardownOrthographicWheelZoom(map)
|
|
98
|
+
restorePerspectiveControllerState(map)
|
|
99
|
+
}
|
|
100
|
+
map.scene.requestRender()
|
|
101
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Cesium from 'cesium'
|
|
2
|
+
import { useMapStore } from '../stores/mapStore.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 2D 正交缩放:同步修改 frustum.width 与相机高度,不使用 setView(避免首帧透视 dollying)
|
|
6
|
+
* @returns {boolean} 是否已按正交模式处理
|
|
7
|
+
*/
|
|
8
|
+
export function applyOrthographicZoomFactor(map, mapId, factor) {
|
|
9
|
+
const camera = map?.camera
|
|
10
|
+
const frustum = camera?.frustum
|
|
11
|
+
if (!(frustum instanceof Cesium.OrthographicFrustum)) return false
|
|
12
|
+
|
|
13
|
+
frustum.width = Cesium.Math.clamp(frustum.width * factor, 100, 10000000)
|
|
14
|
+
|
|
15
|
+
const cartographic = camera.positionCartographic
|
|
16
|
+
if (cartographic) {
|
|
17
|
+
const newHeight = Cesium.Math.clamp(cartographic.height * factor, 100, 1000000)
|
|
18
|
+
const updated = cartographic.clone()
|
|
19
|
+
updated.height = newHeight
|
|
20
|
+
camera.position = Cesium.Cartographic.toCartesian(updated)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (mapId) {
|
|
24
|
+
useMapStore().setViewOrthoWidth(frustum.width, mapId)
|
|
25
|
+
}
|
|
26
|
+
map.scene.requestRender()
|
|
27
|
+
return true
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huweili-cesium",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "基于 Cesium 的地图工具库(无人机态势、轨迹、围栏、工具栏等)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -87,16 +87,34 @@
|
|
|
87
87
|
"./utils/getMapCenterPosition.js": "./js/utils/getMapCenterPosition.js",
|
|
88
88
|
"./utils/droneSelection": "./js/utils/droneSelection.js",
|
|
89
89
|
"./utils/droneSelection.js": "./js/utils/droneSelection.js",
|
|
90
|
+
"./js/utils/droneSelection": "./js/utils/droneSelection.js",
|
|
91
|
+
"./js/utils/droneSelection.js": "./js/utils/droneSelection.js",
|
|
92
|
+
"./utils/orthographicCameraZoom": "./js/utils/orthographicCameraZoom.js",
|
|
93
|
+
"./utils/orthographicCameraZoom.js": "./js/utils/orthographicCameraZoom.js",
|
|
94
|
+
"./utils/cameraInteraction": "./js/utils/cameraInteraction.js",
|
|
95
|
+
"./utils/cameraInteraction.js": "./js/utils/cameraInteraction.js",
|
|
96
|
+
"./js/utils/orthographicCameraZoom": "./js/utils/orthographicCameraZoom.js",
|
|
97
|
+
"./js/utils/orthographicCameraZoom.js": "./js/utils/orthographicCameraZoom.js",
|
|
90
98
|
"./utils/cesium/object": "./js/utils/cesium/object.js",
|
|
91
99
|
"./utils/cesium/object.js": "./js/utils/cesium/object.js",
|
|
100
|
+
"./js/utils/cesium/object": "./js/utils/cesium/object.js",
|
|
101
|
+
"./js/utils/cesium/object.js": "./js/utils/cesium/object.js",
|
|
92
102
|
"./utils/cesium/json": "./js/utils/cesium/json.js",
|
|
93
103
|
"./utils/cesium/json.js": "./js/utils/cesium/json.js",
|
|
104
|
+
"./js/utils/cesium/json": "./js/utils/cesium/json.js",
|
|
105
|
+
"./js/utils/cesium/json.js": "./js/utils/cesium/json.js",
|
|
94
106
|
"./config": "./js/config/index.js",
|
|
95
107
|
"./config/index": "./js/config/index.js",
|
|
108
|
+
"./js/config": "./js/config/index.js",
|
|
109
|
+
"./js/config/index": "./js/config/index.js",
|
|
96
110
|
"./config/hooks": "./js/config/hooks.js",
|
|
97
111
|
"./config/hooks.js": "./js/config/hooks.js",
|
|
112
|
+
"./js/config/hooks": "./js/config/hooks.js",
|
|
113
|
+
"./js/config/hooks.js": "./js/config/hooks.js",
|
|
98
114
|
"./api/gaode": "./js/api/gaode.js",
|
|
99
|
-
"./api/gaode.js": "./js/api/gaode.js"
|
|
115
|
+
"./api/gaode.js": "./js/api/gaode.js",
|
|
116
|
+
"./js/api/gaode": "./js/api/gaode.js",
|
|
117
|
+
"./js/api/gaode.js": "./js/api/gaode.js"
|
|
100
118
|
},
|
|
101
119
|
"files": [
|
|
102
120
|
"index.js",
|