本篇介绍一下openlayers的select,snap的使用,
1 需求
- 点击开始绘制按钮开始绘制多边形,可以连续绘制多个多边形
- 点击撤销上步按钮,撤销上一步绘制点
- 绘制多个多边形(或编辑多边形时),鼠标靠近之前的已绘制完的多边形顶点时,自动吸附
- 点击结束绘制按钮,绘制完成,点击高亮选中多边形,开启编辑模式,显示顶点(调节点)进行编辑
2 分析
主要是 openlayers 中 draw,select,snap,modify 功能的使用
3 实现
<template>
<div id="map" class="map"></div>
<div class="toolbar">
<el-button type="primary" @click="handleClick">{{ drawFlag ? '结束' : '开始' }}绘制</el-button>
<el-button type="warning" :disabled="!drawFlag" @click="handleCancelClick">撤销上步</el-button>
</div>
</template>
<script setup lang="ts">
import { Collection, Feature, Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import { Draw, Modify, Select, Snap } from 'ol/interaction.js';
import { Vector as VectorSource } from 'ol/source.js';
import { Vector as VectorLayer } from 'ol/layer.js';
import { Circle, Fill, Stroke } from 'ol/style.js';
import { LineString, Point, Polygon } from 'ol/geom';
const projection = get('EPSG:4326');
const source = new VectorSource({ wrapX: false });
const map = shallowRef();
const draw = shallowRef();
const modify = shallowRef();
const select = shallowRef();
const snap = shallowRef();
const features = ref(new Collection());//保存绘制的features
const drawFlag = ref(false);
onMounted(() => {
initMap();
initInteraction();
});
const initMap = () => {
map.value = new Map({
target: 'map',
view: new View({
center: [116.406393, 39.909006],
projection: projection,
zoom: 5
}),
layers: [
new VectorLayer({
source: source,
style: styleFunc
})
]
});
};
const initInteraction = () => {
draw.value = new Draw({
active: false,
features: features.value,
source: source,
type: 'Polygon',
style: drawStyleFunc
});
draw.value.on('drawstart', e => {
console.log('e', e);
});
draw.value.on('drawend', e => {
console.log('features.value', features.value);
console.log('coord', e.feature.getGeometry().getCoordinates());
});
map.value.addInteraction(draw.value);
draw.value.setActive(false);
select.value = new Select({
style: selectStyleFunc
});
select.value.on('select', e => {
modify.value.setActive(true);
});
map.value.addInteraction(select.value);
select.value.setActive(false);
modify.value = new Modify({
features: select.value.getFeatures(), // Modify 将处理 Select 交互所选的要素
pixelTolerance: 10, //设置吸附像素值
insertVertexCondition: handleInsertVertexCondition,
style: modifyStyleFunc
});
modify.value.on('modifystart', event => {});
modify.value.on('modifyend', event => {
console.log('modifyend', event.features);
});
map.value.addInteraction(modify.value);
modify.value.setActive(false);
// 用于处理绘制或者编辑多边形时,与已经存在图形的自动吸附,如下是只吸附顶点,不媳妇边
snap.value = new Snap({
source:source,
edge:false,//不吸附边
});
map.value.addInteraction(snap.value);
};
const handleClick = () => {
drawFlag.value = !drawFlag.value;
draw.value.setActive(drawFlag.value);
select.value.setActive(!drawFlag.value);
modify.value.setActive(!drawFlag.value);
select.value.getFeatures().clear();
};
const handleCancelClick = () => {
draw.value.removeLastPoint();
};
const drawStyleFunc = feature => {
const styles = [];
const type = feature.getGeometry().getType();
const coord = feature.getGeometry().getCoordinates();
if (type === 'LineString') {
for (let i = 0; i < coord.length - 1; i++) {
styles.push(
new Style({
geometry: new LineString([coord[i], coord[i + 1]]),
stroke: new Stroke({
color: 'orange',
lineDash: coord.length > 2 && i < coord.length - 2 ? [] : [10],
width: 2
})
})
);
}
}
return styles;
};
const selectStyleFunc = feature => {
const styles = [];
const coord = feature.getGeometry().getCoordinates().flat(1);
for (let i = 0; i < coord.length - 1; i++) {
styles.push(
new Style({
geometry: new Point(coord[i]),
image: new Circle({
radius: 4,
fill: new Fill({
color: '#ffff'
}),
stroke: new Stroke({
color: 'orange',
width: 2
})
})
})
);
}
styles.push(
new Style({
stroke: new Stroke({
color: 'orange',
width: 2
}),
fill: new Fill({
color: '#ffff'
})
})
);
return styles;
};
const modifyStyleFunc = feature => {
const coord = feature.getGeometry().getCoordinates();
const layer = map.value.getLayers().item(0);
const features = layer.getSource().getFeatures();
const coords = features.map(feature => feature.getGeometry().getCoordinates()).flat(2);
let style = undefined;
// 只有鼠标在顶点时才能触发编辑功能
if (
coords.find(c => c.toString() === coord.toString())
) {
style = new Style({
geometry: new Point(coord),
image: new Circle({
radius: 6,
fill: new Fill({
color: '#ffff'
}),
stroke: new Stroke({
color: 'red',
width: 2
})
})
});
}
return style;
};
const handleInsertVertexCondition = e => {
// 点击或者拖动边时不插入新顶点
return false;
};
const styleFunc = feature => {
const styles = [];
styles.push(
new Style({
fill: new Fill({
color: [128, 128, 255, 0.5]
}),
stroke: new Stroke({
color: 'blue',
width: 2
})
})
);
return styles;
};
</script>
<style scoped lang="scss">
.map {
width: 100%;
height: 100%;
background: #000;
}
.toolbar {
position: absolute;
top: 20px;
left: 100px;
}
</style>