前言
cesium目前只提供了entityCluster這個聚合類,使打點聚合更方便快捷的實現(xiàn),但是一般在真正做項目的時候,大家會經(jīng)常碰到成千上萬個甚至幾十萬個點位需要聚合打點,那這時候你如果還是用entity去實現(xiàn)的話,怕是要被用戶按在地上瘋狂摩擦,摩擦。。。??
思考
我們可以通過模擬entityCluster這個類的實現(xiàn)方式,利用源碼中的算法,改成primitive的實現(xiàn)方式;
開發(fā)
拉下cesium的源碼,搜EntityCluster關(guān)鍵字,我們可以找到EntityCluster.js這個文件,那么這個代碼就是實現(xiàn)聚合的核心邏輯,接下來我們可以復(fù)制一份出來,將EntityCluster全部改為PrimitiveCluster,接著getScreenSpacePositions這個方法里將entity的邏輯刪除,否則會因為item.id為entity對象為空導(dǎo)致報錯
function getScreenSpacePositions(
collection,
points,
scene,
occluder,
entityCluster
) {
if (!defined(collection)) {
return;
}
const length = collection.length;
for (let i = 0; i < length; ++i) {
const item = collection.get(i);
item.clusterShow = false;
if (
!item.show ||
(entityCluster._scene.mode === SceneMode.SCENE3D &&
!occluder.isPointVisible(item.position))
) {
continue;
}
// const canClusterLabels =
// entityCluster._clusterLabels && defined(item._labelCollection);
// const canClusterBillboards =
// entityCluster._clusterBillboards && defined(item.id._billboard);
// const canClusterPoints =
// entityCluster._clusterPoints && defined(item.id._point);
// if (canClusterLabels && (canClusterPoints || canClusterBillboards)) {
// continue;
// }
const coord = item.computeScreenSpacePosition(scene);
if (!defined(coord)) {
continue;
}
points.push({
index: i,
collection: collection,
clustered: false,
coord: coord,
});
}
}
好了,源碼大體就是改這么多了,接下來就是怎么用;
使用
import PrimitiveCluster from "@/utils/cesiumCtrl/primitiveCluster";
// 初始化標(biāo)簽實例
const billboardsCollectionCombine = new Cesium.BillboardCollection();
// 初始化實體
const primitives = viewer.scene.primitives.add(
new Cesium.PrimitiveCollection()
);
getGeojson("/json/schools.geojson").then(({ res }) => {
// 先獲取點位數(shù)據(jù)
console.log(res);
const { features } = res;
formatClusterPoint(features);
});
// 整理聚合數(shù)據(jù)
const formatClusterPoint = (features) => {
var scene = viewer.scene;
var primitivecluster = new PrimitiveCluster();
//與entitycluster相同設(shè)置其是否聚合 以及最大最小值
primitivecluster.enabled = true;
primitivecluster.pixelRange = 60;
primitivecluster.minimumClusterSize = 2;
// primitivecluster._pointCollection = pointCollection;
// primitivecluster._labelCollection = labelCollection;
for (let i = 0; i < features.length; i++) {
const feature = features[i];
const coordinates = feature.geometry.coordinates;
const position = Cesium.Cartesian3.fromDegrees(
coordinates[0],
coordinates[1]
);
// 帶圖片的點
billboardsCollectionCombine.add({
image: "/images/mark-icon.png",
width: 32,
height: 32,
position,
});
}
// 將數(shù)據(jù)傳給primitivecluster的標(biāo)簽屬性
primitivecluster._billboardCollection = billboardsCollectionCombine;
// 初始化
primitivecluster._initialize(scene);
// 將標(biāo)簽數(shù)據(jù)添加到實體中
primitives.add(primitivecluster);
// 監(jiān)聽相機縮放
primitivecluster.clusterEvent.addEventListener(
(clusteredEntities, cluster) => {
// 關(guān)閉自帶的顯示聚合數(shù)量的標(biāo)簽
cluster.label.show = false;
cluster.billboard.show = true;
cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
// 根據(jù)聚合數(shù)量的多少設(shè)置不同層級的圖片以及大小
cluster.billboard.image = combineIconAndLabel(
"/images/school-icon.png",
clusteredEntities.length,
64
);
// cluster.billboard.image = "/images/school-icon.png";
cluster.billboard._imageHeight = 60;
cluster.billboard._imageWidth = 60;
cluster.billboard._dirty = false;
cluster.billboard.width = 40;
cluster.billboard.height = 40;
}
);
return primitivecluster;
};
/**
* @description: 將圖片和文字合成新圖標(biāo)使用(參考Cesium源碼)
* @param {*} url:圖片地址
* @param {*} label:文字
* @param {*} size:畫布大小
* @return {*} 返回canvas
*/
function combineIconAndLabel(url, label, size) {
// 創(chuàng)建畫布對象
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, 0, 0);
} catch (e) {
console.log(e);
}
// 渲染字體
// font屬性設(shè)置順序:font-style, font-variant, font-weight, font-size, line-height, font-family
ctx.fillStyle = Cesium.Color.BLACK.toCssColorString();
ctx.font = "bold 20px Microsoft YaHei";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(label, size / 2, size / 2);
return canvas;
});
return promise;
}
ok,以上就是完整的使用方法,主要是如何使用,不然會造成canvas相關(guān)方面的報錯等等;文章來源:http://www.zghlxwxcb.cn/news/detail-706003.html
開源
詳細源碼細節(jié)可以查看:鏈接: primitive實現(xiàn)聚合源碼 ,此開源項目集合了目前常用的一些三維動畫場景,還在不斷更新中;文章來源地址http://www.zghlxwxcb.cn/news/detail-706003.html
到了這里,關(guān)于cesium實現(xiàn)大批量POI點位聚合渲染優(yōu)化方案的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!