Skip to content

ClusterLayer 点聚合

点聚合层:对既有 DataSource 启用 Cesium 原生 EntityCluster,按像素范围把邻近的海量点位 自动聚合成计数徽标(默认 canvas 双层圆 + 计数文本,颜色随数量阈值变化),缩放时聚合/散开实时切换。


能力定位

ClusterLayer 适合:

  • 海量点位可视化:雷达/传感器目标、监控点、轨迹点在数据量大时的聚合显示;
  • 视距自适应:相机拉远自动合并邻近点位为计数徽标,拉近自动散开为原始点位;
  • 原生聚合力:基于 Cesium 公共 EntityCluster,不引入第三方聚合库。

与静态图标桶方案不同——源案例 PointObject/Cluser 预置 10+.png / 30+.png / 150+.png 等静态 图标按数量分档;本实现统一收敛为 createClusterIcon canvas 生成器(对齐 DynamicClusergetCluserImage),按数量取阈值色动态绘制,不依赖静态图标资产。

构造函数

ts
constructor(options: ClusterLayerOptions)
ts
interface ClusterLayerOptions {
  dataSource: DataSource                        // 必填:待聚合的数据源(须已加载点位实体)
  pixelRange?: number                            // 聚合像素范围,默认 30
  minimumClusterSize?: number                    // 最小聚合个数,默认 3
  clusterIcon?: (count: number) => string | HTMLCanvasElement // 聚合图标生成器,默认 createClusterIcon
  labelShow?: boolean                            // 是否显示聚合点 label,默认 false
}
参数类型默认值描述
dataSourceDataSource(必填)待聚合的数据源,调用方负责创建与 add/remove
pixelRangenumber30聚合像素范围(对齐源案例 Cluser
minimumClusterSizenumber3最小聚合个数(对齐源案例 Cluser
clusterIcon(count) => string | HTMLCanvasElementcreateClusterIcon聚合图标生成器,返回 URL/dataURI/canvas
labelShowbooleanfalse是否显示聚合点 label

生命周期

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

ts
on(viewer: Viewer): void      // 启用 dataSource.clustering + 注册 clusterEvent 监听
off(viewer: Viewer): void     // 移除监听器 + 还原 dataSource.clustering.enabled 原值
destroy(viewer: Viewer): void // 等价于 off

清理完整性on 保存 clustering.enabled 原值,off/destroy 还原,不强制关闭调用方 已手动开启的聚类;监听器在 off/destroy 时移除,clusterEvent 不再残留回调。

基础示例

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

// 1. 准备点位数据源(调用方负责 add/remove)
const dataSource = await Cesium.GeoJsonDataSource.load(pointsGeoJson)
viewer.dataSources.add(dataSource)

// 2. 挂载点聚合层
const cluster = new ClusterLayer({
  dataSource,
  pixelRange: 30,
  minimumClusterSize: 3,
})
cluster.on(viewer)

// 3. 页面或场景退出时统一销毁(幂等)
cluster.destroy(viewer)

进阶示例

自定义聚合图标生成器与 label 显示:

ts
import { ClusterLayer, createClusterIcon } from '@nexa/gis-cesium'

const cluster = new ClusterLayer({
  dataSource,
  pixelRange: 40,
  minimumClusterSize: 3,
  // 自定义阈值色带:≥200 深红 / ≥50 橙 / ≥1 绿
  clusterIcon: (count) =>
    createClusterIcon(count, {
      thresholds: [
        { value: 200, color: 'rgb(178, 34, 34)' },
        { value: 50, color: 'rgb(255, 165, 0)' },
        { value: 1, color: 'rgb(0, 200, 0)' },
      ],
    }),
  labelShow: true, // 聚合点同时显示 label
})
cluster.on(viewer)

聚合计数徽标

createClusterIcon(count, options?) 生成聚合徽标(canvas 双层圆 + 白色计数文本), 颜色按 ClusterIconOptions.thresholds 从大到小匹配首个 count >= threshold.value

  • 默认色带(对齐源案例 DynamicCluser):≥100 红 / ≥50 黄 / ≥10 蓝 / ≥1 绿
  • 未命中任何阈值时使用最末阈值色(如 count = 0 → 绿);
  • 图标边长默认按计数位数自适应(String(count).length * 12 + 50),亦可通过 size 固定;
  • 浏览器环境返回 HTMLCanvasElement(可直接赋给 billboard.image);非浏览器环境 (Node/测试)返回 1x1 透明占位 data URI,避免运行时异常。
ts
import { createClusterIcon, pickClusterColor } from '@nexa/gis-cesium'

createClusterIcon(120)          // 红色计数徽标 canvas
pickClusterColor(3)             // 'rgb(0, 255, 0)'(≥1)

实现说明

  • 原生聚合:仅使用 Cesium 公共 EntityCluster API (clustering.enabled / pixelRange / minimumClusterSize + clusterEvent),不触碰私有成员。
  • 聚合样式clusterEvent 回调把聚合点渲染为计数徽标—— billboard.show = truebillboard.verticalOrigin = VerticalOrigin.BOTTOMbillboard.image = createClusterIcon(count)label.showlabelShow 控制。
  • 类型约束:Cesium d.ts 将 Billboard.image 声明为 string(运行时实际接受 HTMLCanvasElement,见 Cesium.d.ts Billboard.image 的 JSDoc)。ClusterLayer 在 回调参数上以局部结构类型 ClusterStyle 放宽该字段,避免在回调内断言,保持严格类型检查。
  • 资源所有权:本层只拥有 clusterEvent 监听器与 clustering.enabled 还原责任, 不创建也不移除调用方提供的 dataSource(数据源归属调用方)。
  • 无外部依赖:源案例的 cluserPoint.json 为外部 URL(http://116.63.83.180:8088/...), 迁移时剥离,示例以内联 GeoJSON 演示,图标由 canvas 生成,不依赖静态图标资产。

清理责任

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

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

Cesium 版本限制

  • 依赖 Cesium 公共 EntityClusterdataSource.clustering)与 Event
  • Billboard.image 类型为 d.ts 已知缺口(string vs HTMLCanvasElement),运行时不受影响;
  • 已验证目标版本:Cesium 1.133.1。