- 前面三篇文章已经对OpenLayers的基本情况以及图斑和图斑的选中有了基本的了解,下面将对OpenLayers的图斑绘制、删除、编辑、平移、框选平移进行逐一介绍。上述所有的功能都需要用到OpenLayers的Draw控件,那么本篇文章先对Draw控件进行介绍。
一、Draw控件概述
- Draw控件是OpenLayers的Interaction中的类,负责勾绘交互,支持的绘制图斑类型包括Point(点)、LineString(线)、Polygon(面)和Circle(圆)。
- 常用触发的事件包括drawstart和drawend,分别在绘制开始时(单击鼠标)和绘制结束时(双击鼠标)触发。还有一个平时用不到的触发事件drawabort,是在绘制中断的时候触发,使用情况较少。
二、Draw控件的常用参数
- source:表示绘制完成的图斑放到哪个数据源中
- type:表示绘制的要素是什么类型的,可选的有Point、LineString、Polygon、Circle
- style:表示绘制的样式,如果没有设置样式,会使用上面Source对应的Layer的样式
- clickTolerance:判断用户的行为是添加点,还是按住鼠标不松开进行拖拽地图。默认值是 6 像素,当按下鼠标和抬起鼠标左键之间的这段时间段内,如果地图被拖动没有超过 6 像素,那么默认为添加一个点,相反如果超过了 6 像素,那么不会添加点,只是平移一下地图。
- snapTolerance:默认值是 12 像素。多边形第一个点和最后一个点的吸附判定范围。
- minPoints:表示绘制单个要素最少的点数限制
- maxPoints:表示绘制单个要素最多的点数限制
- geometryName:设置绘制的要素的名称
- condition:规定了什么情况下触发draw操作,默认不需要特殊条件进行触发。如果想要设置,可以参考OpenLayers官方文档中的Condition类
- freehandCondition:规定了什么情况下触发不用多次点击绘制模式,也就是拖拽鼠标即可绘制要素的模式。默认是Shift按键。
- wrapX:当地图水平显示多个相同位置时(缩放级别低的情况下会发生),是否显示多个勾绘任务。默认为false。
三、Draw控件的结束方式
- 常用的结束绘制的方式主要是双击结束绘制,但是OpenLayers的双击鼠标事件默认是放大地图,所以当我们希望双击结束绘制的同时不放大地图的话,需要先将OpenLayers的默认事件移除,再给双击鼠标设置移除Draw控件。
- 下面这段代码就可以移除OpenLayers默认的双击放大地图事件。
// 移除双击缩放地图功能,使双击只用来结束绘制功能
const dblClickInteraction = map
.getInteractions()
.getArray()
.find((interaction) => {
return interaction instanceof DoubleClickZoom;
});
map.removeInteraction(dblClickInteraction);
- 下面这段代码会监听双击地图事件,当事件触发后,移除Draw控件,也就达到了停止绘制的目的。
// 双击结束绘制
map.on("dblclick", () => {
map.removeInteraction(draw);
});
四、Draw控件的监听事件
- 常用的监听事件有drawstart和drawend,分别在绘制开始时触发和绘制结束时触发。
1. drawstart在绘制前触发
// 监听开始绘制事件
draw.on("drawstart", (evt) => {
console.log("开始绘制");
console.log(evt);
});
2. drawend在绘制结束后触发。需要注意的是,如果本次绘制失败,也就是没有产生图斑,那么drawend是监听不到任何事件的。
// 监听结束绘制事件
draw.on("drawend", (evt) => {
console.log("结束绘制");
console.log(evt);
});
3.监听事件输出的evt包含绘制的要素,也就是Feature。
五、Draw控件的综合使用和完整代码
- 在地图初始化后,通过点击按钮将Draw控件加入到地图当中,随后需要判断用户想要绘制什么类型的图斑,设置Draw控件的绘制方式。
// 将Draw控件加入到地图控件中
// [注]:本文将draw定义为全局变量,所以这里没有声明draw变量,可以在后续的全部代码中查看声明。
draw = new Draw({
source: drawSource,
type: type,
});
map.addInteraction(draw);
- Vue中HTML代码如下:
<template>
<!-- 初始化一个地图容器 -->
<div id="map"></div>
<div style="position: absolute; right: 50px">
<button @click="addDraw('Point')">绘制点</button>
<button @click="addDraw('LineString')">绘制线</button>
<button @click="addDraw('Polygon')">绘制面</button>
<button @click="addDraw('Circle')">绘制圆</button>
</div>
</template>
- Vue中JS代码如下:
// 引入需要的包
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 { Polygon } from "ol/geom";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { Fill, Stroke, Style } from "ol/style";
import { DoubleClickZoom, Draw } from "ol/interaction";
import { fromLonLat } from "ol/proj";
import CircleStyle from "ol/style/Circle";
/**
* 为了方便其他函数调用地图和图层,把变量定义成全局的
*/
let map; // 地图
let vectorLayer; // 存放Feataure的图层
let draw; // 绘制控件
let drawSource = new VectorSource(); // 绘制图层的数据源
/**
* 初始化地图
*/
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, // 缩放级别
}),
};
/**
* 绘制功能
* @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);
});
};
onMounted(() => {
// 立即执行初始化地图函数
initialMap();
});