bxztApp/packages/screen/src/map/services/createEntityService.js
Zzc 105b3296af feat(map): 添加创建 billboard 实体的方法
在实体服务中添加一个新的异步方法 `addBillboard`,支持在地图中创建并添加广告牌实体。该方法支持可配置选项,包括位置、图像、尺寸、贴合度和像素偏移量,以增强地图可视化效果。
2025-11-13 17:55:40 +08:00

215 lines
7.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as Cesium from 'cesium'
import { uid, degToCartesian, degsToCartesians, toCesiumColor, DEFAULT_VECTOR_LAYER_ID } from '@/map/utils/utils'
// deps: { store, layerService }
export function createEntityService(deps) {
const { store, layerService } = deps
const svc = {
_ensureVectorLayer(layerId) {
const id = layerId || DEFAULT_VECTOR_LAYER_ID
if (!store.layers[id]) {
return layerService
.addLayer({ id, type: 'vector', source: null, options: { visible: true } })
.then(() => store.layers[id].obj)
}
return Promise.resolve(store.layers[id].obj)
},
async addPoint(opts) {
const o = opts || {}
const ds = await this._ensureVectorLayer(o.layerId)
const id = o.id || uid('point')
const ent = new Cesium.Entity({
id,
position: degToCartesian(o.position),
point: {
pixelSize: o.pixelSize || 8,
color: toCesiumColor(o.color || '#1E90FF', 1),
heightReference: o.clampToGround
? Cesium.HeightReference.CLAMP_TO_GROUND
: Cesium.HeightReference.NONE,
},
properties: o.properties || {},
})
ds.entities.add(ent)
return id
},
async addPolyline(opts) {
const o = opts || {}
const ds = await this._ensureVectorLayer(o.layerId)
const id = o.id || uid('line')
const ent = new Cesium.Entity({
id,
polyline: {
positions: degsToCartesians(o.positions || []),
width: o.width || 3,
material: toCesiumColor(o.color || '#FF4500', 1),
clampToGround: !!o.clampToGround,
},
properties: o.properties || {},
})
ds.entities.add(ent)
return id
},
async addPolygon(opts) {
const o = opts || {}
const ds = await this._ensureVectorLayer(o.layerId)
const id = o.id || uid('polygon')
const ent = new Cesium.Entity({
id,
polygon: {
hierarchy: new Cesium.PolygonHierarchy(degsToCartesians(o.positions || [])),
material: toCesiumColor(o.fillColor || 'rgba(0,191,255,0.2)'),
outline: true,
outlineColor: toCesiumColor(o.outlineColor || '#00BFFF', 1),
outlineWidth: o.outlineWidth || 1,
perPositionHeight: !(o.clampToGround === undefined ? true : o.clampToGround),
},
properties: o.properties || {},
})
ds.entities.add(ent)
return id
},
async addLabel(opts) {
const o = opts || {}
const ds = await this._ensureVectorLayer(o.layerId)
const id = o.id || uid('label')
const ent = new Cesium.Entity({
id,
position: degToCartesian(o.position),
label: {
text: o.text || '',
font: o.font || '14px sans-serif',
fillColor: toCesiumColor(o.fillColor || '#ffffff', 1),
outlineColor: toCesiumColor(o.outlineColor || '#000000', 1),
outlineWidth: o.outlineWidth || 2,
pixelOffset: o.pixelOffset || new Cesium.Cartesian2(0, -10),
},
properties: o.properties || {},
})
ds.entities.add(ent)
return id
},
/**
* 添加广告牌Billboard实体到地图
* @param {Object} opts - 配置选项
* @param {string} [opts.id] - 实体 ID不提供则自动生成
* @param {string} [opts.layerId] - 图层 ID不提供则使用默认图层
* @param {Array<number>} opts.position - 位置 [经度, 纬度] 或 [经度, 纬度, 高度],高度默认为 0
* @param {string} opts.image - 图片 URL 或路径
* @param {number} [opts.width=32] - 图片宽度(像素)
* @param {number} [opts.height=32] - 图片高度(像素)
* @param {boolean} [opts.clampToGround=true] - 是否贴地
* @param {Cesium.VerticalOrigin} [opts.verticalOrigin] - 垂直对齐方式
* @param {Array<number>|Cesium.Cartesian2} [opts.pixelOffset] - 像素偏移 [x, y]
* @param {number} [opts.disableDepthTestDistance] - 禁用深度测试的距离
* @param {Object} [opts.properties] - 自定义属性
* @returns {Promise<string>} 返回实体 ID
*/
async addBillboard(opts) {
const o = opts || {}
// 验证必需参数
if (!Array.isArray(o.position) || o.position.length < 2) {
throw new Error('addBillboard 需要提供 position 参数 [经度, 纬度] 或 [经度, 纬度, 高度]')
}
const image = o.image || o.icon
if (!image) {
throw new Error('addBillboard 需要提供 image 或 icon 参数')
}
// 确保 position 包含高度,如果没有则默认为 0
const position = o.position.length === 2
? [o.position[0], o.position[1], 0]
: o.position
const ds = await this._ensureVectorLayer(o.layerId)
const id = o.id || uid('billboard')
// 处理像素偏移
let pixelOffset
if (o.pixelOffset instanceof Cesium.Cartesian2) {
pixelOffset = o.pixelOffset
} else if (Array.isArray(o.pixelOffset)) {
pixelOffset = new Cesium.Cartesian2(
o.pixelOffset[0] || 0,
o.pixelOffset[1] || 0
)
} else if (o.pixelOffset && typeof o.pixelOffset === 'object') {
pixelOffset = new Cesium.Cartesian2(
o.pixelOffset.x || 0,
o.pixelOffset.y || 0
)
} else {
pixelOffset = new Cesium.Cartesian2(0, 0)
}
const ent = new Cesium.Entity({
id,
position: degToCartesian(position),
billboard: {
image,
width: o.width || 32,
height: o.height || 32,
verticalOrigin: o.verticalOrigin || Cesium.VerticalOrigin.BOTTOM,
heightReference:
o.clampToGround === false
? Cesium.HeightReference.NONE
: Cesium.HeightReference.CLAMP_TO_GROUND,
disableDepthTestDistance:
typeof o.disableDepthTestDistance === 'number'
? o.disableDepthTestDistance
: Number.POSITIVE_INFINITY,
pixelOffset,
},
properties: o.properties || {},
})
ds.entities.add(ent)
return id
},
removeEntity(entityId) {
if (!entityId) return false
for (const id in store.layers) {
const rec = store.layers[id]
if ((rec.type === 'vector' || rec.type === 'datasource') && rec.obj.entities) {
const e = rec.obj.entities.getById(entityId)
if (e) {
rec.obj.entities.remove(e)
return true
}
}
}
return false
},
getEntity(entityId) {
if (!entityId) return undefined
for (const id in store.layers) {
const rec = store.layers[id]
if ((rec.type === 'vector' || rec.type === 'datasource') && rec.obj.entities) {
const e = rec.obj.entities.getById(entityId)
if (e) return e
}
}
return undefined
},
clearLayerEntities(layerId) {
const id = layerId || DEFAULT_VECTOR_LAYER_ID
const rec = store.layers[id]
if (rec && rec.obj && rec.obj.entities) rec.obj.entities.removeAll()
},
}
return svc
}