huweili-cesium 1.2.99 → 1.3.0
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/js/basis.js +14 -0
- package/js/glbInfoBadge.js +175 -65
- package/js/index.js +1 -0
- package/js/measureBearing.js +379 -0
- package/js/movePoint.js +10 -2
- package/js/setPoint.js +25 -7
- package/package.json +3 -1
package/js/basis.js
CHANGED
|
@@ -22,6 +22,7 @@ import { createZoomController } from './toolbar/zoomController.js'
|
|
|
22
22
|
import { useEventBus } from './utils/useEventBus.js'
|
|
23
23
|
import { applyOrthographicZoomFactor } from './utils/orthographicCameraZoom.js'
|
|
24
24
|
import { measureDistance } from './measureDistance.js'
|
|
25
|
+
import { measureBearing } from './measureBearing.js'
|
|
25
26
|
|
|
26
27
|
export function basicConfig() {
|
|
27
28
|
|
|
@@ -746,6 +747,7 @@ export function basicConfig() {
|
|
|
746
747
|
const { zoomIn: zoomInDefault, zoomOut: zoomOutDefault } = createZoomController()
|
|
747
748
|
const { toggleBasemapPickerPanel } = createBasemapSwitcher()
|
|
748
749
|
const { startMeasure } = measureDistance()
|
|
750
|
+
const { startBearingMeasure } = measureBearing()
|
|
749
751
|
const { emit } = useEventBus()
|
|
750
752
|
|
|
751
753
|
const zoomIn = (factor = 0.8) => {
|
|
@@ -865,6 +867,18 @@ export function basicConfig() {
|
|
|
865
867
|
},
|
|
866
868
|
{
|
|
867
869
|
index: 2,
|
|
870
|
+
title: '测向',
|
|
871
|
+
iconSrc: `${baseUrl}/images/new/cx.svg`,
|
|
872
|
+
onClick: () => {
|
|
873
|
+
startBearingMeasure({
|
|
874
|
+
id: `home_bearing_${Date.now()}`,
|
|
875
|
+
mapId,
|
|
876
|
+
color: '#ffd400',
|
|
877
|
+
})
|
|
878
|
+
},
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
index: 3,
|
|
868
882
|
title: '返回初始点位',
|
|
869
883
|
iconSrc: `${baseUrl}/images/new/home.svg`,
|
|
870
884
|
onClick: (v) => {
|
package/js/glbInfoBadge.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GLB
|
|
2
|
+
* GLB 模型头顶信息牌(车辆信息 + 在线/离线状态)
|
|
3
3
|
*
|
|
4
4
|
* @author huweili
|
|
5
5
|
* @version 1.0.0
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import * as Cesium from 'cesium'
|
|
8
8
|
import { getDroneLabelBatchManager } from './cardPool'
|
|
9
9
|
|
|
10
|
-
const STYLE_ID = 'glb-info-badge-style-
|
|
10
|
+
const STYLE_ID = 'glb-info-badge-style-v3'
|
|
11
11
|
const DEFAULT_LABEL_OFFSET = 1
|
|
12
12
|
const DEFAULT_PIXEL_GAP = 0
|
|
13
13
|
const DEFAULT_HEIGHT_SCALE = 0.72
|
|
@@ -20,6 +20,36 @@ const scratchUp = new Cesium.Cartesian3()
|
|
|
20
20
|
const scratchOffset = new Cesium.Cartesian3()
|
|
21
21
|
const scratchTop = new Cesium.Cartesian3()
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {Object} GlbInfoBadgeData
|
|
25
|
+
* @property {string} [vehicleName] 车辆名称
|
|
26
|
+
* @property {number|string} [lng] 经度
|
|
27
|
+
* @property {number|string} [lat] 纬度
|
|
28
|
+
* @property {string} [address] 位置描述
|
|
29
|
+
* @property {boolean} [isOffline] 是否离线
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {unknown} value
|
|
34
|
+
* @returns {string}
|
|
35
|
+
*/
|
|
36
|
+
const formatCoord = (value) => {
|
|
37
|
+
const num = Number(value)
|
|
38
|
+
return Number.isFinite(num) ? num.toFixed(4) : '--'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {GlbInfoBadgeData} info
|
|
43
|
+
* @returns {GlbInfoBadgeData}
|
|
44
|
+
*/
|
|
45
|
+
const normalizeInfo = (info = {}) => ({
|
|
46
|
+
vehicleName: info.vehicleName ?? '--',
|
|
47
|
+
lng: formatCoord(info.lng),
|
|
48
|
+
lat: formatCoord(info.lat),
|
|
49
|
+
address: info.address || '--',
|
|
50
|
+
isOffline: Boolean(info.isOffline),
|
|
51
|
+
})
|
|
52
|
+
|
|
23
53
|
const ensureGlbInfoBadgeStyle = () => {
|
|
24
54
|
if (document.getElementById(STYLE_ID)) return
|
|
25
55
|
|
|
@@ -36,19 +66,64 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
36
66
|
}
|
|
37
67
|
.glb-info-badge-inner {
|
|
38
68
|
position: relative;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
background: linear-gradient(135deg, rgba(8, 20, 40, 0.92) 0%, rgba(12, 32, 58, 0.88) 100%);
|
|
69
|
+
min-width: 128px;
|
|
70
|
+
max-width: 168px;
|
|
71
|
+
padding: 5px 8px;
|
|
72
|
+
border-radius: 8px;
|
|
73
|
+
background: linear-gradient(135deg, rgba(8, 20, 40, 0.94) 0%, rgba(12, 32, 58, 0.9) 100%);
|
|
45
74
|
border: 1px solid rgba(0, 229, 255, 0.45);
|
|
46
75
|
box-shadow:
|
|
47
76
|
inset 0 0 8px rgba(0, 229, 255, 0.08),
|
|
48
77
|
0 0 10px rgba(0, 229, 255, 0.15);
|
|
49
78
|
overflow: hidden;
|
|
50
79
|
backdrop-filter: blur(4px);
|
|
80
|
+
}
|
|
81
|
+
.glb-info-badge-header {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: space-between;
|
|
85
|
+
gap: 6px;
|
|
86
|
+
margin-bottom: 4px;
|
|
87
|
+
padding-bottom: 4px;
|
|
88
|
+
border-bottom: 1px solid rgba(0, 229, 255, 0.18);
|
|
89
|
+
}
|
|
90
|
+
.glb-info-badge-name {
|
|
91
|
+
flex: 1;
|
|
92
|
+
min-width: 0;
|
|
93
|
+
font-size: 10px;
|
|
94
|
+
font-weight: 700;
|
|
95
|
+
line-height: 1.2;
|
|
96
|
+
color: #e8f7ff;
|
|
51
97
|
white-space: nowrap;
|
|
98
|
+
overflow: hidden;
|
|
99
|
+
text-overflow: ellipsis;
|
|
100
|
+
}
|
|
101
|
+
.glb-info-badge-status {
|
|
102
|
+
display: inline-flex;
|
|
103
|
+
align-items: center;
|
|
104
|
+
gap: 3px;
|
|
105
|
+
flex-shrink: 0;
|
|
106
|
+
}
|
|
107
|
+
.glb-info-badge-row {
|
|
108
|
+
display: flex;
|
|
109
|
+
align-items: flex-start;
|
|
110
|
+
gap: 2px;
|
|
111
|
+
font-size: 9px;
|
|
112
|
+
line-height: 1.35;
|
|
113
|
+
color: #b8d4e8;
|
|
114
|
+
}
|
|
115
|
+
.glb-info-badge-row + .glb-info-badge-row {
|
|
116
|
+
margin-top: 2px;
|
|
117
|
+
}
|
|
118
|
+
.glb-info-badge-label {
|
|
119
|
+
flex-shrink: 0;
|
|
120
|
+
color: rgba(184, 212, 232, 0.82);
|
|
121
|
+
}
|
|
122
|
+
.glb-info-badge-value {
|
|
123
|
+
flex: 1;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
color: #e8f7ff;
|
|
126
|
+
word-break: break-all;
|
|
52
127
|
}
|
|
53
128
|
.glb-info-badge-scan {
|
|
54
129
|
position: absolute;
|
|
@@ -56,7 +131,7 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
56
131
|
left: -100%;
|
|
57
132
|
width: 60%;
|
|
58
133
|
height: 100%;
|
|
59
|
-
background: linear-gradient(90deg, transparent, rgba(0, 229, 255, 0.
|
|
134
|
+
background: linear-gradient(90deg, transparent, rgba(0, 229, 255, 0.14), transparent);
|
|
60
135
|
animation: glb-info-badge-scan 2.8s ease-in-out infinite;
|
|
61
136
|
pointer-events: none;
|
|
62
137
|
}
|
|
@@ -68,10 +143,10 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
68
143
|
box-shadow: 0 0 5px currentColor;
|
|
69
144
|
}
|
|
70
145
|
.glb-info-badge-text {
|
|
71
|
-
font-size:
|
|
146
|
+
font-size: 9px;
|
|
72
147
|
font-weight: 600;
|
|
73
148
|
line-height: 1;
|
|
74
|
-
letter-spacing: 0.
|
|
149
|
+
letter-spacing: 0.04em;
|
|
75
150
|
color: #e8f7ff;
|
|
76
151
|
text-shadow: 0 0 4px rgba(0, 229, 255, 0.5);
|
|
77
152
|
}
|
|
@@ -87,8 +162,11 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
87
162
|
.glb-info-badge.is-online .glb-info-badge-inner {
|
|
88
163
|
border-color: rgba(0, 255, 170, 0.55);
|
|
89
164
|
box-shadow:
|
|
90
|
-
inset 0 0
|
|
91
|
-
0 0
|
|
165
|
+
inset 0 0 8px rgba(0, 255, 170, 0.1),
|
|
166
|
+
0 0 12px rgba(0, 255, 170, 0.2);
|
|
167
|
+
}
|
|
168
|
+
.glb-info-badge.is-online .glb-info-badge-header {
|
|
169
|
+
border-bottom-color: rgba(0, 255, 170, 0.22);
|
|
92
170
|
}
|
|
93
171
|
.glb-info-badge.is-online .glb-info-badge-dot {
|
|
94
172
|
background: #00ffaa;
|
|
@@ -97,7 +175,7 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
97
175
|
}
|
|
98
176
|
.glb-info-badge.is-online .glb-info-badge-text {
|
|
99
177
|
color: #d6fff0;
|
|
100
|
-
text-shadow: 0 0
|
|
178
|
+
text-shadow: 0 0 4px rgba(0, 255, 170, 0.45);
|
|
101
179
|
}
|
|
102
180
|
.glb-info-badge.is-online .glb-info-badge-pointer {
|
|
103
181
|
border-top-color: rgba(0, 255, 170, 0.6);
|
|
@@ -105,9 +183,11 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
105
183
|
.glb-info-badge.is-offline .glb-info-badge-inner {
|
|
106
184
|
border-color: rgba(255, 92, 92, 0.55);
|
|
107
185
|
box-shadow:
|
|
108
|
-
inset 0 0
|
|
109
|
-
0 0
|
|
110
|
-
|
|
186
|
+
inset 0 0 8px rgba(255, 92, 92, 0.12),
|
|
187
|
+
0 0 14px rgba(255, 92, 92, 0.22);
|
|
188
|
+
}
|
|
189
|
+
.glb-info-badge.is-offline .glb-info-badge-header {
|
|
190
|
+
border-bottom-color: rgba(255, 92, 92, 0.22);
|
|
111
191
|
}
|
|
112
192
|
.glb-info-badge.is-offline .glb-info-badge-dot {
|
|
113
193
|
background: #ff5c5c;
|
|
@@ -116,7 +196,7 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
116
196
|
}
|
|
117
197
|
.glb-info-badge.is-offline .glb-info-badge-text {
|
|
118
198
|
color: #ffe8e8;
|
|
119
|
-
text-shadow: 0 0
|
|
199
|
+
text-shadow: 0 0 6px rgba(255, 92, 92, 0.55);
|
|
120
200
|
}
|
|
121
201
|
.glb-info-badge.is-offline .glb-info-badge-pointer {
|
|
122
202
|
border-top-color: rgba(255, 92, 92, 0.65);
|
|
@@ -133,17 +213,65 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
133
213
|
0%, 100% { opacity: 1; transform: scale(1); box-shadow: 0 0 8px #ff5c5c; }
|
|
134
214
|
50% { opacity: 0.45; transform: scale(1.25); box-shadow: 0 0 14px #ff5c5c, 0 0 22px rgba(255, 92, 92, 0.6); }
|
|
135
215
|
}
|
|
136
|
-
@keyframes glb-info-badge-shake {
|
|
137
|
-
0%, 92%, 100% { transform: translateX(0); }
|
|
138
|
-
93% { transform: translateX(-1px); }
|
|
139
|
-
94% { transform: translateX(1px); }
|
|
140
|
-
95% { transform: translateX(-1px); }
|
|
141
|
-
96% { transform: translateX(0); }
|
|
142
|
-
}
|
|
143
216
|
`
|
|
144
217
|
document.head.appendChild(style)
|
|
145
218
|
}
|
|
146
219
|
|
|
220
|
+
/**
|
|
221
|
+
* @param {GlbInfoBadgeData} info
|
|
222
|
+
* @returns {string}
|
|
223
|
+
*/
|
|
224
|
+
const buildBadgeHtml = (info) => {
|
|
225
|
+
const data = normalizeInfo(info)
|
|
226
|
+
return `
|
|
227
|
+
<div class="glb-info-badge-inner">
|
|
228
|
+
<div class="glb-info-badge-header">
|
|
229
|
+
<span class="glb-info-badge-name">${data.vehicleName}</span>
|
|
230
|
+
<span class="glb-info-badge-status">
|
|
231
|
+
<span class="glb-info-badge-dot"></span>
|
|
232
|
+
<span class="glb-info-badge-text">${data.isOffline ? '离线' : '在线'}</span>
|
|
233
|
+
</span>
|
|
234
|
+
</div>
|
|
235
|
+
<div class="glb-info-badge-row">
|
|
236
|
+
<span class="glb-info-badge-label">经度:</span>
|
|
237
|
+
<span class="glb-info-badge-value glb-info-badge-lng">${data.lng}</span>
|
|
238
|
+
</div>
|
|
239
|
+
<div class="glb-info-badge-row">
|
|
240
|
+
<span class="glb-info-badge-label">纬度:</span>
|
|
241
|
+
<span class="glb-info-badge-value glb-info-badge-lat">${data.lat}</span>
|
|
242
|
+
</div>
|
|
243
|
+
<div class="glb-info-badge-row">
|
|
244
|
+
<span class="glb-info-badge-label">位置:</span>
|
|
245
|
+
<span class="glb-info-badge-value glb-info-badge-address">${data.address}</span>
|
|
246
|
+
</div>
|
|
247
|
+
<span class="glb-info-badge-scan"></span>
|
|
248
|
+
</div>
|
|
249
|
+
<div class="glb-info-badge-pointer"></div>
|
|
250
|
+
`
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @param {HTMLElement} badgeEl
|
|
255
|
+
* @param {GlbInfoBadgeData} info
|
|
256
|
+
*/
|
|
257
|
+
const renderBadgeContent = (badgeEl, info) => {
|
|
258
|
+
const data = normalizeInfo(info)
|
|
259
|
+
badgeEl.classList.toggle('is-offline', data.isOffline)
|
|
260
|
+
badgeEl.classList.toggle('is-online', !data.isOffline)
|
|
261
|
+
|
|
262
|
+
const nameEl = badgeEl.querySelector('.glb-info-badge-name')
|
|
263
|
+
const textEl = badgeEl.querySelector('.glb-info-badge-text')
|
|
264
|
+
const lngEl = badgeEl.querySelector('.glb-info-badge-lng')
|
|
265
|
+
const latEl = badgeEl.querySelector('.glb-info-badge-lat')
|
|
266
|
+
const addressEl = badgeEl.querySelector('.glb-info-badge-address')
|
|
267
|
+
|
|
268
|
+
if (nameEl) nameEl.textContent = data.vehicleName
|
|
269
|
+
if (textEl) textEl.textContent = data.isOffline ? '离线' : '在线'
|
|
270
|
+
if (lngEl) lngEl.textContent = data.lng
|
|
271
|
+
if (latEl) latEl.textContent = data.lat
|
|
272
|
+
if (addressEl) addressEl.textContent = data.address
|
|
273
|
+
}
|
|
274
|
+
|
|
147
275
|
/**
|
|
148
276
|
* 读取 Entity 模型 minimumPixelSize(远景会被放大显示,需同步到屏幕偏移)
|
|
149
277
|
* @param {Cesium.Entity} entity
|
|
@@ -163,11 +291,6 @@ const getEntityMinimumPixelSize = (entity, time) => {
|
|
|
163
291
|
|
|
164
292
|
/**
|
|
165
293
|
* 根据模型包围球估算车顶世界坐标
|
|
166
|
-
* @param {Cesium.Viewer} map
|
|
167
|
-
* @param {Cesium.Entity} entity
|
|
168
|
-
* @param {Cesium.Cartesian3} basePos
|
|
169
|
-
* @param {number} fallbackOffset
|
|
170
|
-
* @returns {Cesium.Cartesian3|null}
|
|
171
294
|
*/
|
|
172
295
|
const resolveModelTopWorldPosition = (map, entity, basePos, fallbackOffset) => {
|
|
173
296
|
Cesium.Transforms.eastNorthUpToFixedFrame(basePos, undefined, scratchEnu)
|
|
@@ -192,13 +315,6 @@ const resolveModelTopWorldPosition = (map, entity, basePos, fallbackOffset) => {
|
|
|
192
315
|
|
|
193
316
|
/**
|
|
194
317
|
* 将车顶世界坐标转为屏幕坐标,并兼顾 minimumPixelSize 的可视高度
|
|
195
|
-
* @param {Cesium.Scene} scene
|
|
196
|
-
* @param {Cesium.Cartesian3} basePos
|
|
197
|
-
* @param {Cesium.Cartesian3} topWorldPos
|
|
198
|
-
* @param {number} minPixelSize
|
|
199
|
-
* @param {number} pixelGap
|
|
200
|
-
* @param {number} heightScale
|
|
201
|
-
* @returns {{ x: number, y: number }|null}
|
|
202
318
|
*/
|
|
203
319
|
const resolveBadgeScreenPosition = (scene, basePos, topWorldPos, minPixelSize, pixelGap, heightScale) => {
|
|
204
320
|
const anchorWin = scene.cartesianToCanvasCoordinates(basePos)
|
|
@@ -213,7 +329,6 @@ const resolveBadgeScreenPosition = (scene, basePos, topWorldPos, minPixelSize, p
|
|
|
213
329
|
offsetY = (anchorWin.y - topWin.y) * heightScale
|
|
214
330
|
}
|
|
215
331
|
|
|
216
|
-
// 包围球常大于实际 mesh,对过大偏移做软压缩
|
|
217
332
|
if (offsetY > 0 && minPixelSize > 0 && offsetY > minPixelSize * 0.5) {
|
|
218
333
|
const base = minPixelSize * 0.3
|
|
219
334
|
offsetY = base + (offsetY - base) * 0.35
|
|
@@ -237,17 +352,18 @@ const resolveBadgeScreenPosition = (scene, basePos, topWorldPos, minPixelSize, p
|
|
|
237
352
|
}
|
|
238
353
|
|
|
239
354
|
/**
|
|
240
|
-
*
|
|
355
|
+
* 在模型头顶创建车辆信息牌
|
|
241
356
|
* @param {Object} options
|
|
242
357
|
* @param {Cesium.Viewer} options.map
|
|
243
|
-
* @param {Cesium.Entity} [options.entity]
|
|
358
|
+
* @param {Cesium.Entity} [options.entity]
|
|
244
359
|
* @param {string|number} [options.mapId]
|
|
245
|
-
* @param {Function} options.getPosition
|
|
246
|
-
* @param {Function} [options.
|
|
247
|
-
* @param {
|
|
248
|
-
* @param {
|
|
249
|
-
* @param {number} [options.
|
|
250
|
-
* @param {number} [options.
|
|
360
|
+
* @param {Function} options.getPosition
|
|
361
|
+
* @param {Function} [options.getInfo] 获取车辆信息
|
|
362
|
+
* @param {Function} [options.getVisible]
|
|
363
|
+
* @param {GlbInfoBadgeData} [options.info] 初始信息
|
|
364
|
+
* @param {number} [options.labelOffset=1]
|
|
365
|
+
* @param {number} [options.pixelGap=0]
|
|
366
|
+
* @param {number} [options.heightScale=0.72]
|
|
251
367
|
*/
|
|
252
368
|
export function createGlbInfoBadge(options = {}) {
|
|
253
369
|
const {
|
|
@@ -255,8 +371,9 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
255
371
|
entity,
|
|
256
372
|
mapId,
|
|
257
373
|
getPosition,
|
|
374
|
+
getInfo,
|
|
258
375
|
getVisible,
|
|
259
|
-
|
|
376
|
+
info: initialInfo = {},
|
|
260
377
|
labelOffset = DEFAULT_LABEL_OFFSET,
|
|
261
378
|
pixelGap = DEFAULT_PIXEL_GAP,
|
|
262
379
|
heightScale = DEFAULT_HEIGHT_SCALE,
|
|
@@ -270,17 +387,9 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
270
387
|
|
|
271
388
|
const batchManager = getDroneLabelBatchManager(map, mapId)
|
|
272
389
|
const badgeEl = document.createElement('div')
|
|
273
|
-
badgeEl.className =
|
|
274
|
-
badgeEl.innerHTML =
|
|
275
|
-
|
|
276
|
-
<span class="glb-info-badge-dot"></span>
|
|
277
|
-
<span class="glb-info-badge-text">${isOffline ? '离线' : '在线'}</span>
|
|
278
|
-
<span class="glb-info-badge-scan"></span>
|
|
279
|
-
</div>
|
|
280
|
-
<div class="glb-info-badge-pointer"></div>
|
|
281
|
-
`
|
|
282
|
-
|
|
283
|
-
const textEl = badgeEl.querySelector('.glb-info-badge-text')
|
|
390
|
+
badgeEl.className = 'glb-info-badge'
|
|
391
|
+
badgeEl.innerHTML = buildBadgeHtml(initialInfo)
|
|
392
|
+
renderBadgeContent(badgeEl, initialInfo)
|
|
284
393
|
|
|
285
394
|
const batchEntry = {
|
|
286
395
|
updatePosition(hideByHeight) {
|
|
@@ -338,14 +447,14 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
338
447
|
batchManager.container.appendChild(badgeEl)
|
|
339
448
|
batchManager.add(batchEntry)
|
|
340
449
|
|
|
450
|
+
const updateInfo = (info = {}) => {
|
|
451
|
+
renderBadgeContent(badgeEl, info)
|
|
452
|
+
return normalizeInfo(info)
|
|
453
|
+
}
|
|
454
|
+
|
|
341
455
|
const setOfflineStatus = (offline) => {
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
badgeEl.classList.toggle('is-online', !nextOffline)
|
|
345
|
-
if (textEl) {
|
|
346
|
-
textEl.textContent = nextOffline ? '离线' : '在线'
|
|
347
|
-
}
|
|
348
|
-
return nextOffline
|
|
456
|
+
const currentInfo = typeof getInfo === 'function' ? getInfo() : initialInfo
|
|
457
|
+
return updateInfo({ ...currentInfo, isOffline: Boolean(offline) })
|
|
349
458
|
}
|
|
350
459
|
|
|
351
460
|
const destroy = () => {
|
|
@@ -354,6 +463,7 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
354
463
|
}
|
|
355
464
|
|
|
356
465
|
return {
|
|
466
|
+
updateInfo,
|
|
357
467
|
setOfflineStatus,
|
|
358
468
|
destroy,
|
|
359
469
|
}
|
package/js/index.js
CHANGED
|
@@ -9,6 +9,7 @@ export { createCustomToolbarButtons } from './customToolbarButtons.js'
|
|
|
9
9
|
export { drawFence } from './drawFence.js'
|
|
10
10
|
export { drawFenceNew } from './drawFenceNew.js'
|
|
11
11
|
export { measureDistance } from './measureDistance.js'
|
|
12
|
+
export { measureBearing } from './measureBearing.js'
|
|
12
13
|
export { createDroneRippleDom } from './droneRipple.js'
|
|
13
14
|
export { createGlbInfoBadge } from './glbInfoBadge.js'
|
|
14
15
|
export { geometryConfig } from './geometry.js'
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 地图测向:点击起点与终点,测量第二点相对于第一点的北向角(北向 0°,顺时针)
|
|
3
|
+
*
|
|
4
|
+
* @author huweili
|
|
5
|
+
* @email czxyhuweili@163.com
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
import * as Cesium from 'cesium'
|
|
9
|
+
import { useMapStore } from './stores/mapStore.js'
|
|
10
|
+
|
|
11
|
+
function formatBearingDegrees(deg) {
|
|
12
|
+
if (!Number.isFinite(deg)) return '--'
|
|
13
|
+
return `${(((deg % 360) + 360) % 360).toFixed(1)}°`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getGroundCartesianFromScreen(map, screenPosition) {
|
|
17
|
+
if (!screenPosition) return null
|
|
18
|
+
|
|
19
|
+
const scene = map.scene
|
|
20
|
+
let cartesian = null
|
|
21
|
+
|
|
22
|
+
if (scene.pickPositionSupported) {
|
|
23
|
+
cartesian = scene.pickPosition(screenPosition)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!Cesium.defined(cartesian)) {
|
|
27
|
+
const ray = map.camera.getPickRay(screenPosition)
|
|
28
|
+
if (!ray) return null
|
|
29
|
+
cartesian = scene.globe.pick(ray, scene)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!Cesium.defined(cartesian)) return null
|
|
33
|
+
|
|
34
|
+
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
|
|
35
|
+
return Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, 0)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function cartesianToLngLat(cartesian) {
|
|
39
|
+
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
|
|
40
|
+
return {
|
|
41
|
+
lng: Cesium.Math.toDegrees(cartographic.longitude),
|
|
42
|
+
lat: Cesium.Math.toDegrees(cartographic.latitude),
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function computeGeodesicBearing(lng1, lat1, lng2, lat2) {
|
|
47
|
+
const φ1 = Cesium.Math.toRadians(lat1)
|
|
48
|
+
const φ2 = Cesium.Math.toRadians(lat2)
|
|
49
|
+
const Δλ = Cesium.Math.toRadians(lng2 - lng1)
|
|
50
|
+
const y = Math.sin(Δλ) * Math.cos(φ2)
|
|
51
|
+
const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(Δλ)
|
|
52
|
+
return (Cesium.Math.toDegrees(Math.atan2(y, x)) + 360) % 360
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function computeBearingResult(start, end) {
|
|
56
|
+
const azimuth = computeGeodesicBearing(start.lng, start.lat, end.lng, end.lat)
|
|
57
|
+
const dist = Cesium.Cartesian3.distance(
|
|
58
|
+
Cesium.Cartesian3.fromDegrees(start.lng, start.lat, 0),
|
|
59
|
+
Cesium.Cartesian3.fromDegrees(end.lng, end.lat, 0),
|
|
60
|
+
)
|
|
61
|
+
return {
|
|
62
|
+
azimuth,
|
|
63
|
+
azimuthText: formatBearingDegrees(azimuth),
|
|
64
|
+
distance: dist,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function measureBearing() {
|
|
69
|
+
const mapStore = useMapStore()
|
|
70
|
+
|
|
71
|
+
const createMouseTipEntity = (map, options) => {
|
|
72
|
+
return map.entities.add({
|
|
73
|
+
id: options.id,
|
|
74
|
+
position: new Cesium.CallbackProperty(() => options.getPosition(), false),
|
|
75
|
+
label: {
|
|
76
|
+
text: new Cesium.CallbackProperty(() => options.getText(), false),
|
|
77
|
+
font: options.font || 'bold 10px Microsoft YaHei',
|
|
78
|
+
fillColor: options.fillColor || Cesium.Color.WHITE,
|
|
79
|
+
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
80
|
+
outlineColor: Cesium.Color.BLACK,
|
|
81
|
+
outlineWidth: 2,
|
|
82
|
+
showBackground: true,
|
|
83
|
+
backgroundColor: Cesium.Color.fromCssColorString(options.backgroundColor || 'rgba(0, 0, 0, 0.7)'),
|
|
84
|
+
backgroundPadding: options.backgroundPadding || new Cesium.Cartesian2(4, 4),
|
|
85
|
+
verticalOrigin: options.verticalOrigin || Cesium.VerticalOrigin.BOTTOM,
|
|
86
|
+
horizontalOrigin: options.horizontalOrigin || Cesium.HorizontalOrigin.LEFT,
|
|
87
|
+
pixelOffset: options.pixelOffset || new Cesium.Cartesian2(18, -18),
|
|
88
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
89
|
+
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, options.maxDistance || 2000000),
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {Object} options
|
|
96
|
+
* @param {string} options.id
|
|
97
|
+
* @param {string} [options.mapId]
|
|
98
|
+
* @param {string} [options.color='#ffd400']
|
|
99
|
+
* @param {(result: Object) => void} [options.onFinish]
|
|
100
|
+
* @returns {Object|null}
|
|
101
|
+
*/
|
|
102
|
+
const startBearingMeasure = (options = {}) => {
|
|
103
|
+
const map = mapStore.getMap(options.mapId)
|
|
104
|
+
if (!map) {
|
|
105
|
+
console.error('[测向] 地图实例不存在')
|
|
106
|
+
return null
|
|
107
|
+
}
|
|
108
|
+
if (!options.id) {
|
|
109
|
+
console.error('[测向] 必须提供 id')
|
|
110
|
+
return null
|
|
111
|
+
}
|
|
112
|
+
if (mapStore.hasGraphicMap(options.id, options.mapId)) {
|
|
113
|
+
console.warn(`[测向] id ${options.id} 已存在`)
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const color = Cesium.Color.fromCssColorString(options.color || '#ffd400')
|
|
118
|
+
|
|
119
|
+
let startPosition = null
|
|
120
|
+
let endPosition = null
|
|
121
|
+
let floatingPosition = null
|
|
122
|
+
let cursorPosition = null
|
|
123
|
+
let startPointEntity = null
|
|
124
|
+
let endPointEntity = null
|
|
125
|
+
let lineEntity = null
|
|
126
|
+
let labelEntity = null
|
|
127
|
+
let tipEntity = null
|
|
128
|
+
let deleteButtonEntity = null
|
|
129
|
+
let handler = null
|
|
130
|
+
let deleteHandler = null
|
|
131
|
+
let isFinished = false
|
|
132
|
+
|
|
133
|
+
const tempIds = {
|
|
134
|
+
startPoint: `${options.id}_bearing_start`,
|
|
135
|
+
endPoint: `${options.id}_bearing_end`,
|
|
136
|
+
line: `${options.id}_bearing_line`,
|
|
137
|
+
label: `${options.id}_bearing_label`,
|
|
138
|
+
tip: `${options.id}_bearing_tip`,
|
|
139
|
+
deleteButton: `${options.id}_bearing_delete`,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const getLinePositions = () => {
|
|
143
|
+
if (!startPosition) return []
|
|
144
|
+
const target = endPosition || floatingPosition
|
|
145
|
+
if (!target) return [startPosition]
|
|
146
|
+
return [startPosition, target]
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const getMidPosition = () => {
|
|
150
|
+
const target = endPosition || floatingPosition
|
|
151
|
+
if (!startPosition || !target) return startPosition || target || cursorPosition || null
|
|
152
|
+
const s = Cesium.Cartographic.fromCartesian(startPosition)
|
|
153
|
+
const e = Cesium.Cartographic.fromCartesian(target)
|
|
154
|
+
return Cesium.Cartesian3.fromRadians(
|
|
155
|
+
(s.longitude + e.longitude) / 2,
|
|
156
|
+
(s.latitude + e.latitude) / 2,
|
|
157
|
+
0,
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const getCurrentBearingText = () => {
|
|
162
|
+
const target = endPosition || floatingPosition
|
|
163
|
+
if (!startPosition || !target) return '--'
|
|
164
|
+
const start = cartesianToLngLat(startPosition)
|
|
165
|
+
const end = cartesianToLngLat(target)
|
|
166
|
+
return computeBearingResult(start, end).azimuthText
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const getTipText = () => {
|
|
170
|
+
if (!startPosition) return '点击确定起点'
|
|
171
|
+
if (!endPosition) return `点击确定终点,当前北向角:${getCurrentBearingText()}`
|
|
172
|
+
return `测向完成,北向角:${getCurrentBearingText()}`
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const ensurePreviewEntities = () => {
|
|
176
|
+
if (!startPointEntity) {
|
|
177
|
+
startPointEntity = map.entities.add({
|
|
178
|
+
id: tempIds.startPoint,
|
|
179
|
+
position: startPosition,
|
|
180
|
+
point: {
|
|
181
|
+
pixelSize: 6,
|
|
182
|
+
color,
|
|
183
|
+
outlineColor: Cesium.Color.WHITE,
|
|
184
|
+
outlineWidth: 1.5,
|
|
185
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
186
|
+
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
187
|
+
scaleByDistance: new Cesium.NearFarScalar(1000, 1.5, 5000000, 0.5),
|
|
188
|
+
},
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (!lineEntity) {
|
|
193
|
+
lineEntity = map.entities.add({
|
|
194
|
+
id: tempIds.line,
|
|
195
|
+
polyline: {
|
|
196
|
+
positions: new Cesium.CallbackProperty(() => getLinePositions(), false),
|
|
197
|
+
width: 3,
|
|
198
|
+
material: new Cesium.PolylineGlowMaterialProperty({ color, glowPower: 0.25 }),
|
|
199
|
+
clampToGround: true,
|
|
200
|
+
},
|
|
201
|
+
})
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (!labelEntity) {
|
|
205
|
+
labelEntity = map.entities.add({
|
|
206
|
+
id: tempIds.label,
|
|
207
|
+
position: new Cesium.CallbackProperty(() => getMidPosition(), false),
|
|
208
|
+
label: {
|
|
209
|
+
text: new Cesium.CallbackProperty(() => `北向角 ${getCurrentBearingText()}`, false),
|
|
210
|
+
font: 'bold 10px Microsoft YaHei',
|
|
211
|
+
fillColor: Cesium.Color.WHITE,
|
|
212
|
+
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
213
|
+
outlineColor: Cesium.Color.BLACK,
|
|
214
|
+
outlineWidth: 2,
|
|
215
|
+
showBackground: true,
|
|
216
|
+
backgroundColor: Cesium.Color.fromCssColorString('rgba(0, 0, 0, 0.75)'),
|
|
217
|
+
backgroundPadding: new Cesium.Cartesian2(4, 4),
|
|
218
|
+
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
|
219
|
+
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
|
220
|
+
pixelOffset: new Cesium.Cartesian2(0, -16),
|
|
221
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
222
|
+
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 2000000),
|
|
223
|
+
},
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const createEndPointEntity = () => {
|
|
229
|
+
if (endPointEntity || !endPosition) return
|
|
230
|
+
endPointEntity = map.entities.add({
|
|
231
|
+
id: tempIds.endPoint,
|
|
232
|
+
position: endPosition,
|
|
233
|
+
point: {
|
|
234
|
+
pixelSize: 6,
|
|
235
|
+
color,
|
|
236
|
+
outlineColor: Cesium.Color.WHITE,
|
|
237
|
+
outlineWidth: 1.5,
|
|
238
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
239
|
+
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
|
240
|
+
scaleByDistance: new Cesium.NearFarScalar(1000, 1.5, 5000000, 0.5),
|
|
241
|
+
},
|
|
242
|
+
})
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const removeEntities = () => {
|
|
246
|
+
[startPointEntity, endPointEntity, lineEntity, labelEntity, deleteButtonEntity, tipEntity].forEach((entity) => {
|
|
247
|
+
if (entity) map.entities.remove(entity)
|
|
248
|
+
})
|
|
249
|
+
startPointEntity = null
|
|
250
|
+
endPointEntity = null
|
|
251
|
+
lineEntity = null
|
|
252
|
+
labelEntity = null
|
|
253
|
+
deleteButtonEntity = null
|
|
254
|
+
tipEntity = null
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const destroyGraphic = () => {
|
|
258
|
+
if (handler) {
|
|
259
|
+
handler.destroy()
|
|
260
|
+
handler = null
|
|
261
|
+
}
|
|
262
|
+
if (deleteHandler) {
|
|
263
|
+
deleteHandler.destroy()
|
|
264
|
+
deleteHandler = null
|
|
265
|
+
}
|
|
266
|
+
removeEntities()
|
|
267
|
+
mapStore.removeGraphicMap(options.id, options.mapId)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const cancel = () => {
|
|
271
|
+
if (isFinished) return
|
|
272
|
+
if (handler) {
|
|
273
|
+
handler.destroy()
|
|
274
|
+
handler = null
|
|
275
|
+
}
|
|
276
|
+
removeEntities()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const finalize = () => {
|
|
280
|
+
if (isFinished || !startPosition || !endPosition) return null
|
|
281
|
+
isFinished = true
|
|
282
|
+
if (handler) {
|
|
283
|
+
handler.destroy()
|
|
284
|
+
handler = null
|
|
285
|
+
}
|
|
286
|
+
if (tipEntity) {
|
|
287
|
+
map.entities.remove(tipEntity)
|
|
288
|
+
tipEntity = null
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
createEndPointEntity()
|
|
292
|
+
|
|
293
|
+
deleteButtonEntity = map.entities.add({
|
|
294
|
+
id: tempIds.deleteButton,
|
|
295
|
+
position: new Cesium.CallbackProperty(() => getMidPosition(), false),
|
|
296
|
+
label: {
|
|
297
|
+
text: '✕',
|
|
298
|
+
font: 'bold 12px Arial',
|
|
299
|
+
fillColor: color,
|
|
300
|
+
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
|
301
|
+
outlineColor: Cesium.Color.BLACK,
|
|
302
|
+
outlineWidth: 2,
|
|
303
|
+
verticalOrigin: Cesium.VerticalOrigin.CENTER,
|
|
304
|
+
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
|
305
|
+
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
306
|
+
},
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
deleteHandler = new Cesium.ScreenSpaceEventHandler(map.scene.canvas)
|
|
310
|
+
deleteHandler.setInputAction((movement) => {
|
|
311
|
+
const picked = map.scene.pick(movement.position)
|
|
312
|
+
if (!Cesium.defined(picked?.id)) return
|
|
313
|
+
if (picked.id === deleteButtonEntity || picked.id === tempIds.deleteButton) {
|
|
314
|
+
destroyGraphic()
|
|
315
|
+
}
|
|
316
|
+
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
317
|
+
|
|
318
|
+
const start = cartesianToLngLat(startPosition)
|
|
319
|
+
const end = cartesianToLngLat(endPosition)
|
|
320
|
+
const result = { id: options.id, start, end, ...computeBearingResult(start, end) }
|
|
321
|
+
|
|
322
|
+
mapStore.setGraphicMap(options.id, {
|
|
323
|
+
id: options.id,
|
|
324
|
+
type: 'measureBearing',
|
|
325
|
+
result,
|
|
326
|
+
destroy: destroyGraphic,
|
|
327
|
+
}, options.mapId)
|
|
328
|
+
|
|
329
|
+
if (typeof options.onFinish === 'function') options.onFinish(result)
|
|
330
|
+
return result
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
tipEntity = createMouseTipEntity(map, {
|
|
334
|
+
id: tempIds.tip,
|
|
335
|
+
getPosition: () => cursorPosition || endPosition || floatingPosition || startPosition,
|
|
336
|
+
getText: getTipText,
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
handler = new Cesium.ScreenSpaceEventHandler(map.scene.canvas)
|
|
340
|
+
|
|
341
|
+
handler.setInputAction((movement) => {
|
|
342
|
+
if (isFinished) return
|
|
343
|
+
cursorPosition = getGroundCartesianFromScreen(map, movement.endPosition)
|
|
344
|
+
if (startPosition && cursorPosition) {
|
|
345
|
+
floatingPosition = cursorPosition
|
|
346
|
+
}
|
|
347
|
+
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
|
|
348
|
+
|
|
349
|
+
handler.setInputAction((click) => {
|
|
350
|
+
if (isFinished) return
|
|
351
|
+
const cartesian = getGroundCartesianFromScreen(map, click.position)
|
|
352
|
+
if (!cartesian) return
|
|
353
|
+
|
|
354
|
+
if (!startPosition) {
|
|
355
|
+
startPosition = cartesian
|
|
356
|
+
floatingPosition = cartesian
|
|
357
|
+
cursorPosition = cartesian
|
|
358
|
+
ensurePreviewEntities()
|
|
359
|
+
return
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
endPosition = cartesian
|
|
363
|
+
floatingPosition = null
|
|
364
|
+
createEndPointEntity()
|
|
365
|
+
finalize()
|
|
366
|
+
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
|
|
367
|
+
|
|
368
|
+
handler.setInputAction(() => {
|
|
369
|
+
cancel()
|
|
370
|
+
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
|
|
371
|
+
|
|
372
|
+
return { id: options.id, finish: finalize, cancel, destroy: destroyGraphic }
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return {
|
|
376
|
+
startBearingMeasure,
|
|
377
|
+
formatBearingDegrees,
|
|
378
|
+
}
|
|
379
|
+
}
|
package/js/movePoint.js
CHANGED
|
@@ -84,7 +84,7 @@ export function movePointConfig(baseUrl) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
* 移动 GLB
|
|
87
|
+
* 移动 GLB 信息牌点位到新的坐标位置,并更新车辆信息
|
|
88
88
|
* @param options 配置选项
|
|
89
89
|
* @param options.pointId 点位唯一标识
|
|
90
90
|
* @param options.lng 新的经度
|
|
@@ -92,6 +92,8 @@ export function movePointConfig(baseUrl) {
|
|
|
92
92
|
* @param options.height 高度(可选,默认0)
|
|
93
93
|
* @param options.heading 朝向(可选,默认0)
|
|
94
94
|
* @param options.pitch 俯仰(可选,默认0)
|
|
95
|
+
* @param options.vehicleName 车辆名称(可选)
|
|
96
|
+
* @param options.address 位置描述(可选)
|
|
95
97
|
* @param options.isOffline 是否离线(true=离线,false=在线;不传则保持原状态)
|
|
96
98
|
* @param options.mapId 地图ID
|
|
97
99
|
*/
|
|
@@ -137,7 +139,13 @@ export function movePointConfig(baseUrl) {
|
|
|
137
139
|
)
|
|
138
140
|
}
|
|
139
141
|
|
|
140
|
-
if (
|
|
142
|
+
if (typeof point.updateInfo === 'function') {
|
|
143
|
+
const infoPatch = { lng, lat }
|
|
144
|
+
if (options.vehicleName !== undefined) infoPatch.vehicleName = options.vehicleName
|
|
145
|
+
if (options.address !== undefined) infoPatch.address = options.address
|
|
146
|
+
if (options.isOffline !== undefined) infoPatch.isOffline = options.isOffline
|
|
147
|
+
point.updateInfo(infoPatch)
|
|
148
|
+
} else if (options.isOffline !== undefined && typeof point.setOfflineStatus === 'function') {
|
|
141
149
|
point.setOfflineStatus(options.isOffline)
|
|
142
150
|
}
|
|
143
151
|
|
package/js/setPoint.js
CHANGED
|
@@ -221,7 +221,7 @@ export function setPoint(baseUrl) {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
/**
|
|
224
|
-
* 设置点位(GLB 模型 +
|
|
224
|
+
* 设置点位(GLB 模型 + 头顶车辆信息牌)
|
|
225
225
|
* @param options 配置选项
|
|
226
226
|
* @param options.url GLB模型路径(本地/网络)
|
|
227
227
|
* @param options.id 点位唯一标识
|
|
@@ -229,8 +229,9 @@ export function setPoint(baseUrl) {
|
|
|
229
229
|
* @param options.lat 纬度
|
|
230
230
|
* @param options.height 高度(可选,默认0)
|
|
231
231
|
* @param options.heading 朝向(可选,默认0)
|
|
232
|
+
* @param options.vehicleName 车辆名称
|
|
233
|
+
* @param options.address 位置描述
|
|
232
234
|
* @param options.isOffline 是否离线(true=离线,false=在线,默认 false)
|
|
233
|
-
* @param options.modelHeight 模型高度兜底值(米,可选,默认 1;未加载包围球时使用)
|
|
234
235
|
* @param options.mapId 地图ID
|
|
235
236
|
* @returns 创建的点位包装对象
|
|
236
237
|
*/
|
|
@@ -275,6 +276,13 @@ export function setPoint(baseUrl) {
|
|
|
275
276
|
const glbPoint = {
|
|
276
277
|
entity: modelEntity,
|
|
277
278
|
isOffline,
|
|
279
|
+
info: {
|
|
280
|
+
vehicleName: options.vehicleName || '--',
|
|
281
|
+
lng,
|
|
282
|
+
lat,
|
|
283
|
+
address: options.address || '--',
|
|
284
|
+
isOffline,
|
|
285
|
+
},
|
|
278
286
|
infoBadge: null,
|
|
279
287
|
get position() {
|
|
280
288
|
return this.entity.position
|
|
@@ -288,10 +296,20 @@ export function setPoint(baseUrl) {
|
|
|
288
296
|
set orientation(value) {
|
|
289
297
|
this.entity.orientation = value
|
|
290
298
|
},
|
|
299
|
+
updateInfo(partial = {}) {
|
|
300
|
+
if (partial.lng !== undefined) this.info.lng = Number(partial.lng)
|
|
301
|
+
if (partial.lat !== undefined) this.info.lat = Number(partial.lat)
|
|
302
|
+
if (partial.vehicleName !== undefined) this.info.vehicleName = partial.vehicleName
|
|
303
|
+
if (partial.address !== undefined) this.info.address = partial.address
|
|
304
|
+
if (partial.isOffline !== undefined) {
|
|
305
|
+
this.isOffline = Boolean(partial.isOffline)
|
|
306
|
+
this.info.isOffline = this.isOffline
|
|
307
|
+
}
|
|
308
|
+
this.infoBadge?.updateInfo?.(this.info)
|
|
309
|
+
return this.info
|
|
310
|
+
},
|
|
291
311
|
setOfflineStatus(offline) {
|
|
292
|
-
this.isOffline
|
|
293
|
-
this.infoBadge?.setOfflineStatus?.(this.isOffline)
|
|
294
|
-
return this.isOffline
|
|
312
|
+
return this.updateInfo({ isOffline: offline })
|
|
295
313
|
},
|
|
296
314
|
destroy() {
|
|
297
315
|
this.infoBadge?.destroy?.()
|
|
@@ -305,8 +323,8 @@ export function setPoint(baseUrl) {
|
|
|
305
323
|
map,
|
|
306
324
|
mapId,
|
|
307
325
|
entity: modelEntity,
|
|
308
|
-
|
|
309
|
-
|
|
326
|
+
info: glbPoint.info,
|
|
327
|
+
getInfo: () => glbPoint.info,
|
|
310
328
|
getPosition: () => {
|
|
311
329
|
const posProp = modelEntity.position
|
|
312
330
|
if (posProp instanceof Cesium.Cartesian3) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "huweili-cesium",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "基于 Cesium 的地图工具库(无人机态势、轨迹、围栏、工具栏等)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
"./drawFenceNew.js": "./js/drawFenceNew.js",
|
|
42
42
|
"./measureDistance": "./js/measureDistance.js",
|
|
43
43
|
"./measureDistance.js": "./js/measureDistance.js",
|
|
44
|
+
"./measureBearing": "./js/measureBearing.js",
|
|
45
|
+
"./measureBearing.js": "./js/measureBearing.js",
|
|
44
46
|
"./dronePlannedRoute": "./js/dronePlannedRoute.js",
|
|
45
47
|
"./dronePlannedRoute.js": "./js/dronePlannedRoute.js",
|
|
46
48
|
"./droneRipple": "./js/droneRipple.js",
|