前两篇介绍了 openlayers 中 draw 的使用,自定义了绘制中和绘制结束后的样式,绘制结束后可以获取到绘制图形的featue或者进一步获取轮廓坐标(如下),可以进行坐标保存或者将feature添加到其他层进一步自定义显示
draw.value.on("drawend", (e) => {
console.log("feature", e.feature);
const coord = e.feature.getGeometry().getCoordinates();
console.log("coord", coord);
});
本篇介绍一下编辑工具 modify
1 需求
使用 openlayers 绘图功能绘制多边形,绘制完成后可进行编辑
2 分析
主要是 openlayers 中 draw,modify 功能的使用
3 实现
为了方便,直接使用绘制功能
3.1 简单实现
<template>
<div id="map" class="map"></div>
</template>
<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import { Draw, Modify } 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();
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({
source: source,
type: 'Polygon',
style: drawStyleFunc
});
draw.value.on('drawstart', e => {
console.log('e', e);
});
draw.value.on('drawend', e => {
console.log('coord', e.feature.getGeometry().getCoordinates());
});
map.value.addInteraction(draw.value);
modify.value = new Modify({
source: source
});
modify.value.on('modifystart', (event) =>{});
modify.value.on('modifyend', (event)=> {
// 获取编辑后的轮廓
event.features.forEach(feature => {
console.log(feature.getGeometry().getCoordinates())
});
});
map.value.addInteraction(modify.value);
};
const drawStyleFunc = feature => {
const styles = [];
const type = feature.getGeometry().getType();
const coord = feature.getGeometry().getCoordinates();
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
})
})
})
);
}
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 styleFunc = feature => {
const styles = [];
const coord = feature.getGeometry().getCoordinates();
for (let i = 0; i < coord[0].length - 1; i++) {
styles.push(
new Style({
geometry: new Point(coord[0][i]),
image: new Circle({
radius: 4,
fill: new Fill({
color: '#ffff'
}),
stroke: new Stroke({
color: 'orange',
width: 2
})
})
})
);
}
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;
}
</style>
3.2 需求更新 1
新需求:
- 点击边的时候不自动增加新顶点
- 不允许调整边,只允许调整点
- 自定义鼠标悬浮顶点时的样式
- 鼠标悬浮在顶点附近,吸附距离自定义
分析:
这里主要是pixelTolerance,insertVertexCondition和styleFunction的灵活使用
实现:
<template>
<div id="map" class="map"></div>
</template>
<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import { Draw, Modify } 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();
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({
source: source,
type: 'Polygon',
style: drawStyleFunc
});
draw.value.on('drawstart', e => {
console.log('e', e);
});
draw.value.on('drawend', e => {
console.log('coord', e.feature.getGeometry().getCoordinates());
});
map.value.addInteraction(draw.value);
modify.value = new Modify({
source: source,
pixelTolerance: 10, //设置吸附像素值
insertVertexCondition: handleInsertVertexCondition,
style: modifyStyleFunc
});
modify.value.on('modifystart', event => {});
modify.value.on('modifyend', event => {
event.features.forEach(feature => {
console.log(feature.getGeometry().getCoordinates());
});
});
map.value.addInteraction(modify.value);
};
const drawStyleFunc = feature => {
const styles = [];
const type = feature.getGeometry().getType();
const coord = feature.getGeometry().getCoordinates();
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
})
})
})
);
}
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 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 = [];
const coord = feature.getGeometry().getCoordinates();
for (let i = 0; i < coord[0].length - 1; i++) {
styles.push(
new Style({
geometry: new Point(coord[0][i]),
image: new Circle({
radius: 4,
fill: new Fill({
color: '#ffff'
}),
stroke: new Stroke({
color: 'orange',
width: 2
})
})
})
);
}
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;
}
</style>