Vue-CLI and Leaflet (5): 点 绘制

3,943 阅读4分钟

一、功能分析

前面讲了,向地图中添加 marker, polyline, polygon的图形要素。这些功能都是属于比较基础的功能,通常会应用到查询结果或分析结果的展示场景。除此之外,这些基础图形的绘制也是其他高级别功能的基础,例如框选、量测等功能。这章内容就主要讲在地图上实现图像绘制与量测功能。

点,线,面的绘制的关键在于根据用户在的操作上的操作去获取正确的坐标,并将这些坐标组织为不同要素类型数据。三种类型的要素的绘制中相同的地方在于都必须监测到用户在地图上所做到操作,不同在于对用户操作结果的响应。

而监测用户对于地图的操作就是监听 map 对象的 click, dbclick, mouseover 等事件。下面会分要素做功能分析。下面讲的绘制的功能逻辑为是左键单击进行绘制,双击结束绘制。

点要素的绘制非常简单,只需要监听 map 对象的左键单击事件,然后添加点要素就可以了。完整的流程如下图所示。

PiontFlow

二、代码实现

所有的代码都是在第一章的项目结构中添加或者修改的

1)添加地图绘制组件(MapDraw.vue),作为开启绘制的开关。

// src\components\MapDraw.vue

<template>
  <div class="map-tools">
    <ul>
      <li :class="[{active: activeTool == 'point'}]" @click="point">Point</li>
      <li @click="$emit('polyline')">Polyline</li>
      <li @click="$emit('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");
      }
    }
  }
};
</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) 新添加一个视图 Point.vue

// src\views\Point.vue

<template>
  <div class="map-container">
    <div id="map-container"></div>
    <MapDraw @point="drawPoint" @polyline="drawPolyline" @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"
    };
  },
  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(fn) {
      // 监听地图点击事件
      this.map.off("click");
      this.map.on("click", evt => fn(evt));
    },
    drawOff() {
      // 移除监听地图点击事件
      this.map.off("click");
    },
    drawPoint() {
      this.drawOn(evt => {
        this.$utils.map.createMakerByLatlng(evt.latlng).addTo(this.map);
      });
    },
    drawPolyline() {},
    drawPolygon() {}
  }
};
</script>
<style lang="less">
.map-container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;

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

地图开关组件和 Point 页面的时间绑定请不详细介绍了。

以上页面为绘制线、面的功能留出了接口,后面的文章会用到。如果顺利的话你看的效果是如下:

DrawPoint

点绘制很简单。不过有几个细节需要注意。

  1. 绘制开始时,启动对 map 对象的监听,然后点击地图后添加点(即 marker)到地图。在没有结束之前之前,每次点击都应该添加地图上。
  2. 使用 Leaflet 添加默认的 marker 样式时,添加的 maker icon 的左上角为当前所点击的坐标点。
  3. 当地图属于绘制状态时,应该通过改变地图上鼠标样式提高点击的精准度,同时也作为地图状态的标志提升用户体验。
  4. 绘制结束时或切换绘制工具时,地图状态的处理。

接着我们对上述问题依次进行处理。

3) 默认图标的位置的修正

Vue-CLI and Leaflet (3): 添加 marker, polyline, polygon 中提到修复默认图标无法加载显示的问题,我们在map.js 添加了代码,添加上 iconAnchor 属性。[ iconWidth / 2, iconHeight]

// src\utils\map.js

......

// 解决默认 maker 无法显示的问题
import icon from "leaflet/dist/images/marker-icon.png";
import iconShadow from "leaflet/dist/images/marker-shadow.png";
let DefaultIcon = $L.icon({
  iconAnchor: [13, 41],
  iconUrl: icon,
  shadowUrl: iconShadow
});
$L.Marker.prototype.options.icon = DefaultIcon;

......

4) 改变鼠标样式

在 map.js 添加修改样式和还原鼠标样式的代码。

//  src\utils\map.js
......
// 存储鼠标样式
let CursorStyle = "";

......

// 添加鼠标样式
const addCursorStyle = (map, cursorStyle) => {
  CursorStyle = cursorStyle;
  $L.DomUtil.addClass(map._container, cursorStyle);
};
// 移除鼠标样式
const removerCoursorStyle = map => {
  $L.DomUtil.removeClass(map._container, CursorStyle);
};

......

除此之外还需要在全局样式中添加上对应的样式类,并正确调用上面的修改样式的方法才能实现对应的效果。这里我在 assets->style 下添加了一个 leaflet.less,注意添加后要将其引用

// 添加点,鼠标的样式
.leaflet-container.pointer-cursor {
  cursor: pointer;
}

修改 Point.vue,在绘制开始时即监听地图点击事件时修改鼠标样式 // src\views\Point.vue

<template>
  <div class="map-container">
    <div id="map-container"></div>
    <MapDraw @point="drawPoint" @polyline="drawPolyline" @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"
    };
  },
  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(fn) {
      // 监听地图点击事件
      this.map.off("click");
      this.map.on("click", evt => fn(evt));
    },
    drawOff() {
      // 移除监听地图点击事件
      this.map.off("click");
      // 复原鼠标平移样式
      this.$utils.map.removerCoursorStyle(this.map);
    },
    drawPoint() {
      this.$utils.map.addCursorStyle(this.map, "pointer-cursor");
      this.drawOn(evt => {
        this.$utils.map.createMakerByLatlng(evt.latlng).addTo(this.map);
      });
    },
    drawPolyline() {},
    drawPolygon() {}
  }
};
</script>
<style lang="less">
.map-container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;

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

效果如下:

DrawPoint2

5)结束绘制

这里,我结束绘制的功能放在,绘制开关的按钮上的,再次点击Point 按钮,回复移除地图点击事件,复原地图鼠标样式,复原 Point 按钮样式。这样就有一个完成第绘制的功能了。

// src\views\Point.vue => method

drawOff() {
    // 移除监听地图点击事件
    this.map.off("click");
    // 复原鼠标平移样式
    this.$utils.map.removerCoursorStyle(this.map);
}

DrawPoint4

三)总结

以上就是点绘制功能的介绍,本来想点线面一起出的,但是怕文章太长了会不好阅读。所以后面会陆续更新线绘制面绘制等功能。如果有任何建议请各位留言。




目录

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