一、遇到的问题
在三维开发中如果数据量过大时使用Entity会出现数据加载耗时较长、页面卡顿等情况,但是如果使用Primitive又没有聚合图的功能,在camera高度较高时点位密密麻麻观感比较差。
二、解决方案
1、实现Primitive聚合图
通过查找资料发现可以通过模拟EntityCluster这个类的实现方式,利用源码中的算法,改成Primitive的实现方式。
缺点:数据量太大的的时候,camera高度变化时还是会有卡顿的现象
2、热力图
可以设置在camera高于一定高度时显示热力图、高度较低时再显示Primitive
1)直接加载iServer热力图
缺点:会被三维挡住(或许可以使用S3MTilesLayer的coverImageryLayer 方法尝试一下)
2)通过heatmap.js加载
缺点:不能随高度变化进行点位变化,通过随高度修改radius参数的方式也不够美观。
3、设置广告牌scaleByDistance 参数
scaleByDistance 参数可以根据广告牌与相机的距离,获取或设置广告牌的远近缩放属性。
三、具体操作
1、Primitive聚合图
在Vue中可以通过以下方式来使用PrimitiveCluster
let cesiumLib = require("./PrimitiveCluster.js")
let PrimitiveCluster = cesiumLib.default;
// 创建广告牌集合
let billboardsCollectionCombine = Viewer.scene.primitives.add(
new Cesium.BillboardCollection({
scene: Viewer.scene,
})
);
// 交给聚合类进行处理
this.addPrimitiveClusterToScene(billboardsCollectionCombine);
//创建具有指定初始属性的广告牌并将其添加到集合中
for (let i = 0; i < features.length; i++) {
const feature = features[i];
// 带图片的点
billboardsCollectionCombine.add({
id: i,
name: "HwVideo",
image: "./static/img/extendApp/icon/camera-blue.png",
width: 32,
height: 32,
scale: 1,
show: true,
position: Cesium.Cartesian3.fromDegrees(feature.longitude, feature.latitude, 15),
});
}
addPrimitiveClusterToScene(data,isPrimitiveCollection = true){
formatClusterPoint(data,isPrimitiveCollection);
// 整理聚合数据
function formatClusterPoint(data,isPrimitiveCollection){
let scene = Viewer.scene;
let primitivecluster = new PrimitiveCluster();
let primitivesCollection = new Cesium.PrimitiveCollection();
//与entitycluster相同设置其是否聚合 以及最大最小值
primitivecluster.enabled = true;
primitivecluster.pixelRange = 60;
primitivecluster.minimumClusterSize = 2;
let billboardsCollectionCombine;
if(isPrimitiveCollection){
billboardsCollectionCombine = data;
}else{
billboardsCollectionCombine = scene.primitives.add(
new Cesium.BillboardCollection({
scene: scene,
})
);
//后面设置聚合的距离及聚合后的图标颜色显示与官方案例一样
for (let i = 0; i < data.length; i++) {
const feature = data[i];
const position = feature.position;
// 带图片的点
billboardsCollectionCombine.add({
image: "./static/img/extendApp/icon/facility.gif",
// width: 32,
// height: 32,
scale: 1,
position,
});
}
}
primitivecluster._billboardCollection = billboardsCollectionCombine;
// 同时在赋值时调用_initialize方法
primitivecluster._initialize(scene,500);
primitivesCollection.add(primitivecluster);
let primitives = Viewer.scene.primitives.add(primitivesCollection);
let pinBuilder = new Cesium.PinBuilder();
let pin10000 = pinBuilder.fromText('10000+', Cesium.Color.RED, 65).toDataURL();
let pin5000 = pinBuilder.fromText('5000+', Cesium.Color.ORANGE, 65).toDataURL();
let pin1000 = pinBuilder.fromText('1000+', Cesium.Color.YELLOW, 65).toDataURL();
primitivecluster.clusterEvent.addEventListener((clusteredEntities, cluster) => {
// 关闭自带的显示聚合数量的标签
cluster.label.show = false;
cluster.billboard.show = true;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
cluster.billboard._dirty = false;
if (clusteredEntities.length >= 10000) {
cluster.billboard.image = pin10000;
} else if (clusteredEntities.length >= 5000) {
cluster.billboard.image = pin5000;
} else if (clusteredEntities.length >= 1000) {
cluster.billboard.image = pin1000;
} else {
cluster.billboard.image = pinBuilder.fromText(clusteredEntities.length, Cesium.Color.VIOLET, 65).toDataURL()
}
}
);
return primitivecluster;
};
}