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

1、概述

接着上一篇文章,这里介绍 线绘制 的功能。Leaflet 中由于没有图层渲染的相关类,因此再图形上没有Geometry 和 Graphic 这两个概念没有很明确的划分。这样使得在完成图像功能时,代码会简单了许多。如上一篇文章讲到的提到的**点,线,面的绘制的关键在于根据用户在的操做上的操做去获取正确的坐标,并将这些坐标组织为不一样要素类型数据。**三种类型的要素的绘制中相同的地方在于都必须监测到用户在地图上所作到操做,不一样在于对用户操做结果的响应。javascript

1、功能分析

line-flowwork

线绘制功能流程图

线绘制功能 在绘制的完整流程如上图所示。其中有几个地方,按照个人对功能理解与设计,我以为下面几处须要简单说明一下。vue

1. 橡皮筋效果

橡皮筋效果,其实是在一条线段尚未绘制完成以前,将已有节点与鼠标当前位置链接起来的实时预览。其实,这个效果不是必须的。为了对用户更加友好,几乎全部关于绘制的功能,包括二维和三维的GIS 平台的,都将会提供这样的效果。java

elastic

2. 取消和完成绘制

取消,是结束以前,用户若是不想保留当前结果并推出绘制状态。node

完成绘制,保留当前绘制结果不退出绘制状态。git

*这里是指个人功能设计你将看到的状况。github

2、代码实现

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

代码仍是在上一篇文章提到的 MapDraw.vuemap.js 、和新建的Polyline.vue 中。先看看全部代码,再对某些部分进行说明。为了使文章和源码的能 一 一对应,我这里把 Point 和 Polygon 暂时屏蔽掉了。less

// 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) 新添加一个视图 Polyline.vue

// src\views\Polyline.vue
<template>
  <div class="map-container">
    <div id="map-container"></div>
    <MapDraw @point="{}" @polyline="drawPolyline" @polygon="{}" @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: {
        polylines: []
      },
      tempGp: {
        lineNode: [],
        lineNodeLen: 0,
        tempLine: null,
        tempNode: []
      }
    };
  },
  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);
    },
    drawPolyline() {
      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.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", () => {
        this.overLayer.polylines.push(
          this.$utils.map.createPolyline(
            this.map,
            this.tempGp.lineNode,
            finalPolygonOpts
          )
        );
        this.tempGp.lineNode = [];
        this.tempGp.lineNodeLen = 0;
        this.tempGp.tempLine.remove();
        this.tempGp.tempNode.map(el => el.remove());
      });
    },
    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;
    }
  }
};
</script>
<style lang="less">
.map-container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;

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

复制代码

以上绘制的线的全部代码,实现起来其实比较简单。下面我选择一些我以为须要说明的地方解释,ssh

1) data 中的临时数据

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

所以 ,绘制过程当中必须会产生用以辅助的中间数据,须要在data提早定义好

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

复制代码

2)绘制代码说明

drawPolyline() {
    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.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 => {
        // 第一次点击时地图上只现实第一个节点
        // 从第二次开始到绘制结束以前,无论用户添加了多少个点,鼠标移动时须要去跟新当 
        // this.tempGp.lineNode 中的第 n+1 个 这样来实现橡皮筋效果
        if (this.tempGp.lineNodeLen >= 1) {
            // 移除上一个图形
            if (this.tempGp.tempLine) this.tempGp.tempLine.remove();
            // 第n+1个点的索引为 this.tempGp.lineNodeLen + 1
            // 只要在下一次点击事件发生前,this.tempGp.lineNodeLen + 1 都同样
            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", () => {
        this.overLayer.polylines.push(
            this.$utils.map.createPolyline(
                this.map,
                this.tempGp.lineNode,
                finalPolygonOpts
            )
        );

        // 重置临时数据
        this.tempGp.lineNode = [];
        this.tempGp.lineNodeLen = 0;
        this.tempGp.tempLine.remove();
        this.tempGp.tempNode.map(el => el.remove());
    });
}
复制代码

最终效果:

三)总结

绘制线功能自己时很简单的,初学者最容易卡住的地方在于橡皮筋效果的实现这一步上。实现上面的功能以前必定要对 leaflet 中的 map, markerpolyline 等对象的 构造方法,属性,事件等基础信息要有必定的了解。同时要必定要弄清实现的思路,这样才能触类旁通,之后再处理相似功能就熟练了。




目录

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

相关文章
相关标签/搜索