zoukankan      html  css  js  c++  java
  • react+百度地图添加大量点标记如何减缓首次加载压力

    在百度地图添加大量的点标记的时候,页面会非常的卡顿,翻阅了很多文档,发现原创作者代码有缺失,导致照搬文章都一样是不完整的。如图,缺失在一个for循环里(queryInRect()函数中,下面进行了补全),然后自己便研究了一下缺失的到底是什么。

     

    首先我是在react项目中结合echarts,和百度地图去实现一个带标注的热力地图。之前写过一篇博客,有兴趣可以直接在百度搜索 https://www.cnblogs.com/class1/p/13691867.html,下面的代码就是在上一次的基础上改动的。后来因为加的标注太多,改成首次加载200个标注。后续在地图发生变化的时候再加载出全部的标注。

    先看热力地图 的代码:

    // heatMap.js
    
    import React, { Component } from 'react';
    
    import echarts from 'echarts/lib/echarts';
    // 引入热力图
    import 'echarts/lib/chart/heatmap';
    // 引入提示框和标题组件
    import 'echarts/lib/component/tooltip';
    import 'echarts/lib/component/title';
    import 'echarts/extension/bmap/bmap';
    import 'echarts/lib/component/visualMap';
    
    class EchartsTest extends Component {
      constructor(props) {
        super(props);
        this.state = {
          data: props.data,
        };
      }
    
      componentDidMount() {
        this.getCharts();
      }
    
      // 保证再次请求数据时候,地图重新加载
      // eslint-disable-next-line no-unused-vars
      componentWillReceiveProps(nextProps, nextContext) {
        this.setState({
          data: nextProps.data,
        });
        setTimeout(() => {
          if(!nextProps.data.length===0){
            this.getCharts();
          }
        }, 500);
      }
    
       getCharts = () => {
        const { data } = this.state;
        const maxdata = data
          .map(item => item[2])
          .sort()
          .reverse()[0];
        const myChart = echarts.init(document.getElementById('container'));
        const option = {
          animation: false,
          bmap: {
            center: [data[0][0], data[0][1]],
            zoom: this.getMapGrade(data),
            roam: true,
          },
          visualMap: {
            show: true,
            bottom: 50,
            left: 0,
            min: 0,
            max: maxdata,
            seriesIndex: 0,
            calculable: true,
            inRange: {
              color: ['blue', 'green', 'yellow', 'red'],
            },
          },
          series: [
            {
              name: 'gid热力值',
              type: 'heatmap',
              coordinateSystem: 'bmap',
              data,
              pointSize: 8,
              blurSize: 8,
            },
          ],
        };
        myChart.setOption(option); // 设置的option是使用echarts的一些配置
        // 添加百度地图插件
        const bmap = myChart
          .getModel()
          .getComponent('bmap')
          .getBMap();
    
        bmap.addControl(new BMap.NavigationControl()); // 地图平移缩放控件
    
        bmap.addControl(new BMap.ScaleControl()); // 地图比例尺控件
    
        const points = [];
        const markers = [];
        const currMarkers = {};
    
        const lengths = data.length;
        
        for (let i = 0; i < lengths; i += 1) {
          const point = new BMap.Point(data[i][0], data[i][1]);
          points.push({ ...point, num: data[i][2] });
          markers.push(new BMap.Marker(point));
          if (i < 200) {
            // 初始显示200个点(可自定义自己能容忍卡顿时间的极限点数)
            bmap.addOverlay(markers[i]); // 绘制到地图上
            const infoWindow = new BMap.InfoWindow(`
                <div style="margin:0;line-height:20px;padding:2px;">
                  标题:热点详细信息
                  <br/>地理位置:${markers[i].point.lng}, ${markers[i].point.lat}
                  <br/>最近三个月热力值:${points[i].num}
                </div>`);
            markers[i].infoWindow = infoWindow; // 给当前标注新增一个属性以便保存窗口信息infoWindow
            markers[i].addEventListener('click', function(e) {
              this.openInfoWindow(e.target.infoWindow); // 点击标注时,打开改标注对打开改标注对应的回调信息
            });
    
            currMarkers[`markers${i}`] = markers[i]; // 添加到已显示的点内
          }
        }
    
        // eslint-disable-next-line no-undef
        bmap.addControl(
          // eslint-disable-next-line no-undef
          new BMap.MapTypeControl({
            mapTypes: [
              // eslint-disable-next-line no-undef
              BMAP_NORMAL_MAP,
              // BMAP_HYBRID_MAP
            ],
          })
        );
        // 去掉上面的{mapTypes:[...]}  就会显示地图,卫星,三维三个图层
    
        function queryInRect() {
          const cp = bmap.getBounds(); // 返回map可视区域,以地理坐标表示
          const swn = cp.getSouthWest(); // 返回矩形区域的西南角
          const nen = cp.getNorthEast(); // 返回矩形区域的东北角
          const zoom = bmap.getZoom(); // 当前缩放级别
    
          const swlng = swn.lng;
          const swlat = swn.lat;
          const nelng = nen.lng;
          const nelat = nen.lat;
          let currShowCount = 0; // 本次拖动或缩放已显示的点数
          const allLength = points.length;
          for (let i = 0; i < allLength; i += 1) {
            if (
              points[i].lng > swlng &&
              points[i].lng < nelng &&
              points[i].lat > swlat &&
              points[i].lat < nelat
            ) {
              if (currMarkers[`markers${i}`] === undefined) {
                // 判断当前点是否已显示在地图上,显示则无需重新绘制
                if (zoom === 18 || currShowCount < 50) {
                  // 放大到最大层数后,则显示当前可视区内所有点,鉴于层级较大显示的摄像头较少,因此不会出现卡顿情况
                  bmap.addOverlay(markers[i]);
                  //  console.log(allLength,i,markers[i].point)
                  // eslint-disable-next-line no-undef
                  const infoWindow = new BMap.InfoWindow(`
                <div style="margin:0;line-height:20px;padding:2px;">
                  标题:热点详细信息
                  <br/>地理位置:${markers[i].point.lng}, ${markers[i].point.lat}
                  <br/>最近三个月热力值:${points[i].num}
                </div>`);
                  markers[i].infoWindow = infoWindow; // 给当前标注新增一个属性以便保存窗口信息infoWindow
                  markers[i].addEventListener('click', function(e) {
                    this.openInfoWindow(e.target.infoWindow); // 点击标注时,打开改标注对打开改标注对应的回调信息
                  });
    
                  currMarkers[`markers${i}`] = markers[i]; // 记录已显示的点
                  // eslint-disable-next-line no-const-assign,no-plusplus
                  currShowCount += 1; // 本次已显示数加1
                } else {
                  return;
                }
              }
            }
          }
        }
        bmap.addEventListener('moveend', queryInRect);  // 地图在移动的时候,继续加载标注点
        bmap.addEventListener('zoomend', queryInRect);// 地图在缩放的时候,继续加载标注点
      };
    
      // 计算经纬度距离(千米),四个参数分别是点A的纬度,经度,点B的纬度,经度(位置不要搞错了,我就弄错了,搞了好久)
      getDistance =(lat1, lng1, lat2, lng2)=>{
        const radLat1 = lat1*Math.PI / 180.0;
        const radLat2 = lat2*Math.PI / 180.0;
        const a = radLat1 - radLat2;
        const b = lng1*Math.PI / 180.0 - lng2*Math.PI / 180.0;
        // eslint-disable-next-line no-restricted-properties
        let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
          // eslint-disable-next-line no-restricted-properties
          Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
        s *=6378.137 ;
        s = Math.round(s * 10000) / 10000;
        return s;
      };
    
     // 计算地图初始化所有点中最远的距离
      getZooms = val => {
        const arr = [];
        if (val.length === 1) {
          arr.push(1);
        } else {
          const xLeng = val.map(item => item[0]);
          const yLeng = val.map(item => item[1]);
          const xmin = Math.min(...xLeng);
          const xmax = Math.max(...xLeng);
          const ymin = Math.min(...yLeng);
          const ymax = Math.max(...yLeng);
          arr.push(this.getDistance(ymin, xmin, ymax, xmax));
        }
        return Math.max(...arr);
      };
    
      // 计算比例尺对应的百度地图等级
      getMapGrade=(val)=>{
      // console.log("数据 ",val);
        const num=this.getZoom(val);
      //   console.log("最大距离",num);
        let zoom=0;
       if(num<=1){
         zoom=15
       }else if(num>1&&num<=50){
         zoom=10
        }else if(num>50&&num<=100){
         zoom=9
       }else if(num>100&&num<=500){
         zoom=7
       }else if(num>500&&num<=1000){
         zoom=6
       }else{
         zoom=4
       }
       return zoom
      };
    
    
      render() {
        return (
          <div id="main" style={{  '100%', height: 600 }}></div>
        );
      }
    }
    
    export default EchartsTest;
    

      

    虽说首次加载减缓了压力,后续加载页面依旧卡顿。研究了一下高德地图,非常的好用。下次重点说说如何使用高德地图的海量点标记。

  • 相关阅读:
    u盘的超级用法
    文件夹访问被拒绝
    web移动前端的click点透问题
    call()apply()ind()备忘录
    Safari中的new Date()格式化坑
    dataURI V.S. CSS Sprites 移动端
    css3属性之 box-sizing
    多人协作代码--公共库的引用与业务约定
    web前端本地测试方法
    依赖包拼合方法
  • 原文地址:https://www.cnblogs.com/class1/p/14116837.html
Copyright © 2011-2022 走看看