仔细排查之后发现问题
- 可能是填充颜色透明度问题,透明度必须为非1值
- 可能是贴地设置的问题,必须不贴地,polygon必须设置height属性,注意PolygonHierarchy的position属性中携带的高度不生效
- label/billboard被遮挡问题无法通过设置解决(我没找到),可以通过直接在dom上模拟效果来实现具体代码如下
import { SceneTransforms, Viewer, Cartesian3, Cartesian2 } from 'cesium'
import DefMark from './template.vue'
import { createVNode, render } from 'vue'
interface MarkOption {
id?: string
position?: Cartesian3
show?: boolean
img?: any
name?: string
imgWidth?: number
imgHeight?: number
text?: string
background?: boolean // 图片是否作为文字的背景,文字在图片中居中展示
backgroundColor?: string // 是否给文字添加背景色
className?: string // 设置mark的类名
imgClassName?: string // 设置mark中图片的类名
textClassName?: string // 设置mark中文字的类名
template?: any // 标记模板
pointerEvents?: 'none' | 'all',
properties?: any
}
interface Mark {
dom: HTMLDivElement,
position: Cartesian3,
vNode: VNode,
show: boolean,
noNeedUpdate?: boolean,
properties: any
}
class UIMark {
viewer: Viewer
container: HTMLElement
marks: {[key: string]: Mark}
animationId: number
animations: Function[]
nameSpace: {[key: string]: string[]}
constructor( viewer: Viewer = window.viewer, container: string | HTMLElement ) {
this.viewer = viewer
this.marks = {}
this.nameSpace = {}
this.container = typeof container === 'string' ? document.querySelector('#'+container) : container
this.animations = []
this.startAnimation()
this.updatePositionAnimation()
}
private startAnimation() {
const _this = this
function animationFrame() {
_this.animations.forEach(fn => fn())
requestAnimationFrame(animationFrame)
}
this.animationId = requestAnimationFrame(animationFrame)
}
c3ToView (c3: Cartesian3) {
return SceneTransforms.worldToWindowCoordinates(this.viewer.scene, c3, new Cartesian2())
}
getViewerPosition(dom: HTMLDivElement,position:Cartesian3) {
const c2 = this.c3ToView(position)
if(!c2) return
dom.style.left = c2.x + 'px'
dom.style.top = c2.y + 'px'
}
setFrameAction(callback: Function) {
this.animations.push(callback)
}
removeFrameAction(callback: Function) {
this.animations = this.animations.filter(fn => fn !== callback)
}
updatePosition(id: string, position: Cartesian3) {
this.marks[id].position = position
}
updateProps(id: string, newProps:any) {
Object.keys(newProps).forEach((key:any) => {
this.marks[id].vNode.component.props[key] = newProps[key]
})
}
updatePositionAnimation() {
const _this = this
function animation() {
Object.values(_this.marks).forEach(item => {
if(!item.show || !item.position || item.noNeedUpdate) return
_this.getViewerPosition(item.dom, item.position)
})
}
this.setFrameAction(animation)
}
createMark(opt: MarkOption) {
// 获取容器
const dom = document.createElement('div')
const id = opt.id ?? `${+new Date()}`
dom.id = id
// 设置容器位置
dom.style.position = 'absolute'
// 暂时只能居中
dom.style.transform = 'translate(-50%, -50%)'
opt.show = opt.show === undefined ? true : opt.show ? true : false
dom.style.display = opt.show ? 'block' : 'none'
if(opt.pointerEvents !== 'all') dom.style.pointerEvents = 'none'
// 创建mark的vnode
const opt1 = reactive(Object.assign(opt))
delete opt1.template
const vn = createVNode(opt.template || DefMark, opt1)
render(vn, dom)
this.container.append(dom)
this.marks[id] = {dom, position:opt.position, vNode: vn, show: opt.show, properties: opt.properties}
if(opt.name) {
if (!this.nameSpace[opt.name]) this.nameSpace[opt.name] = []
this.nameSpace[opt.name].push(id)
}
return dom
}
clear() {
Object.keys(this.marks).forEach(key => this.remove(key))
}
destroy() {
cancelAnimationFrame(this.animationId)
this.clear()
this.nameSpace = {}
}
}