huweili-cesium 1.2.98 → 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 +188 -77
- 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
|
-
inset 0 0
|
|
48
|
-
0 0
|
|
76
|
+
inset 0 0 8px rgba(0, 229, 255, 0.08),
|
|
77
|
+
0 0 10px rgba(0, 229, 255, 0.15);
|
|
49
78
|
overflow: hidden;
|
|
50
|
-
backdrop-filter: blur(
|
|
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,38 +131,42 @@ 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
|
}
|
|
63
138
|
.glb-info-badge-dot {
|
|
64
|
-
width:
|
|
65
|
-
height:
|
|
139
|
+
width: 5px;
|
|
140
|
+
height: 5px;
|
|
66
141
|
border-radius: 50%;
|
|
67
142
|
flex-shrink: 0;
|
|
68
|
-
box-shadow: 0 0
|
|
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;
|
|
149
|
+
letter-spacing: 0.04em;
|
|
74
150
|
color: #e8f7ff;
|
|
75
|
-
text-shadow: 0 0
|
|
151
|
+
text-shadow: 0 0 4px rgba(0, 229, 255, 0.5);
|
|
76
152
|
}
|
|
77
153
|
.glb-info-badge-pointer {
|
|
78
154
|
width: 0;
|
|
79
155
|
height: 0;
|
|
80
|
-
margin:
|
|
81
|
-
border-left:
|
|
82
|
-
border-right:
|
|
83
|
-
border-top:
|
|
84
|
-
filter: drop-shadow(0 0
|
|
156
|
+
margin: 1px auto 0;
|
|
157
|
+
border-left: 4px solid transparent;
|
|
158
|
+
border-right: 4px solid transparent;
|
|
159
|
+
border-top: 5px solid rgba(0, 229, 255, 0.55);
|
|
160
|
+
filter: drop-shadow(0 0 3px rgba(0, 229, 255, 0.4));
|
|
85
161
|
}
|
|
86
162
|
.glb-info-badge.is-online .glb-info-badge-inner {
|
|
87
163
|
border-color: rgba(0, 255, 170, 0.55);
|
|
88
164
|
box-shadow:
|
|
89
|
-
inset 0 0
|
|
90
|
-
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);
|
|
91
170
|
}
|
|
92
171
|
.glb-info-badge.is-online .glb-info-badge-dot {
|
|
93
172
|
background: #00ffaa;
|
|
@@ -96,7 +175,7 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
96
175
|
}
|
|
97
176
|
.glb-info-badge.is-online .glb-info-badge-text {
|
|
98
177
|
color: #d6fff0;
|
|
99
|
-
text-shadow: 0 0
|
|
178
|
+
text-shadow: 0 0 4px rgba(0, 255, 170, 0.45);
|
|
100
179
|
}
|
|
101
180
|
.glb-info-badge.is-online .glb-info-badge-pointer {
|
|
102
181
|
border-top-color: rgba(0, 255, 170, 0.6);
|
|
@@ -104,9 +183,11 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
104
183
|
.glb-info-badge.is-offline .glb-info-badge-inner {
|
|
105
184
|
border-color: rgba(255, 92, 92, 0.55);
|
|
106
185
|
box-shadow:
|
|
107
|
-
inset 0 0
|
|
108
|
-
0 0
|
|
109
|
-
|
|
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);
|
|
110
191
|
}
|
|
111
192
|
.glb-info-badge.is-offline .glb-info-badge-dot {
|
|
112
193
|
background: #ff5c5c;
|
|
@@ -115,7 +196,7 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
115
196
|
}
|
|
116
197
|
.glb-info-badge.is-offline .glb-info-badge-text {
|
|
117
198
|
color: #ffe8e8;
|
|
118
|
-
text-shadow: 0 0
|
|
199
|
+
text-shadow: 0 0 6px rgba(255, 92, 92, 0.55);
|
|
119
200
|
}
|
|
120
201
|
.glb-info-badge.is-offline .glb-info-badge-pointer {
|
|
121
202
|
border-top-color: rgba(255, 92, 92, 0.65);
|
|
@@ -132,17 +213,65 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
132
213
|
0%, 100% { opacity: 1; transform: scale(1); box-shadow: 0 0 8px #ff5c5c; }
|
|
133
214
|
50% { opacity: 0.45; transform: scale(1.25); box-shadow: 0 0 14px #ff5c5c, 0 0 22px rgba(255, 92, 92, 0.6); }
|
|
134
215
|
}
|
|
135
|
-
@keyframes glb-info-badge-shake {
|
|
136
|
-
0%, 92%, 100% { transform: translateX(0); }
|
|
137
|
-
93% { transform: translateX(-1px); }
|
|
138
|
-
94% { transform: translateX(1px); }
|
|
139
|
-
95% { transform: translateX(-1px); }
|
|
140
|
-
96% { transform: translateX(0); }
|
|
141
|
-
}
|
|
142
216
|
`
|
|
143
217
|
document.head.appendChild(style)
|
|
144
218
|
}
|
|
145
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
|
+
|
|
146
275
|
/**
|
|
147
276
|
* 读取 Entity 模型 minimumPixelSize(远景会被放大显示,需同步到屏幕偏移)
|
|
148
277
|
* @param {Cesium.Entity} entity
|
|
@@ -162,11 +291,6 @@ const getEntityMinimumPixelSize = (entity, time) => {
|
|
|
162
291
|
|
|
163
292
|
/**
|
|
164
293
|
* 根据模型包围球估算车顶世界坐标
|
|
165
|
-
* @param {Cesium.Viewer} map
|
|
166
|
-
* @param {Cesium.Entity} entity
|
|
167
|
-
* @param {Cesium.Cartesian3} basePos
|
|
168
|
-
* @param {number} fallbackOffset
|
|
169
|
-
* @returns {Cesium.Cartesian3|null}
|
|
170
294
|
*/
|
|
171
295
|
const resolveModelTopWorldPosition = (map, entity, basePos, fallbackOffset) => {
|
|
172
296
|
Cesium.Transforms.eastNorthUpToFixedFrame(basePos, undefined, scratchEnu)
|
|
@@ -191,13 +315,6 @@ const resolveModelTopWorldPosition = (map, entity, basePos, fallbackOffset) => {
|
|
|
191
315
|
|
|
192
316
|
/**
|
|
193
317
|
* 将车顶世界坐标转为屏幕坐标,并兼顾 minimumPixelSize 的可视高度
|
|
194
|
-
* @param {Cesium.Scene} scene
|
|
195
|
-
* @param {Cesium.Cartesian3} basePos
|
|
196
|
-
* @param {Cesium.Cartesian3} topWorldPos
|
|
197
|
-
* @param {number} minPixelSize
|
|
198
|
-
* @param {number} pixelGap
|
|
199
|
-
* @param {number} heightScale
|
|
200
|
-
* @returns {{ x: number, y: number }|null}
|
|
201
318
|
*/
|
|
202
319
|
const resolveBadgeScreenPosition = (scene, basePos, topWorldPos, minPixelSize, pixelGap, heightScale) => {
|
|
203
320
|
const anchorWin = scene.cartesianToCanvasCoordinates(basePos)
|
|
@@ -212,7 +329,6 @@ const resolveBadgeScreenPosition = (scene, basePos, topWorldPos, minPixelSize, p
|
|
|
212
329
|
offsetY = (anchorWin.y - topWin.y) * heightScale
|
|
213
330
|
}
|
|
214
331
|
|
|
215
|
-
// 包围球常大于实际 mesh,对过大偏移做软压缩
|
|
216
332
|
if (offsetY > 0 && minPixelSize > 0 && offsetY > minPixelSize * 0.5) {
|
|
217
333
|
const base = minPixelSize * 0.3
|
|
218
334
|
offsetY = base + (offsetY - base) * 0.35
|
|
@@ -236,17 +352,18 @@ const resolveBadgeScreenPosition = (scene, basePos, topWorldPos, minPixelSize, p
|
|
|
236
352
|
}
|
|
237
353
|
|
|
238
354
|
/**
|
|
239
|
-
*
|
|
355
|
+
* 在模型头顶创建车辆信息牌
|
|
240
356
|
* @param {Object} options
|
|
241
357
|
* @param {Cesium.Viewer} options.map
|
|
242
|
-
* @param {Cesium.Entity} [options.entity]
|
|
358
|
+
* @param {Cesium.Entity} [options.entity]
|
|
243
359
|
* @param {string|number} [options.mapId]
|
|
244
|
-
* @param {Function} options.getPosition
|
|
245
|
-
* @param {Function} [options.
|
|
246
|
-
* @param {
|
|
247
|
-
* @param {
|
|
248
|
-
* @param {number} [options.
|
|
249
|
-
* @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]
|
|
250
367
|
*/
|
|
251
368
|
export function createGlbInfoBadge(options = {}) {
|
|
252
369
|
const {
|
|
@@ -254,8 +371,9 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
254
371
|
entity,
|
|
255
372
|
mapId,
|
|
256
373
|
getPosition,
|
|
374
|
+
getInfo,
|
|
257
375
|
getVisible,
|
|
258
|
-
|
|
376
|
+
info: initialInfo = {},
|
|
259
377
|
labelOffset = DEFAULT_LABEL_OFFSET,
|
|
260
378
|
pixelGap = DEFAULT_PIXEL_GAP,
|
|
261
379
|
heightScale = DEFAULT_HEIGHT_SCALE,
|
|
@@ -269,17 +387,9 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
269
387
|
|
|
270
388
|
const batchManager = getDroneLabelBatchManager(map, mapId)
|
|
271
389
|
const badgeEl = document.createElement('div')
|
|
272
|
-
badgeEl.className =
|
|
273
|
-
badgeEl.innerHTML =
|
|
274
|
-
|
|
275
|
-
<span class="glb-info-badge-dot"></span>
|
|
276
|
-
<span class="glb-info-badge-text">${isOffline ? '离线' : '在线'}</span>
|
|
277
|
-
<span class="glb-info-badge-scan"></span>
|
|
278
|
-
</div>
|
|
279
|
-
<div class="glb-info-badge-pointer"></div>
|
|
280
|
-
`
|
|
281
|
-
|
|
282
|
-
const textEl = badgeEl.querySelector('.glb-info-badge-text')
|
|
390
|
+
badgeEl.className = 'glb-info-badge'
|
|
391
|
+
badgeEl.innerHTML = buildBadgeHtml(initialInfo)
|
|
392
|
+
renderBadgeContent(badgeEl, initialInfo)
|
|
283
393
|
|
|
284
394
|
const batchEntry = {
|
|
285
395
|
updatePosition(hideByHeight) {
|
|
@@ -337,14 +447,14 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
337
447
|
batchManager.container.appendChild(badgeEl)
|
|
338
448
|
batchManager.add(batchEntry)
|
|
339
449
|
|
|
450
|
+
const updateInfo = (info = {}) => {
|
|
451
|
+
renderBadgeContent(badgeEl, info)
|
|
452
|
+
return normalizeInfo(info)
|
|
453
|
+
}
|
|
454
|
+
|
|
340
455
|
const setOfflineStatus = (offline) => {
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
badgeEl.classList.toggle('is-online', !nextOffline)
|
|
344
|
-
if (textEl) {
|
|
345
|
-
textEl.textContent = nextOffline ? '离线' : '在线'
|
|
346
|
-
}
|
|
347
|
-
return nextOffline
|
|
456
|
+
const currentInfo = typeof getInfo === 'function' ? getInfo() : initialInfo
|
|
457
|
+
return updateInfo({ ...currentInfo, isOffline: Boolean(offline) })
|
|
348
458
|
}
|
|
349
459
|
|
|
350
460
|
const destroy = () => {
|
|
@@ -353,6 +463,7 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
353
463
|
}
|
|
354
464
|
|
|
355
465
|
return {
|
|
466
|
+
updateInfo,
|
|
356
467
|
setOfflineStatus,
|
|
357
468
|
destroy,
|
|
358
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",
|