官方点聚合 · Official Point Cluster · ▶ 在线运行案例
- 案例合集: 三维可视化功能案例(threehub.cn)
- 开源仓库github地址: https://github.com/z2586300277/three-cesium-examples
- 400个案例代码: 网盘链接

你将学到什么
- CustomDataSource + Entity.point 管理点集
- dataSource.clustering 开箱聚合
- clusterEvent 自定义聚合 billboard 样式
- Canvas 缓存不同数量的簇图标
效果说明
随机 10000 个黄点分布全球;缩小时自动聚成带数字的圆形图标,数量越多圆越大。
核心概念
启用聚合
const dataSource = new Cesium.CustomDataSource('points');
viewer.dataSources.add(dataSource);
// 循环 entities.add({ position, point: { pixelSize, color } })
`const clustering = dataSource.clustering;
clustering.enabled = true;
clustering.pixelRange = 100; // 屏幕像素距离内合并
clustering.minimumClusterSize = 3; // 至少 3 点才聚合
`
clusterEvent 自定义样式
clustering.clusterEvent.addEventListener((clusteredEntities, cluster) => {
`cluster.label.show = false;
cluster.billboard.show = true;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
const count = clusteredEntities.length;
cluster.billboard.image = cache[count] || createClusterCanvas(size, count);
});
`
Cesium 自动维护簇 Entity;你只需改 cluster.billboard / cluster.label。
与 Supercluster 对比
| | 官方 clustering | Supercluster | |--|----------------|--------------| | 依赖 | 无 | 外部库 | | 数据层 | Entity | 自行转 Billboard | | 自定义 | clusterEvent | 完全自控 |
实现步骤
- CustomDataSource add 10000 随机 Entity
- 配置 clustering 三参数
- clusterEvent 里 Canvas 画圆 + 数字,cache 按 count 复用
- 隐藏默认 label,显示自定义 billboard
代码要点
import * as Cesium from 'cesium'
const DOM = document.getElementById('box')
const viewer = new Cesium.Viewer(DOM, {
animation: false, // 是否创建动画小器件,左下角仪表
baseLayerPicker: false, // 是否显示图层选择器,右上角图层选择按钮
baseLayer: Cesium.ImageryLayer.fromProviderAsync(Cesium.ArcGisMapServerImageryProvider.fromUrl('https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer')),
fullscreenButton: false, // 是否显示全屏按钮,右下角全屏选择按钮
timeline: false, // 是否显示时间轴
infoBox: false // 是否显示信息框
})
// 1. 隐藏Cesium Logo版权信息,保持界面简洁
// _cesiumWidget是Viewer的内部组件,_creditContainer是显示版权信息的DOM元素
viewer._cesiumWidget._creditContainer.style.display = "none"
// 2. 创建数据源并添加进 Viewer
// CustomDataSource是Cesium中用于管理自定义实体集合的数据源
// 与Cesium内置的数据源(如KML、GeoJSON等)不同,CustomDataSource允许完全自定义实体
// 'points'是这个数据源的唯一标识名称
const dataSource = new Cesium.CustomDataSource('points');
// 将自定义数据源添加到Viewer的数据源集合中
// 这样数据源中的实体就会在地球上显示出来
viewer.dataSources.add(dataSource);
// 3. 随机生成 10000 个点
// 创建大量随机分布的点用于演示聚合效果
// 实际项目中,这些点数据可能来自API调用、文件加载等方式
const randomPoints = 10000;
// 循环创建5000个随机点实体
for (let i = 0; i < randomPoints; i++) {
// 使用Cesium.Math.randomBetween方法在指定范围内生成随机数
// 经度范围:-180到180度(全球范围)
// 纬度范围:-60到60度(避免极地地区,因为投影变形较大)
const lon = Cesium.Math.randomBetween(-180, 180);
const lat = Cesium.Math.randomBetween(-50, 50);
// 向数据源中添加一个实体(Entity)
// Entity是Cesium中表示任何地理对象的基本单位
dataSource.entities.add({
// 设置实体的位置,使用经纬度转为笛卡尔坐标
// fromDegrees方法将经纬度(单位:度)转换为笛卡尔坐标(单位:米)
// 参数:经度、纬度、高度(这里设为0,即贴地)
position: Cesium.Cartesian3.fromDegrees(lon, lat, 0),
point: {
pixelSize: 15, // 点的像素大小
color: Cesium.Color.YELLOW, // 点的颜色
outlineColor: Cesium.Color.WHITE, // 点的边框颜色
outlineWidth: 3 // 点的边框宽度
},
});
}
// 4. 启用聚合
// 获取数据源的聚合功能对象,这是控制点聚合行为的核心接口
// 每个DataSource都有一个clustering属性,用于控制该数据源中实体的聚合行为
const clustering = dataSource.clustering;
// 启用聚合功能,设置为true后,当地图缩放到一定程度时,相近的点会自动聚合
clustering.enabled = true;
// 设置聚合像素范围(单位:像素)
// 当两个点在屏幕上的距离小于这个值时,它们会被聚合为一个点
// 值越大,聚合效果越明显,聚合的点会越多
clustering.pixelRange = 100;
// 设置最小聚合数量
// 当聚合区域内的点数量不少于这个值时才进行聚合
// 小于这个数量的点会保持独立显示,避免对少量点也进行不必要的聚合
clustering.minimumClusterSize = 3;
// 聚合图标缓存对象,用于存储已创建的聚合图标
// 以聚合点数量为键,图标为值
// 避免重复创建相同数量的聚合图标,提高性能
const cache = {};
// 5. 自定义聚合样式
// 监听聚合事件,当点被聚合时会触发此事件
// 这个事件在每次地图视角变化导致聚合状态改变时都会触发
// clusteredEntities: 被聚合到一起的实体数组
// cluster: 聚合后的对象,包含聚合点的位置、标签等信息
clustering.clusterEvent.addEventListener((clusteredEntities, cluster) => {
// 隐藏默认的标签显示(Cesium默认会显示聚合数量的标签)
// 我们将使用自定义的billboard来显示聚合点
cluster.label.show = false;
// 显示自定义的聚合图标(billboard)
cluster.billboard.show = true;
// 设置聚合点的垂直对齐方式为底部对齐
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
// 获取聚合点包含的实体数量,这个数量决定了聚合点的样式
const count = clusteredEntities.length;
// 从缓存中查找是否有对应数量的聚合图标
let img = cache[count];
// 如果缓存中没有对应数量的图标,则创建新的图标
if (!img) {
// 根据聚合点数量动态调整图标大小,数量越多图标越大
// Math.min确保图标不会过大,最大为100像素
// 30是基础大小,count/10是根据数量增加的大小
const size = Math.min(100, 30 + count / 10);
// 调用自定义函数创建聚合图标
img = createClusterCanvas(size, count);
// 将新创建的图标存入缓存,下次可以直接使用
cache[count] = img;
}
// 设置聚合点的图标为刚刚获取或创建的图标
cluster.billboard.image = img;
});
/**
* 工具函数:生成聚合图标
* 创建一个显示聚合数量的圆形图标
* * @param {Number} size - 图标尺寸(像素)
* @param {Number} count - 聚合点数量
* @returns {String} DataURL格式的图片字符串
*/
function createClusterCanvas(size, count) {
// 创建画布元素
const canvas = document.createElement('canvas');
// 设置画布的宽高都为size,创建正方形画布
canvas.width = canvas.height = size;
// 获取2D绘图上下文
const ctx = canvas.getContext('2d');
// 开始绘制路径
ctx.beginPath();
// 绘制聚合点背景圆
// 圆心位于画布中心(x,y,r,startAangle,endAngle),半径为画布尺寸的一半
ctx.arc(size / 2, size / 2, size / 2, 0, 2 * Math.PI);
// 设置填充颜色为红色半透明,rgba中最后一个参数0.8表示80%不透明度
ctx.fillStyle = 'rgba(255, 0, 0, 0.8)';
// 填充圆形区域
ctx.fill();
// 绘制边框
ctx.strokeStyle = '#fff'; // 白色边框
ctx.lineWidth = 2; // 边框线宽2像素
ctx.stroke(); // 绘制边框
// 绘制聚合数量文本
ctx.font = 'bold 14px Arial'; // 设置字体样式:粗体、14像素、Arial字体
ctx.fillStyle = '#fff'; // 设置文字颜色为白色
ctx.textAlign = 'center'; // 文字水平对齐方式:居中
ctx.textBaseline = 'middle'; // 文字垂直对齐方式:居中
// 在指定位置绘制文字
// 参数:文字内容、x坐标(这里在画布中心)、y坐标(这里在画布中心)
ctx.fillText(count, size / 2, size / 2);
`// 返回图片的DataURL
return canvas.toDataURL();
}
`
完整源码:GitHub
小结
- 本文提供 官方点聚合 完整 Cesium.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
- 更多 Cesium.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库