Skip to content

HTML div 点标注(DivPointLayer)

在 Viewer 容器上叠加一个 DOM 覆盖层图层,把任意 HTML 内容(富卡片、状态面板、图表、 徽标)持续锚定到地理坐标:每帧随 scene.postRender 把世界坐标投影到屏幕像素刷新位置, 相机拉远到视高超过阈值后自动隐藏。适合大屏 / 监控台的高密度业务标注。


能力定位

DivPointLayer 适合:

  • 监测站点卡片:名称 + 实时数据面板(流量 / 液位 / 状态徽标)锚定到设备位置;
  • 大屏态势标注:复杂 DOM 标记(图表、状态徽标、富文本说明)跟随相机但不必绘制为 Cesium 几何体;
  • 批量管理:支持批量 addPoint、单点 remove、整层 removeAllhide/show 显隐。

与相关能力的分工:

能力形态差异
DivPointLayer任意 HTML 覆盖层标注图层通用、批量、每点任意 HTML,支持动态更新位置
AnimatePointEffect单点脉冲涟漪效果只有圆点扩散,无 HTML 内容
PopupManager点击弹窗事件驱动、单例弹窗,非图层化标注
BillboardGifEffect图标点 GIF 动效WebGL billboard 渲染,非 DOM

构造函数

ts
constructor(options?: DivPointLayerOptions)
ts
interface DivPointLayerOptions {
  hideHeight?: number // 相机视高超过该阈值(米)后隐藏全部标注点,默认 14000
}
参数类型默认值描述
hideHeightnumber14000视点高度(米)超过该值时隐藏全部标注点,拉近后自动恢复(对齐源案例行为)

生命周期

实现 Lifecycle<Viewer> 契约,on/off/destroy 均幂等:

ts
on(viewer: Viewer): void      // 创建图层容器 + 注册 scene.postRender 逐帧投影
off(viewer: Viewer): void     // 移除监听 + 图层容器 + 全部标注点(幂等,可再次 on)
destroy(viewer: Viewer): void // 等价于 off(幂等)

清理完整性:本类只拥有自身创建的图层容器 DOM、各标注点 DOM 与 scene.postRender 监听,off/destroy 一并移除,不触碰调用方其他资源。

基础示例

ts
import { DivPointLayer } from '@nexa/gis-cesium'

const layer = new DivPointLayer({ hideHeight: 14000 })
layer.on(viewer) // 挂载图层,开始逐帧投影

const marker = layer.addPoint({
  position: Cesium.Cartesian3.fromDegrees(116.274028, 30.978035, 944.63),
  content: '<div class="my-card">明山泉水</div>',
})

marker.element // 标注点根 DOM,可追加样式 / 事件
marker.position // 当前世界坐标的独立副本
marker.updatePosition(nextPosition) // 拖拽/数据更新后改变锚定位置
marker.remove() // 移除该标注点

layer.hide()  // 临时隐藏全部标注点(DOM 保留)
layer.show()  // 重新显示

// 页面或场景退出时统一清理(幂等)
layer.destroy(viewer)

进阶示例

批量添加富卡片标注,并演示内容函数的三种写法:

ts
const layer = new DivPointLayer()
layer.on(viewer)

// content 支持三种形式:字符串(innerHTML)/ HTMLElement / 函数(挂载时调用一次)
layer.addPoint({ position: p1, content: '<div>字符串内容</div>' })

const el = document.createElement('div')
el.textContent = 'DOM 元素内容'
layer.addPoint({ position: p2, content: el })

layer.addPoint({
  position: p3,
  content: () => `<div>函数内容,${new Date().toLocaleTimeString()}</div>`,
})

// 单点移除
const marker = layer.addPoint({ position: p4, content: '<div>待移除</div>' })
marker.remove()

// 整层清空
layer.removeAll()

动态位置与编辑

DivPointMarker.position 返回坐标副本,外部修改不会绕过图层状态。位置变更必须通过 updatePosition 提交,新位置会在下一次 postRender 投影中生效:

ts
const marker = layer.addPoint({ position, content: card })

dragHandler.onMove((screenPosition) => {
  const nextPosition = viewer.scene.pickPosition(screenPosition)
  if (nextPosition) marker.updatePosition(nextPosition)
})

// 已 remove 的 marker 不会因 updatePosition 重新挂载,重复调用安全
marker.remove()
marker.updatePosition(nextPosition)

绘制、选中、拖拽与 GeoJSON 持久化的完整组合用法见 HTML 标注绘制与编辑

实现说明

  • 投影 API:每帧通过公共 SceneTransforms.worldToWindowCoordinates(scene, position) 把 世界坐标投影到屏幕像素,刷新 leftbottombottom = canvasHeight - y)。源案例使用的 wgs84ToWindowCoordinates 在目标 Cesium 1.133 已移除,本实现已迁移。
  • 高度裁剪:通过 scene.globe.ellipsoid.cartesianToCartographic(camera.position).height 计算视点高度,超过 hideHeight(默认 14000 米)隐藏全部标注点,拉近后恢复(对齐源案例 PointObject/DivPointcamera.positionCartographic.height > 14000 行为)。
  • 投影不可见处理:投影返回 undefined(点位于相机后方等情形)时隐藏该标注点。
  • 指针穿透:图层容器 pointer-events: none 不遮挡 canvas 交互;标注点本身 pointer-events: auto 可接收鼠标事件。
  • 位置快照position 返回 Cartesian3 副本;updatePosition 同样克隆输入, 避免调用方之后就地修改对象导致图层状态无法追踪。
  • 源案例缺陷修复:源实现逐点注册 postRender 监听且 windowClose 只置空 DOM 不移除; 本实现改为单图层统一监听 + Lifecycle 幂等 on/off/destroy 完整清理。
  • 公共 API:仅使用 Cesium 公共 SceneTransforms.worldToWindowCoordinatesEllipsoid.cartesianToCartographicscene.postRender,不触碰私有字段。
  • 无外部依赖:源案例的 Vue 组件 / element-ui tooltip / 外网地形与底图等 demo 编排迁移时 剥离,标注内容以纯 HTML 字符串 / DOM 呈现,使用 SDK 默认底图与示例区域视角。

清理责任

ts
layer.destroy(viewer) // 或 layer.off(viewer),等价且幂等

重复调用 destroy/off 安全(未 on 时为空操作)。销毁后重新 on 可再次挂载。

Cesium 版本限制

  • 依赖 Cesium 公共 SceneTransforms.worldToWindowCoordinates / Ellipsoid.cartesianToCartographic / Scene.postRender
  • 已验证目标版本:Cesium 1.133.1。