詳解cesium實(shí)現(xiàn)大批量POI點(diǎn)位聚合渲染優(yōu)化方案
前言
cesium目前只提供了entityCluster這個(gè)聚合類,使打點(diǎn)聚合更方便快捷的實(shí)現(xiàn),但是一般在真正做項(xiàng)目的時(shí)候,大家會(huì)經(jīng)常碰到成千上萬(wàn)個(gè)甚至幾十萬(wàn)個(gè)點(diǎn)位需要聚合打點(diǎn),那這時(shí)候你如果還是用entity去實(shí)現(xiàn)的話,怕是要被用戶按在地上瘋狂摩擦,摩擦。。。??
思考
我們可以通過(guò)模擬entityCluster這個(gè)類的實(shí)現(xiàn)方式,利用源碼中的算法,改成primitive的實(shí)現(xiàn)方式;
開(kāi)發(fā)
拉下cesium的源碼,搜EntityCluster關(guān)鍵字,我們可以找到EntityCluster.js這個(gè)文件,那么這個(gè)代碼就是實(shí)現(xiàn)聚合的核心邏輯,接下來(lái)我們可以復(fù)制一份出來(lái),將EntityCluster全部改為PrimitiveCluster,接著getScreenSpacePositions這個(gè)方法里將entity的邏輯刪除,否則會(huì)因?yàn)閕tem.id為entity對(duì)象為空導(dǎo)致報(bào)錯(cuò)
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, }); } }
好了,源碼大體就是改這么多了,接下來(lái)就是怎么用;
使用
import PrimitiveCluster from "@/utils/cesiumCtrl/primitiveCluster"; // 初始化標(biāo)簽實(shí)例 const billboardsCollectionCombine = new Cesium.BillboardCollection(); // 初始化實(shí)體 const primitives = viewer.scene.primitives.add( new Cesium.PrimitiveCollection() ); getGeojson("/json/schools.geojson").then(({ res }) => { // 先獲取點(diǎn)位數(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] ); // 帶圖片的點(diǎn) 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ù)添加到實(shí)體中 primitives.add(primitivecluster); // 監(jiān)聽(tīng)相機(jī)縮放 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è)置不同層級(jí)的圖片以及大小 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:畫(huà)布大小 * @return {*} 返回canvas */ function combineIconAndLabel(url, label, size) { // 創(chuàng)建畫(huà)布對(duì)象 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,以上就是完整的使用方法,主要是如何使用,不然會(huì)造成canvas相關(guān)方面的報(bào)錯(cuò)等等;
詳細(xì)源碼細(xì)節(jié)可以查看:github.com/tingyuxuan2… ,此開(kāi)源項(xiàng)目集合了目前常用的一些三維動(dòng)畫(huà)場(chǎng)景,還在不斷更新中;
以上就是詳解cesium實(shí)現(xiàn)大批量POI點(diǎn)位聚合渲染優(yōu)化方案的詳細(xì)內(nèi)容,更多關(guān)于cesium大批量POI點(diǎn)位聚合渲染的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解ES6之a(chǎn)sync+await 同步/異步方案
這篇文章主要介紹了詳解ES6之a(chǎn)sync+await 同步/異步方案,本文以最簡(jiǎn)明的方式來(lái)疏通 async + await,有興趣的可以了解下2017-09-09BOM系列第三篇之定時(shí)器應(yīng)用(時(shí)鐘、倒計(jì)時(shí)、秒表和鬧鐘)
這篇文章主要介紹了BOM系列第三篇之定時(shí)器應(yīng)用(時(shí)鐘、倒計(jì)時(shí)、秒表和鬧鐘) 的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08可以拖動(dòng)的div 實(shí)現(xiàn)代碼
可以拖動(dòng)的div是一個(gè)比較難以做到的效果,特別是在瀏覽器對(duì)于js代碼的運(yùn)行效率還不是足夠高的情況下,不過(guò)聽(tīng)說(shuō)firefox對(duì)于js的支持正在增加,大概是料到了js在網(wǎng)頁(yè)瀏覽的桌面化趨勢(shì)中所占的重要地位吧。2009-06-06el-input 標(biāo)簽中密碼的顯示和隱藏功能的實(shí)例代碼
本文通過(guò)實(shí)例代碼給大家介紹了el-input 標(biāo)簽中密碼的顯示和隱藏 ,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07JS焦點(diǎn)圖,JS 多個(gè)頁(yè)面放多個(gè)焦點(diǎn)圖的實(shí)例
下面小編就為大家?guī)?lái)一篇JS焦點(diǎn)圖,JS 多個(gè)頁(yè)面放多個(gè)焦點(diǎn)圖的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12微信小程序?qū)崿F(xiàn)獲取自己所處位置的經(jīng)緯度坐標(biāo)功能示例
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)獲取自己所處位置的經(jīng)緯度坐標(biāo)功能,涉及微信小程序地圖功能獲取經(jīng)緯度信息的相關(guān)操作技巧,需要的朋友可以參考下2017-11-11微信小程序云開(kāi)發(fā) 搭建一個(gè)管理小程序
這篇文章主要為大家詳細(xì)介紹了微信小程序云開(kāi)發(fā),搭建一個(gè)管理小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05