官网demo地址:
Draw Features
先初始化地图,准备一个空的矢量图层,用于显示绘制的图形。
initLayers() {const raster = new TileLayer({source: new XYZ({url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",}),});const source = new VectorSource({ wrapX: false });this.vectorlayer = new VectorLayer({source: source,});this.map = new Map({layers: [raster, this.vectorlayer],target: "map",view: new View({center: [-11000000, 4600000],zoom: 4,}),});},
想要在地图上绘制图形,需要用到一个交互类Draw,new Draw,设置绘制的图形类型。常见类型包括 'Point'
, 'LineString'
, 'Polygon'
, 'Circle'
, 'MultiPoint'
, 'MultiLineString'
, 'MultiPolygon'
。
addDrawInteraction() {this.draw = new Draw({source: this.vectorlayer.getSource(),type: this.type,});this.map.addInteraction(this.draw);},
Draw还有些常用参数
-
clickTolerance
:- 类型:
number
- 描述: 指定绘制时允许的点击距离容差(以像素为单位)。这是为了允许用户在移动鼠标时具有一定的容差,以便更容易地点击绘制。
- 默认值:
6
- 类型:
-
features
:- 类型:
ol.Collection<ol.Feature>
- 描述: 一个
Collection
实例,用于存储绘制的特征。如果指定了此属性,绘制的特征将添加到该集合中。
- 类型:
-
source
:- 类型:
ol.source.Vector
- 描述: 一个
VectorSource
实例,用于存储绘制的特征。如果没有指定features
,绘制的特征将添加到此数据源中。
- 类型:
-
dragVertexDelay
:- 类型:
number
- 描述: 指定绘制顶点时拖动操作的延迟时间(以毫秒为单位)。
- 默认值:
500
- 类型:
-
snapTolerance
:- 类型:
number
- 描述: 指定绘制时顶点的捕捉容差(以像素为单位)。这是为了使用户更容易将新顶点捕捉到现有顶点上。
- 默认值:
12
- 类型:
-
stopClick
:- 类型:
boolean
- 描述: 是否停止点击事件。设置为
true
时,绘制交互将停止触发地图的点击事件。 - 默认值:
false
- 类型:
-
maxPoints
:- 类型:
number
- 描述: 绘制的最大顶点数。对于线和多边形,这个值可以限制绘制的顶点数量。
- 默认值:
Infinity
- 类型:
-
minPoints
:- 类型:
number
- 描述: 绘制的最小顶点数。例如,对于多边形,至少需要三个顶点来形成一个闭合的形状。
- 默认值:
2
- 类型:
-
style
:- 类型:
ol.style.Style
或Array<ol.style.Style>
或ol.StyleFunction
- 描述: 指定绘制过程中几何图形的样式。可以是一个样式实例、样式实例数组或一个样式函数。
- 类型:
-
geometryFunction
:- 类型:
function
- 描述: 自定义几何生成函数,用于在绘制时生成几何图形。该函数接收两个参数:
coordinates
(当前坐标数组)和geometry
(当前几何图形)。
- 类型:
下拉框切换时需要先移除之前的Draw,再实例化一个新的Draw添加到地图上。
changeDrawType() {this.map.removeInteraction(this.draw);this.addDrawInteraction();},
使用removeLastPoint方法可以撤回最后绘制的一个点。
document.getElementById("undo").addEventListener("click", ()=> {this.draw.removeLastPoint();});
一般来说,在地图上绘制完图形肯定要拿到图形数据上传或者做其他的操作,我们来看看怎么获取数据。
方法一:直接从vectorlayer图层上获取
this.vectorlayer.getSource().getFeatures()
方法二:使用Draw的参数features绑定数组
let featureArr = new Collection();
this.draw = new Draw({features: featureArr,
});
features绑定的数组不是普通的数组,Collection是openlayers内部定义的一个类似数组的集合。它拥有一些跟数组类似的方法。具体介绍和方法可以参考官网文档:
OpenLayers v9.2.4 API - Class: Collection
如果获取数据的时机是绘制完成之后点击按钮后获取,那两种方式没什么区别。但若是希望绘制完成后马上获取,使用this.vectorlayer.getSource().getFeatures()就会有一点小问题。。。
this.draw.on("drawend", (e) => {console.log("draw", e.feature);console.log("获取数据:", this.vectorlayer.getSource().getFeatures());});
已经绘制了一个图形,但是并没有获取到 。this.vectorlayer.getSource().getFeatures()不能实时获取到绘制图形的数据,因为drawend事件里feature还没被加到图层上。
但,也不是没有解决办法,变成异步就可以。
setTimeout(() => {console.log("获取数据:", this.vectorlayer.getSource().getFeatures());
});
而使用Draw的features参数绑定Collection就不会有这个问题。
this.draw.on("drawend", (e) => {console.log("draw", e.feature);console.log("featureArr", this.featureArr);});
总的来说,两种方法都可以,甚至可以定义一个数组,每次绘制完都push一下当前绘制的feature。 具体怎么使用看业务需求喽。
完整代码:
<template><div class="box"><h1>Draw Features绘制图形</h1><div id="map"></div><div class="row"><div class="col-auto"><span class="input-group"><label class="input-group-text" for="type">Geometry type:</label><selectclass="form-select"id="type"@change="changeDrawType"v-model="type"><option value="Point">Point</option><option value="LineString">LineString</option><option value="Polygon">Polygon</option><option value="Circle">Circle</option><option value="None">None</option></select><input class="form-control" type="button" value="Undo" id="undo" /></span><el-button type="primary" @click="getDrawFeatures">获取</el-button></div></div></div>
</template><script>
import Draw from "ol/interaction/Draw.js";
import { createBox } from "ol/interaction/Draw";
import Map from "ol/Map.js";
import View from "ol/View.js";
import { OSM, Vector as VectorSource } from "ol/source.js";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
import XYZ from "ol/source/XYZ";
import Feature from "ol/Feature.js";
import Polygon from "ol/geom/Polygon.js";
import Point from "ol/geom/Point.js";
import { Collection } from "ol";
export default {data() {return {map: null,vectorlayer: null,type: "Point",draw: null,featureArr: new Collection(),};},methods: {getDrawFeatures() {console.log("方法一", this.vectorlayer.getSource().getFeatures());console.log("方法二", this.featureArr);},changeDrawType() {this.map.removeInteraction(this.draw);this.addDrawInteraction();},initLayers() {const raster = new TileLayer({source: new XYZ({url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",}),});const source = new VectorSource({ wrapX: false });this.vectorlayer = new VectorLayer({source: source,});this.map = new Map({layers: [raster, this.vectorlayer],target: "map",view: new View({center: [-11000000, 4600000],zoom: 4,}),});},addDrawInteraction() {this.draw = new Draw({source: this.vectorlayer.getSource(),type: this.type,features: this.featureArr,//freehand: true, //是否启用自由绘制模式});this.map.addInteraction(this.draw);this.draw.on("drawend", (e) => {console.log("draw", e.feature);// console.log("获取数据:", this.vectorlayer.getSource().getFeatures());console.log("featureArr", this.featureArr);// setTimeout(() => {// console.log("source", this.vectorlayer.getSource().getFeatures());// });});},},mounted() {this.initLayers();this.addDrawInteraction();document.getElementById("undo").addEventListener("click", () => {this.draw.removeLastPoint();});},
};
</script>
<style scoped>
#map {width: 100%;height: 500px;
}
.box {height: 100%;
}
</style>