开发环境:"ol": "^6.5.0", "vue": "^2.6.12", 。node版本:14.18.3
1.将绘制的代码封装成类,olDrawTool.js
import { Feature } from "ol";
import * as olExtent from "ol/extent";
import { GeoJSON } from "ol/format";
import Overlay from "ol/Overlay";
import { Vector as VectorSource } from "ol/source";
import { Vector as VectorLayer } from "ol/layer";
import { Stroke, Style } from "ol/style";
import { Draw, Modify, Snap } from "ol/interaction";
/**
* 绘制多边形工具
* @param {Object} map 地图实例对象
* @param {Object} options 需要的参数
*/
class olDrawTool{
constructor(map, options) {
this.map = map; //地图实例
this.options = options || {};
this.initData();
}
initData() {
this.drawInteraction = null; //绘制图层对象
this.clickHandler = null; //绘制图层对象
this.drawLayers = []; //绘制图层集合
this.delLayers = []; //删除图层的图标
}
//开始绘制
/**
*
* @param {Function} drawendFun 绘制结束事件
*/
startDraw(drawendFun) {
const type = this.options.type || "Polygon";
//实例化一个矢量图层Vector作为绘制层
let vector = new VectorLayer({
source: new VectorSource({ wrapX: false }),
style: this.options.style || this.layerStyle(),
});
this.drawInteraction = new Draw({
source: vector.getSource(),
type: type,
geometryFunction: this.options.geometryFunction,
});
this.map.addLayer(vector);
//绘制结束
this.drawInteraction.on("drawend", (event) => {
const feature = event.feature;
this.drawLayers.push(vector);
drawendFun && drawendFun(this.drawLayers);
//这里绘制图形结束需要先关闭绘制功能,再打开,保证每个图形独立
this.map.removeInteraction(this.drawInteraction);
this.drawInteraction = null;
this.startDraw(drawendFun);
});
this.map.addInteraction(this.drawInteraction);
}
//编辑所有图层
editLayer() {
// 先取消绘制图形控件
this.drawInteraction.setActive(false);
this.drawLayers.forEach((layer) => {
const modify = new Modify({ source: layer.getSource() });
this.map.addInteraction(modify);
let snap = new Snap({ source: layer.getSource() });
this.map.addInteraction(snap);
});
}
//完成图层编辑
editLayerEnd() {
this.drawInteraction.setActive(true);
// 移除Modify和Snap交互
let ModifyArr = this.map
.getInteractions()
.getArray()
.filter(
(interaction) =>
interaction instanceof Modify || interaction instanceof Snap
);
ModifyArr.forEach((item) => this.map.removeInteraction(item));
}
//撤销
revokeDraw() {
if (this.drawInteraction) {
this.drawInteraction.removeLastPoint();
}
}
// 创建样式
createDeleteButton(src, layer, delCallback) {
let deleteButton = document.createElement("div");
let img = document.createElement("img");
img.style.width = "22px";
img.style.height = "22px";
img.style.transform = "translate(-50%, -100%)";
img.src = src;
deleteButton.appendChild(img);
// 点击删除按钮时,删除对应的 VectorLayer(图层)和 ‘删除图标’
deleteButton.addEventListener("click", () => {
this.map.removeLayer(layer);
const overlay = this.delLayers.find(
(ov) => ov.get("layerid") === layer.ol_uid
);
if (overlay) {
this.map.removeOverlay(overlay);
this.delLayers.splice(this.delLayers.indexOf(overlay), 1);
}
let index = this.drawLayers.indexOf(layer);
if (index != -1) this.drawLayers.splice(index, 1);
delCallback && delCallback(layer, this.drawLayers);
});
return deleteButton;
}
/**
* @param {String} delIcon assets/images路径下的图片
* @param {Function} delCallback 删除结束回调函数
*/
//删除图层
delDraw(delCallback,delIcon) {
if(!delIcon){
delIcon = require("../../../assets/images/del.png");
}
this.drawInteraction.setActive(false);
this.drawLayers.forEach((layer) => {
const deleteButton = this.createDeleteButton(delIcon, layer, delCallback);
const deleteOverlay = new Overlay({
element: deleteButton,
position: [0, 0], // 这里先随便设置一个位置,后面再根据 layer 更新它的位置
});
deleteOverlay.set("layerid", layer.ol_uid); // 将对应的 VectorLayer的ol_uid 存储在 Overlay 对象中
const extent = layer.getSource().getExtent();
const center = olExtent.getCenter(extent);
deleteOverlay.setPosition(center);
this.delLayers.push(deleteOverlay);
this.map.addOverlay(deleteOverlay);
});
}
//完成删除
delDrawEnd() {
this.drawInteraction.setActive(true);
this.delLayers.forEach((item) => {
this.map.removeOverlay(item);
});
this.delLayers = [];
}
//清除绘制的图形,事件等
clear() {
this.drawLayers.forEach((item) => this.map.removeLayer(item));
this.delLayers.forEach((item) => this.map.removeLayer(item));
this.editLayerEnd();
this.map.removeInteraction(this.drawInteraction);
this.initData();
}
layerStyle() {
return new Style({
stroke: new Stroke({
color: "red",
width: 3,
lineDash: [4, 8],
}),
});
}
}
export default olDrawTool;
2. 使用,ToolBarDarw.vue
<template>
<div>
<div
@click="startDraw"
class="flex-dc"
>
<i class="el-icon-zoom-in"></i>
<span>开始绘制</span>
</div>
<div
class="flex-dc"
@click="editLayer"
>
<i class="el-icon-edit-outline"></i>
<span>{{ isEditing ? "完成" : "" }}编辑</span>
</div>
<div
class="flex-dc"
@click="revokeDraw"
>
<i class="el-icon-refresh-left"></i>
<span>撤销</span>
</div>
<div class="flex-dc" @click="delDraw">
<i class="el-icon-delete"></i>
<span>{{ isDeling ? "完成" : "" }}删除</span>
</div>
<div class="flex-dc" @click="escEdit">
<i class="el-icon-s-unfold"></i>
<span>退出</span>
</div>
</div>
</template>
<script>
import olDrawTool from "../js/olDrawTool";
props: ["map"],
data() {
return {
isEditing: false, //是否编辑状态
isDeling: false, //是否删除状态
isDrawing: true,
DrawTool: null, //绘制工具实例
drawLayers: [],
};
},
methods: {
// 绘制矢量图层
drawPolygon() {
if(!this.DrawTool){
this.DrawTool = new olDrawTool(this.map);
}
this.DrawTool.startDraw((drawLayers) => {
//绘制完成回调函数,根据业务决定是否需要
this.drawLayers = drawLayers;
});
},
// 撤销绘制
revokeDraw() {
this.DrawTool.revokeDraw();
},
// 删除矢量图层
delDraw() {
this.isDeling = !this.isDeling;
if (this.isDeling) {
this.isDrawing = false;
this.DrawTool.delDraw((layer, drawLayers) => {
console.log(drawLayers, layer, "=======删除!");
});
} else {
this.isDrawing = true;
this.DrawTool.delDrawEnd();
}
},
// 编辑矢量图层
editLayer() {
this.isEditing = !this.isEditing;
if (this.isEditing) {
this.isDrawing = false;
this.DrawTool.editLayer();
} else {
this.isDrawing = true;
this.DrawTool.editLayerEnd();
}
},
// 退出
escEdit() {
this.DrawTool.clear();
this.isEditing = false;
this.isDeling = false;
this.isDrawing = true;
this.DrawTool = null;
},
}
</script>
到这里基本功能就可以实现了,功能上还存在细节上的问题,还需根据需求完善。
下面是点击删除时的效果。