Appearance
PopupManager 弹窗管理器
PopupManager 在 Cesium 地理坐标上挂载 HTML 弹窗,并在 scene.postRender 后更新屏幕位置。它支持普通内容、自定义 HTMLElement、函数模板、宿主 Vue 组件,以及安全的结构化字段弹窗。
创建与销毁
typescript
import { CesiumViewer, PopupManager } from '@nexa/gis-cesium'
const nexaGis = new CesiumViewer('container')
const popupManager = new PopupManager(nexaGis.viewer)
// 离开页面时先清 PopupManager,再销毁 Viewer
popupManager.destroy()
nexaGis.destroy()destroy() 会移除全部 Popup DOM、postRender 监听和内部交互资源。创建 PopupManager 的组件或服务拥有它,不能只销毁 Viewer 而遗留 manager。
add(options)
typescript
const popup = popupManager.add({
position: { longitude: 116.397, latitude: 39.908, height: 100 },
title: '北京',
content: '监控中心',
anchor: 'top',
offset: { x: 0, y: -12 },
autoHide: true,
cameraHeightRange: { maximum: 8000 },
onClose: () => console.log('弹窗已关闭'),
})
popup.updatePosition()
popup.close()PopupOptions
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
position | Cartesian3 | { longitude, latitude, height? } | 必填 | 地理锚点 |
type | 'info' | 'confirm' | 'info' | 内置模板类型 |
title | string | '信息' | 内置标题 |
content | string | — | 内置正文;字符串模板由业务方负责内容可信性 |
template | string | HTMLElement | function | PopupVueComponent | — | 自定义内容模板 |
anchor | PopupAnchor | 'bottom' | top/bottom/left/right/center 及四角锚点 |
offset | { x: number; y: number } | { x: 0, y: 0 } | 屏幕像素偏移 |
autoHide | boolean | true | 锚点被地球遮挡或离开视口时自动隐藏 |
cameraHeightRange | { minimum?: number; maximum?: number } | — | 相机高度范围,单位米;超出时隐藏 |
className | string | — | 追加到弹窗根元素的 CSS 类 |
style | Partial<CSSStyleDeclaration> | — | 弹窗根元素内联样式 |
onClose | () => void | — | 点击关闭按钮时调用,随后移除弹窗 |
onConfirm | (data) => void | — | 内置确认弹窗的确认回调 |
PopupManager 自动生成唯一 ID。返回的 PopupInstance 提供 id、container、visible、options、updatePosition() 和 close()。
addFields(options)
接口数据、设备属性等键值内容应优先使用 addFields。字段名和值通过 DOM textContent 写入,不会当作 HTML 执行。
typescript
const popup = popupManager.addFields({
position: { longitude: 106.4569, latitude: 29.5049, height: 10 },
title: '监控信息',
fields: [
{ label: '监控名称', value: '北京西路与北京路交叉口' },
{ label: 'IP 地址', value: '42.23.33.23' },
{ label: '监控类型', value: '固定枪机' },
{ label: '监控状态', value: '在线' },
],
emptyText: '暂无',
anchor: 'top',
cameraHeightRange: { maximum: 4000 },
})FieldPopupOptions
FieldPopupOptions 继承除 type/content/template 外的 PopupOptions,并增加:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fields | readonly PopupField[] | 必填 | { label: string; value: unknown } 字段数组 |
emptyText | string | '—' | null 或 undefined 的显示文本 |
不要为了展示接口字段拼接 innerHTML。确需富文本时才使用 template: HTMLElement,并由业务方自行完成内容白名单或清洗。
管理实例
typescript
const first = popupManager.add({
position: { longitude: 116.4, latitude: 39.9 },
content: '第一个弹窗',
})
popupManager.get(first.id)
popupManager.remove(first.id)
popupManager.clear() // 移除全部实例
popupManager.closeAll() // 等价于 clear()与装备选择联动
Viewer 已内建实体选择流程,不需要再创建一套 ScreenSpaceEventHandler:
typescript
const removeSelectedListener = viewer.selectedEntityChanged.addEventListener(entity => {
currentPopup?.close()
const position = entity?.position?.getValue(viewer.clock.currentTime)
if (!position) return
currentPopup = popupManager.addFields({
position,
title: '装备信息',
fields: [{ label: '装备名称', value: entity.name }],
})
})
// cleanup
removeSelectedListener()
popupManager.destroy()装备本身应通过项目统一的 viewer.createEntity / EntityManager 接口创建。PopupManager 只读取公开 Entity 位置并管理弹窗,不负责创建或删除业务装备。
注意事项
- 数百个弹窗会增加 DOM 布局和每帧投影成本;短时交互弹窗应及时关闭。
autoHide判断地球遮挡;cameraHeightRange控制业务可见距离,两者可以同时使用。closeAll()当前等价于clear(),会移除实例和 DOM,不是仅隐藏。- 传入字符串
template会使用innerHTML,只适合可信静态模板;动态接口字段使用addFields()。 - 不访问
position._value、_cesiumWidget等 Cesium 私有字段。