- 前面几篇文章已经对OpenLayers的交互和Draw控件的使用有了基本的了解,下面将对OpenLayers的图斑删除、编辑、平移、框选平移进行逐一介绍。
目录
一、删除图斑
- 图斑的删除是非常简单的,只要我们能获取到这个Feature,再将这个Feature从包含它的Source中移除就完成了删除功能。
- 之前的文章介绍过使用OpenLayers点击事件选中图斑和使用Select控件选中图斑,在删除功能中,这两个方式都是可行的。
1、使用Select控件获取图斑并删除
- 之前的文章已经介绍过Select控件的用法,如果对Select控件不了解的朋友可以查看这里。
1.1 初始化Select控件
// 定义一个Select控件实例对象,并设置相关样式
let select = new Select({
style: new Style({
fill: new Fill({
color: "rgba(255,0,0,0.5)",
}),
stroke: new Stroke({
color: "rgba(0,0,255,1)",
}),
}),
});
// 将Select控件添加到地图中
map.addInteraction(select);
// 监听select选中事件
// 【注】:delFeature定义成了全局变量,这段只是截取出来的代码,所以没有包含delFeature的定义
select.on("select", (evt) => {
delFeature = select.getFeatures().getArray();
});
1.2 初始化地图
/**
* 为了方便其他函数调用地图和图层,把变量定义成全局的
*/
let map; // 地图
let vectorLayer; // 存放Feataure的图层
let delFeature; // 等待删除的图斑
let draw; // 绘制控件
let drawSource = new VectorSource(); // 绘制图层的数据源
let select; // 选中控件
/**
* 初始化地图
*/
const initialMap = () => {
map = new Map({
target: "map", // 地图放到哪个容器中,值应该是div的id
layers: [
new TileLayer({
source: new OSM(), // 加载OSM底图
}),
new VectorLayer({
source: drawSource,
style: new Style({
fill: new Fill({
color: "rgba(255, 255, 255, 0.2)",
}),
stroke: new Stroke({
// color: "#ffcc33",
color: "#ff0033",
width: 2,
}),
image: new CircleStyle({
radius: 3,
fill: new Fill({
color: "#ffcc33",
}),
}),
}),
}),
],
// 以EPSG:4326为坐标系定义地图的视图中心和缩放级别
view: new View({
projection: "EPSG:4326",
center: [125.3574397847, 43.8865062907],
zoom: 18,
}),
});
// 添加面图层
addLayer();
// 选中事件
select = new Select({
style: new Style({
fill: new Fill({
color: "rgba(255,0,0,0.5)",
}),
stroke: new Stroke({
color: "rgba(0,0,255,1)",
}),
}),
});
map.addInteraction(select);
// 监听select选中事件
select.on("select", (evt) => {
delFeature = select.getFeatures().getArray();
});
};
const addLayer = () => {
vectorLayer = new VectorLayer({
source: new VectorSource(),
});
vectorLayer.getSource().addFeature(
// 添加面图层
new Feature({
geometry: new Polygon([
[
[125.3579180563, 43.888298024],
[125.3587389704, 43.887798338],
[125.3574397847, 43.8865062907],
[125.3579180563, 43.888298024],
],
]),
})
);
map.addLayer(vectorLayer);
map.getView().setCenter([125.3579180563, 43.888298024]);
};
1.3 使用Select控件删除图斑
- 上面的代码中,已经监听到了select事件选中的图斑,也就是delFeature,下面就可以通过这个Feature找到对应的Source,并将Feature从Source中删除。
- 我在网页上新增了一个删除按钮,当用户选中图斑以后,再点击删除按钮就可以删除该图斑。
1.3.1 第一种情况
第一种情况是将Layer单独设置成全局变量,直接使用layer.getSource()方法获取到Source,然后删除该图斑
const delFeatures = () => {
if (delFeature.length > 0) {
vectorLayer.getSource().removeFeature(delFeature[0]);
}
};
1.3.2 第二种情况
第二种情况是将Source单独设置成全局变量,直接使用source.removeFeature()就可以直接删除图斑。
其中,removeFeature()中要填写对应的Feature
【注】:本文没有为Source单独设置全局变量,下面代码中的vectorSource是假定Source的变量名。
const delFeatures = () => {
if (delFeature.length > 0) {
vectorSource.removeFeature(delFeature[0]);
}
};
1.3.3 第三种情况
第三种情况只适用于Select,是Select控件自己的方法,鼠标事件无法使用。
const delFeatures = () => {
if (delFeature.length > 0) {
select.getLayer(delFeature[0]).getSource().removeFeature(delFeature[0]);
}
};
2、使用鼠标单击事件删除图斑
- 需要将最开始初始化地图的方法中初始化监听鼠标事件。
2.1 初始化鼠标单击事件
// 地图监听事件
map.on("singleclick", function (evt) {
delFeature = map.getFeaturesAtPixel(evt.pixel);
});
2.2 初始化地图的完整代码
/**
* 为了方便其他函数调用地图和图层,把变量定义成全局的
*/
let map; // 地图
let vectorLayer; // 存放Feataure的图层
let delFeature; // 等待删除的图斑
let draw; // 绘制控件
let drawSource = new VectorSource(); // 绘制图层的数据源
let select; // 选中控件
/**
* 初始化地图
*/
const initialMap = () => {
map = new Map({
target: "map", // 地图放到哪个容器中,值应该是div的id
layers: [
new TileLayer({
source: new OSM(), // 加载OSM底图
}),
new VectorLayer({
source: drawSource,
style: new Style({
fill: new Fill({
color: "rgba(255, 255, 255, 0.2)",
}),
stroke: new Stroke({
// color: "#ffcc33",
color: "#ff0033",
width: 2,
}),
image: new CircleStyle({
radius: 3,
fill: new Fill({
color: "#ffcc33",
}),
}),
}),
}),
],
// 以EPSG:4326为坐标系定义地图的视图中心和缩放级别
view: new View({
projection: "EPSG:4326",
center: [125.3574397847, 43.8865062907],
zoom: 18,
}),
});
// 固定添加点、线、面图层
addLayer();
// 地图监听事件
map.on("singleclick", function (evt) {
delFeature = map.getFeaturesAtPixel(evt.pixel);
});
};
const addLayer = () => {
vectorLayer = new VectorLayer({
source: new VectorSource(),
});
vectorLayer.getSource().addFeature(
// 添加面图层
new Feature({
geometry: new Polygon([
[
[125.3579180563, 43.888298024],
[125.3587389704, 43.887798338],
[125.3574397847, 43.8865062907],
[125.3579180563, 43.888298024],
],
]),
})
);
map.addLayer(vectorLayer);
map.getView().setCenter([125.3579180563, 43.888298024]);
};
2.3 使用鼠标监听事件删除图斑
- 这里的方法和上述Select控件删除图斑的前两种方法是一样的,不再进行赘述。
- 但是需要注意的是,无法使用第三种方法。
3、完整代码
<template>
<!-- 初始化一个地图容器 -->
<div id="map"></div>
<div style="position: absolute; right: 50px">
<button @click="delFeatures()">删除</button>
<!-- <button @click="addDraw('Point')">绘制点</button>-->
<!-- <button @click="addDraw('LineString')">绘制线</button>-->
<!-- <button @click="addDraw('Polygon')">绘制面</button>-->
<!-- <button @click="addDraw('Circle')">绘制圆</button>-->
</div>
</template>
<script setup>
// 引入需要的包
import TileLayer from "ol/layer/Tile";
import { OSM } from "ol/source";
import { Feature, View } from "ol";
import { Map } from "ol";
import { onMounted } from "vue";
import { Point, Polygon } from "ol/geom";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { Fill, Icon, Stroke, Style } from "ol/style";
import { DoubleClickZoom, Draw, Select } from "ol/interaction";
import { fromLonLat } from "ol/proj";
import CircleStyle from "ol/style/Circle";
/**
* 为了方便其他函数调用地图和图层,把变量定义成全局的
*/
let map; // 地图
let vectorLayer; // 存放Feataure的图层
let delFeature; // 等待删除的图斑
let draw; // 绘制控件
let drawSource = new VectorSource(); // 绘制图层的数据源
let select; // 选中控件
/**
* 初始化地图
*/
const initialMap = () => {
map = new Map({
target: "map", // 地图放到哪个容器中,值应该是div的id
layers: [
new TileLayer({
source: new OSM(), // 加载OSM底图
}),
new VectorLayer({
source: drawSource,
style: new Style({
fill: new Fill({
color: "rgba(255, 255, 255, 0.2)",
}),
stroke: new Stroke({
// color: "#ffcc33",
color: "#ff0033",
width: 2,
}),
image: new CircleStyle({
radius: 3,
fill: new Fill({
color: "#ffcc33",
}),
}),
}),
}),
],
// // 以EPSG:3857为坐标系定义地图的视图中心和缩放级别
// view: new View({
// projection: "EPSG:3857", // 坐标系
// // fromLonLat()是OpenLayers内置的函数,可以将一个坐标系转换成另一个坐标系。本文将EPSG:4326坐标系转成EPSG:3857坐标系
// center: fromLonLat([125.35, 43.88]), // 视图中心
// zoom: 18, // 缩放级别
// }),
// 以EPSG:4326为坐标系定义地图的视图中心和缩放级别
view: new View({
projection: "EPSG:4326",
center: [125.3574397847, 43.8865062907],
zoom: 18,
}),
});
addLayer();
// // 添加全屏控件
// let fullScreen = new FullScreen()
// map.addControl(fullScreen)
//
// // 比例尺控件
// let scaleLine = new ScaleLine()
// map.addControl(scaleLine)
//
// 地图监听事件
// map.on("singleclick", function (evt) {
// delFeature = map.getFeaturesAtPixel(evt.pixel);
// // let pixel = map.getEventPixel(evt.originalEvent); //获取点击的像素点
// // let coordinate = map.getCoordinateFromPixel(pixel); //获取像素点的坐标
// // console.log(coordinate);
// });
// 选中事件
select = new Select({
style: new Style({
fill: new Fill({
color: "rgba(255,0,0,0.5)",
}),
stroke: new Stroke({
color: "rgba(0,0,255,1)",
}),
}),
});
map.addInteraction(select);
// 监听select选中事件
select.on("select", (evt) => {
delFeature = select.getFeatures().getArray();
});
};
const addLayer = () => {
vectorLayer = new VectorLayer({
source: new VectorSource(),
});
vectorLayer.getSource().addFeature(
// 添加点图层
// new Feature({
// geometry: new Point([125.35, 43.88]),
// })
// // 添加线图层
// new Feature({
// geometry: new LineString([
// [125.3579180563, 43.888298024],
// [125.3587389704, 43.887798338],
// ]),
// }),
// 添加面图层
new Feature({
geometry: new Polygon([
[
[125.3579180563, 43.888298024],
[125.3587389704, 43.887798338],
[125.3574397847, 43.8865062907],
[125.3579180563, 43.888298024],
],
]),
})
);
map.addLayer(vectorLayer);
map.getView().setCenter([125.3579180563, 43.888298024]);
};
/**
* 绘制功能
* @param type 想要绘制什么类型的图斑
*/
const addDraw = (type) => {
draw = new Draw({
source: drawSource,
type: type,
});
map.addInteraction(draw);
// 监听开始绘制事件
draw.on("drawstart", (evt) => {
console.log("开始绘制");
console.log(evt);
});
// 监听结束绘制事件
draw.on("drawend", (evt) => {
console.log("结束绘制");
console.log(evt);
});
// 移除双击缩放地图功能,使双击只用来结束绘制功能
const dblClickInteraction = map
.getInteractions()
.getArray()
.find((interaction) => {
return interaction instanceof DoubleClickZoom;
});
map.removeInteraction(dblClickInteraction);
// 双击结束绘制
map.on("dblclick", () => {
map.removeInteraction(draw);
});
};
const delFeatures = () => {
if (delFeature.length > 0) {
// vectorLayer.getSource().removeFeature(delFeature[0]);
select.getLayer(delFeature[0]).getSource().removeFeature(delFeature[0]);
}
};
onMounted(() => {
// 立即执行初始化地图函数
initialMap();
// addLayer();
});
</script>
<style scoped>
#map {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
:deep(.ol-attribution) {
display: none;
}
</style>
3、实现效果
3.1 使用Select控件删除图斑
3.2 使用鼠标监听事件删除图斑
4、两种方法的对比
- 可以看出,使用Select控件删除图斑时,可以高亮已经选中的图斑,能够清晰的展示出要删除的图斑。
- 但是如果使用鼠标单击事件,可能会导致不知道是否已经正确选中图斑的情况发生。不过这种情况可以通过新增一个高亮图层,将已经选中的图斑clone进高亮图层中,在删除时,同时删除两个图层中的图斑。
- 读者可以自行选择使用哪种方法。