需求:将大量GPS数据点渲染在中国地图上 (后续数据量可达百万级,目前未实验,国庆节以后再进行测试)

数据格式: [[118.17681,39.66119], [117.88331, 33.195477], ...]
echarts版本:5.0.2

效果(10W)。渲染速度非常快,这与我们设置的large和largeThreshold有关;

在这里插入图片描述

<script>
// charts实例不要放在data里,echarts.init原型链绑一大堆对性能不友好
let charts = null;
export default {
	data() {
		return {
			// ES5新增特性,冻结对象,阻止修改现有属性;
			// 如果你有非常庞大的数组,确定不会修改他们,可以使用Object.freeze()大幅提升性能。
			dataList: Object.freeze([]),
			 // 模拟批次请求
			xmlPath: [
		        "gis_1.txt",
		        "gix_2.txt",
		        "gis_3.txt",
		        "gis_4.txt",
		        "gis_5.txt",
		     ],
			xmlCount: 0,
		}
	}
}
</script>

切换页面销毁echarts实例(未使用keepAlive请使用beforeDestroy)

// 销毁时清除计时器,释放内存
  deactivated() {
      charts && this.$echarts.dispose(charts);
  },

后台未提供接口,给出了几个txt文件先请求测试一下(部分截图)
在这里插入图片描述

init() {
  // 初始化,因为使用了keepAlive来回切换dataList不会清空;
  this.xmlCount = 0;
  this.dataList = Object.freeze([]);
  this.getXml(this.xmlPath[0]);


  // ...省略部分代码,直接贴出来setOptions


    charts.setOption({
      tooltip: {
        show: false,
      },
      geo: [
        {
          map: "china-contour",
          zoom: 1.2, //当前视角的缩放比例
          zlevel: 0,
          center: [105, 36], // 调整地图位置
          label: {
            show: false,
          },
          silent: true,
          itemStyle: {
            areaColor: "rgba(0,0,0,0.45)",
            borderColor: "#2F5DBE", // 地图边框颜色
            borderWidth: 4,
            shadowColor: "rgba(46,255,243,0.6)",
            shadowBlur: 100,
          },
        },
        {
          map: "china",
          zoom: 1.2, //当前视角的缩放比例
          center: [105, 36], // 调整地图位置
          label: {
            show: true, // 省份名称展示
            textStyle: {
              color: "#AFB7C9", // 省份文字颜色
              fontSize: 10,
            },
          },
          // 高亮
          emphasis: {
            label: {
              show: true,
              textStyle: {
                color: "#AFB7C9", // 省份文字颜色
                fontSize: 10,
              },
            },
            itemStyle: {
              areaColor: "rgba(0,0,0,0.8)",
              borderColor: "#204CA3",
              borderWidth: 1,
              color: "rgba(0,0,0,0.5)",
            },
          },
          itemStyle: {
            areaColor: {},
            borderColor: "#204CA3", // 地图内边框颜色
            borderWidth: 1,
          },
        },
      ],
      series: [
        {
          type: "scatter",
          coordinateSystem: "geo",
          // 'lttb' 采用 Largest-Triangle-Three-Bucket 算法,可以最大程度保证采样后线条的趋势,形状和极值。
          // 'average' 取过滤点的平均值
          // 'max' 取过滤点的最大值
          // 'min' 取过滤点的最小值
          // 'sum' 取过滤点的和
          sampling: "lttb", // 数据量远大于像素点时候的降采样策略
          data: [],
          itemStyle: {
            color: "#27d5ec",
            shadowBlur: 10,
            shadowColor: "#333",
          },
          symbolSize: 1,
          large: true,
           // 大规模阀值,large为true且数据量>largeThreshold才启用大规模模式
          largeThreshold: 500,
        },
      ],
    });
    this.$resize.on(byId, () => charts && charts.resize());
  }
}

模拟请求

getXml(path) {
   let xhr = newXMLHttpRequest();
   xhr.open("get", path, true);
   xhr.responseType = "arraybuffer";
   let that = this;
   xhr.onload = function (e) {
     let unit8_msg = new Uint8Array(this.response);
     let len = unit8_msg.length;
     // 解码为字符串
     let binary = "";
     for (let i = 0; i < len; i++) {
       binary += String.fromCharCode(unit8_msg[i]);
     }
     let res = JSON.parse(binary);
     let data = [];
     // 因为文件里数据格式不符合我们想要的格式,所以需要对数据格式进行处理
     // 这里判断奇偶数来判断经纬度提取为一组
     res.forEach((item, index) => {
       if (index % 2 === 0) data.push([item, res[index + 1]]);
     });
     that.dataList = Object.freeze(data);
     // 分片渲染
     charts.appendData({
       seriesIndex: 0,
       data: that.dataList,
     });
   };
   xhr.send();
   xhr.onloadend = function () {
     that.xmlCount += 1;
     if (that.xmlPath.length > that.xmlCount) {
       that.getXml(that.xmlPath[that.xmlCount]);
     } else {
       console.log("请求完成");
     }
   };
 }

如果浏览器打开了多个标签页,我们在切换其他标签页时候或者使浏览器缩在后台,长时间会使项目挂在后台会导致echarts内存不断增加,导致崩溃(原因是只有打开当前标签页时,内存才会释放),此时可使用visibilitychange来监听是否切换标签页进行清除和渲染的操作;

// 监听窗口变化
    document.addEventListener("visibilitychange", () => {
      if (document.hidden) {
        // 隐藏
        // 清除示例
      } else {
        // 显示
		// 渲染
      }
    });

总结:

  1. 使用Object.freeze()大幅提升性能。
  2. large 和 largeThreshold
  3. appendData分片渲染,多次渲染不会覆盖之前的数据
  4. echarts实例的性能优化
    a: charts实例不要放在data里
    b: 及时销毁实例

————————11.19日——分批次请求接口

<script>
let dataList = []; 放在script里
export default { ... }
...

methods:
	// 获取gps点
    getGeoPoint(index) {
      GeoPoint({ page: index }).then((res) => {
        // console.log(res);
        // 渲染
        const data = res.data;
        charts.appendData({
          seriesIndex: 0,
          data,
        });
        index--;
        dataList.push(Object.freeze(data));
        if (index < 0) {
          return;
        }
        this.getGeoPoint(index);
      });
    },
    appendData() {
      if (dataList.length) {
        const list = Object.freeze(dataList);
        // 增加timeout原因是,dataList变量存有大量数据,来回切换页面会卡顿一下,增加timeout延迟foreach循环 为的就是先把页面加载出来
        setTimeout(() => {
	        list.forEach((data) => {
	          charts.appendData({
	            seriesIndex: 0,
	            data: data,
	          });
	        });
        }, 1200);
      } else {
        this.getGeoPoint(103);
      }
    },```

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐