详解cesium实现大批量POI点位聚合渲染优化方案
作者:不浪brown
这篇文章主要为大家介绍了cesium实现大批量POI点位聚合渲染优化方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
前言
cesium目前只提供了entityCluster这个聚合类,使打点聚合更方便快捷的实现,但是一般在真正做项目的时候,大家会经常碰到成千上万个甚至几十万个点位需要聚合打点,那这时候你如果还是用entity去实现的话,怕是要被用户按在地上疯狂摩擦,摩擦。。。😅
思考
我们可以通过模拟entityCluster这个类的实现方式,利用源码中的算法,改成primitive的实现方式;
开发
拉下cesium的源码,搜EntityCluster关键字,我们可以找到EntityCluster.js这个文件,那么这个代码就是实现聚合的核心逻辑,接下来我们可以复制一份出来,将EntityCluster全部改为PrimitiveCluster,接着getScreenSpacePositions这个方法里将entity的逻辑删除,否则会因为item.id为entity对象为空导致报错
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"; // 初始化标签实例 const billboardsCollectionCombine = new Cesium.BillboardCollection(); // 初始化实体 const primitives = viewer.scene.primitives.add( new Cesium.PrimitiveCollection() ); getGeojson("/json/schools.geojson").then(({ res }) => { // 先获取点位数据 console.log(res); const { features } = res; formatClusterPoint(features); }); // 整理聚合数据 const formatClusterPoint = (features) => { var scene = viewer.scene; var primitivecluster = new PrimitiveCluster(); //与entitycluster相同设置其是否聚合 以及最大最小值 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, }); } // 将数据传给primitivecluster的标签属性 primitivecluster._billboardCollection = billboardsCollectionCombine; // 初始化 primitivecluster._initialize(scene); // 将标签数据添加到实体中 primitives.add(primitivecluster); // 监听相机缩放 primitivecluster.clusterEvent.addEventListener( (clusteredEntities, cluster) => { // 关闭自带的显示聚合数量的标签 cluster.label.show = false; cluster.billboard.show = true; cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; // 根据聚合数量的多少设置不同层级的图片以及大小 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: 将图片和文字合成新图标使用(参考Cesium源码) * @param {*} url:图片地址 * @param {*} label:文字 * @param {*} size:画布大小 * @return {*} 返回canvas */ function 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, 0, 0); } catch (e) { console.log(e); } // 渲染字体 // font属性设置顺序: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相关方面的报错等等;
详细源码细节可以查看:github.com/tingyuxuan2… ,此开源项目集合了目前常用的一些三维动画场景,还在不断更新中;
以上就是详解cesium实现大批量POI点位聚合渲染优化方案的详细内容,更多关于cesium大批量POI点位聚合渲染的资料请关注脚本之家其它相关文章!