在实体服务中添加一个新的异步方法 `addBillboard`,支持在地图中创建并添加广告牌实体。该方法支持可配置选项,包括位置、图像、尺寸、贴合度和像素偏移量,以增强地图可视化效果。
215 lines
7.0 KiB
JavaScript
215 lines
7.0 KiB
JavaScript
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
|
||
}
|
||
|