2019-03-28-百度地图接入及使用

背景

近期工作中涉及大量百度mapv使用。其中包含,汇聚图效果、动态街道路径效果、动态热力图效果。

百度mapv引入

mapv示例文档

 <script src="http://mapv.baidu.com/build/mapv.min.js"></script>

热力图

/**
*  绘制热力图
*/
drowHotDary() {
    var randomCount = 600;
    var data = [];        // 清除所有遮盖物
    this.clearCurrentBoundCity()
    
    // 构造数据
    while (randomCount--) {
      var cityCenter = mapv.utilCityCenter.getCenterByCityName(this.hotMapcitys[parseInt(Math.random() * this.hotMapcitys.length)]);
      data.push({
        geometry: {
          type: 'Point',
          coordinates: [cityCenter.lng - 2 + Math.random() * 2, cityCenter.lat - 2 + Math.random() * 2]
        },
        count: 30 * Math.random(),
        time: 100 * Math.random()
      });
    }
    
    var dataSet = new mapv.DataSet(data);
    
    var options = {
      size: 13,
      gradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"},
      max: 60,
      animation: {
        type: 'time',
        stepsRange: {
          start: 0,
          end: 100
        },
        trails: 10,
        duration: 10,
      },
      draw: 'heatmap'
    }
    
    var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
},

汇聚图效果

  /**
   *  汇聚图
   */
  drawConvergenceMap() {
    var randomCount = 100;

    var node_data = {
      "0":{"x":116.4136103013, "y":39.9110666857},
      "1":{"x":121.485124, "y":31.235317},
    };

    var edge_data = [
      {"source":"1", "target":"0"}
    ]

    var citys = ["承德", "莆田", "宜昌","重庆"];

    // 构造数据
    for (var i = 1; i < randomCount; i++) {
      var cityCenter = mapv.utilCityCenter.getCenterByCityName(citys[parseInt(Math.random() * citys.length)]);
      node_data[i] = {
        x: cityCenter.lng - 5 + Math.random() * 10,
        y: cityCenter.lat - 5 + Math.random() * 10,
      }
      edge_data.push(
        {"source": ~~(i * Math.random()), "target": '0'}
      );
    }

    var fbundling = mapv.utilForceEdgeBundling()
      .nodes(node_data)
      .edges(edge_data);

    var results = fbundling();

    var data = [];
    var timeData = [];

    for (var i = 0; i < results.length; i++) {
      var line = results[i];
      var coordinates = [];
      for (var j = 0; j < line.length; j++) {
        coordinates.push([line[j].x, line[j].y]);
        timeData.push({
          geometry: {
            type: 'Point',
            coordinates: [line[j].x, line[j].y]
          },
          count: 1,
          time: j
        });
      }
      data.push({
        geometry: {
          type: 'LineString',
          coordinates: coordinates
        }
      });
    }

    var dataSet = new mapv.DataSet(data);

    var options = {
      strokeStyle: 'rgba(55, 50, 250, 0.3)',
      globalCompositeOperation: 'lighter',
      shadowColor: 'rgba(55, 50, 250, 0.5)',
      shadowBlur: 10,
      methods: {
        click: function (item) {
        }
      },
      lineWidth: 1.0,
      draw: 'simple'
    }

    var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);

    var dataSet = new mapv.DataSet(timeData);

    var options = {
      fillStyle: 'rgba(255, 250, 250, 0.9)',
      globalCompositeOperation: 'lighter',
      size: 1.5,
      animation: {
        type: 'time',
        stepsRange: {
          start: 0,
          end: 100
        },
        trails: 1,
        duration: 5,
      },
      draw: 'simple'
    }

    var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
  },

航线图

/**
*  绘制航线图
*/
drawHangxian(scenicSpot) {
    var to = '重庆';
     var qianxi = new mapv.DataSet(scenicSpot);
     var qianxiData = qianxi.get();
     
     var lineData = [];
     var pointData = [];
     var textData = [];
     var timeData = [];
     
     var citys = {}
     
     for (var i = 0; i < qianxiData.length; i++) {
       var fromCenter = mapv.utilCityCenter.getCenterByCityName(qianxiData[i].from);
       var toCenter = mapv.utilCityCenter.getCenterByCityName(to);
       if (!fromCenter || !toCenter) {
         continue;
       }
       citys[qianxiData[i].from] = qianxiData[i].count;
       citys[to] = 100;
       pointData.push(
         {
           geometry: {
             type: 'Point',
             coordinates: [fromCenter.lng, fromCenter.lat]
           }
         }
       );
       pointData.push(
         {
           geometry: {
             type: 'Point',
             coordinates: [toCenter.lng, toCenter.lat]
           }
         }
       );
       textData.push(
         {
           geometry: {
             type: 'Point',
             coordinates: [fromCenter.lng, fromCenter.lat]
           },
           text: qianxiData[i].from
         }
       );
       textData.push(
         {
           geometry: {
             type: 'Point',
             coordinates: [toCenter.lng, toCenter.lat]
           },
           text: to
         }
       );
     
       var curve = mapv.utilCurve.getPoints([fromCenter, toCenter]);
     
       for (var j = 0; j < curve.length; j++) {
         timeData.push({
           geometry: {
             type: 'Point',
             coordinates: curve[j]
           },
           count: 1,
           time: j
         });
       }
     
       lineData.push({
         geometry: {
           type: 'LineString',
           coordinates: curve
           //coordinates: [[fromCenter.lng, fromCenter.lat], [toCenter.lng, toCenter.lat]]
         },
         count: 30 * Math.random()
       });
     
     }
     
     var textDataSet = new mapv.DataSet(textData);
     
     var textOptions = {
       draw: 'text',
       font: '14px Arial',
       fillStyle: 'white',
       shadowColor: 'yellow',
       shadowBlue: 10,
       zIndex: 11,
       shadowBlur: 10
     }
     
     var textMapvLayer = new mapv.baiduMapLayer(this.map, textDataSet, textOptions);
     
     var lineDataSet = new mapv.DataSet(lineData);
     
     var lineOptions = {
       strokeStyle: 'rgba(255, 250, 50, 0.8)',
       shadowColor: 'rgba(255, 250, 50, 1)',
       shadowBlur: 20,
       lineWidth: 2,
       zIndex: 100,
       draw: 'simple'
     }
     
     var lineLayer = new mapv.baiduMapLayer(this.map, lineDataSet, lineOptions);
     
     // 描绘点
     var pointOptions = {
       fillStyle: 'rgba(254,175,3,0.7)',
       shadowColor: 'rgba(55, 50, 250, 0.5)',
       shadowBlur: 10,
       size: 5,
       zIndex: 10,
       draw: 'simple'
     }
     
     var pointDataSet = new mapv.DataSet(pointData);
     
     var pointLayer = new mapv.baiduMapLayer(this.map, pointDataSet, pointOptions);
     
     // 动态效果
     var timeDataSet = new mapv.DataSet(timeData);
     
     var timeOptions = {
       fillStyle: 'rgba(255, 250, 250, 0.5)',
       zIndex: 200,
       size: 2.5,
       animation: {
         type: 'time',
         stepsRange: {
           start: 0,
           end: 50
         },
         trails: 10,
         duration: 2,
       },
       draw: 'simple'
     }
     
     var timeMapvLayer = new mapv.baiduMapLayer(this.map, timeDataSet, timeOptions);
},

动态街道路径效果

/**
*  显示航线图
*/
showLinesOnMap(lines) {
    // 重置地图样式
    this.map.clearOverlays()
    this.map.centerAndZoom(new BMap.Point(106.543254,29.556327), 14);
    
    var data = [];
    var timeData = [];
    let rs = Object.keys(lines).map(function (key) {
      return lines[key]
    })
    for (var i = 0; i < rs.length; i++) {
      var item = rs[i]
      var coordinates = [];
    
      for (let j = 0; j < item.length; j++) {
        coordinates.push([Number.parseFloat(item[j].lng), Number.parseFloat(item[j].lat)]);
        timeData.push({
          geometry: {
            type: 'Point',
            coordinates: [Number.parseFloat(item[j].lng), Number.parseFloat(item[j].lat)]
          },
          count: 1,
          time: j
        });
      }
      data.push({
        geometry: {
          type: 'LineString',
          coordinates: coordinates
        }
      });
    
    }
    var dataSet = new mapv.DataSet(data);
    
    var options = {
      strokeStyle: 'rgba(53,57,255,0.5)',
      coordType: 'bd09mc',
      // globalCompositeOperation: 'lighter',
      shadowColor: 'rgba(53,57,255,0.2)',
      shadowBlur: 3,
      lineWidth: 3.0,
      draw: 'simple'
    }
    
    var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
    var dataSet = new mapv.DataSet(timeData);
    
    var options = {
      fillStyle: 'rgba(255, 250, 250, 0.2)',
      coordType: 'bd09mc',
      globalCompositeOperation: "lighter",
      size: 1.5,
      animation: {
        stepsRange: {
          start: 0,
          end: 100
        },
        trails: 3,
        duration: 5,
      },
      draw: 'simple'
    }
    
    var mapvLayer = new mapv.baiduMapLayer(this.map, dataSet, options);
},

附:经纬度坐标转墨卡托坐标

在做mapv街道路径图的时候,发现无法直接使用普通经纬度数据,进行街道路径绘制,需要将原有经纬度坐标转换墨卡托坐标。以下附转换函数供参考使用。

export default {
  x_pi: 3.14159265358979324 * 3000.0 / 180.0,
  LLBAND: [75, 60, 45, 30, 15, 0],
  LL2MC: [
    [-0.0015702102444, 111320.7020616939, 1704480524535203, -10338987376042340, 26112667856603880, -35149669176653700, 26595700718403920, -10725012454188240, 1800819912950474, 82.5],
    [0.0008277824516172526, 111320.7020463578, 647795574.6671607, -4082003173.641316, 10774905663.51142, -15171875531.51559, 12053065338.62167, -5124939663.577472, 913311935.9512032, 67.5],
    [0.00337398766765, 111320.7020202162, 4481351.045890365, -23393751.19931662, 79682215.47186455, -115964993.2797253, 97236711.15602145, -43661946.33752821, 8477230.501135234, 52.5],
    [0.00220636496208, 111320.7020209128, 51751.86112841131, 3796837.749470245, 992013.7397791013, -1221952.21711287, 1340652.697009075, -620943.6990984312, 144416.9293806241, 37.5],
    [-0.0003441963504368392, 111320.7020576856, 278.2353980772752, 2485758.690035394, 6070.750963243378, 54821.18345352118, 9540.606633304236, -2710.55326746645, 1405.483844121726, 22.5],
    [-0.0003218135878613132, 111320.7020701615, 0.00369383431289, 823725.6402795718, 0.46104986909093, 2351.343141331292, 1.58060784298199, 8.77738589078284, 0.37238884252424, 7.45]
  ],
  getRange(cC, cB, T) {
    if (cB != null) {
      cC = Math.max(cC, cB);
    }
    if (T != null) {
      cC = Math.min(cC, T);
    }
    return cC;
  },
  getLoop(cC, cB, T) {
    while (cC > T) {
      cC -= T - cB;
    }
    while (cC < cB) {
      cC += T - cB;
    }
    return cC;
  },
  convertor(cC, cD) {
    if (!cC || !cD) {
      return null;
    }
    let T = cD[0] + cD[1] * Math.abs(cC.x);
    const cB = Math.abs(cC.y) / cD[9];
    let cE = cD[2] + cD[3] * cB + cD[4] * cB * cB +
      cD[5] * cB * cB * cB + cD[6] * cB * cB * cB * cB +
      cD[7] * cB * cB * cB * cB * cB +
      cD[8] * cB * cB * cB * cB * cB * cB;
    T *= (cC.x < 0 ? -1 : 1);
    cE *= (cC.y < 0 ? -1 : 1);
    return [T, cE];
  },
  /// 经纬度坐标转墨卡托坐标
  convertLL2MC(T) {
    let cD, cC, len;
    T.x = this.getLoop(T.x, -180, 180);
    T.y = this.getRange(T.y, -74, 74);
    const cB = T;
    for (cC = 0, len = this.LLBAND.length; cC < len; cC++) {
      if (cB.y >= this.LLBAND[cC]) {
        cD = this.LL2MC[cC];
        break;
      }
    }
    if (!cD) {
      for (cC = this.LLBAND.length - 1; cC >= 0; cC--) {
        if (cB.y <= -this.LLBAND[cC]) {
          cD = this.LL2MC[cC];
          break;
        }
      }
    }
    const cE = this.convertor(T, cD);
    return cE;
  }
}