I. Functional analysis

Surface drawing function Users operate in almost the same way as line drawing function. The difference lies in the part that responds to user actions. There are only two differences in the response part.

1) When the user adds 1 points, the map shows the effect of linear rubber bands.

2) When the user adds more than 2 points, the map shows the effect of linear rubber bands.

Two, code implementation

* All code was added or modified in the project structure of Chapter 1.

The code is still in mapdraw.vue, map.js, and the newly created Polygon.vue mentioned in the previous article. Take a look at all the code and then explain some parts.

// 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>

Copy the code

2) Add a new view polygon.vue

In order to make the article and source code consistent, I have temporarily blocked the Point and Polyline.

// 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() {// Remove the listener map event this.map.off("click");
      this.map.off("mousemove");
      this.map.off("dblclick");
      this.map.doubleClickZoom.disable();
    },
    drawOff() {// Remove the listener map click event this.map.off("click");
      this.map.off("mousemove");
      this.map.off("dblclick"); this.map.doubleClickZoom.enable(); // Undo the mouse pan style 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)"Opacity: 0.85};let finalPolygonOpts = {
        color: "Rgba (0, 255, 0, 0.85)"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>
Copy the code

All of the above code, almost like the line drawing code, is a brief description of some of the data

1) Temporary data in data

In fact, the process of drawing is the process of constantly deleting lines and adding lines. As long as the coordinate changes are monitored, the previous graph will be deleted and a new graph will be drawn.

. overLayer: {polygon: []   // Store the face object generated after the final drawing
},
tempGp: {
    polygonNode: [].// The coordinate string used to generate the surface graph during the drawing process
    polygonNodeLen: 0.// Number of added nodes
    tempPolygon: null.// Draw line objects on the map before completion
    tempNode: []    // The node object generated by each click}...Copy the code

2) Draw code description

drawPolygon() {
    this.$utils.map.addCursorStyle(this.map, "crosshare-cursor");
    // The face style in the drawing process
    let tempPolygonOpts = {
        color: "Rgba (255, 0, 0, 0.85)".weight: 3.opacity: 0.85
    };
    // The finished surface style can be the same as the surface style in the drawing process above, but the color is used here for differentiation
    let finalPolygonOpts = {
        color: "Rgba (0, 255, 0, 0.85)".weight: 3.opacity: 0.85
    };

    this.drawOn();
    // Each click counts as adding a node to the surface the user wants to draw
    // All points collected by the user will be organized into a data structure based on faces (actually the same as lines) -- a series of coordinates


    this.map.on("click", evt => {
        this.tempGp.polygonNode.push([evt.latlng.lat, evt.latlng.lng]);
        this.tempGp.polygonNodeLen = this.tempGp.polygonNode.length;
        // Update the number of added nodes
        this.tempGp.tempNode.push(this.addNode(evt.latlng, this.map));
    });

    this.map.on("mousemove", evt => {
        // Remove the last generated graph from the map before the next drawing
        if (this.tempGp.tempPolygon) this.tempGp.tempPolygon.remove();
		// When the number of nodes added is 1, the linear rubber band effect is displayed
        if (this.tempGp.polygonNodeLen == 1) {
            // The key to the rubber band effect is to update the position of n+1 nodes of the graph as the mouse moves
            // The index of the n+1 point is the number of nodes
            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) {
            // When the number of nodes added is greater than = 2, the elastic effect is displayed
            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", () = > {// Draw the final face shape and save it
        this.overLayer.polygons.push(
            this.$utils.map.createPolygon(
                this.map,
                this.tempGp.polygonNode,
                finalPolygonOpts
            )
        );
        // Clear all intermediate data
        this.tempGp.polygonNode = [];
        this.tempGp.polygonNodeLen = 0;
        this.tempGp.tempPolygon.remove();
        this.tempGp.tempNode.map(el= > el.remove());
    });
}
Copy the code

End result:

3) the summary

Because online drawing and surface drawing functions are very similar, what you see in this article is not much different from what you saw in the previous article. The leaflet supports the custom styles of points, lines and planes well. When drawing, if you want to draw more attractive surface, line and plane elements, you must have enough attributes for its constructors and related attributes.

More complex functions such as drawing composite line elements, the idea of composite surface elements is also based on these simple elements to draw to achieve. Similarly, distance and area measurement on the map also require the realization of graph drawing function first. The next article will introduce the implementation of map measurement function.

directory

Vue-cli and Leaflet: Start using the Leaflet in VUe-CLI

(2) VUE-CLI and Leaflet: basic map operations (zoom in, zoom out, translation, positioning, etc.)

Vue-cli and Leaflet: Add marker, polyline, polygon

Vue-cli and Leaflet: Add tooltips and popup

Vue-cli and Leaflet: point drawing

Vue-cli and Leaflet: line drawing

(7) VuE-CLI and Leaflet: surface painting system

Vue-cli and Leaflet: Load Esri ArcGIS Map Service

(9) VUE-CLI and Leaflet: layer control implementation of basic functions

(10) VUE-CLI and Leaflet: AGS attribute query and point map query

Vue-cli and Leaflet: point aggregation leaflet. markerCluster

Please refer to my GitHub for the source code. Since the article is written at the same time as coding, the source code in GitHub may be a little confused, you can find the corresponding code according to the function. Later will be sorted out and improved.