前言
说实话,做项目挺难的,尤其是一个人做项目,遇到问题只能网上各种搜索,查找资料等等。重点是有时候一些冷门的东西(尤其是可视化相关),网上有用的资料非常的少。当我第一次遇到这个需求,需要一次性渲染上千个marker和文字标记的时候,并没有想到会导致什么问题,只是想把它渲染出来。我以为地图会自己做处理,但是发现自己想多了。
卡顿原因分析
一开始我以为是多次调用渲染函数导致,因为我在地图zoomed的时候有进行重新渲染的操作,经过多次调试,发现这个并不是主要原因,尤其是当我大量渲染poyline的时候,方法我只是初始化调用了一次,但是仍然十分的卡顿,后来仔细想了想才发现主要原因是页面上的dom元素太多了,每个节点,都是一个div元素合成的,可以打开控制台看一下。
解决问题的方法
找到了导致卡顿的原因,解决起来就会有一些眉路了,既然是dom一次性加载太多,那所谓地图渲染和我们平常渲染长列表一样,让dom只在可视区域进行加载,不在可视区域的清除,这样处理,就行提升很大的性能。怎么判断当前经纬度是不是在可视区域呢?这里借助高德api封装了一个方法, 参数为此点的经纬度
// 是否在可视区域
isInview(lonLat) {
const bounds = this.map.getBounds();
const NorthEast = bounds.getNorthEast();
const SouthWest = bounds.getSouthWest();
const SouthEast = [NorthEast.lng, SouthWest.lat];
const NorthWest = [SouthWest.lng, NorthEast.lat];
const path = [
[NorthEast.lng, NorthEast.lat],
SouthEast,
[SouthWest.lng, SouthWest.lat],
NorthWest,
]; // 将地图可视区域四个角位置按照顺序放入path,用于判断point是否在可视区域
const isInView = this.resMap.GeometryUtil.isPointInRing(
lonLat,
path
);
return isInView
},
比如我此处要大量渲染的是点位,点位源数据 pointData,定义一个数组存储当前渲染的点 parkMarks = []
// 渲染点位
renderPoint() {
if (this.parkMarks.length > 0) {
this.map.remove(this.parkMarks)
}
for (let i = 0; i < this.pointData.length; i++) {
const isInview = this.isInview(JSON.parse(this.pointData[i].lonLat)[0])
if (isInview) {
// 绘制机位
let circleMarker = new this.resMap.CircleMarker({
center: JSON.parse(this.pointData[i].lonLat)[0],
radius: 1, //3D视图下,CircleMarker半径不要超过64px
strokeColor: "rgba(0,0,255,1)",
strokeWeight: 2,
strokeOpacity: 0.5,
fillColor: "red",
fillOpacity: 0.5,
zIndex: 10,
bubble: true,
clickable: true,
});
this.parkMarks.push(circleMarker);
circleMarker.setMap(this.map);
}
}
},
当地图移动结束的时候zoomend
this.map.on("moveend", () => {
var zoom = this.map.getZoom();
if (zoom > 15) {
this.renderPoint();
}
});
如果有其他标记,也可以这么处理。ok 经过实测,完美解决卡顿问题,欢迎评论