vue项目中实现百度地图测距的两种方法

712 阅读4分钟

突然来了个新需求,产品说要在地图上加一个测距功能。经历一定波折后,最终还是圆满实现了。 今天我将基于百度地图,用两种方法实现测距功能。

效果大致如下图。这是从 百度地图官网上看到的,可以看出百度地图其实是自带测距功能的,只是需要自己调用它。

image.png

一、引入百度地图

1.1获得ak

在一切的开始之前,要有百度地图的AK密钥。具体可参考官网的 文档,此处不做过多赘述。

1.2vue项目中引入

创建一个vue项目,建立一个ceju.vue文件。在template中加入下面的代码: <div class="map" id="container"></div>。要给这个div的样式上增加高度和宽度。根据 教程,在mounted中写入以下的代码:

 let map = new BMapGL.Map("container");
 let point = new BMapGL.Point(116.404, 39.915);
 map.centerAndZoom(point, 15);
 this.map = map;

在public的index.html文件下,加入这样一行代码<script type="text/javascript" src="https://api.map.baidu.com/api?v=1.0&&type=webgl&ak=你的ak"></script>

在这里需要注意的是,我引入的地图版本是GL,百度地图还有其他版本。引入的代码也是不同的。当然之后new BMapGL.Map这行代码也要进行相应的修改。如果想要使用bmap-draw库的话,要用GL版本的。

JavaScript API v3.0:<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=您的密钥"></script>

JavaScript API Lite v1.0:<script type="text/javascript" src="//api.map.baidu.com/api?ak=您的密钥&type=lite&v=1.0"></script>

image.png

启动服务后,可以看到地图,代表我们第一步完成了。

image.png

二、基于bmap-draw库的测距方法实现功能

2.1关于bmap-draw

BMap Draw 是一个基于百度地图 JSAPI 的轻量级鼠标绘制库,提供了鼠标绘制、编辑、裁切、合并、复制黏贴、移动、测量等多种几何图形操作能力,助力开发者开箱即用式快速实现自己的几何图形编辑器。如下图:

image.png

我们想要的测距就在其中。

2.2引入

根据 教程操作。通过npm引入。

npm install bmap-draw

引入距离测绘类 DistanceMeasure,根据 文档 操作。此外也可以参考距离测绘类来写。官网的教程是用react写的,我们使用vue,需要进行一定的修改。

引入测距。

import { DrawScene, DistanceMeasure } from "bmap-draw";

画两个按钮,绑定两个事件。

   <button @click="openMeasure">开始测距</button>
   <button @click="closeMeasure">关闭测距</button>

再写两个方法。开始测距的方法。

openMeasure() {
  const scene = new DrawScene(this.map);
  const distance = new DistanceMeasure(scene, {
    isSeries: false, // 不连续测量
     // unit: 'metric'
  });
  this.distance = distance
  // 监听测量结果
  distance.addEventListener("measure-length-end", (e) => {
    console.log("measure-end", e);
  });
},

结束测距的方法:

closeMeasure() {
      this.distance.close()
},

效果如下,感觉还可以。 image.png 关闭测距功能是这样的,一般来说,你可以双击地图关闭测距,你也可以不双击地图,直接点关测距,缺点是线段结束的地方没有圆点,没有总和长度。如下图。 image.png

三、自己写一个测距功能

还有一种方法是自己写,这里主要用的是getDistance(start: Point , end: Point )这个方法,返回的结果是两点之间的距离,单位为米。自己画的话,最好有个UI,因为那些红圈啊,红叉啊,得有个图,比较方便,不然的话就是svg。我也只是做了一个很粗糙的,勉强实现功能,要真的说效果的话,还是百度的方法比较好。

具体思路: 开始测距后,监听地图的单击事件,得到point,然后绘制一个圆点marker,绘制折线,计算每两个点的距离并绘制label,监听双击事件,结束绘制,并移除地图的监听事件。这里有个问题是同时监听单击事件和双击事件的情况下,在地图上双击,也会触发两次单击,这样地图上的点就会多,我这里就不监听 dblclick了,两次单击间隔不超过某个时间段,就算是双击了。主要是三个方法:

openMeasure:开始测距点击事件。

openMeasure() {
  this.map.addEventListener("click", this.mapClick);
},

closeMeasure:关闭测距点击事件。

closeMeasure() {
  this.map.removeEventListener("click");
  this.totalDistance = 0;
},

mapClick:地图点击事件。

 mapClick(e) {
      const timestamp = new Date().getTime();
      this.timeList.push(timestamp);
      let point = e.latlng;
      if (
        this.timeList.length > 1 &&
        timestamp - this.timeList[this.timeList.length - 2] < 250
      ) {
        let icon = new BMapGL.Icon(this.closeUrl, new BMapGL.Size(12, 12), {
          imageOffset: new BMapGL.Size(0, 0),
        });
        let endMarker = new BMapGL.Marker(point, { icon });
        endMarker.addEventListener("click", (e) => {
          this.map.clearOverlays();
        });
        let label = new BMapGL.Label(`总长:${this.totalDistance}米`, {
          offset: new BMapGL.Size(-45, -25),
        });
        endMarker.setLabel(label);
        this.map.addOverlay(endMarker);
        this.closeMeasure();
        return;
      }
      this.pointList.push(point);
      let icon = new BMapGL.Icon(this.circleUrl, new BMapGL.Size(12, 12), {
        imageOffset: new BMapGL.Size(0, 0),
      });
      let marker = new BMapGL.Marker(point, { icon });

      if (this.pointList.length > 1) {
        let end = this.pointList.length;
        let list = [this.pointList[end - 1], this.pointList[end - 2]];
        let line = new BMapGL.Polyline(list, {
          strokeColor: "#FF0E0E",
          strokeWeight: 2,
          strokeOpacity: 0.5,
        });
        this.map.addOverlay(line);
        let distance = this.map.getDistance(...list);
        this.totalDistance += distance;
        let label = new BMapGL.Label(`${distance}米`);
        marker.setLabel(label);
      }
      this.map.addOverlay(marker);
    },

大概效果如下:

image.png