Skip to content

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

属性类型默认值说明
positionCartesian3 | { longitude, latitude, height? }必填地理锚点
type'info' | 'confirm''info'内置模板类型
titlestring'信息'内置标题
contentstring内置正文;字符串模板由业务方负责内容可信性
templatestring | HTMLElement | function | PopupVueComponent自定义内容模板
anchorPopupAnchor'bottom'top/bottom/left/right/center 及四角锚点
offset{ x: number; y: number }{ x: 0, y: 0 }屏幕像素偏移
autoHidebooleantrue锚点被地球遮挡或离开视口时自动隐藏
cameraHeightRange{ minimum?: number; maximum?: number }相机高度范围,单位米;超出时隐藏
classNamestring追加到弹窗根元素的 CSS 类
stylePartial<CSSStyleDeclaration>弹窗根元素内联样式
onClose() => void点击关闭按钮时调用,随后移除弹窗
onConfirm(data) => void内置确认弹窗的确认回调

PopupManager 自动生成唯一 ID。返回的 PopupInstance 提供 idcontainervisibleoptionsupdatePosition()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,并增加:

属性类型默认值说明
fieldsreadonly PopupField[]必填{ label: string; value: unknown } 字段数组
emptyTextstring'—'nullundefined 的显示文本

不要为了展示接口字段拼接 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 私有字段。