Vue CLI and Leaflet (7)面绘制

1、功能分析

polygon-workflow

面图形绘制流程

面绘制功能用户的操做方式和线绘制功能几乎是如出一辙的。不一样在于对用户操做的响应的部分。二响应部分只有两处不一样。javascript

1)当用户添加的点数为1时,地图上的显示线状橡皮筋效果。

Elasic Polyline

线状橡皮筋效果

2)当用户添加的点数大于2时,地图上的显示线状橡皮筋效果。

Elistic Polygon

2、代码实现

*全部的代码都是在第一章的项目结构中添加或者修改的。vue

代码仍是在上一篇文章提到的 MapDraw.vuemap.js 、和新建的Polygon.vue 中。先看看全部代码,再对某些部分进行说明。java

// src\components\MapDraw.vue

<template>
  <div class="map-tools">
    <ul>
      <li :class="[{active: activeTool == 'point'}]" @click="point">Point</li>
      <li :class="[{active: activeTool == 'polyline'}]" @click="polyline">Polyline</li>
      <li :class="[{active: activeTool == 'polygon'}]" @click="polygon">Polygon</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "mapDraw",
  data() {
    return {
      activeTool: ""
    };
  },
  methods: {
    point() {
      if (this.activeTool !== "point") {
        this.activeTool = "point";
        this.$emit("point");
      } else {
        this.activeTool = "";
        this.$emit("end");
      }
    },
    polyline() {
      if (this.activeTool !== "polyline") {
        this.activeTool = "polyline";
        this.$emit("polyline");
      } else {
        this.activeTool = "";
        this.$emit("end");
      }
    },
    polygon() {
      if (this.activeTool !== "polygon") {
        this.activeTool = "polygon";
        this.$emit("polygon");
      } else {
        this.activeTool = "";
        this.$emit("end");
      }
    }
  }
};
</script>
<style lang="less">
.map-tools {
  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.active {
      background-color: rgb(102, 156, 255);
      color: #fff;
    }
    li:hover {
      background-color: rgb(212, 224, 246);
    }
  }
}
</style>

复制代码

2) 新添加一个视图 Polygon.vue

为了使文章和源码的能 一 一对应,我这里把 Point 和 Polyline 暂时屏蔽掉了。node

// src\views\Polygon.vue
<template>
  <div class="map-container">
    <div id="map-container"></div>
    <MapDraw @point="{}" @polyline="{}" @polygon="drawPolygon" @end="drawOff"></MapDraw>
  </div>
</template>

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

export default {
  name: "map-point",
  components: { MapDraw },
  data() {
    return {
      map: null,
      OSMUrl: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
      overLayer: {
        polygons: []
      },
      tempGp: {
        polygonNode: [],
        polygonNodeLen: 0,
        tempNode: [],
        tempPolygon: null
      }
    };
  },
  mounted() {
    this.map = this.$utils.map.createMap("map-container");
    this.$utils.map.createTileLayer(this.map, this.OSMUrl, {});
    this.map.setView([51.505, -0.09], 13);
  },
  methods: {
    drawOn() {
      // 移除监听地图事件
      this.map.off("click");
      this.map.off("mousemove");
      this.map.off("dblclick");
      this.map.doubleClickZoom.disable();
    },
    drawOff() {
      // 移除监听地图点击事件
      this.map.off("click");
      this.map.off("mousemove");
      this.map.off("dblclick");
      this.map.doubleClickZoom.enable();

      // 复原鼠标平移样式
      this.$utils.map.removerCoursorStyle(this.map);
    },
    drawPoint() {
      this.drawOn();

      this.$utils.map.addCursorStyle(this.map, "pointer-cursor");
      this.map.on("click", evt => {
        this.$utils.map.createMakerByLatlng(evt.latlng).addTo(this.map);
      });
    },
    addNode(latlng, map) {
      let node = this.$utils.map.createIcon({
        iconUrl: require("./../assets/images/node.png"),
        iconSize: [16, 16]
      });
      node = this.$utils.map.createMakerByLatlng(latlng, {
        icon: node
      });
      node.addTo(map);
      return node;
    },
    drawPolygon() {
      this.$utils.map.addCursorStyle(this.map, "crosshare-cursor");

      let tempPolygonOpts = {
        color: "rgba(255, 0, 0, 0.85)",
        weight: 3,
        opacity: 0.85
      };

      let finalPolygonOpts = {
        color: "rgba(0, 255, 0, 0.85)",
        weight: 3,
        opacity: 0.85
      };

      this.drawOn();

      this.map.on("click", evt => {
        this.tempGp.polygonNode.push([evt.latlng.lat, evt.latlng.lng]);
        this.tempGp.polygonNodeLen = this.tempGp.polygonNode.length;

        this.tempGp.tempNode.push(this.addNode(evt.latlng, this.map));
      });

      this.map.on("mousemove", evt => {
        if (this.tempGp.tempPolygon) this.tempGp.tempPolygon.remove();

        if (this.tempGp.polygonNodeLen == 1) {
          this.tempGp.polygonNode[this.tempGp.polygonNodeLen] = [
            evt.latlng.lat,
            evt.latlng.lng
          ];
          this.tempGp.tempPolygon = this.$utils.map.createPolyline(
            this.map,
            this.tempGp.polygonNode,
            tempPolygonOpts
          );
        } else if (this.tempGp.polygonNodeLen >= 2) {
          this.tempGp.polygonNode[this.tempGp.polygonNodeLen] = [
            evt.latlng.lat,
            evt.latlng.lng
          ];

          this.tempGp.tempPolygon = this.$utils.map.createPolygon(
            this.map,
            this.tempGp.polygonNode,
            tempPolygonOpts
          );
        }
      });

      this.map.on("dblclick", () => {
        this.overLayer.polygons.push(
          this.$utils.map.createPolygon(
            this.map,
            this.tempGp.polygonNode,
            finalPolygonOpts
          )
        );
        this.tempGp.polygonNode = [];
        this.tempGp.polygonNodeLen = 0;
        this.tempGp.tempPolygon.remove();
        this.tempGp.tempNode.map(el => el.remove());
      });
    }
  }
};
</script>
<style lang="less">
.map-container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;

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

以上绘制的面的全部代码,几乎和线绘制代码同样,仍是对其中的一些数据作简要的说明git

1) data 中的临时数据

绘制的过程,实际上是不断的删除线和添加线的过程,只要监听到坐标变化就删掉上一个图形,绘制新的图形。github

...... 
overLayer: {
    polygon: []   // 存放最终完成绘制后产生的面对象
},
tempGp: {
    polygonNode: [],   // 绘制过程当中用于生成面图形的坐标串
    polygonNodeLen: 0, // 已添加节点数量
    tempPolygon: null, // 绘制完成前地图上的线对象
    tempNode: []    // 每次单击产生的节点对象
}
......

复制代码

2)绘制代码说明

drawPolygon() {
    this.$utils.map.addCursorStyle(this.map, "crosshare-cursor");
    // 绘制过程当中的面样式
    let tempPolygonOpts = {
        color: "rgba(255, 0, 0, 0.85)",
        weight: 3,
        opacity: 0.85
    };
    // 完成绘制的面样式,能够和上面的绘制过程当中的面样式相同,但这里为了区分,取了颜色
    let finalPolygonOpts = {
        color: "rgba(0, 255, 0, 0.85)",
        weight: 3,
        opacity: 0.85
    };

    this.drawOn();
    // 每一次点击都视为用户为想要绘制的面添加了一个节点
    // 全部用户采集的点将会组织成按面的数据结构组织(其实和线是同样的)-- 一组坐标串


    this.map.on("click", evt => {
        this.tempGp.polygonNode.push([evt.latlng.lat, evt.latlng.lng]);
        this.tempGp.polygonNodeLen = this.tempGp.polygonNode.length;
        // 更新已添加节点数量
        this.tempGp.tempNode.push(this.addNode(evt.latlng, this.map));
    });

    this.map.on("mousemove", evt => {
        // 下一次绘制前,从map中移除掉上一次产生的图形
        if (this.tempGp.tempPolygon) this.tempGp.tempPolygon.remove();
		// 当添加的节点的数量为1时,显示线状橡皮筋效果
        if (this.tempGp.polygonNodeLen == 1) {
            // 橡皮筋效果的关键就是,随鼠标移动更新图形的 n+1 个节点的位置
            // 而第 n+1 个点的索引为 节点的数量
            this.tempGp.polygonNode[this.tempGp.polygonNodeLen] = [
                evt.latlng.lat,
                evt.latlng.lng
            ];
            this.tempGp.tempPolygon = this.$utils.map.createPolyline(
                this.map,
                this.tempGp.polygonNode,
                tempPolygonOpts
            );
        } else if (this.tempGp.polygonNodeLen >= 2) {
            // 当添加的节点的数量 >= 2时,显示面状橡皮筋效果
            this.tempGp.polygonNode[this.tempGp.polygonNodeLen] = [
                evt.latlng.lat,
                evt.latlng.lng
            ];

            this.tempGp.tempPolygon = this.$utils.map.createPolygon(
                this.map,
                this.tempGp.polygonNode,
                tempPolygonOpts
            );
        }
    });

    this.map.on("dblclick", () => {
        // 绘制最终的面图形,并保存
        this.overLayer.polygons.push(
            this.$utils.map.createPolygon(
                this.map,
                this.tempGp.polygonNode,
                finalPolygonOpts
            )
        );
        // 清空全部中间数据
        this.tempGp.polygonNode = [];
        this.tempGp.polygonNodeLen = 0;
        this.tempGp.tempPolygon.remove();
        this.tempGp.tempNode.map(el => el.remove());
    });
}
复制代码

最终效果: bash

DrawPolygon

三)总结

由于在线绘制和面绘制功能很是类似,因此这篇文章你看到的内容和上一篇的变化不大。leaflet 对点、线、面的自定义样式支持的很好,在绘制的时候,若是想要绘制更好看的 面,线,面要素,必定要对其构造方法与其相关属性足够属性。数据结构

更复杂的功能如绘制复合线要素复合面要素 的思路也是基于这些简单要素绘制来实现的。一样的,地图上的距离,和面积量测一样也是要求先实现图形绘制功能。下一篇文章将为你们介绍 地图量测功能的实现。less

目录

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

(二) 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 里面的源码可能有点乱,能够根据功能来找对应的代码。后面会陆续整理完善。

相关文章
相关标签/搜索