关于VUE项目地图开发中大量点标记绘制一些总结
問題說明
在地圖開發(fā)中,當(dāng)?shù)貓D中繪制大量的標(biāo)記點(diǎn)后,無論是拖動(dòng)或者縮放,都會(huì)感覺到明顯的卡頓現(xiàn)象。(一般超過800個(gè)點(diǎn)后就比較明顯了).在平時(shí)的工作業(yè)務(wù)中,由于公司的實(shí)時(shí)監(jiān)控頁面需要展現(xiàn)5000-20000車輛的實(shí)時(shí)定位跟蹤,特別是切換到車輛密集的港口碼頭卡頓現(xiàn)象非常嚴(yán)重(如下圖),看起來非常難看,用戶體驗(yàn)也非常差。在此寫下一些開發(fā)優(yōu)化中的心得體會(huì)(本文中使用的是高德地圖為參考)。
解決思路
首先我們應(yīng)該將地圖上的所有覆蓋物(包括Marker,Icon,Text,Polygon)分組添加到多個(gè)OverlayGroup中對(duì)每一類統(tǒng)一管理。部分覆蓋物默認(rèn)隱藏,需要時(shí)才展現(xiàn)。
不要將大量的覆蓋物信息都直接掛載在地圖對(duì)象上,可以按需加載,減少地圖在移動(dòng)后重新渲染的工作量
合理的使用覆蓋物聚合(聚合雖然會(huì)減少卡頓,但是覆蓋物數(shù)量太多依舊會(huì)比較卡)
解決方法
首先,添加一個(gè)地圖設(shè)置勾選面板,將除車輛點(diǎn)標(biāo)記以外的所有覆蓋物按類型分類,添加到一個(gè)個(gè)單獨(dú)的OverlayGroup中默認(rèn)不掛載在地圖上,在勾選時(shí)才調(diào)用OverlayGroup.setMap(map)方法添加到地圖上。去掉了這些不必要覆蓋物,首次進(jìn)入時(shí)立馬清爽了許多。
盡管去掉了各類網(wǎng)點(diǎn),文字,等覆蓋物,但是我們需要渲染的車輛標(biāo)記點(diǎn)依舊是非常多的。在此基礎(chǔ)上,我們采用按屏幕加載,篩選出屏幕內(nèi)的點(diǎn),屏幕外的標(biāo)記點(diǎn)不渲染,監(jiān)控每次地圖的moveend,zoomend,resize,每次的改變后重新計(jì)算屏幕內(nèi)的標(biāo)記點(diǎn),當(dāng)屏幕內(nèi)標(biāo)記點(diǎn)較少,比如200以下(這個(gè)隨個(gè)人需要定),直接繪制在地圖上。當(dāng)屏幕內(nèi)標(biāo)記點(diǎn)比較多,大于200,調(diào)用聚合方法,將標(biāo)記點(diǎn)聚合后繪制在地圖上。
參考代碼
/**監(jiān)聽地圖拖拽,放大事件,根據(jù)屏幕范圍動(dòng)態(tài)渲染點(diǎn)位 */reloadMarks(){AMap.event.addListener(this.map,'moveend',()=> {this.computeMarkers();})AMap.event.addListener(this.map,'zoomend',()=> {this.computeMarkers();})AMap.event.addListener(this.map,'resize',()=> {this.computeMarkers();})},/** 根據(jù)當(dāng)前屏幕范圍帥選marker */computeMarkers(){this.newViewData={};//獲取當(dāng)前視圖范圍let now_bounds = this.map.getBounds();//遍歷車輛數(shù)據(jù),為了減少后臺(tái)傳入的重復(fù)數(shù)據(jù),我的車輛信息列表一直使用對(duì)象保存for(let sel_deviceNo in this.carDataObj0){let item=this.carDataObj0[sel_deviceNo];//判斷當(dāng)前點(diǎn)的坐標(biāo)是否存在于視圖內(nèi)if(now_bounds.contains(item.gcj02_coords.split(','))){//將當(dāng)前屏幕內(nèi)的視圖點(diǎn)保存this.newViewData[sel_deviceNo] = item;}}this.renderMarker();now_bounds=null;},/** 創(chuàng)建聚合**/createCluser(markerArr) {AMap.plugin(['AMap.MarkerClusterer'], () => {this.cluster = new AMap.MarkerClusterer(this.map, markerArr, {gridSize: 80,renderCluserMarker,minClusterSize: 1,maxZoom: 18});})},/** 將markers渲染到map上 */renderMarker(){//判斷目前是否有當(dāng)前覆蓋物組!this.overLayGroup && this.overLayGroup = new AMap.OverlayGroup([]);let MarkerAddArr = [];for(let sel_deviceNo in this.newViewData){/**我的所有創(chuàng)建的Marker點(diǎn)對(duì)象都是長(zhǎng)期存在于this.markerObj中,并不銷毀,每次數(shù)據(jù)更新后調(diào)用marker對(duì)象的setPosition(),setAngle(),setIcon()等方法改變狀態(tài),再篩選出需要掛載上的一起加到地圖上 **/if(this.markerObj[sel_deviceNo]){MarkerAddArr.push(this.markerObj[sel_deviceNo]);}}this.overLayGroup.clearOverlays();//超過200個(gè)點(diǎn)則開啟聚合模式 且在聚合模式下不渲染面板展示點(diǎn)if(MarkerAddArr.length>=200){if(this.cluster){this.cluster.clearMarkers();this.cluster.setMarkers(MarkerAddArr);}else{this.createCluser(MarkerAddArr);}}else{if(this.cluster){this.cluster.clearMarkers();}this.overLayGroup.addOverlays(MarkerAddArr);this.overLayGroup.setMap(this.map);}MarkerAddArr=null;},代碼直接從業(yè)務(wù)中復(fù)制的,耦合度比較高,還請(qǐng)見諒。 做完了標(biāo)記點(diǎn)按屏幕分組加載之后,我們?cè)谔砑右粋€(gè)簡(jiǎn)單的防抖方法,防止連續(xù)的拖動(dòng)或者縮放導(dǎo)致computeMarkers方法被觸發(fā),減少方法調(diào)用次數(shù)
const debounce = (fn, wait=500) =>{return function() {clearTimeout(fn.timer)fn.timer = setTimeout(fn.bind(this, ...arguments), wait)} }完成后效果如下:減少了地圖的計(jì)算與渲染,每次只計(jì)算視野內(nèi)的點(diǎn)數(shù),因此總數(shù)的大小不會(huì)影響地圖性能,當(dāng)視野內(nèi)超過200個(gè)點(diǎn)都會(huì)聚合,200以下時(shí)顯示。
平時(shí)寫文章比較少,文筆很差,還請(qǐng)多多見諒,謝謝。總結(jié)
以上是生活随笔為你收集整理的关于VUE项目地图开发中大量点标记绘制一些总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 开源|蚂蚁金服开源AntV F2:一个专
- 下一篇: Web 开发中 Blob 与 FileA