Vue CLI and Leaflet (8)地图量测

1、功能分析

地图的量测功能,是地理信息系统中的经常使用功能。主要量测地图上的距离,面积,或者线要素的长度,面要素周长和面积。javascript

这篇文章将介绍第一个基于 leaflet.js 实现地图量测插件 leaflet-measure-path 。使用这个插件的缘由是它简单好用,若是你看了以前的文章或掌握了 leaflet 中图形加载与绘制,借助这个插件可以快速的实现地图量测功能。css

1)leaflet-measure-path 插件

插件的介绍以下,详细信息查询 leaflet-measure-path官方示例vue

A plugin to show measurements on paths (polylines, polygons and circles currently supported).java

一个在路径的上现实测量结果的插件(目前支持线,面 和 圆圈)。node

此插件实现的量测的方式是,对 leaflet.js 中的 polyline, polygoncircle 三中图形类作了 量测数据获取与展现等相关功能 拓展。有点就是简单易用,缺点目前只以为在线要素的长度信息标注上有时候会出现比较不合理的状况。git

2) 量测功能分析

根据个人对这个功能的理解,我将常见的量测功能分为如下量测。github

(1) 已知图形的量测

地图上已经存在线,面等要素,须要获取到其长度货面积。功能的效果就是,直接地图上加载图形并显示出图形的量测信息。如 官方示例 中的效果:bash

static-measurement

(2) 动态量测

动态量测实际上就是咱们常常看到的量测功能,这里主要是为了上面的量测方式作区别。在用户绘制的过程当中实时显示量测信息。这个功能须要以绘制功能为基础,能够参考之前的文章:Vue-CLI and Leaflet(6): 线 绘制Vue CLI and Leaflet (7) 面绘制less

dynamic-measurement

2、代码实现

在实现功能以前必定要了解熟悉 leaflet-measure-path 插件的用法。还有全部的代码都是基于第一篇文章中建好的目录结构中添加的,请参考Vue-CLI and Leaflet (1):显示一个地图ssh

1)插件的引入

leaflet-measure-path 插件引入很简单,若是是初学者可能会在对 Vue-CLI 中引用插件遇到问题。如下是引入方式。

// src\utils\map.js
import $L from "leaflet";
import "leaflet/dist/leaflet.css";

// 注意:
// 必定要在 leaflet.js 成功引入以后,在引用此插件
import "leaflet-measure-path";
import "leaflet-measure-path/leaflet-measure-path.css";

复制代码

2)已知图形的量测

首先介绍简单的已知图形的量测信息的显示。插件引入成功以后,leaflet.js 中的 polyline, polygoncircle 要素就已经得到了 leaflet-measure-path 插件 的支持。显示图形量测信息的方法就是在建立要素时,开启量测信息展现的属性。

我在工程的 views 目录线新建了一个 MeasureStatic.vue

// src\views\MeasureStatic.vue

<template>
  <div class="map-container">
    <div id="map-container"></div>
  </div>
</template>

<script>
export default {
  name: "map-point",
  data() {
    return {
      map: null,
      OSMUrl: "http://tile.osm.org/{z}/{x}/{y}.png",
      overLayer: {
        polylines: [],
        polygons: [],
        measurements: []
      },
      existLine: [
        [51.49404942257001, -0.14136314392089847],
        [51.48640717153227, -0.12797355651855472],
        [51.48640717153227, -0.12797355651855472],
        [51.48464339321334, -0.10376930236816408],
        [51.48464339321334, -0.10376930236816408],
        [51.486353724706795, -0.09801864624023438],
        [51.486353724706795, -0.09801864624023438],
        [51.486353724706795, -0.09801864624023438]
      ],
      existLinePolygon: [
        [51.497175428776025, -0.11269569396972658],
        [51.48825104864774, -0.1149272918701172],
        [51.48825104864774, -0.1149272918701172],
        [51.48723558931616, -0.09758949279785158],
        [51.48723558931616, -0.09758949279785158],
        [51.49450364191158, -0.09282588958740236],
        [51.49450364191158, -0.09282588958740236],
        [51.499980636437265, -0.10437011718750001],
        [51.499980636437265, -0.10437011718750001],
        [51.499980636437265, -0.10437011718750001]
      ]
    };
  },
  mounted() {
    this.map = this.$utils.map.createMap("map-container");
    this.map.setView([51.505, -0.09], 14);
    this.$utils.map.createTileLayer(this.map, this.OSMUrl, {});
    let existLineOpts = {
      color: "rgba(255, 58, 0, 1)",
      weight: 4,
      opacity: 1,
      // 是否显示量测信息
      showMeasurements: true,
      // 量测信息的属性:
      measurementOptions: { 
          minDistance: 30 // 显示 最小的线长度为30m(默认),小于此长度则不显示
      }
    };
      
    this.$utils.map.createPolyline(this.map, this.existLine, existLineOpts);

    let existPolygonOpts = {
      color: "rgba(0, 58, 255, 0.85)",
      weight: 2,
      opacity: 0.85,
      // 是否显示量测信息
      showMeasurements: true,
      // 量测信息的属性:
      measurementOptions: { 
          showOnHover: true // 开始鼠标移动到图形上时显示量测信息
      }
    };
    this.$utils.map.createPolygon(
      this.map,
      this.existLinePolygon,
      existPolygonOpts
    );
  }
};
</script>
<style lang="less">
.map-container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;

  #map-container {
    width: 100%;
    height: 100%;
  }
}
</style>
复制代码

此外,插件还提供了 formatDistanceformatDistance 用来自定义量测结果的标注样式。

3)动态量测

动态量测的关键仍是在图形绘制上。如下的实现方式是在基于之前的绘制功能实现的。若是不熟悉绘制功能的实现方式,请移步至: Vue-CLI and Leaflet(6): 线 绘制Vue CLI and Leaflet (7) 面绘制

实现关键是,在绘制图形的绘制工程中对全部须要建立的图形像上面同样设置正确的 showMeasurements: true, measurementOptions: { ... } 属性。为了让文章过长,如下以距离量测做为代码示例, 完整量测功能请参看在 github 中参看源码:

新增 量测开关组件 组件。

// src\components\MapMeasureDistance.vue
<template>
  <div class="map-tool-measure">
    <ul>
      <li @click="$emit('polyline')">动态线-量测</li>
      <li @click="$emit('showMeasurements')">显示-量测结果</li>
      <li @click="$emit('hideMeasurements')">隐藏-量测结果</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "map-measure-dsitance"
};
</script>
<style lang="less">
.map-tool-measure {
  position: absolute;
  right: 15px;
  top: 15px;
  z-index: 999;

  height: 36px;
  box-shadow: 0px 0px 50px 2px rgba(0, 0, 0, 0.35);
  background-color: #fff;
  ul {
    display: flex;
    padding: 0;
    margin: 0;
    list-style: none;

    li {
      padding: 0 15px;
      height: 36px;
      font-size: 13px;
      line-height: 36px;
      cursor: pointer;
    }

    li:hover {
      background-color: rgb(212, 224, 246);
    }
  }
}
</style>
复制代码

新增 距离量测组件 组件

// src\views\MeasureDistance.vue

<template>
  <div class="map-container">
    <div id="map-container"></div>
    <MapMeasureDistance
      @polyline="measurePolyline"
      @showMeasurements="showMeasurements"
      @hideMeasurements="hideMeasurements"
    ></MapMeasureDistance>
  </div>
</template>

<script>
import MapMeasureDistance from "@/components/MapMeasureDistance.vue";

export default {
  name: "map-point",
  components: { MapMeasureDistance },
  data() {
    return {
      map: null,
      OSMUrl: "http://tile.osm.org/{z}/{x}/{y}.png",
      overLayer: {
        polylines: [],
        polygons: [],
        measurements: []
      },
      tempGp: {
        lineNode: [],
        lineNodeLen: 0,
        tempLine: null,
        tempNode: []
      }
    };
  },
  mounted() {
    this.map = this.$utils.map.createMap("map-container");
    this.map.setView([51.505, -0.09], 14);
    this.$utils.map.createTileLayer(this.map, this.OSMUrl, {});
  },
  methods: {
    drawOn() {
      this.clearTemps();
      this.map.doubleClickZoom.disable();

      // 移除监听地图事件
      this.map.off("click");
      this.map.off("mousemove");
      this.map.off("dblclick");
    },
    drawOff() {
      // 移除监听地图点击事件
      this.map.off("click");
      this.map.off("mousemove");
      this.map.off("dblclick");
      this.map.doubleClickZoom.enable();

      // 复原鼠标平移样式
      this.$utils.map.removerCoursorStyle(this.map);
    },
    clearTemps() {
      // 清空面中间数据
      this.tempGp.lineNode = [];
      this.tempGp.lineNodeLen = 0;
      if (this.tempGp.tempLine) this.tempGp.tempLine.remove();
      this.tempGp.tempNode.map(el => el.remove());
    },
    measurePolyline() {
      this.$utils.map.addCursorStyle(this.map, "crosshare-cursor");
      this.drawOn();

      let tempPolygonOpts = {
        color: "rgba(255, 0, 0, 0.85)",
        weight: 3,
        opacity: 0.85,
        // 添加量测信息属性,并开启
        showMeasurements: true,
        // 根据须要设置量测显示的参数
        measurementOptions: { minDistance: 500 }
      };

      let finalPolygonOpts = {
        color: "rgba(0, 255, 0, 0.85)",
        weight: 3,
        opacity: 0.85,
          // 同上
         // 添加量测信息属性,并开启
        showMeasurements: true,
         // 根据须要设置量测显示的参数
        measurementOptions: { minDistance: 500 }
      };
      this.map.on("click", evt => {
        this.tempGp.lineNode.push([evt.latlng.lat, evt.latlng.lng]);
        this.tempGp.tempNode.push(this.addNode(evt.latlng, this.map));
        this.tempGp.lineNodeLen = this.tempGp.lineNode.length;
      });

      this.map.on("mousemove", evt => {
        if (this.tempGp.lineNodeLen >= 1) {
          if (this.tempGp.tempLine) this.tempGp.tempLine.remove();
          this.tempGp.lineNode[this.tempGp.lineNodeLen] = [
            evt.latlng.lat,
            evt.latlng.lng
          ];

          this.tempGp.tempLine = this.$utils.map.createPolyline(
            this.map,
            this.tempGp.lineNode,
            tempPolygonOpts
          );
        }
      });

      this.map.on("dblclick", () => {
        let polyline = this.$utils.map.createPolyline(
          this.map,
          this.tempGp.lineNode,
          finalPolygonOpts
        );
        this.overLayer.polylines.push(polyline);
        this.clearTemps();
      });
    },
    addNode(latlng, map) {
      let node = this.$utils.map.createIcon({
        iconUrl: require("./../assets/images/node.png"),
        iconSize: [10, 10]
      });
      node = this.$utils.map.createMakerByLatlng(latlng, {
        icon: node
      });
      node.addTo(map);
      return node;
    },
    showMeasurements() {
      this.overLayer.polylines.map(el => el.showMeasurements());
    },
    hideMeasurements() {
      this.overLayer.polylines.map(el => el.hideMeasurements());
    }
  }
};
</script>
<style lang="less">
.map-container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;

  #map-container {
    width: 100%;
    height: 100%;
  }
}
</style>
复制代码

这样动态量测功能就实现了。

dynamic-measurement2

4)控制量测信息的显示与隐藏

leaflet-measure-path 插件 提供了 showMeasurements,hideMeasurements 方法,可实现量测信息的显示控制。使用方法为:

// feature 为已经加载在地图中的 线,面或圆 图形要素
// measurementOptions 即上文使用过的量测显示属性
feature.showMeasurements(measurementOptions)
feature.hideMeasurements()

复制代码

在上文 2)动态量测 中提供了使用实例,效果以下:

dynamic-measurement3

3、总结

以上就是量测功能的介绍。 leaflet-measure-path 插件,目前是我以为最为简单好用的基于 leaflet.js 的图形量测插件了。文章实例相对来说是比较简单的,主要是没有具体的业务需求。但我相信掌握了这个量测插件的使用方法再结合实际业务需求,必定能实现很是丰富高效的功能。

若是有任何错误或疏漏,请各位多多指教。

目录

(一) Vue-CLI and Leaflet:起步 - 在 Vue-CLI 中使用 Leaflet

(二) Vue-CLI and Leaflet:地图基本操做(放大,缩小,平移,定位等)

(三) Vue-CLI and Leaflet: 添加 marker, polyline, polygon

(四) Vue-CLI and Leaflet: 添加 tooltips 和 popup

(五) Vue-CLI and Leaflet: 点 绘制

(六) Vue-CLI and Leaflet: 线 绘制

(七) Vue-CLI and Leaflet: 面 绘 制

(八) Vue-CLI and Leaflet :加载 Esri ArcGIS Map Service

(九) Vue-CLI and Leaflet: 图层控制基本功能的实现

(十) Vue-CLI and Leaflet: AGS 属性查询与点图查询

(十一)Vue-CLI and Leaflet: 点聚合 Leaflet.markercluster

源码请参看 个人GitHub,因为文章是一边coding,一边写的因此 Github 里面的源码可能有点乱,能够根据功能来找对应的代码。后面会陆续整理完善。

相关文章
相关标签/搜索