面繪製功能用戶的操做方式和線繪製功能幾乎是如出一轍的。不一樣在於對用戶操做的響應的部分。二響應部分只有兩處不一樣。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 裏面的源碼可能有點亂,能夠根據功能來找對應的代碼。後面會陸續整理完善。