需求:
需要在地图上渲染大量的点位,点位太密集了,看起来效果很差,所以需要把某一个相同范围内的点聚合起来显示一个数字,代表这个范围有多少个内容,当相机靠近的时候才把这些定位的详细绘制出来
实现思路:
cesium中已经实现了 EntityCluster 聚合类
enabled: 是否启用集群
pixelRange: 扩展屏幕空间边界框的像素范围。(这个值越大聚合的范围就会越大,显示到屏幕上的点就会越少)
minimumClusterSize:可聚类的屏幕空间对象的最小数量。
clusterBillboards: 是否对实体的广告牌进行聚类。
clusterLabels: 是否对实体的标签进行聚类。
clusterPoints: 是否对实体的点进行聚类。
show: 确定是否显示集群中的实体。
实现代码:
import * as Cesium from 'cesium';
import type { Viewer } from 'cesium';
export default class DrawService {
viewer: Viewer;
dataSource: any; // 聚合点的容器
removeListener: any;
constructor(viewer: Viewer) {
this.viewer = viewer;
this.dataSource = new Cesium.CustomDataSource('myData');
this.initClustering();
this.viewer.dataSources.add(this.dataSource);
}
// 有聚合功能的点用这个方法
drawclusteringPoint(positions: Cesium.Cartesian3, imgUrl: string, text?: string) {
const billboard = this.dataSource.entities.add({
position: positions,
billboard: {
image: imgUrl, // default: undefined
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
// pixelOffset: new Cesium.Cartesian2(0, -50), // default: (0, 0)
// eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), // default
// horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // default
// verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // default: CENTER
scale: 0.4, // default: 1.0
// color: Cesium.Color.LIME, // default: WHITE
// rotation: Cesium.Math.PI_OVER_FOUR, // default: 0.0
// alignedAxis: Cesium.Cartesian3.ZERO, // default
// width: 100, // default: undefined
// height: 25, // default: undefined
},
});
if (text) {
billboard.label = new Cesium.LabelGraphics({
text: text,
show: false,
font: '14px Helvetica',
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -20),
});
}
return billboard;
}
initClustering() {
const that = this;
const dataSourcePromise = this.viewer.dataSources.add(this.dataSource);
dataSourcePromise.then(function (dataSource) {
const pixelRange = 50; // 增加这个值可以使平面中聚合的访问更大,显示的点就会变少很多
const minimumClusterSize = 3;
const enabled = true;
dataSource.clustering.enabled = enabled; // 是否聚合
dataSource.clustering.pixelRange = pixelRange;
dataSource.clustering.minimumClusterSize = minimumClusterSize;
that.customStyle();
});
}
customStyle() {
const that = this;
const pinBuilder = new Cesium.PinBuilder();
const singleDigitPins = new Array(8);
for (let i = 0; i < singleDigitPins.length; ++i) {
singleDigitPins[i] = pinBuilder.fromText(`${i + 2}`, Cesium.Color.VIOLET, 48).toDataURL();
}
if (Cesium.defined(that.removeListener)) {
that.removeListener && that.removeListener();
that.removeListener = undefined;
} else {
that.removeListener = that.dataSource.clustering.clusterEvent.addEventListener(function (
clusteredEntities,
cluster
) {
cluster.label.show = false;
cluster.label.font = '14px Helvetica';
cluster.billboard.show = true;
cluster.billboard.id = cluster.label.id;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
if (clusteredEntities.length >= 100) {
cluster.billboard.image = './assets/img/cluster/100.png';
cluster.billboard.scale = 1.4;
} else if (clusteredEntities.length >= 50) {
cluster.billboard.image = './assets/img/cluster/50.png';
cluster.billboard.scale = 1.3;
} else if (clusteredEntities.length >= 20) {
cluster.billboard.image = './assets/img/cluster/20.png';
cluster.billboard.scale = 1.2;
} else if (clusteredEntities.length >= 10) {
cluster.billboard.image = './assets/img/cluster/10.png';
cluster.billboard.scale = 1.2;
} else if (clusteredEntities.length >= 3) {
cluster.billboard.image = './assets/img/cluster/3plus.png';
// cluster.billboard.image = combineIconAndLabel(
// './assets/img/cluster/1.png',
// clusteredEntities.length,
// 44
// );
// cluster.billboard.scale = 1.2;
// cluster.billboard.image = singleDigitPins[clusteredEntities.length - 2];
// cluster.billboard.scale = 0.8;
}
});
}
const { pixelRange } = that.dataSource.clustering;
that.dataSource.clustering.pixelRange = 0;
that.dataSource.clustering.pixelRange = pixelRange;
}
setSoucerceShowOrHide(isShow: boolean) {
this.dataSource.entities.values.forEach((entity) => {
entity.show = isShow;
});
}
// 根据某一类来控制显示和隐藏
setResourceShowOrHideByType(type: string, isShow: boolean) {
this.dataSource.entities.values.forEach((entity) => {
if (entity.workName === type) {
entity.show = isShow;
}
});
}
}