面绘制功能用户的操做方式和线绘制功能几乎是如出一辙的。不一样在于对用户操做的响应的部分。二响应部分只有两处不一样。javascript
*全部的代码都是在第一章的项目结构中添加或者修改的。vue
代码仍是在上一篇文章提到的 MapDraw.vue
、map.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>
复制代码
为了使文章和源码的能 一 一对应,我这里把 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
绘制的过程,实际上是不断的删除线和添加线的过程,只要监听到坐标变化就删掉上一个图形,绘制新的图形。github
......
overLayer: {
polygon: [] // 存放最终完成绘制后产生的面对象
},
tempGp: {
polygonNode: [], // 绘制过程当中用于生成面图形的坐标串
polygonNodeLen: 0, // 已添加节点数量
tempPolygon: null, // 绘制完成前地图上的线对象
tempNode: [] // 每次单击产生的节点对象
}
......
复制代码
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
由于在线绘制和面绘制功能很是类似,因此这篇文章你看到的内容和上一篇的变化不大。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 :加载 Esri ArcGIS Map Service
(九) Vue-CLI and Leaflet: 图层控制基本功能的实现
(十) Vue-CLI and Leaflet: AGS 属性查询与点图查询
(十一)Vue-CLI and Leaflet: 点聚合 Leaflet.markercluster
源码请参看 个人GitHub,因为文章是一边coding,一边写的因此 Github 里面的源码可能有点乱,能够根据功能来找对应的代码。后面会陆续整理完善。