Appearance
HTML 标注绘制与编辑
组合
DrawManager与DivPointLayer,完成 HTML 点标注的绘制、选中、拖拽编辑、 GeoJSON 导入导出和完整资源清理。
能力边界
HTML 标注不需要新的集合管理器。它由两个可组合的公共 API 完成:
| 能力 | 责任 |
|---|---|
DrawManager | 从 Cesium 场景中采集新标注的世界坐标 |
DivPointLayer | 管理 HTML DOM、逐帧屏幕投影、位置更新与图层生命周期 |
| 调用方 | 决定 HTML 模板、属性表单、选中规则和 GeoJSON 业务字段 |
PopupManager 面向短时交互弹窗,GeoJsonLayer 面向 Cesium DataSource 矢量数据, 都不代替持久 DOM 标注图层。
基础用法:点击地图创建标注
ts
import { CesiumViewer, DivPointLayer, DrawManager } from '@nexa/gis-cesium'
const nexaGis = new CesiumViewer('container')
const viewer = nexaGis.viewer
const layer = new DivPointLayer({ hideHeight: 8000 })
const drawManager = new DrawManager(viewer)
layer.on(viewer)
drawManager.onDrawComplete(({ entity, positions }) => {
// DrawManager 的结果点只用于采集坐标,调用方只移除这个自有 Entity
viewer.entities.remove(entity)
const card = document.createElement('div')
card.textContent = '新建标注'
layer.addPoint({ position: positions[0], content: card })
})
drawManager.startDraw('point')
// 页面或场景退出
drawManager.destroy()
layer.destroy(viewer)DrawManager 完成点绘制时会返回一个结果 Entity。若它只是 HTML 标注的坐标采集器, 应立即移除该 Entity,避免 DOM 标注底部遗留重复的 Cesium 点。
进阶用法:选中与拖拽
DivPointMarker.element 可以直接绑定 DOM 选中事件。拖拽时将指针屏幕坐标转为 Cesium 世界坐标,再调用 updatePosition:
ts
const marker = layer.addPoint({ position, content: card })
marker.element.addEventListener('pointerdown', () => {
// 拖拽开始时先保存原始相机控制状态,再临时禁用旋转/平移
})
window.addEventListener('pointermove', (event) => {
const rect = viewer.scene.canvas.getBoundingClientRect()
const screen = new Cesium.Cartesian2(event.clientX - rect.left, event.clientY - rect.top)
const next = viewer.scene.pickPositionSupported
? viewer.scene.pickPosition(screen)
: viewer.camera.pickEllipsoid(screen, viewer.scene.globe.ellipsoid)
if (next) marker.updatePosition(next)
})拖拽结束、取消或页面销毁时,必须同时:
- 移除
window的pointermove/pointerup/pointercancel监听; - 恢复拖拽前的
enableRotate/enableTranslate/enableTilt值; - 恢复页面 cursor;
- 不得使用
viewer._element等 Cesium 私有字段。
GeoJSON 导入导出
DOM 模板是调用方 UI,不应直接写入 GeoJSON。持久化时仅保存稳定的点几何与业务属性:
ts
const cartographic = Cesium.Cartographic.fromCartesian(marker.position)
const feature = {
type: 'Feature',
properties: {
id: 'station-a',
plotType: 'gradient',
label: '通信中继站',
},
geometry: {
type: 'Point',
coordinates: [
Cesium.Math.toDegrees(cartographic.longitude),
Cesium.Math.toDegrees(cartographic.latitude),
cartographic.height,
],
},
}导入时应验证 FeatureCollection、Point 和有限数值坐标。浏览器下载通过 URL.createObjectURL 创建地址后,需调用 URL.revokeObjectURL 释放。
资源所有权与清理
| 资源 | 创建者 | 清理方式 |
|---|---|---|
| 绘制事件处理器、Tooltip、临时 Entity | DrawManager | drawManager.destroy() |
图层 DOM、标注 DOM、postRender 监听 | DivPointLayer | layer.destroy(viewer) |
| 面板、样式、window pointer 监听 | 调用方 | 页面 cleanup 中显式移除 |
| GeoJSON Blob URL | 调用方 | 下载触发后 URL.revokeObjectURL() |
不要在清理时调用 viewer.entities.removeAll() 或 imageryLayers.removeAll();这会误删其他模块拥有的资源。
迁移说明
- 源案例使用 React 内部
_reactInternals、Cesiumviewer._element和 jQuery document 事件, 目标实现全部改为 DOM 和 Cesium 公共 API。 - 源案例逐标注注册
postRender;DivPointLayer改为整层单监听批量投影。 - 源案例的 HTTP 3D Tiles、高德底图和业务 GeoJSON 仅是演示背景/数据,不属于 HTML 标注能力,本案例使用默认地球与内联中性数据。
- 依赖 Cesium 1.133.1 公共
SceneTransforms.worldToWindowCoordinates、pickPosition、camera.pickEllipsoid与scene.postRender。