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 裏面的源碼可能有點亂,能夠根據功能來找對應的代碼。後面會陸續整理完善。

相關文章
相關標籤/搜索