huweili-cesium 1.1.13 → 1.1.14
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 +3 -4
- package/js/basis.js +18 -78
- package/js/hemisphere.js +357 -359
- package/js/stores/mapStore.js +0 -10
- package/js/toolbar/zoomController.js +5 -6
- package/package.json +1 -1
- package/js/utils/cesiumContext.js +0 -36
- package/js/utils/frustumCompat.js +0 -97
- package/postinstall.mjs +0 -79
package/index.vue
CHANGED
|
@@ -205,6 +205,9 @@ const initCesium = async () => {
|
|
|
205
205
|
// 开启/关闭 动态大气光照从太阳开始
|
|
206
206
|
map.scene.globe.dynamicAtmosphereLightingFromSun = mapOptions.scene.globe.dynamicAtmosphereLightingFromSun;
|
|
207
207
|
|
|
208
|
+
// 设置场景模式(2D/3D)
|
|
209
|
+
const sceneMode = mapOptions.scene.sceneMode || '3D';
|
|
210
|
+
mapStore.setSceneMode(sceneMode, props.mapId);
|
|
208
211
|
// 设置场景模式(2D/3D)时候的 正交投影(2D)还是透视投影(3D)
|
|
209
212
|
switch(mapOptions.scene.sceneMode){
|
|
210
213
|
case '2D':
|
|
@@ -229,10 +232,6 @@ const initCesium = async () => {
|
|
|
229
232
|
alt: mapOptions.scene.center.alt,
|
|
230
233
|
}, props.mapId)
|
|
231
234
|
mapStore.setMap(map, props.mapId)
|
|
232
|
-
|
|
233
|
-
// 设置场景模式(2D/3D)
|
|
234
|
-
const sceneMode = mapOptions.scene.sceneMode || '3D';
|
|
235
|
-
mapStore.setSceneMode(sceneMode, props.mapId);
|
|
236
235
|
|
|
237
236
|
// 初始化半球区域
|
|
238
237
|
const center = mapOptions.scene.center || {}
|
package/js/basis.js
CHANGED
|
@@ -10,19 +10,6 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import * as Cesium from 'cesium'
|
|
12
12
|
import { useMapStore } from './stores/mapStore.js'
|
|
13
|
-
import {
|
|
14
|
-
bindFrustumConstructors,
|
|
15
|
-
createOrthographicFrustum,
|
|
16
|
-
createPerspectiveFrustum,
|
|
17
|
-
ensure3DCompatibleFrustum,
|
|
18
|
-
detectDuplicateCesium,
|
|
19
|
-
getCanvasAspectRatio,
|
|
20
|
-
isOrthographicFrustum,
|
|
21
|
-
isPerspectiveFrustum,
|
|
22
|
-
isValid3DFrustum,
|
|
23
|
-
warnDuplicateCesiumOnce,
|
|
24
|
-
} from './utils/frustumCompat.js'
|
|
25
|
-
import { getCesium } from './utils/cesiumContext.js'
|
|
26
13
|
|
|
27
14
|
export function basicConfig() {
|
|
28
15
|
|
|
@@ -135,7 +122,7 @@ export function basicConfig() {
|
|
|
135
122
|
const finalTargetAlt = targetAlt !== undefined ? targetAlt : (centerInfo.targetAlt || 0)
|
|
136
123
|
|
|
137
124
|
// 检查当前是正交投影(2D)还是透视投影(3D)
|
|
138
|
-
const isOrthographic =
|
|
125
|
+
const isOrthographic = map.camera.frustum instanceof Cesium.OrthographicFrustum
|
|
139
126
|
|
|
140
127
|
if (isOrthographic) {
|
|
141
128
|
const orthoWidth = computeOrthoWidthFromHeight(map, finalAltitude)
|
|
@@ -201,20 +188,12 @@ export function basicConfig() {
|
|
|
201
188
|
const restorePerspectiveFrustum = (map) => {
|
|
202
189
|
if (!map) return
|
|
203
190
|
|
|
204
|
-
bindFrustumConstructors(map)
|
|
205
191
|
const currentFrustum = map.camera.frustum
|
|
206
|
-
|
|
207
|
-
if (isPerspectiveFrustum(currentFrustum)) {
|
|
208
|
-
currentFrustum.fov = getPerspectiveVerticalFovRadians()
|
|
209
|
-
currentFrustum.aspectRatio = getCanvasAspectRatio(map)
|
|
210
|
-
return
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const perspectiveFrustum = createPerspectiveFrustum(map, currentFrustum)
|
|
192
|
+
const perspectiveFrustum = new Cesium.PerspectiveFrustum()
|
|
214
193
|
perspectiveFrustum.fov = getPerspectiveVerticalFovRadians()
|
|
215
|
-
perspectiveFrustum.aspectRatio =
|
|
216
|
-
perspectiveFrustum.near = currentFrustum
|
|
217
|
-
perspectiveFrustum.far = currentFrustum
|
|
194
|
+
perspectiveFrustum.aspectRatio = map.canvas.clientWidth / map.canvas.clientHeight
|
|
195
|
+
perspectiveFrustum.near = currentFrustum.near || 1.0
|
|
196
|
+
perspectiveFrustum.far = currentFrustum.far || 10000000.0
|
|
218
197
|
map.camera.frustum = perspectiveFrustum
|
|
219
198
|
}
|
|
220
199
|
|
|
@@ -259,36 +238,28 @@ export function basicConfig() {
|
|
|
259
238
|
const applyOrthographicFrustum = (map, viewHeight, orthoWidth) => {
|
|
260
239
|
if (!map) return
|
|
261
240
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
return
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const current = map.camera.frustum
|
|
241
|
+
const canvas = map.canvas
|
|
242
|
+
const frustum = new Cesium.OrthographicFrustum()
|
|
243
|
+
const width = canvas.clientWidth
|
|
244
|
+
const height = canvas.clientHeight
|
|
270
245
|
|
|
271
246
|
let widthValue
|
|
272
247
|
if (Number.isFinite(orthoWidth) && orthoWidth > 0) {
|
|
273
248
|
widthValue = orthoWidth
|
|
274
249
|
} else if (Number.isFinite(viewHeight) && viewHeight > 0) {
|
|
275
250
|
widthValue = computeOrthoWidthFromHeight(map, viewHeight)
|
|
276
|
-
} else if (
|
|
277
|
-
const cameraHeight = map.camera.positionCartographic?.height ?? 10000
|
|
251
|
+
} else if (map.scene.camera.frustum instanceof Cesium.PerspectiveFrustum) {
|
|
252
|
+
const cameraHeight = map.scene.camera.positionCartographic?.height ?? 10000
|
|
278
253
|
widthValue = computeOrthoWidthFromHeight(map, cameraHeight)
|
|
279
254
|
} else {
|
|
280
|
-
widthValue =
|
|
255
|
+
widthValue = map.scene.camera.frustum.width || 20000
|
|
281
256
|
}
|
|
282
257
|
|
|
283
|
-
const frustum = isOrthographicFrustum(current)
|
|
284
|
-
? current
|
|
285
|
-
: createOrthographicFrustum()
|
|
286
|
-
|
|
287
258
|
frustum.width = widthValue
|
|
288
|
-
frustum.aspectRatio =
|
|
259
|
+
frustum.aspectRatio = width / height
|
|
289
260
|
frustum.near = 0.1
|
|
290
261
|
frustum.far = 10000000.0
|
|
291
|
-
map.camera.frustum = frustum
|
|
262
|
+
map.scene.camera.frustum = frustum
|
|
292
263
|
}
|
|
293
264
|
|
|
294
265
|
/**
|
|
@@ -421,7 +392,7 @@ export function basicConfig() {
|
|
|
421
392
|
}
|
|
422
393
|
|
|
423
394
|
const camera = map.camera
|
|
424
|
-
const isOrthographic =
|
|
395
|
+
const isOrthographic = camera.frustum instanceof Cesium.OrthographicFrustum
|
|
425
396
|
|
|
426
397
|
let currentMode
|
|
427
398
|
if (isOrthographic) {
|
|
@@ -448,7 +419,7 @@ export function basicConfig() {
|
|
|
448
419
|
*/
|
|
449
420
|
const getEffective2DOrthoWidth = (map) => {
|
|
450
421
|
const frustum = map?.camera?.frustum
|
|
451
|
-
if (!
|
|
422
|
+
if (!(frustum instanceof Cesium.OrthographicFrustum)) return 0
|
|
452
423
|
if (frustum.width > 0) return frustum.width
|
|
453
424
|
|
|
454
425
|
const cameraHeight = map?.camera?.positionCartographic?.height
|
|
@@ -612,7 +583,7 @@ export function basicConfig() {
|
|
|
612
583
|
const { distance2D, distance3D } = options
|
|
613
584
|
|
|
614
585
|
const camera = map.camera
|
|
615
|
-
const isOrthographic =
|
|
586
|
+
const isOrthographic = camera.frustum instanceof Cesium.OrthographicFrustum
|
|
616
587
|
|
|
617
588
|
let currentMode
|
|
618
589
|
if (isOrthographic) {
|
|
@@ -626,35 +597,6 @@ export function basicConfig() {
|
|
|
626
597
|
return { success: true, currentMode }
|
|
627
598
|
}
|
|
628
599
|
|
|
629
|
-
/**
|
|
630
|
-
* 场景模式切换(如 Cesium 自带 sceneModePicker)后修复不兼容的视锥体
|
|
631
|
-
* @param {import('cesium').Viewer} map
|
|
632
|
-
* @param {string=} mapId
|
|
633
|
-
*/
|
|
634
|
-
const setupFrustumGuard = (map, mapId) => {
|
|
635
|
-
if (!map?.scene?.morphComplete) return
|
|
636
|
-
|
|
637
|
-
map.scene.morphComplete.addEventListener(() => {
|
|
638
|
-
const mode = map.scene.mode
|
|
639
|
-
if (
|
|
640
|
-
mode !== Cesium.SceneMode.SCENE3D &&
|
|
641
|
-
mode !== Cesium.SceneMode.COLUMBUS_VIEW
|
|
642
|
-
) {
|
|
643
|
-
return
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
if (isValid3DFrustum(map.camera.frustum)) return
|
|
647
|
-
|
|
648
|
-
const preferOrtho = mapStore.getSceneMode(mapId) === '2D'
|
|
649
|
-
ensure3DCompatibleFrustum(map, preferOrtho)
|
|
650
|
-
if (preferOrtho) {
|
|
651
|
-
applyOrthographicFrustum(map)
|
|
652
|
-
} else {
|
|
653
|
-
restorePerspectiveFrustum(map)
|
|
654
|
-
}
|
|
655
|
-
})
|
|
656
|
-
}
|
|
657
|
-
|
|
658
600
|
return {
|
|
659
601
|
isInChina,
|
|
660
602
|
mouseController,
|
|
@@ -675,8 +617,6 @@ export function basicConfig() {
|
|
|
675
617
|
set2DView,
|
|
676
618
|
set3DView,
|
|
677
619
|
applyOrthographicFrustum,
|
|
678
|
-
restorePerspectiveFrustum
|
|
679
|
-
bindFrustumConstructors,
|
|
680
|
-
setupFrustumGuard,
|
|
620
|
+
restorePerspectiveFrustum
|
|
681
621
|
}
|
|
682
622
|
}
|
package/js/hemisphere.js
CHANGED
|
@@ -1,360 +1,358 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 半球体实体管理模块
|
|
3
|
-
*
|
|
4
|
-
* 提供在Cesium地图上创建、更新、移动和删除半球体实体的功能
|
|
5
|
-
* 支持自定义半球体的位置、半径、颜色等属性
|
|
6
|
-
*
|
|
7
|
-
* @author huweili
|
|
8
|
-
* @email czxyhuweili@163.com
|
|
9
|
-
* @version 1.0.0
|
|
10
|
-
*/
|
|
11
|
-
import * as Cesium from 'cesium'
|
|
12
|
-
import { BaseConfig } from './config/index.js';
|
|
13
|
-
import { useMapStore } from './stores/mapStore.js'
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* @
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* @param {string}
|
|
49
|
-
* @
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* @param {
|
|
63
|
-
* @param {
|
|
64
|
-
* @param {number
|
|
65
|
-
* @param {
|
|
66
|
-
* @param {string} options.
|
|
67
|
-
* @param {string} options.
|
|
68
|
-
* @
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
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
|
-
* @param {
|
|
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
|
-
const
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
* @param {
|
|
217
|
-
* @param {
|
|
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
|
-
const
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
* @param {
|
|
281
|
-
* @param {string} options.
|
|
282
|
-
* @param {
|
|
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
|
-
setHemisphereVisible
|
|
359
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 半球体实体管理模块
|
|
3
|
+
*
|
|
4
|
+
* 提供在Cesium地图上创建、更新、移动和删除半球体实体的功能
|
|
5
|
+
* 支持自定义半球体的位置、半径、颜色等属性
|
|
6
|
+
*
|
|
7
|
+
* @author huweili
|
|
8
|
+
* @email czxyhuweili@163.com
|
|
9
|
+
* @version 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
import * as Cesium from 'cesium'
|
|
12
|
+
import { BaseConfig } from './config/index.js';
|
|
13
|
+
import { useMapStore } from './stores/mapStore.js'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 半球体实体管理配置函数
|
|
17
|
+
* 初始化半球体管理模块,返回半球体操作相关方法
|
|
18
|
+
*
|
|
19
|
+
* @returns {Object} 半球体操作方法集合
|
|
20
|
+
*/
|
|
21
|
+
export function hemisphereConfig() {
|
|
22
|
+
|
|
23
|
+
// 获取地图store实例
|
|
24
|
+
const mapStore = useMapStore()
|
|
25
|
+
|
|
26
|
+
// 从配置中心读取 labelEntity 应该处于的角度,并确保在0到90度之间
|
|
27
|
+
const radians = Cesium.Math.toRadians(BaseConfig.hemisphereLabelAngle);
|
|
28
|
+
const hemisphereLabelAngle = Math.max(0, Math.min(Math.PI / 2, radians));
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 格式化半球半径标签
|
|
32
|
+
* 将米为单位的半径值转换为千米,并添加km单位
|
|
33
|
+
* @param {number|string} radius - 半径值(米)
|
|
34
|
+
* @returns {string} - 格式化后的半径标签,如 "3km"
|
|
35
|
+
*/
|
|
36
|
+
const formatHemisphereRadiusLabel = (radius) => {
|
|
37
|
+
const radiusValue = Number(radius);
|
|
38
|
+
if (!Number.isFinite(radiusValue)) {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
return `${radiusValue / 1000}km`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 获取半球标签文本
|
|
46
|
+
* 组合标签名称和半径信息,生成完整的半球标签显示文本
|
|
47
|
+
* @param {string} label - 半球标签名称
|
|
48
|
+
* @param {number|string} radius - 半径值(米)
|
|
49
|
+
* @returns {string} - 完整的标签文本,如 "探测区\n半径:3km"
|
|
50
|
+
*/
|
|
51
|
+
const getHemisphereLabelText = (label, radius) => {
|
|
52
|
+
const radiusLabel = formatHemisphereRadiusLabel(radius);
|
|
53
|
+
return radiusLabel ? `${label}\n${radiusLabel}` : label;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 【创建并设置半球体实体】
|
|
58
|
+
* 在指定位置创建一个半球体实体,支持自定义半径和颜色
|
|
59
|
+
* 半球体默认紧贴地面(高度为0),并设置为半透明效果
|
|
60
|
+
*
|
|
61
|
+
* @param {Object} options 半球体配置参数
|
|
62
|
+
* @param {string} options.id 半球体唯一标识
|
|
63
|
+
* @param {number[]} options.center 半球体中心经纬度坐标 [longitude, latitude]
|
|
64
|
+
* @param {number} options.radius 半球体半径(米)
|
|
65
|
+
* @param {string} options.sphericalColor 半球体颜色(CSS颜色字符串)
|
|
66
|
+
* @param {string} options.label 半球体标签文本(可选)
|
|
67
|
+
* @param {string} options.labelBgColor 半球体标签背景颜色(CSS颜色字符串)
|
|
68
|
+
* @returns {Cesium.Entity|null} 创建的半球体实体,若创建失败则返回null
|
|
69
|
+
*/
|
|
70
|
+
const setHemisphere = (options) => {
|
|
71
|
+
const { mapId } = options
|
|
72
|
+
const map = mapStore.getMap(mapId)
|
|
73
|
+
if (!map) {
|
|
74
|
+
console.error('地图实例不存在')
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (mapStore.getGraphicMap(`${options.id}`, mapId)) {
|
|
79
|
+
console.warn(`id: ${options.id} 半球体实体已存在`)
|
|
80
|
+
return null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 经纬度转Cesium笛卡尔坐标(球心定位)
|
|
84
|
+
// 确保球心的高度为0,紧贴地面
|
|
85
|
+
const centerCartesian = Cesium.Cartesian3.fromDegrees(options.center[0], options.center[1], 0);
|
|
86
|
+
|
|
87
|
+
// 使用Entity方式创建半球体(更稳定可靠)
|
|
88
|
+
const hemisphereEntity = map.entities.add({
|
|
89
|
+
position: centerCartesian,
|
|
90
|
+
ellipsoid: {
|
|
91
|
+
radii: new Cesium.Cartesian3(options.radius, options.radius, options.radius),
|
|
92
|
+
material: Cesium.Color.fromCssColorString(options.sphericalColor), // 设置半透明效果,0.5为透明度值(范围0-1)
|
|
93
|
+
// 使用maximumCone和minimumCone创建半球
|
|
94
|
+
maximumCone: 0, // 上半球(z轴正方向)
|
|
95
|
+
minimumCone: Math.PI / 2 // 从z轴正方向到水平面(90度)
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// 保存原始参数,用于后面计算
|
|
100
|
+
hemisphereEntity._originalOptions = { ...options };
|
|
101
|
+
|
|
102
|
+
// 计算标签位置(半球体表面右侧)
|
|
103
|
+
// 使用笛卡尔坐标系确保标签始终在半球体外侧
|
|
104
|
+
// 使用全局变量 hemisphereLabelAngle 控制仰角
|
|
105
|
+
const localX = options.radius * Math.cos(hemisphereLabelAngle);
|
|
106
|
+
const localZ = options.radius * Math.sin(hemisphereLabelAngle);
|
|
107
|
+
|
|
108
|
+
// 确保最小高度
|
|
109
|
+
const safeZ = Math.max(localZ, 50);
|
|
110
|
+
|
|
111
|
+
// 创建局部偏移向量
|
|
112
|
+
const localOffset = new Cesium.Cartesian3(localX, 0, safeZ);
|
|
113
|
+
|
|
114
|
+
// 将局部偏移转换到世界坐标系
|
|
115
|
+
const enuToFixed = Cesium.Transforms.eastNorthUpToFixedFrame(centerCartesian, map.scene.globe.ellipsoid);
|
|
116
|
+
|
|
117
|
+
// 计算最终标签位置:球心 + 偏移向量
|
|
118
|
+
const labelPosition = Cesium.Matrix4.multiplyByPoint(enuToFixed, localOffset, new Cesium.Cartesian3());
|
|
119
|
+
|
|
120
|
+
// 创建独立的文本框Entity
|
|
121
|
+
let labelEntity = null;
|
|
122
|
+
if (options.label) {
|
|
123
|
+
labelEntity = map.entities.add({
|
|
124
|
+
position: new Cesium.CallbackProperty(() => {
|
|
125
|
+
return labelPosition;
|
|
126
|
+
}, false),
|
|
127
|
+
label: {
|
|
128
|
+
text: getHemisphereLabelText(options.label, options.radius),
|
|
129
|
+
font: '10px Microsoft YaHei',
|
|
130
|
+
fillColor: Cesium.Color.WHITE,
|
|
131
|
+
// style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
132
|
+
// 确保背景显示的关键属性
|
|
133
|
+
showBackground: true,
|
|
134
|
+
backgroundColor: Cesium.Color.fromCssColorString(options.labelBgColor), // 背景颜色
|
|
135
|
+
backgroundPadding: new Cesium.Cartesian2(3, 3),
|
|
136
|
+
// 定位属性 - 标签在右手边
|
|
137
|
+
verticalOrigin: Cesium.VerticalOrigin.CENTER,
|
|
138
|
+
horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
|
|
139
|
+
pixelOffset: new Cesium.Cartesian2(10, 0),
|
|
140
|
+
// 其他属性
|
|
141
|
+
eyeOffset: new Cesium.Cartesian3(0, 0, 0),
|
|
142
|
+
// disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
143
|
+
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 100000)
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
// 将文本框Entity也缓存到store中,使用id+_label作为键
|
|
147
|
+
mapStore.setGraphicMap(`${options.id}_label`, labelEntity, mapId);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 将半球体缓存到 graphicMap 中,防止重复创建
|
|
151
|
+
mapStore.setGraphicMap(`${options.id}`, hemisphereEntity, mapId);
|
|
152
|
+
|
|
153
|
+
// 返回创建的半球体实体,方便调用者使用
|
|
154
|
+
return hemisphereEntity;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 【移动半球体实体位置】
|
|
159
|
+
* 更新指定ID的半球体实体到新的经纬度位置
|
|
160
|
+
*
|
|
161
|
+
* @param {Object} options 移动配置参数
|
|
162
|
+
* @param {string} options.hemisphereId 半球体唯一标识
|
|
163
|
+
* @param {number[]} options.center 新的中心经纬度坐标 [longitude, latitude]
|
|
164
|
+
* @returns {null} 无返回值
|
|
165
|
+
*/
|
|
166
|
+
const moveHemisphere = (options) => {
|
|
167
|
+
const { mapId } = options
|
|
168
|
+
const map = mapStore.getMap(mapId)
|
|
169
|
+
if (!map) {
|
|
170
|
+
console.error('地图实例不存在')
|
|
171
|
+
return null
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const hemisphereEntity = mapStore.getGraphicMap(`${options.hemisphereId}`, mapId)
|
|
175
|
+
if (!hemisphereEntity) {
|
|
176
|
+
console.warn(`id: ${options.hemisphereId} 半球体实体不存在`)
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 更新半球体位置
|
|
181
|
+
const newPosition = Cesium.Cartesian3.fromDegrees(options.center[0], options.center[1], 0);
|
|
182
|
+
hemisphereEntity.position = newPosition;
|
|
183
|
+
|
|
184
|
+
// 检查是否存在独立的文本框Entity
|
|
185
|
+
const labelEntity = mapStore.getGraphicMap(`${options.hemisphereId}_label`, mapId);
|
|
186
|
+
if (labelEntity) {
|
|
187
|
+
// 从保存的原始参数中获取半径值
|
|
188
|
+
let radius = 1000; // 默认半径值
|
|
189
|
+
if (hemisphereEntity._originalOptions && hemisphereEntity._originalOptions.radius) {
|
|
190
|
+
radius = hemisphereEntity._originalOptions.radius;
|
|
191
|
+
}
|
|
192
|
+
// 计算标签新位置(半球体表面右侧)
|
|
193
|
+
const localX = radius * Math.cos(hemisphereLabelAngle);
|
|
194
|
+
const localZ = radius * Math.sin(hemisphereLabelAngle);
|
|
195
|
+
const safeZ = Math.max(localZ, 50);
|
|
196
|
+
|
|
197
|
+
const localOffset = new Cesium.Cartesian3(localX, 0, safeZ);
|
|
198
|
+
const currentPosition = hemisphereEntity.position.getValue(Cesium.JulianDate.now());
|
|
199
|
+
|
|
200
|
+
const enuToFixed = Cesium.Transforms.eastNorthUpToFixedFrame(currentPosition, map.scene.globe.ellipsoid);
|
|
201
|
+
const newLabelPosition = Cesium.Matrix4.multiplyByPoint(enuToFixed, localOffset, new Cesium.Cartesian3());
|
|
202
|
+
|
|
203
|
+
// 使用CallbackProperty确保位置平滑更新
|
|
204
|
+
labelEntity.position = new Cesium.CallbackProperty(() => {
|
|
205
|
+
return newLabelPosition;
|
|
206
|
+
}, false);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* 【更新半球体实体半径】
|
|
212
|
+
* 修改指定ID的半球体实体的半径大小
|
|
213
|
+
*
|
|
214
|
+
* @param {Object} options 更新配置参数
|
|
215
|
+
* @param {string} options.mapId 地图实例ID
|
|
216
|
+
* @param {string} options.hemisphereId 半球体唯一标识
|
|
217
|
+
* @param {number} options.radius 新的半球体半径(米)
|
|
218
|
+
* @returns {null} 无返回值
|
|
219
|
+
*/
|
|
220
|
+
const updateHemisphere = (options) => {
|
|
221
|
+
const { mapId } = options
|
|
222
|
+
const map = mapStore.getMap(mapId)
|
|
223
|
+
if (!map) {
|
|
224
|
+
console.error('地图实例不存在')
|
|
225
|
+
return null
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const hemisphereEntity = mapStore.getGraphicMap(`${options.hemisphereId}`, mapId)
|
|
229
|
+
if (!hemisphereEntity) {
|
|
230
|
+
console.error(`id: ${options.hemisphereId} 半球体实体不存在`)
|
|
231
|
+
return null
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// 更新半球体半径
|
|
235
|
+
hemisphereEntity.ellipsoid.radii = new Cesium.Cartesian3(options.radius, options.radius, options.radius);
|
|
236
|
+
|
|
237
|
+
// 更新保存的原始参数中的半径值
|
|
238
|
+
if (hemisphereEntity._originalOptions) {
|
|
239
|
+
hemisphereEntity._originalOptions.radius = options.radius;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 检查是否存在独立的文本框Entity
|
|
243
|
+
const labelEntity = mapStore.getGraphicMap(`${options.hemisphereId}_label`, mapId);
|
|
244
|
+
if (labelEntity) {
|
|
245
|
+
// 更新标签中的半径值
|
|
246
|
+
const originalLabel = hemisphereEntity._originalOptions?.label;
|
|
247
|
+
if (originalLabel && labelEntity.label) {
|
|
248
|
+
labelEntity.label.text = getHemisphereLabelText(originalLabel, options.radius);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 计算标签新位置(半球体表面右侧)
|
|
252
|
+
const localX = options.radius * Math.cos(hemisphereLabelAngle);
|
|
253
|
+
const localZ = options.radius * Math.sin(hemisphereLabelAngle);
|
|
254
|
+
const safeZ = Math.max(localZ, 50);
|
|
255
|
+
|
|
256
|
+
const localOffset = new Cesium.Cartesian3(localX, 0, safeZ);
|
|
257
|
+
const currentPosition = hemisphereEntity.position.getValue(Cesium.JulianDate.now());
|
|
258
|
+
|
|
259
|
+
const enuToFixed = Cesium.Transforms.eastNorthUpToFixedFrame(currentPosition, map.scene.globe.ellipsoid);
|
|
260
|
+
const newLabelPosition = Cesium.Matrix4.multiplyByPoint(enuToFixed, localOffset, new Cesium.Cartesian3());
|
|
261
|
+
|
|
262
|
+
// 使用CallbackProperty确保位置平滑更新
|
|
263
|
+
labelEntity.position = new Cesium.CallbackProperty(() => {
|
|
264
|
+
return newLabelPosition;
|
|
265
|
+
}, false);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* 解析半球唯一标识(与 setHemisphere 的 id 一致,兼容 hemisphereId)
|
|
271
|
+
*/
|
|
272
|
+
const resolveHemisphereId = (options) => options.id ?? options.hemisphereId
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* 【控制半球体显示/隐藏】
|
|
276
|
+
* 根据 mapId 与半球唯一标识,同时控制半球体实体及其标签的可见性
|
|
277
|
+
*
|
|
278
|
+
* @param {Object} options
|
|
279
|
+
* @param {string} options.mapId 地图实例ID
|
|
280
|
+
* @param {string} options.id 半球体唯一标识(与 setHemisphere 的 id 一致)
|
|
281
|
+
* @param {string} [options.hemisphereId] 同 id,二选一
|
|
282
|
+
* @param {boolean} [options.visible=true] 是否显示
|
|
283
|
+
* @returns {{ success: boolean }} 操作结果
|
|
284
|
+
*/
|
|
285
|
+
const setHemisphereVisible = (options) => {
|
|
286
|
+
const { mapId, visible = true } = options
|
|
287
|
+
const hemisphereId = resolveHemisphereId(options)
|
|
288
|
+
|
|
289
|
+
if (!hemisphereId) {
|
|
290
|
+
console.error('缺少半球体唯一标识 id / hemisphereId')
|
|
291
|
+
return { success: false }
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const map = mapStore.getMap(mapId)
|
|
295
|
+
if (!map) {
|
|
296
|
+
console.error('地图实例不存在')
|
|
297
|
+
return { success: false }
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const hemisphereEntity = mapStore.getGraphicMap(hemisphereId, mapId)
|
|
301
|
+
if (!hemisphereEntity) {
|
|
302
|
+
console.warn(`id: ${hemisphereId} 半球体实体不存在`)
|
|
303
|
+
return { success: false }
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
hemisphereEntity.show = visible
|
|
307
|
+
|
|
308
|
+
const labelEntity = mapStore.getGraphicMap(`${hemisphereId}_label`, mapId)
|
|
309
|
+
if (labelEntity) {
|
|
310
|
+
labelEntity.show = visible
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return { success: true }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 【删除半球体实体】
|
|
318
|
+
* 移除指定ID的半球体实体,并从缓存中清除记录
|
|
319
|
+
*
|
|
320
|
+
* @param {Object} options 删除配置参数
|
|
321
|
+
* @param {string} options.hemisphereId 半球体唯一标识
|
|
322
|
+
* @returns {null} 无返回值
|
|
323
|
+
*/
|
|
324
|
+
const removeHemisphere = (options) => {
|
|
325
|
+
const { mapId } = options
|
|
326
|
+
const map = mapStore.getMap(mapId)
|
|
327
|
+
if (!map) {
|
|
328
|
+
console.error('地图实例不存在')
|
|
329
|
+
return null
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const hemisphereEntity = mapStore.getGraphicMap(`${options.hemisphereId}`, mapId)
|
|
333
|
+
if (!hemisphereEntity) {
|
|
334
|
+
console.error(`id: ${options.hemisphereId} 半球体实体不存在`)
|
|
335
|
+
return null
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 删除半球体实体
|
|
339
|
+
map.entities.remove(hemisphereEntity);
|
|
340
|
+
// 从缓存中移除
|
|
341
|
+
mapStore.removeGraphicMap(`${options.hemisphereId}`, mapId);
|
|
342
|
+
|
|
343
|
+
// 检查并删除独立的文本框Entity
|
|
344
|
+
const labelEntity = mapStore.getGraphicMap(`${options.hemisphereId}_label`, mapId);
|
|
345
|
+
if (labelEntity) {
|
|
346
|
+
map.entities.remove(labelEntity);
|
|
347
|
+
mapStore.removeGraphicMap(`${options.hemisphereId}_label`, mapId);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
setHemisphere,
|
|
353
|
+
updateHemisphere,
|
|
354
|
+
removeHemisphere,
|
|
355
|
+
moveHemisphere,
|
|
356
|
+
setHemisphereVisible
|
|
357
|
+
}
|
|
360
358
|
}
|
package/js/stores/mapStore.js
CHANGED
|
@@ -43,7 +43,6 @@ export const useMapStore = defineStore('map', () => {
|
|
|
43
43
|
trailTime: 30, // 轨迹时间
|
|
44
44
|
sceneMode: '3D', // 场景模式:'2D' 或 '3D'
|
|
45
45
|
viewOrthoWidth: null, // 2D/3D 切换时保持稳定的正交可视宽度(米)
|
|
46
|
-
cesiumModule: null, // 与 Viewer 同一份 Cesium(由宿主传入,避免双份 cesium)
|
|
47
46
|
rtkData: {
|
|
48
47
|
latitude: 0, // RTK纬度
|
|
49
48
|
longitude: 0, // RTK经度
|
|
@@ -153,13 +152,6 @@ export const useMapStore = defineStore('map', () => {
|
|
|
153
152
|
getContext(mapId).map.value = mapInstance
|
|
154
153
|
}
|
|
155
154
|
|
|
156
|
-
/** @param {typeof import('cesium')} cesiumModule */
|
|
157
|
-
const setCesiumModule = (cesiumModule, mapId) => {
|
|
158
|
-
getContext(mapId).cesiumModule = cesiumModule
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const getCesiumModule = (mapId) => getContext(mapId).cesiumModule
|
|
162
|
-
|
|
163
155
|
// 获取地图对象
|
|
164
156
|
const getMap = (mapId) => {
|
|
165
157
|
return getContext(mapId).map.value
|
|
@@ -377,8 +369,6 @@ export const useMapStore = defineStore('map', () => {
|
|
|
377
369
|
clearAllGroundLinks,
|
|
378
370
|
setMap,
|
|
379
371
|
getMap,
|
|
380
|
-
setCesiumModule,
|
|
381
|
-
getCesiumModule,
|
|
382
372
|
clearLayer,
|
|
383
373
|
resetLayer,
|
|
384
374
|
setTrailTime,
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import * as Cesium from 'cesium'
|
|
11
11
|
import { useMapStore } from '../stores/mapStore.js'
|
|
12
|
-
import { isOrthographicFrustum } from '../utils/frustumCompat.js'
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* 创建缩放控制器
|
|
@@ -38,7 +37,7 @@ export function createZoomController() {
|
|
|
38
37
|
if (!mapId) return
|
|
39
38
|
if (isOrthographic) {
|
|
40
39
|
const frustum = camera.frustum
|
|
41
|
-
if (
|
|
40
|
+
if (frustum instanceof Cesium.OrthographicFrustum && frustum.width > 0) {
|
|
42
41
|
mapStore.setViewOrthoWidth(frustum.width, mapId)
|
|
43
42
|
}
|
|
44
43
|
return
|
|
@@ -76,7 +75,7 @@ export function createZoomController() {
|
|
|
76
75
|
if (!map) return
|
|
77
76
|
|
|
78
77
|
const camera = map.camera
|
|
79
|
-
const isOrthographic =
|
|
78
|
+
const isOrthographic = camera.frustum instanceof Cesium.OrthographicFrustum
|
|
80
79
|
|
|
81
80
|
if (isOrthographic) {
|
|
82
81
|
const position = camera.positionCartographic
|
|
@@ -86,7 +85,7 @@ export function createZoomController() {
|
|
|
86
85
|
const newHeight = Math.max(100, currentHeight * factor)
|
|
87
86
|
const heightRatio = currentHeight > 0 ? newHeight / currentHeight : factor
|
|
88
87
|
|
|
89
|
-
if (
|
|
88
|
+
if (frustum instanceof Cesium.OrthographicFrustum && frustum.width > 0) {
|
|
90
89
|
frustum.width = Math.max(100, frustum.width * heightRatio)
|
|
91
90
|
}
|
|
92
91
|
|
|
@@ -139,7 +138,7 @@ export function createZoomController() {
|
|
|
139
138
|
if (!map) return
|
|
140
139
|
|
|
141
140
|
const camera = map.camera
|
|
142
|
-
const isOrthographic =
|
|
141
|
+
const isOrthographic = camera.frustum instanceof Cesium.OrthographicFrustum
|
|
143
142
|
|
|
144
143
|
if (isOrthographic) {
|
|
145
144
|
const position = camera.positionCartographic
|
|
@@ -149,7 +148,7 @@ export function createZoomController() {
|
|
|
149
148
|
const newHeight = Math.min(1000000, currentHeight * factor)
|
|
150
149
|
const heightRatio = currentHeight > 0 ? newHeight / currentHeight : factor
|
|
151
150
|
|
|
152
|
-
if (
|
|
151
|
+
if (frustum instanceof Cesium.OrthographicFrustum && frustum.width > 0) {
|
|
153
152
|
frustum.width = Math.min(10000000, frustum.width * heightRatio)
|
|
154
153
|
}
|
|
155
154
|
|
package/package.json
CHANGED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 按 mapId 使用与 Viewer 同一份 Cesium 命名空间,避免 Vite 双份 cesium 导致 Color / Frustum instanceof 失败
|
|
3
|
-
*/
|
|
4
|
-
import * as defaultCesium from 'cesium'
|
|
5
|
-
import { useMapStore } from '../stores/mapStore.js'
|
|
6
|
-
|
|
7
|
-
export function getCesium(mapId) {
|
|
8
|
-
return useMapStore().getCesiumModule(mapId) || defaultCesium
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** @param {typeof import('cesium')} cesiumModule */
|
|
12
|
-
export function toCssColorString(color) {
|
|
13
|
-
if (color == null) return 'rgba(0,191,255,0.85)'
|
|
14
|
-
if (typeof color === 'string') return color
|
|
15
|
-
if (typeof color.toCssColorString === 'function') return color.toCssColorString()
|
|
16
|
-
if (typeof color.toCssHexString === 'function') {
|
|
17
|
-
const hex = color.toCssHexString()
|
|
18
|
-
const a = color.alpha ?? 1
|
|
19
|
-
return a < 1 ? `rgba(${Math.round(color.red * 255)},${Math.round(color.green * 255)},${Math.round(color.blue * 255)},${a})` : hex
|
|
20
|
-
}
|
|
21
|
-
if (color.red !== undefined) {
|
|
22
|
-
const { red, green, blue, alpha = 1 } = color
|
|
23
|
-
return `rgba(${Math.round(red * 255)},${Math.round(green * 255)},${Math.round(blue * 255)},${alpha})`
|
|
24
|
-
}
|
|
25
|
-
return String(color)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* 创建与当前 Viewer 同模块的 Color(用于 entity material / point.color)
|
|
30
|
-
* @param {string=} mapId
|
|
31
|
-
* @param {import('cesium').Color | string | object} value
|
|
32
|
-
*/
|
|
33
|
-
export function createViewerColor(mapId, value) {
|
|
34
|
-
const Cs = getCesium(mapId)
|
|
35
|
-
return Cs.Color.fromCssColorString(toCssColorString(value))
|
|
36
|
-
}
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 与 Viewer 使用同一套 Cesium 构造视锥体,避免 Vite 双份 cesium 导致 Camera.update 报错
|
|
3
|
-
*/
|
|
4
|
-
import * as Cesium from 'cesium'
|
|
5
|
-
|
|
6
|
-
let PerspectiveFrustumCtor = Cesium.PerspectiveFrustum
|
|
7
|
-
let OrthographicFrustumCtor = Cesium.OrthographicFrustum
|
|
8
|
-
|
|
9
|
-
export function getFrustumTypeName(frustum) {
|
|
10
|
-
return frustum?.constructor?.name ?? ''
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function isPerspectiveFrustum(frustum) {
|
|
14
|
-
return getFrustumTypeName(frustum) === 'PerspectiveFrustum'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function isOrthographicFrustum(frustum) {
|
|
18
|
-
return getFrustumTypeName(frustum) === 'OrthographicFrustum'
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function isValid3DFrustum(frustum) {
|
|
22
|
-
const name = getFrustumTypeName(frustum)
|
|
23
|
-
return name === 'PerspectiveFrustum' || name === 'OrthographicFrustum'
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function getCanvasAspectRatio(map) {
|
|
27
|
-
const canvas = map?.canvas
|
|
28
|
-
if (!canvas) return 1
|
|
29
|
-
const w = canvas.clientWidth || 1
|
|
30
|
-
const h = canvas.clientHeight || 1
|
|
31
|
-
return w / h
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 从已创建的 Viewer 上绑定与引擎一致的 Frustum 构造函数
|
|
36
|
-
* @param {import('cesium').Viewer} map
|
|
37
|
-
*/
|
|
38
|
-
export function bindFrustumConstructors(map) {
|
|
39
|
-
const frustum = map?.camera?.frustum
|
|
40
|
-
if (!frustum?.constructor) return
|
|
41
|
-
|
|
42
|
-
const name = getFrustumTypeName(frustum)
|
|
43
|
-
if (name === 'PerspectiveFrustum') {
|
|
44
|
-
PerspectiveFrustumCtor = frustum.constructor
|
|
45
|
-
} else if (name === 'OrthographicFrustum') {
|
|
46
|
-
OrthographicFrustumCtor = frustum.constructor
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function createPerspectiveFrustum(map, sourceFrustum) {
|
|
51
|
-
if (isPerspectiveFrustum(sourceFrustum)) {
|
|
52
|
-
return sourceFrustum
|
|
53
|
-
}
|
|
54
|
-
const frustum = new PerspectiveFrustumCtor()
|
|
55
|
-
frustum.near = sourceFrustum?.near ?? 1.0
|
|
56
|
-
frustum.far = sourceFrustum?.far ?? 10000000.0
|
|
57
|
-
return frustum
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function createOrthographicFrustum() {
|
|
61
|
-
return new OrthographicFrustumCtor()
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function ensure3DCompatibleFrustum(map, preferOrthographic = false) {
|
|
65
|
-
if (!map?.camera) return
|
|
66
|
-
const current = map.camera.frustum
|
|
67
|
-
if (isValid3DFrustum(current)) return
|
|
68
|
-
|
|
69
|
-
if (preferOrthographic && detectDuplicateCesium(map)) {
|
|
70
|
-
preferOrthographic = false
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
map.camera.frustum = preferOrthographic
|
|
74
|
-
? createOrthographicFrustum()
|
|
75
|
-
: createPerspectiveFrustum(map, current)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let duplicateCesiumWarned = false
|
|
79
|
-
|
|
80
|
-
/** Vite 未 dedupe cesium 时,库内 new 的 Frustum 与 Viewer 不是同一类 */
|
|
81
|
-
export function detectDuplicateCesium(map, cesiumModule) {
|
|
82
|
-
const Cs = cesiumModule || Cesium
|
|
83
|
-
const frustum = map?.camera?.frustum
|
|
84
|
-
if (!frustum) return false
|
|
85
|
-
return (
|
|
86
|
-
getFrustumTypeName(frustum) === 'PerspectiveFrustum' &&
|
|
87
|
-
!(frustum instanceof Cs.PerspectiveFrustum)
|
|
88
|
-
)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function warnDuplicateCesiumOnce(map) {
|
|
92
|
-
if (duplicateCesiumWarned || !detectDuplicateCesium(map)) return
|
|
93
|
-
duplicateCesiumWarned = true
|
|
94
|
-
console.warn(
|
|
95
|
-
'[huweili-cesium] 检测到两份 cesium 副本,正交视锥可能触发 Camera.update 报错。请在 vite.config 设置 resolve.dedupe: ["cesium"],并将 cesium、huweili-cesium 加入 optimizeDeps.include。'
|
|
96
|
-
)
|
|
97
|
-
}
|
package/postinstall.mjs
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 依赖安装完成后在终端打印欢迎信息(npm / pnpm / yarn 均会触发 postinstall)
|
|
3
|
-
* 放在包根目录,避免 .npmignore 的 scripts/ 导致发布包缺失
|
|
4
|
-
*/
|
|
5
|
-
import { readFileSync } from 'node:fs'
|
|
6
|
-
import { dirname, resolve } from 'node:path'
|
|
7
|
-
import { fileURLToPath } from 'node:url'
|
|
8
|
-
|
|
9
|
-
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
10
|
-
const pkgRoot = resolve(__dirname)
|
|
11
|
-
|
|
12
|
-
if (
|
|
13
|
-
process.env.CI === 'true' ||
|
|
14
|
-
process.env.CI === '1' ||
|
|
15
|
-
process.env.SKIP_POSTINSTALL_WELCOME === '1'
|
|
16
|
-
) {
|
|
17
|
-
process.exit(0)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const initCwd = process.env.INIT_CWD ? resolve(process.env.INIT_CWD) : ''
|
|
21
|
-
if (initCwd && initCwd === pkgRoot) {
|
|
22
|
-
process.exit(0)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const pkg = JSON.parse(readFileSync(resolve(pkgRoot, 'package.json'), 'utf8'))
|
|
26
|
-
const { version = '?', name = 'huweili-cesium' } = pkg
|
|
27
|
-
|
|
28
|
-
const npmUrl = `https://www.npmjs.com/package/${name}`
|
|
29
|
-
|
|
30
|
-
function normalizeRepoUrl(repo) {
|
|
31
|
-
if (!repo) return ''
|
|
32
|
-
const raw = typeof repo === 'string' ? repo : repo.url
|
|
33
|
-
if (!raw) return ''
|
|
34
|
-
return raw
|
|
35
|
-
.replace(/^git\+/, '')
|
|
36
|
-
.replace(/^git:\/\//, 'https://')
|
|
37
|
-
.replace(/^git@github\.com:/, 'https://github.com/')
|
|
38
|
-
.replace(/\.git$/, '')
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const repoUrl = normalizeRepoUrl(pkg.homepage || pkg.repository)
|
|
42
|
-
|
|
43
|
-
const c = {
|
|
44
|
-
reset: '\x1b[0m',
|
|
45
|
-
bold: '\x1b[1m',
|
|
46
|
-
dim: '\x1b[2m',
|
|
47
|
-
cyan: '\x1b[36m',
|
|
48
|
-
green: '\x1b[32m',
|
|
49
|
-
yellow: '\x1b[33m',
|
|
50
|
-
magenta: '\x1b[35m',
|
|
51
|
-
blue: '\x1b[34m',
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const banner = `
|
|
55
|
-
${c.cyan}${c.bold} ╔══════════════════════════════════════════════════════════╗
|
|
56
|
-
║ ║
|
|
57
|
-
║ 🌍 huweili-cesium ${c.green}v${version}${c.cyan}${c.bold} — Cesium 三维地图工具库已就绪 ║
|
|
58
|
-
║ ║
|
|
59
|
-
╚══════════════════════════════════════════════════════════╝${c.reset}
|
|
60
|
-
|
|
61
|
-
${c.yellow}${c.bold} 快速开始${c.reset}
|
|
62
|
-
${c.dim} ─────────────────────────────────────────────────────────${c.reset}
|
|
63
|
-
${c.green}组件${c.reset} import CesiumMap from ${c.cyan}'huweili-cesium'${c.reset}
|
|
64
|
-
${c.green}工具${c.reset} import { basicConfig } from ${c.cyan}'huweili-cesium'${c.reset}
|
|
65
|
-
${c.green}按钮${c.reset} import { createCustomToolbarButtons } from ${c.cyan}'huweili-cesium/customToolbarButtons'${c.reset}
|
|
66
|
-
|
|
67
|
-
${c.yellow}${c.bold} 使用前请确认${c.reset}
|
|
68
|
-
${c.dim}·${c.reset} 已安装 peer:${c.magenta}cesium · vue · pinia · mitt · qrcode${c.reset}
|
|
69
|
-
${c.dim}·${c.reset} 已加载 ${c.cyan}constants.js${c.reset}(MapConfig / DroneConfig 等)
|
|
70
|
-
${c.dim}·${c.reset} Vite:${c.cyan}resolve.dedupe: ['cesium']${c.reset} 或组件传 ${c.cyan}:cesium="Cesium"${c.reset}
|
|
71
|
-
|
|
72
|
-
${c.yellow}${c.bold} 链接${c.reset}
|
|
73
|
-
${c.dim}·${c.reset} npm ${c.blue}${npmUrl}${c.reset}${repoUrl ? `\n ${c.dim}·${c.reset} 仓库 ${c.blue}${repoUrl}${c.reset}` : ''}
|
|
74
|
-
|
|
75
|
-
${c.dim} 文档见包内 README · 祝绘制愉快 🚁${c.reset}
|
|
76
|
-
${c.dim} 关闭欢迎: set SKIP_POSTINSTALL_WELCOME=1${c.reset}
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
console.log(banner)
|