vue2+Ts中openLayer绘图工具组件封装
效果:
封装组件代码:
<!-- openLayer绘图工具 -->
<template>
<a-button-group v-show="isShow">
<a-button v-if="shouldShowButton('point')" @click="draw('Point')">
绘点
<a-icon type="dot-chart" />
</a-button>
<a-button v-if="shouldShowButton('line')" @click="draw('LineString')">
绘线
<a-icon type="line-chart" />
</a-button>
<a-button v-if="shouldShowButton('polygon')" @click="draw('Polygon')">
绘面
<a-icon type="border" />
</a-button>
<a-button v-if="shouldShowButton('edit')" @click="edit()">
编辑
<a-icon type="edit" />
</a-button>
<a-button v-if="shouldShowButton('undo')" @click="undo()">
撤销
<a-icon type="undo" />
</a-button>
<a-button v-if="shouldShowButton('redo')" @click="redo()">
重做
<a-icon type="redo" />
</a-button>
<a-button v-if="shouldShowButton('save')" @click="save()">
保存
<a-icon type="save" />
</a-button>
</a-button-group>
</template>
<script lang="ts">
import abpbase from '@/libs/abpbase';
import VectorSource from 'ol/source/Vector';
import Map from 'ol/Map';
import { Component, Emit, Prop } from 'vue-property-decorator';
import ol from 'ol';
import VectorLayer from 'ol/layer/Vector';
import Draw, { createRegularPolygon } from 'ol/interaction/Draw';
import Modify from 'ol/interaction/Modify';
import {
singleClick, doubleClick, pointerMove, never,
} from 'ol/events/condition';
import Select from 'ol/interaction/Select';
import Translate from 'ol/interaction/Translate';
import Snap from 'ol/interaction/Snap';
// eslint-disable-next-line import/no-unresolved
import * as jsts_io from 'jsts/org/locationtech/jts/io';
import {
Style, Fill, Stroke, Circle,
} from 'ol/style';
import {
LinearRing,
LineString,
MultiLineString,
MultiPoint,
MultiPolygon,
Point,
Polygon,
} from 'ol/geom.js';
import MapBrowserEventType from 'ol/MapBrowserEventType';
@Component({
name: 'OpenLayerDrawTool',
components: {
},
})
export default class OpenLayerDrawTool extends abpbase {
/**
* 最大可绘制要素数量
*/
@Prop({type:Number, default:1})
maxFeatures
@Prop({ type: Array, default: () => ["point", "line", "polygon", "undo", "redo", "save", "edit"] })
buttonsToShow: string[];
/**
* 编辑操作
*/
editOperation: Modify;
shouldShowButton(buttonName: string): boolean {
return this.buttonsToShow.includes(buttonName);
}
/**
* 绘制的矢量图层
*/
drawVectorLayer: VectorLayer<any>;
/**
* 绘制的数据源
*/
drawSource: VectorSource;
/**
* 传入的openLayer地图
*/
map: Map = null;
/**
* 绘制操作
*/
drawOperation: Draw;
/**
* 绘制的图形堆栈
*/
drawStack = []
/**
* 重做的图形堆栈
*/
redoStack = []
selectOperation: Select
translateOperation: Translate
snapOperation: Snap
get isShow() {
return this.map != null;
}
/**
* 初始化地图控件,需要在父组件调用;
* @param map openLayer地图对象
* @param requestDataId 请求的数据参数
*/
initCtrl(map: Map) {
this.map = map;
this.drawSource = new VectorSource();
const createCustomStyle = () => (feature) => {
const geometryType = feature.getGeometry().getType();
let style;
switch (geometryType) {
case 'Point':
style = new Style({
image: new Circle({
radius: 6,
fill: new Fill({ color: 'rgba(255, 0, 0, 0.5)' }),
stroke: new Stroke({ color: 'red', width: 2 }),
}),
});
break;
case 'LineString':
style = new Style({
stroke: new Stroke({
color: 'blue',
width: 4,
}),
});
break;
case 'Polygon':
style = new Style({
fill: new Fill({ color: 'rgba(0, 255, 0, 0.2)' }),
stroke: new Stroke({ color: 'green', width: 3 }),
});
break;
default: {
break;
}
}
return style;
};
this.drawVectorLayer = new VectorLayer<any>({
source: this.drawSource,
style: createCustomStyle(),
zIndex: 999,
});
this.map.addLayer(this.drawVectorLayer);
this.$forceUpdate();
}
draw(type) {
this.map.removeInteraction(this.drawOperation);
this.drawOperation = new Draw({
source: this.drawSource,
type,
condition: (event) => event.type === MapBrowserEventType.POINTERDOWN && event.originalEvent.button === 0,
});
this.map.addInteraction(this.drawOperation);
this.drawOperation.on('drawend', (e) => {
// 为要素分配一个唯一的 ID
e.feature.set('id', Date.now());
this.drawStack.push(e.feature);
// 如果绘制的图形数量超过最大限制,移除最早添加的图形
if (this.drawStack.length > this.maxFeatures) {
const firstFeature = this.drawStack.shift();
this.drawSource.removeFeature(firstFeature);
}
this.map.removeInteraction(this.drawOperation);
});
}
undo() {
const lastFeature = this.drawStack.pop();
if (lastFeature) {
this.drawSource.removeFeature(lastFeature);
this.redoStack.push(lastFeature);
}
}
redo() {
const lastFeature = this.redoStack.pop();
if (lastFeature) {
// 如果绘制的图形数量达到最大限制,移除最早添加的图形并将其从重做堆栈中移除
if (this.drawStack.length >= this.maxFeatures) {
const firstFeature = this.drawStack.shift();
this.drawSource.removeFeature(firstFeature);
}
this.drawSource.addFeature(lastFeature);
this.drawStack.push(lastFeature);
}
}
save() {
const parser = new jsts_io.OL3Parser();
parser.inject(
Point,
LineString,
LinearRing,
Polygon,
MultiPoint,
MultiLineString,
MultiPolygon,
);
const format = new jsts_io.WKTWriter();
const features = this.drawSource.getFeatures();
const wkts = features.map((feature) => {
const olGeom = feature.getGeometry();
const jstsGeom = parser.read(olGeom);
return format.write(jstsGeom);
});
console.log(JSON.stringify(wkts));
}
mounted() {
}
edit() {
// 移除 drawOperation 交互
this.map.removeInteraction(this.drawOperation);
// // 创建 selectOperation 交互对象
this.selectOperation = new Select({
condition: singleClick,
});
this.map.addInteraction(this.selectOperation);
// 创建 translateOperation 交互对象
this.translateOperation = new Translate({
features: this.selectOperation.getFeatures(),
});
this.map.addInteraction(this.translateOperation);
// 创建 modifyOperation 交互对象
this.editOperation = new Modify({
features: this.selectOperation.getFeatures(),
});
this.editOperation.setActive(false);
this.map.addInteraction(this.editOperation);
this.editOperation.on('modifyend', (e) => {
// 更新 drawStack 中的要素
const updatedFeature = e.features.getArray()[0];
const featureIndex = this.drawStack.findIndex(
(feature) => feature.get('id') === updatedFeature.get('id'),
);
if (featureIndex >= 0) {
this.drawStack.splice(featureIndex, 1, updatedFeature);
}
});
// 为地图添加双击事件侦听器
this.map.on('dblclick', (event) => {
const features = this.map.getFeaturesAtPixel(event.pixel);
if (features && features.length > 0) {
this.editOperation.setActive(true);
this.snapOperation.setActive(true);
this.translateOperation.setActive(false);
} else {
this.editOperation.setActive(false);
this.snapOperation.setActive(false);
this.translateOperation.setActive(true);
}
});
// 为地图添加 pointermove 事件侦听器
// this.map.on('pointermove', (event) => {
// const features = this.map.getFeaturesAtPixel(event.pixel);
// if (features && features.length > 0) {
// this.editOperation.setActive(true);
// } else {
// this.editOperation.setActive(false);
// }
// });
}
// 初始化
// init() {
// }
// created() {
// }
}
</script>
<style lang="less" scoped>
.home-wrap {
min-width: 1280px;
overflow: auto;
}
</style>
父组件使用:
<div class="absolute right-4 top-4">
<open-layer-draw-tool ref="drawTool"></open-layer-draw-tool>
</div>
initDrawTool() {
this.$nextTick(() => {
(this.$refs.drawTool as any).initCtrl(this.map);
});
}