huweili-cesium 1.2.95 → 1.2.97
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/glbInfoBadge.js +113 -38
- package/js/setPoint.js +3 -0
- package/package.json +1 -1
package/js/glbInfoBadge.js
CHANGED
|
@@ -8,7 +8,14 @@ import * as Cesium from 'cesium'
|
|
|
8
8
|
import { getDroneLabelBatchManager } from './cardPool'
|
|
9
9
|
|
|
10
10
|
const STYLE_ID = 'glb-info-badge-style'
|
|
11
|
-
const DEFAULT_LABEL_OFFSET =
|
|
11
|
+
const DEFAULT_LABEL_OFFSET = 1
|
|
12
|
+
const DEFAULT_PIXEL_GAP = 2
|
|
13
|
+
|
|
14
|
+
const scratchBoundingSphere = new Cesium.BoundingSphere()
|
|
15
|
+
const scratchEnu = new Cesium.Matrix4()
|
|
16
|
+
const scratchUp = new Cesium.Cartesian3()
|
|
17
|
+
const scratchOffset = new Cesium.Cartesian3()
|
|
18
|
+
const scratchTop = new Cesium.Cartesian3()
|
|
12
19
|
|
|
13
20
|
const ensureGlbInfoBadgeStyle = () => {
|
|
14
21
|
if (document.getElementById(STYLE_ID)) return
|
|
@@ -19,9 +26,10 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
19
26
|
.glb-info-badge {
|
|
20
27
|
position: absolute;
|
|
21
28
|
pointer-events: none;
|
|
22
|
-
transform:
|
|
29
|
+
transform: translate(-50%, -100%);
|
|
23
30
|
z-index: 10000;
|
|
24
31
|
filter: drop-shadow(0 0 8px rgba(0, 229, 255, 0.35));
|
|
32
|
+
will-change: left, top;
|
|
25
33
|
}
|
|
26
34
|
.glb-info-badge-inner {
|
|
27
35
|
position: relative;
|
|
@@ -132,24 +140,108 @@ const ensureGlbInfoBadgeStyle = () => {
|
|
|
132
140
|
document.head.appendChild(style)
|
|
133
141
|
}
|
|
134
142
|
|
|
143
|
+
/**
|
|
144
|
+
* 读取 Entity 模型 minimumPixelSize(远景会被放大显示,需同步到屏幕偏移)
|
|
145
|
+
* @param {Cesium.Entity} entity
|
|
146
|
+
* @param {Cesium.JulianDate} time
|
|
147
|
+
* @returns {number}
|
|
148
|
+
*/
|
|
149
|
+
const getEntityMinimumPixelSize = (entity, time) => {
|
|
150
|
+
const model = entity?.model
|
|
151
|
+
if (!model) return 0
|
|
152
|
+
|
|
153
|
+
const value = typeof model.minimumPixelSize?.getValue === 'function'
|
|
154
|
+
? model.minimumPixelSize.getValue(time)
|
|
155
|
+
: model.minimumPixelSize
|
|
156
|
+
|
|
157
|
+
return Number.isFinite(value) ? value : 0
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 根据模型包围球估算车顶世界坐标
|
|
162
|
+
* @param {Cesium.Viewer} map
|
|
163
|
+
* @param {Cesium.Entity} entity
|
|
164
|
+
* @param {Cesium.Cartesian3} basePos
|
|
165
|
+
* @param {number} fallbackOffset
|
|
166
|
+
* @returns {Cesium.Cartesian3|null}
|
|
167
|
+
*/
|
|
168
|
+
const resolveModelTopWorldPosition = (map, entity, basePos, fallbackOffset) => {
|
|
169
|
+
Cesium.Transforms.eastNorthUpToFixedFrame(basePos, undefined, scratchEnu)
|
|
170
|
+
Cesium.Matrix4.getColumn(scratchEnu, 2, scratchUp)
|
|
171
|
+
Cesium.Cartesian3.normalize(scratchUp, scratchUp)
|
|
172
|
+
|
|
173
|
+
const dataSourceDisplay = map._dataSourceDisplay || map.dataSourceDisplay
|
|
174
|
+
if (entity && dataSourceDisplay?.getBoundingSphere) {
|
|
175
|
+
const ok = dataSourceDisplay.getBoundingSphere(entity, true, scratchBoundingSphere)
|
|
176
|
+
if (ok && scratchBoundingSphere.radius > 0) {
|
|
177
|
+
Cesium.Cartesian3.multiplyByScalar(scratchUp, scratchBoundingSphere.radius, scratchOffset)
|
|
178
|
+
return Cesium.Cartesian3.add(scratchBoundingSphere.center, scratchOffset, scratchTop)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
Cesium.Cartesian3.multiplyByScalar(scratchUp, fallbackOffset, scratchOffset)
|
|
183
|
+
return Cesium.Cartesian3.add(basePos, scratchOffset, scratchTop)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 将车顶世界坐标转为屏幕坐标,并兼顾 minimumPixelSize 的可视高度
|
|
188
|
+
* @param {Cesium.Scene} scene
|
|
189
|
+
* @param {Cesium.Cartesian3} basePos
|
|
190
|
+
* @param {Cesium.Cartesian3} topWorldPos
|
|
191
|
+
* @param {number} minPixelSize
|
|
192
|
+
* @param {number} pixelGap
|
|
193
|
+
* @returns {{ x: number, y: number }|null}
|
|
194
|
+
*/
|
|
195
|
+
const resolveBadgeScreenPosition = (scene, basePos, topWorldPos, minPixelSize, pixelGap) => {
|
|
196
|
+
const anchorWin = scene.cartesianToCanvasCoordinates(basePos)
|
|
197
|
+
if (!anchorWin || Number.isNaN(anchorWin.x) || Number.isNaN(anchorWin.y)) {
|
|
198
|
+
return null
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const topWin = scene.cartesianToCanvasCoordinates(topWorldPos)
|
|
202
|
+
let offsetY = 0
|
|
203
|
+
|
|
204
|
+
if (topWin && !Number.isNaN(topWin.y)) {
|
|
205
|
+
offsetY = anchorWin.y - topWin.y
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// minimumPixelSize 会让远景模型在屏幕上被抬高,仅用世界高度会产生“飘”感
|
|
209
|
+
if (minPixelSize > 0) {
|
|
210
|
+
offsetY = Math.max(offsetY, minPixelSize * 0.55)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (offsetY <= 0) {
|
|
214
|
+
offsetY = minPixelSize > 0 ? minPixelSize * 0.55 : 28
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
x: anchorWin.x,
|
|
219
|
+
y: anchorWin.y - offsetY - pixelGap,
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
135
223
|
/**
|
|
136
224
|
* 在模型头顶创建在线/离线信息牌
|
|
137
225
|
* @param {Object} options
|
|
138
226
|
* @param {Cesium.Viewer} options.map
|
|
227
|
+
* @param {Cesium.Entity} [options.entity] GLB 实体(用于读取包围球与 minimumPixelSize)
|
|
139
228
|
* @param {string|number} [options.mapId]
|
|
140
229
|
* @param {Function} options.getPosition 获取模型世界坐标
|
|
141
230
|
* @param {Function} [options.getVisible] 是否显示信息牌
|
|
142
231
|
* @param {boolean} [options.isOffline=false] true=离线,false=在线
|
|
143
|
-
* @param {number} [options.labelOffset=
|
|
232
|
+
* @param {number} [options.labelOffset=1] 模型未加载完成时的兜底高度(米)
|
|
233
|
+
* @param {number} [options.pixelGap=2] 信息牌与车顶之间的像素间距
|
|
144
234
|
*/
|
|
145
235
|
export function createGlbInfoBadge(options = {}) {
|
|
146
236
|
const {
|
|
147
237
|
map,
|
|
238
|
+
entity,
|
|
148
239
|
mapId,
|
|
149
240
|
getPosition,
|
|
150
241
|
getVisible,
|
|
151
242
|
isOffline = false,
|
|
152
243
|
labelOffset = DEFAULT_LABEL_OFFSET,
|
|
244
|
+
pixelGap = DEFAULT_PIXEL_GAP,
|
|
153
245
|
} = options
|
|
154
246
|
|
|
155
247
|
if (!map || typeof getPosition !== 'function') {
|
|
@@ -172,27 +264,6 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
172
264
|
|
|
173
265
|
const textEl = badgeEl.querySelector('.glb-info-badge-text')
|
|
174
266
|
|
|
175
|
-
const getBadgePosition = () => {
|
|
176
|
-
const basePos = getPosition()
|
|
177
|
-
if (!basePos) return null
|
|
178
|
-
|
|
179
|
-
if (!(basePos instanceof Cesium.Cartesian3)) {
|
|
180
|
-
return null
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const cartographic = Cesium.Cartographic.fromCartesian(basePos)
|
|
184
|
-
if (!Number.isFinite(cartographic.longitude) || !Number.isFinite(cartographic.latitude)) {
|
|
185
|
-
return null
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const height = Number.isFinite(cartographic.height) ? cartographic.height : 0
|
|
189
|
-
return Cesium.Cartesian3.fromRadians(
|
|
190
|
-
cartographic.longitude,
|
|
191
|
-
cartographic.latitude,
|
|
192
|
-
height + labelOffset
|
|
193
|
-
)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
267
|
const batchEntry = {
|
|
197
268
|
updatePosition(hideByHeight) {
|
|
198
269
|
if (!map?.scene) {
|
|
@@ -210,34 +281,38 @@ export function createGlbInfoBadge(options = {}) {
|
|
|
210
281
|
return
|
|
211
282
|
}
|
|
212
283
|
|
|
213
|
-
let
|
|
284
|
+
let basePos
|
|
214
285
|
try {
|
|
215
|
-
|
|
286
|
+
basePos = getPosition()
|
|
216
287
|
} catch (err) {
|
|
217
288
|
badgeEl.style.display = 'none'
|
|
218
289
|
return
|
|
219
290
|
}
|
|
220
291
|
|
|
221
|
-
if (!
|
|
292
|
+
if (!basePos || !(basePos instanceof Cesium.Cartesian3)) {
|
|
222
293
|
badgeEl.style.display = 'none'
|
|
223
294
|
return
|
|
224
295
|
}
|
|
225
296
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
297
|
+
const time = map.clock.currentTime
|
|
298
|
+
const minPixelSize = getEntityMinimumPixelSize(entity, time)
|
|
299
|
+
const topWorldPos = resolveModelTopWorldPosition(map, entity, basePos, labelOffset)
|
|
300
|
+
const screenPos = resolveBadgeScreenPosition(
|
|
301
|
+
map.scene,
|
|
302
|
+
basePos,
|
|
303
|
+
topWorldPos,
|
|
304
|
+
minPixelSize,
|
|
305
|
+
pixelGap
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
if (!screenPos) {
|
|
230
309
|
badgeEl.style.display = 'none'
|
|
231
310
|
return
|
|
232
311
|
}
|
|
233
312
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
badgeEl.style.display = 'block'
|
|
238
|
-
} else {
|
|
239
|
-
badgeEl.style.display = 'none'
|
|
240
|
-
}
|
|
313
|
+
badgeEl.style.left = `${screenPos.x}px`
|
|
314
|
+
badgeEl.style.top = `${screenPos.y}px`
|
|
315
|
+
badgeEl.style.display = 'block'
|
|
241
316
|
}
|
|
242
317
|
}
|
|
243
318
|
|
package/js/setPoint.js
CHANGED
|
@@ -230,6 +230,7 @@ export function setPoint(baseUrl) {
|
|
|
230
230
|
* @param options.height 高度(可选,默认0)
|
|
231
231
|
* @param options.heading 朝向(可选,默认0)
|
|
232
232
|
* @param options.isOffline 是否离线(true=离线,false=在线,默认 false)
|
|
233
|
+
* @param options.modelHeight 模型高度兜底值(米,可选,默认 1;未加载包围球时使用)
|
|
233
234
|
* @param options.mapId 地图ID
|
|
234
235
|
* @returns 创建的点位包装对象
|
|
235
236
|
*/
|
|
@@ -303,7 +304,9 @@ export function setPoint(baseUrl) {
|
|
|
303
304
|
glbPoint.infoBadge = createGlbInfoBadge({
|
|
304
305
|
map,
|
|
305
306
|
mapId,
|
|
307
|
+
entity: modelEntity,
|
|
306
308
|
isOffline,
|
|
309
|
+
labelOffset: Number(options.modelHeight) > 0 ? Number(options.modelHeight) : undefined,
|
|
307
310
|
getPosition: () => {
|
|
308
311
|
const posProp = modelEntity.position
|
|
309
312
|
if (posProp instanceof Cesium.Cartesian3) {
|