“This is the fifth day of my participation in the November Gwen Challenge. See details of the event: The Last Gwen Challenge 2021”.

preface

Due to the recent needs of the project, IT is necessary to use OpenLayers in the VUE project to develop GIS map. There are not many articles on OpenLayers on the Internet, so I would like to take this opportunity to share some of my experience in the actual use of the project.

This series will share some of the feature points implemented over the course of the project.

This article continues with the previous vue+OpenLayers project practice (4) : Setting up the fence, and continues to explain the function points of the fence.

The specific implementation

Functions to be implemented in this article:

  • Design and parse the data storage format of the fence
  • Handling repeated drawing
  • View the History fence

Design data formats

The function of drawing the fence has been completed in the last article, so how to store the drawn fence information for subsequent use? In the last article, we reserved a method to save the fence data, so we will continue to improve this part of the code.

handleSave() {
  / / save
},
Copy the code

Here we add a new method called drawEnd that listens to parse the data when the drawing is complete:

// Finish drawing the parse structure
drawEnd(evt) {
  let geo = evt.feature.getGeometry();
  let type = geo.getType(); // Get the type
  const handle = {
    Circle: () = > {
      // Get the center point and radius
      let center = geo.getCenter();
      let radius = geo.getRadius();
      this.circleInfo = {
        center: center,
        radius: parseInt(radius),
      };
    },
    Polygon: () = > {
      // get the coordinates
      let points = geo.getCoordinates();
      this.polygonPath = points[0]; }};if (handle[type]) handle[type]();
},
Copy the code

A handle object is defined to handle the drawn data. The circle stores the center point and radius to this.circleInfo, and the polygon stores the point path to this.polygonPath. Register listening in addInteraction:

this.fenceDraw.on("drawend".(e) = > {
  // Draw the completed callback
  this.drawEnd(e);
});
Copy the code

Take a look at the print:

It can be seen that the fence information has been obtained, but the coordinates are not common longitude and latitude information, so we will conduct data processing when saving.

Start by defining the data handler function

import * as olProj from "ol/proj";
// Data processing
formatFenceData() {
  const handle = {
    Circle: () = > {
      if (!this.circleInfo) {
        this.$message.error(this.$t("lan_map.lan_map_fences.pdrwf"));
        return;
      }
      const center = this.circleInfo.center;
      const radius = this.circleInfo.radius;
      const p = olProj.toLonLat(center);
      return `Circle (${p[0]} ${p[1]}.${radius}) `;
    },
    Polygon: () = > {
      if (this.polygonPath.length === 0) {
        this.$message.error(this.$t("lan_map.lan_map_fences.pdrwf"));
        return;
      }
      const path = this.polygonPath;
      const pathArr = [];
      path.forEach((item) = > {
        const p = olProj.toLonLat(item);
        pathArr.push(`${p[0]} ${p[1]}`);
      });
      return `Polygon (${pathArr.join(",")}) `; }};const type = this.tool;
  if (handle[type]) {
    returnhandle[type](); }},Copy the code

Circle (${p[0]} ${p[1]}, ${radius}) and Polygon (${patharr.join (“, “)})

Circle (107.62493031295215, 33.55224298744986, 21716)

Polygon (107.60051625976537 33.56038110614992, 107.71404159451102 33.612243570978194, 107.77995947944197, 33.47591089982609)

Finally modify the handleSave method, here is stored locally, XDM can directly adjust the back end of the interface to store the fence information, this paper is directly stored in the local VUex, vuex added without more explanation, front-end base operation. Interested can directly look at the source code.

handleSave() {
  / / save
  if (!this.name) {
    this.$message.error("Please enter fence name");
    return;
  }
  const area = this.formatFenceData();
  if (area) {
    let data = {
      name: this.name,
      area: area,
    };
    // Can call the backend API to save, this article directly stored in the local vuex
    this.addFences(data); }},Copy the code

Handling repeated drawing

In the process of using it, we found that multiple overlapping areas could be drawn when drawing the fence, which was obviously not what we wanted. For example, when we finished drawing a circle, we did not allow overlap to draw a circle, but empty and draw a new one.

The method mapOnly needs to be added

addInteraction() {
  this.fenceDraw = new Draw({
    source: this.fenceSource,
    type: this.tool,
  });
  this.openMap.addInteraction(this.fenceDraw);
  this.fenceDraw.on("drawend".(e) = > {
    // Draw the completed callback
    this.drawEnd(e);
  });
  // Check for duplicate drawing
  this.mapOnly();
},

mapOnly() {
  this.fenceDraw.on("drawstart".() = > {
    if (this.tool === "Polygon") {
      Delete the previous geometry if it already exists
      if (this.polygonPath)
        this.fenceSource.clear() && (this.polygonPath = []);
    } else {
      if (this.circleInfo)
        this.fenceSource.clear() && (this.circleInfo = null); }}); },Copy the code

Only one circle/polygon can be drawn when the fence is drawn.

View the History fence

OK, the above are the functions of the newly added fence, so the new purpose is to view the historical fence records after storage, and the function of viewing will be implemented now.

// Home.vue obtains fence data from vuex
computed: {
  ...mapGetters(["fences"]),},Copy the code

We need to add a drop down in the bottom right corner to toggle the display fence as we did with the map. Refer to vue+OpenLayers project practice (2) : Switching between multiple maps

<! -- Map fence --><el-select v-model="fence" style="width: 150px">
  <el-option
    label="Do not show the fence"
    value="1"
    key="1"
    @click.native="handleSelectFence(null)"
  ></el-option>
  <el-option
    v-for="(item, index) in fences"
    :label="item.name"
    :value="item.name"
    :key="index"
    @click.native="handleSelectFence(item)"
  ></el-option>
</el-select>
Copy the code
data(){
  return{...fence: null,}}...// Display the fence
handleSelectFence() {},
Copy the code

Next, implement handleSelectFence and draw the fence on the map.

First add the data conversion function

// Fence data conversion
areaFomart(area) {
  // eslint-disable-next-line
  const point = area.match(/ [^ \] (\) + (? =\))/g) [0].split(",");
  if (area.match("Circle")) {
    return {
      type: "Circle".center: olProj.fromLonLat(point[0].split("")),
      radius: Number(point[1]),}; }if (area.match("Polygon")) {
    const path = [];
    point.forEach((item) = > {
      path.push(olProj.fromLonLat(item.split("")));
    });
    return {
      type: "Polygon".path: path, }; }}Copy the code

Modify the handleSelectFence method

// Display the fence
handleSelectFence(data) {
  // Clear the previous fence when switching
  if (this.fenceVector) {
    this.openMap.removeLayer(this.fenceVector);
  }
  if(! data) {this.fence = null;
    return false;
  }
  // Data conversion
  const area = this.areaFomart(data.area);
  // Draw the fence
  this.setFenceSource(area);
},
Copy the code

setFenceSource

// Draw the fence
setFenceSource(area) {
  let feature;
  switch (area.type) {
    case "Circle": {
      feature = new Feature(new gCircle(area.center, area.radius));
      break;
    }
    case "Polygon": {
      feature = new Feature(new Polygon([area.path]));
      break;
    }
    default:
      break;
  }
  // Zoom to the fenced area
  this.mapFit(feature.getGeometry());
  // Vector layer
  let source = new VectorSource({
    features: [feature],
  });
  let vector = new VectorLayer({
    source,
    style: new Style({
      fill: new Fill({
        color: "Rgba (49173252, 0.2)",}).stroke: new Stroke({
        color: "#0099FF".width: 3,}).image: new sCircle({
        radius: 7.fill: new Fill({
          color: "#0099FF",}),}),}),});this.fenceVector = vector;
  this.openMap.addLayer(vector);
},
// Scale by boundaries
mapFit(extent) {
  this.openMap
    .getView()
    .fit(extent, { duration: 1000.padding: [200.200.200.200]}); },Copy the code

The mapFit method can automatically zoom the map to the fence.

OK, all functions related to the fence have been implemented. The following is the final effect:

Past Catalogue:

  1. Vue +OpenLayers Project Practice (I) : Basic drawing and clicking pop-ups

  2. Vue +OpenLayers Project Practice (2) : Switching between multiple maps

  3. Vue +OpenLayers Project Practice (3) : Cluster

  4. Vue +OpenLayers Project Practice 4: Set up a fence

The last

Gitee address: gitee.com/shtao_056/v…

Thank you for reading

It would be a great honor if I could help you.

In the future, more functions will be updated, as well as some problems encountered in the project, interested partners can click favorites/follow.