关于百度地图应用技术分享

294 阅读5分钟
  1. 主题:关于百度地图应用技术分享
  2. 背景:做项目过程中遇到的新需求与优化,具体体现在作战地图、轨迹分析模块。
  3. 大纲:百度地图GL版、turf.js、离线版GL、GraphHopper
  4. 内容:

1.项目中的轨迹分析优化(通过GraphHopper服务 优化轨迹路线)

github.com/graphhopper…

  1. 优化前:     

    

截图.png

  1. 优化后:

      截图 (1).png

路线根据道路将站点之间路线,丰富成汽车导航规划路线。道路点数量约为优化前的10倍。

2.项目中作战地图

截图 (2).png

(1)多城市多边形轮廓覆盖物

截图 (3).png

通过在

datav.aliyun.com/tools/atlas… 网址将8个市区的轮廓数据下载转坐标后存入项目中,然后用BMapGL.Polygon生成多个多边形。

    new BMapGL.Polygon(xinxiangArea, {
        strokeWeight: 0.01,   //边框宽度
        fillColor: "#DDE4F0", //填充颜色
        fillOpacity: 0.5, enableMassClear: false
      }); //建
      this.map.addOverlay(xinxiang)
      this.polygonDistrict.push(xinxiang)

(2)菏泽市轮廓线

截图 (4).png

通过在datav.aliyun.com/tools/atlas… 网址下载轮廓点坐标,在其中找到两个点划分出两条线段存入项目,然后用 BMapGL.Polyline生成加载到地图中

    // 画边界线
    paintingHeZeLine () {
      this.paintingHeZeLineRightData = new BMapGL.Polyline(pointsFormLineString(lineRight), { strokeWeight: 2, strokeColor: "#7ABB4F", enableMassClear: false });
      this.paintingHeZeLineData = new BMapGL.Polyline(pointsFormLineString(lineLeft), { strokeWeight: 2, strokeColor: "#00CCFF", enableMassClear: false });
      this.map.addOverlay(this.paintingHeZeLineData);  //添加覆盖物
      this.map.addOverlay(this.paintingHeZeLineRightData);  //添加覆盖物
    },

(3)省际线5km线、10km线

截图 (5).png

这里用到了turf.js的辐射区功能(为给定半径的Feature计算一个缓冲区。支持的单位是英里、公里和度数),他可以支持多个maker点,通过他生成一个菏泽市往内5km或10km的一个轮廓数据(一堆marker点)。然后同菏泽市轮廓线逻辑找到两个点截通过用BMapGL.Polyline加载,然后与边界线轮廓形成多边形用BMapGL.Polygon加载。

    // 画5公里覆盖物
    paintingFivePolygon () {
      // 菏泽边界线+5公里边界线+菏泽线的第一个坐标
      this.paintingFiveLine = new BMapGL.Polyline(pointsFormLineString(fiveLeft), { strokeWeight: 1, strokeColor: "#FF2A2A", enableMassClear: false });
      this.paintingFivePolygonData = new BMapGL.Polygon(pointsFormLineString(fiveArea), { strokeWeight: 1, strokeColor: "#FF2A2A", fillColor: "red", fillOpacity: 0.1, enableMassClear: false });
      this.map.addOverlay(this.paintingFiveLine);
      this.map.addOverlay(this.paintingFivePolygonData);
      // this.paintingFivePolygonHide();
    },
    //5公里覆盖物展示
    paintingFivePolygonShow () {
      this.paintingFiveLine.show()
      this.paintingFivePolygonData.show()
    },
    //5公里覆盖物隐藏
    paintingFivePolygonHide () {
      this.paintingFiveLine.hide()
      this.paintingFivePolygonData.hide()
    },

(4)多maker点渲染机制

截图 (6).png

在这个项目中maker点多达3万多。在项目中验证过地图渲染点超过1万的已经很卡了。在这里做了一个优化,逻辑跟百度地图的使用罗一样,通过放大的层级与展示的区域,来筛选展示的maker点,在1-10层只展示大概的60个,13、14层只展示大概的120个,15、16层只展示大概的210个,在17、18、19层全部展示。为了数据展示更合理,根据每种的比例来渲染个数,个数较少的则全部展示,有数据的至少展示一个。

//获取选中种类,maker占比
    getProportion (arr, keys, maxNum) {
      let p = {
        "8": 0,
        "13": 0,
        "14": 0,
        "15": 0,
        "17": 0,
        "18": 0,
        "19": 0,
        'all': 0
      }
      arr.map(item => {
        if (keys.includes(8) && item.type == 'ordinary') {
          p['8']++
          p['all']++
        }
        if (keys.includes(13) && item.partyMember == '1') {
          p['13']++
          p['all']++
        }
        if (keys.includes(14) && item.groupLeader == '1') {
          p['14']++
          p['all']++
        }
        if (keys.includes(15) && item.information == '1') {
          p['15']++
          p['all']++
        }
        if (keys.includes(17) && item.illegal == '1') {
          p['17']++
          p['all']++
        }
        if (keys.includes(18) && item.sensitive == '1') {
          p['18']++
          p['all']++
        }
        if (keys.includes(19) && item.outflow == '1') {
          p['19']++
          p['all']++
        }
      })
      if (p['all'] > maxNum) {
        return {
          "8": Math.ceil(p['8'] / p['all'] * maxNum),
          "13": Math.ceil(p['13'] / p['all'] * maxNum),
          "14": Math.ceil(p['14'] / p['all'] * maxNum),
          "15": Math.ceil(p['15'] / p['all'] * maxNum),
          "17": Math.ceil(p['17'] / p['all'] * maxNum),
          "18": Math.ceil(p['18'] / p['all'] * maxNum),
          "19": Math.ceil(p['19'] / p['all'] * maxNum),
          'all': p['all']
        }
      } else {
        return p
      }
    },
    
    // 合理分配点位
    getBuisnessType (number) {
      var selectKeys = this.$refs.tree.getCheckedKeys(true);
      var businessList = this.getMarker.businessList || []
      // console.log("this.getMarker.businessList", this.getMarker.businessList)
      var bs = this.map.getBounds();
      var topSelect = this.checkListBusiness[0]
      var arr = []
      if (topSelect == 1) {
        arr = businessList.filter(item => {
          return (item.marginal == 1) && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
        })
      } else if (topSelect == 2) {
        arr = businessList.filter(item => {
          return (item.marginal == 0) && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
        })
      } else if (topSelect == 3) {
        arr = businessList.filter(item => {
          return (item.marketType == "town") && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
        })

      } else if (topSelect == 4) {
        arr = businessList.filter(item => {
          return (item.marketType == "countryside") && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
        })

      } else {
        arr = businessList.filter(item => {
          return bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
        })
      }

      var list = []
      var jisun1 = 0
      var jisun2 = 0
      var jisun3 = 0
      var jisun4 = 0
      var jisun5 = 0
      var jisun6 = 0
      var jisun7 = 0
      var otherArr = []
      var allNOSelect = true
      var keys = [8, 13, 14, 15, 17, 18, 19]
      var selectsright = selectKeys.filter(item => {
        return keys.includes(item)
      })

      let proportion = this.getProportion(arr, selectsright, number)
      // console.log('proportion:' + JSON.stringify(proportion))
      for (var i = 0; i < arr.length; i++) {
        var item = arr[i]
        if (selectsright.length == 0 || selectsright.length == 7) {
          var loop = parseInt(number / 7)
          if (item.partyMember == '1') {
            if (jisun1++ < loop) {
              list.push(item)
            }
          } else if (item.groupLeader == '1') {
            if (jisun2++ < loop) {
              list.push(item)
            }
          } else if (item.information == '1') {
            if (jisun3++ < loop) {
              list.push(item)
            }
          } else if (item.illegal == '1') {
            if (jisun4++ < loop) {
              list.push(item)
            }
          } else if (item.sensitive == '1') {
            if (jisun5++ < loop) {
              list.push(item)
            }
          } else if (item.outflow == '1') {
            if (jisun6++ < loop) {
              list.push(item)
            }
          } else if (item.type == 'ordinary') {
            if (jisun7++ < loop) {
              list.push(item)
            }
          }
          if (list.length > number) {
            return list
          }
        } else {
          //   var loop = parseInt(number / selectsright.length)
          let loop = 0
          if (selectKeys.includes(8)) {
            if (item.type == 'ordinary') {
              loop = proportion['8']
              if (jisun1++ < parseInt(loop)) {
                list.push(item)
              }
            }
          }
          if (selectKeys.includes(13)) {
            if (item.partyMember == '1') {
              loop = proportion['13']
              if (jisun2++ < parseInt(loop)) {
                list.push(item)
              }
            }
          }

          if (selectKeys.includes(14)) {
            if (item.groupLeader == '1') {
              loop = proportion['14']
              if (jisun3++ < parseInt(loop)) {
                list.push(item)
              }
            }
          }

          if (selectKeys.includes(15)) {
            if (item.information == '1') {
              loop = proportion['15']
              if (jisun4++ < parseInt(loop)) {
                list.push(item)
              }
            }
          }

          if (selectKeys.includes(17)) {
            if (item.illegal == '1') {
              loop = proportion['17']
              if (jisun5++ < loop) {
                list.push(item)
              }
            }
          }

          if (selectKeys.includes(18)) {
            if (item.sensitive == '1') {
              loop = proportion['18']
              if (jisun6++ < loop) {
                list.push(item)
              }
            }
          }

          if (selectKeys.includes(19)) {
            if (item.outflow == '1') {
              loop = proportion['19']
              if (jisun7++ < loop) {
                list.push(item)
              }
            }
          }

          if (list.length > number) {
            return list
          }
        }
      }

      if (selectsright.length == 0 || selectsright.length == 7) {
        if (list.length < number) {
          //补齐点
          for (var i = 0; i < arr.length; i++) {
            // debugger
            var item = arr[arr.length - 1 - i]
            if (list.length < number) {
              if (item.type == 'ordinary') {
                list.push(item)
              }
            }
          }
        }
      }
      return list
    },

(5)高危路线

截图 (7).png

  数据通过后端接口计算,然后用 BMapGL.Polyline生成加载到地图中

// 获取高危路线

    getHighRiskRoute () {
      var that = this
      for (var i = 0; i < this.getMarker.highRiskRouteList.length; i++) {
        var highLine = new BMapGL.Polyline(pointsFormLineString(this.getMarker.highRiskRouteList[i]), { strokeWeight: 6, strokeColor: that.highLineColor[i] })
        // that.map.addOverlay(highLine);
        that.highRiskRouteData.push(highLine);
        // highLine.hide();
        highLine.addEventListener("click", function (type) {
          if (that.lushuPageShow) {
            return
          }
          that.lushuLine = new BMapGL.Polyline(type.currentTarget.getPath(), { strokeWeight: 6, strokeColor: type.currentTarget.getStrokeColor() })
          that.map.addOverlay(that.lushuLine);
          // that.highRiskRouteData.push(highLine);
          // that.map.addOverlay(type.currentTarget)
          that.map.setViewport(that.lushuLine.getPath());
          that.saveOverlay()
          that.lushuStop();
          that.lushuPageShow = true;
          that.lushu = new BMapGLLib.LuShu(that.map, that.lushuLine.getPath(), {
            autoCenter: true,
            icon: new BMapGL.Icon(require('../../assets/images/mapIndex/car.png'), new BMapGL.Size(34, 16)),
            speed: 10000,
            enableRotation: true
          });
        })
      }
    },

(6)刻画路线

image.png

地图添加两个监听是事件分别是“click”、“dblclick”。每次触发click添加一个maker,并与刻画一下这条线,有两个点之后就通过setPath修改这条线。dblclick:结束监听,并添加可清除轨迹maker的小叉号。

// 打开轨迹刻画
    paintingBeginLine () {
      this.paintingBlock = !this.paintingBlock;
      if (this.paintingBlock) {
        this.paintingBegin()
      }
    },

    // 地图上描点

    paintingBegin () {
      if (this.paintingBeginData != true) {
        this.paintingBeginData = true;
        this.paintingBeginNum += 1;
        this.paintingPolyline.push({ line: null, marker: [], deleteMarker: null, });
        this.paintingBeginlisten();
      }
    },

    // 监听折线绘画
    paintingBeginlisten () {
      var that = this;
      this.map.addEventListener("click", function ({ latlng }) { //当鼠标单击时
        if (that.paintingBeginData) { //判断是否绘制曲线完毕
          //创建marker点
          var marker = new BMapGL.Marker(latlng, { icon: new BMapGL.Icon(require('../../assets/images/mapIndex/LineMarker.png'), new BMapGL.Size(16, 18), { anchor: new BMapGL.Size(7, 20) }) });
          // var marker = new BMapGL.Marker(new BMapGL.Point(e1.point.lng, e1.point.lat));
          that.map.addOverlay(marker);
          that.paintingPolyline[that.paintingBeginNum].marker.push(marker);
          that.startPainting = latlng
          // 划线
          that.pLine.push(latlng) //存储曲线上每个点的经纬度
          if (that.pLine.length < 2) { return; } //当折线上的点只有一个时,不绘制
          if (that.paintingPolyline[that.paintingBeginNum].line) {
            that.paintingPolyline[that.paintingBeginNum].line.setPath(that.pLine)
          } else {
            that.paintingPolyline[that.paintingBeginNum].line = new BMapGL.Polyline(that.pLine, { strokeColor: "#589EFF", strokeWeight: 3, strokeOpacity: 1, });
            that.map.addOverlay(that.paintingPolyline[that.paintingBeginNum].line); //绘制曲线
          }
        }
      });
      this.map.addEventListener("dblclick", function ({ latlng }) { //当鼠标双击时:结束绘制,并可以编辑曲线
        if (that.paintingBeginData) {
          that.paintingBeginData = false;//停止监听
          that.startPainting = null;//把最终开始点去掉
          // 线清空,为下一次刻画准备
          that.pLine = [];
          var marker = new BMapGL.Marker(latlng, { icon: new BMapGL.Icon(require('../../assets/images/mapIndex/LineDelete.png'), new BMapGL.Size(12, 12)) });
          marker.setOffset(new BMapGL.Size(10, 10));
          that.paintingPolyline[that.paintingBeginNum].deleteMarker = marker;
          that.map.addOverlay(marker);
          that.paintingPolyline[that.paintingBeginNum].line.disableEditing();//停止绘画
          for (var i = 0; i < that.paintingPolyline.length; i++) {
            that.paintingPolyline[i].deleteMarker.addEventListener("click", function (type) {
              for (var j = 0; j < that.paintingPolyline.length; j++) {
                if (type.currentTarget == that.paintingPolyline[j].deleteMarker) {
                  that.map.removeOverlay(that.paintingPolyline[j].line);
                  that.map.removeOverlay(that.paintingPolyline[j].deleteMarker);
                  for (var k = 0; k < that.paintingPolyline[j].marker.length; k++) {
                    that.map.removeOverlay(that.paintingPolyline[j].marker[k]);
                  }
                }
              }
            })
          }
        }
      })
    },