高德地图渲染多个点(文字,marker等等)卡顿优化指南

5,910 阅读2分钟

前言

说实话,做项目挺难的,尤其是一个人做项目,遇到问题只能网上各种搜索,查找资料等等。重点是有时候一些冷门的东西(尤其是可视化相关),网上有用的资料非常的少。当我第一次遇到这个需求,需要一次性渲染上千个marker和文字标记的时候,并没有想到会导致什么问题,只是想把它渲染出来。我以为地图会自己做处理,但是发现自己想多了。

卡顿原因分析

一开始我以为是多次调用渲染函数导致,因为我在地图zoomed的时候有进行重新渲染的操作,经过多次调试,发现这个并不是主要原因,尤其是当我大量渲染poyline的时候,方法我只是初始化调用了一次,但是仍然十分的卡顿,后来仔细想了想才发现主要原因是页面上的dom元素太多了,每个节点,都是一个div元素合成的,可以打开控制台看一下。

1634628608(1).png

解决问题的方法

找到了导致卡顿的原因,解决起来就会有一些眉路了,既然是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 经过实测,完美解决卡顿问题,欢迎评论