点聚合
在Cesium相关项目开发过程中,当加载大量的点位后对底图有遮挡,需要使用点聚合功能,因此在聚合时需要动态更新聚合图标上被聚合的点位的数量。
实现效果
效果不是太理想,我用来测试的POI数据密度太大了。
QQ录屏20220506161341
https://blog.csdn.net/weixin_45782925/article/details/123054390
实现代码
最开始图片显示不完全修改combineIconAndLabel(url, label, size)中传入size的大小总算是显示出来了,也可能是自定义的图片有问题。参考文章在上面,记录一下。
<template>
<div class="point-gather">
<Map />
<div class="gather">
<div class="gather-con">
<div class="box">
<div class="txt">POI 点的聚合</div>
</div>
</div>
</div>
</div>
</template>
<script>
import Map from "@/components/cesiumCommon/DTGlobeDark.vue";
import { DTGlobe } from "@/components/cesiumCommon/globe";
export default {
components: { Map },
data() {
return {};
},
mounted() {
this.Initial();
},
methods: {
Initial() {
let viewer = DTGlobe.viewer;
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(
114.32536,
30.569676,
5000.0
),
});
this.initCluster(viewer);
//开启深度检测
viewer.scene.globe.depthTestAgainstTerrain = true;
},
initCluster(viewer) {
let that = this;
new Cesium.GeoJsonDataSource.load("./data/人口岗位_质心.geojson").then(
(dataSource) => {
viewer.dataSources.add(dataSource);
// 设置聚合参数
dataSource.clustering.enabled = true;
dataSource.clustering.pixelRange = 30;
dataSource.clustering.minimumClusterSize = 2;
// foreach用于调用数组的每个元素,并将元素传递给回调函数。
dataSource.entities.values.forEach((entity) => {
// 将点拉伸一定高度,防止被地形压盖
entity.position._value.z += 50.0;
// 使用大小为64*64的icon,缩小展示poi
entity.billboard = {
image: require("@/assets/imgs/point/报亭.png"),
width: 32,
height: 32,
};
// entity.label = {
// // text: "POI",
// font: "bold 15px Microsoft YaHei",
// // 竖直对齐方式
// verticalOrigin: Cesium.VerticalOrigin.CENTER,
// // 水平对齐方式
// horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
// // 偏移量
// pixelOffset: new Cesium.Cartesian2(15, 0),
// };
});
// 添加监听函数
dataSource.clustering.clusterEvent.addEventListener(function (
clusteredEntities,
cluster
) {
// 关闭自带的显示聚合数量的标签
cluster.label.show = false;
cluster.billboard.show = true;
cluster.billboard.id = cluster.label.id;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
// console.log("-----", cluster);
// 根据聚合数量的多少设置不同层级的图片以及大小
if (clusteredEntities.length >= 50) {
cluster.billboard.image = that.combineIconAndLabel(
require("@/assets/imgs/point/circ1.png"),
clusteredEntities.length,
192
);
cluster.billboard.width = 72;
cluster.billboard.height = 72;
} else if (clusteredEntities.length >= 40) {
cluster.billboard.image = that.combineIconAndLabel(
require("@/assets/imgs/point/circ2.png"),
clusteredEntities.length,
192
);
cluster.billboard.width = 56;
cluster.billboard.height = 56;
} else if (clusteredEntities.length >= 20) {
cluster.billboard.image = that.combineIconAndLabel(
require("@/assets/imgs/point/circ3.png"),
clusteredEntities.length,
192
);
cluster.billboard.width = 48;
cluster.billboard.height = 48;
} else {
cluster.billboard.image = that.combineIconAndLabel(
require("@/assets/imgs/point/circ4.png"),
clusteredEntities.length,
192
);
cluster.billboard.width = 40;
cluster.billboard.height = 40;
}
});
}
);
},
/**
* @description: 将图片和文字合成新图标使用
* @param {*} url:图片地址
* @param {*} label:文字
* @param {*} size:画布大小
* @return {*} 返回canvas
*/
combineIconAndLabel(url, label, size) {
// 创建画布对象
let canvas = document.createElement("canvas");
canvas.width = size;
canvas.height = size;
let ctx = canvas.getContext("2d");
let promise = new Cesium.Resource.fetchImage(url).then((image) => {
// 异常判断
try {
ctx.drawImage(image, -5, -5);
} catch (e) {
console.log(e);
}
// console.log("-----", ctx);
// 渲染字体
ctx.fillStyle = Cesium.Color.WHITE.toCssColorString();
ctx.font = "bold 50px Microsoft YaHei";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(label, size / 2, size / 2);
return canvas;
});
return promise;
},
},
};
</script>
<style lang="scss" scoped>
.point-gather {
width: 100%;
height: 100%;
.gather {
position: absolute;
z-index: 99;
&-con {
padding: 5px;
.box {
border-radius: 6px;
background: #304156b3;
.txt {
padding: 10px;
}
}
}
}
}
</style>