1、概述
通过cesium中dataSource自带的clustering来实现billboard数据的聚合显示效果,并根据数据类别设置显示不同的billboard图标。
2、数据处理
将后端返回的json数据处理成标准的geojson格式,如果后端返回的数据或者使用的测试数据已是geojson格式,请忽略此处。
javascript
//数据处理--后端返回数据转换成geojson数据
const data2Geojson = (data) => {
const geojson = {
"type": "FeatureCollection",
"features": []
}
data.forEach(item => {
geojson.features.push({
"type": "Feature",
"geometry": {
"type": "Point",
"icon": item.icon,
"coordinates": [parseFloat(item.longitude), parseFloat(item.latitude)]
},
"properties": {
...item
}
})
})
return geojson;
}
3、聚合实现
加载geojson数据,完成聚合效果的显示和清除操作。
ini
import pic from "@/assets/clusterIcon/facility.gif"; //默认billboard
import cluster1 from "@/assets/clusterIcon/cluster1.png";
import cluster2 from "@/assets/clusterIcon/cluster2.png";
import cluster3 from "@/assets/clusterIcon/cluster3.png";
//实现聚合效果
let dataSourceCollection = null;
let dataSourcePromise = null;
const setEntityCluster = async(data) => {
await removeEntityCluster(); //清除上一次绘制的聚合效果
let geojson = await data2Geojson(data); //数据转换为geojson格式
//读取geojson,并将数据源添加至DataSourceCollection
dataSourceCollection = new Cesium.DataSourceCollection();
dataSourcePromise = dataSourceCollection.add(Cesium.GeoJsonDataSource.load(geojson));
dataSourcePromise.then(dataSource =>{
// 加载geojson
viewer.dataSources.add(dataSource);
//命名用于后续删除
dataSource.name = 'entityClusterGeojson';
// 视角切换到geojson
viewer.flyTo(dataSource.entities.values);
//设置entity属性
dataSource.entities.values.forEach(entity => {
let properties = entity.properties;
let icon = pic;
if(properties.type._value == "1"){
icon = cluster1;
}else if(properties.type._value == "2"){
icon = cluster2;
}else{
icon = cluster3;
}
entity.uuid = properties.id._value;
entity.name = properties.name._value;
entity.billboard = {
image: icon,
width: 36,
height: 36,
};
entity.label = {
show: true,
text: properties.name._value || 'test',
font: 'bold 15px Microsoft YaHei',
verticalOrigin: Cesium.VerticalOrigin.CENTER,// 竖直对齐方式
horizontalOrigin: Cesium.HorizontalOrigin.LEFT, // 水平对齐方式
pixelOffset: new Cesium.Cartesian2(15, 0),// 偏移量
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,//贴地
disableDepthTestDistance: Number.POSITIVE_INFINITY,//一直显示,不被地形等遮挡
};
entity.type = properties.type._value;
})
//聚合参数设置
dataSource.clustering.enabled = true; //开启聚合功能
dataSource.clustering.pixelRange = 46; //聚合像素范围
dataSource.clustering.minimumClusterSize = 1; //最小聚合数量
let removeListener;
const customStyle = () => {
if (Cesium.defined(removeListener)) {
removeListener();
removeListener = undefined;
} else {
removeListener = dataSource.clustering.clusterEvent.addEventListener(
(clusteredEntities, cluster) => {
if (cluster.label.id.length == 0 || !cluster.label.id[0]) {
cluster.label.show = false;
cluster.billboard.show = false;
return;
}
//设置聚合后billboard样式,当有多个图标时,显示第一个图标和对应label
const img = cluster.label.id[0].billboard.image._value;
cluster.label.show = true;
cluster.label.text = cluster.label.id[0].label.text._value || "";
cluster.label.showBackground = true;
cluster.label.verticalOrigin = Cesium.VerticalOrigin.CENTER;
cluster.label.horizontalOrigin = Cesium.HorizontalOrigin.CENTER;
cluster.label.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
cluster.label.disableDepthTestDistance = Number.POSITIVE_INFINITY;
cluster.label.pixelOffset = new Cesium.Cartesian2(0, 10);
cluster.label.font = " bold 15px Microsoft YaHei";
cluster.label.backgroundColor = Cesium.Color.ORANGE.withAlpha(0.2);
cluster.billboard.show = true;
cluster.billboard.id = cluster.label.id;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
cluster.billboard.width = 36;
cluster.billboard.height = 36;
cluster.billboard.image = img;
cluster.entityType = "entityCluster";
cluster.billboard.horizontalOrigin = Cesium.HorizontalOrigin.CENTER;
cluster.billboard.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
cluster.billboard.disableDepthTestDistance = Number.POSITIVE_INFINITY;
}
)
}
const pixelRange = dataSource.clustering.pixelRange;
dataSource.clustering.pixelRange = 0;
dataSource.clustering.pixelRange = pixelRange;
}
//设置鼠标点击事件
let isFirst = true; //设置标识,避免重复执行点击事件
viewer.screenSpaceEventHandler.setInputAction((click) => {
const pickedObject = viewer.scene.pick(click.position);
if (pickedObject && pickedObject.id && pickedObject.id instanceof Array){
//获取点击数据对象
let obj = data.find((item) => item.id == pickedObject.id[0].uuid);
if(obj && isFirst){
isFirst = false;
//自定义后续操作逻辑...
setTimeout(() => {
isFirst = true;
}, 1000)
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
customStyle();//调用聚合监听事件
})
}
//清除聚合
const removeEntityCluster = () =>{
dataSourceCollection = dataSourceCollection && dataSourceCollection.destroy();
if(dataSourcePromise){
viewer.dataSources.remove(viewer.dataSources.getByName("entityClusterGeojson")[0])
}
},
4、实现效果
项目地址:github.com/DLFouge/vue...
欢迎指正与star