1 需求
使用openlayers绘图功能绘制多边形
2 分析
主要是openlayers中draw功能的使用,感觉比较简单,祖传CV大法搞起来
3 实现
为了方便,就不加载底图了,直接使用绘制功能
2.1 简单实现
<template>
<div id="map" class="map"></div>
</template>
<script setup lang="ts">
import { Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import { Fill, Stroke } from 'ol/style.js';
import Draw from 'ol/interaction/Draw.js';
import { Vector as VectorSource } from 'ol/source.js';
import { Vector as VectorLayer } from 'ol/layer.js';
const projection = get('EPSG:4326');
const source = new VectorSource();
const map = ref();
const draw = ref();
onMounted(() => {
initMap();
initDraw();
});
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: new Style({
stroke: new Stroke({
color: 'orange',
width: 2
}),
fill: new Fill({
color: [203, 150, 62, 0.5]
})
})
})
]
});
};
const initDraw = () => {
draw.value = new Draw({
source: source,
type: 'Polygon'
});
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);
};
</script>
<style scoped lang="scss">
.map {
width: 100%;
height: 100%;
background: #000;
}
</style>
2.2 需求更新1
新需求:
- 自定义绘制时的样式,没有绘制完成时,显示虚线,顶点增加Point
- 绘制完成后每个顶点需要显示一个Point
分析:
这里主要是styleFunction的灵活使用
实现:
<template>
<div id="map" class="map"></div>
</template>
<script setup lang="ts">
import { Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import Draw from 'ol/interaction/Draw.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 { Point } from 'ol/geom';
const projection = get('EPSG:4326');
const source = new VectorSource();
const map = ref();
const draw = ref();
onMounted(() => {
initMap();
initDraw();
});
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 initDraw = () => {
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);
};
const drawStyleFunc = (feature) => {
const styles = [];
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
})
})
})
);
}
styles.push(
new Style({
fill: new Fill({
color: [255, 255, 255, 0.5]
}),
stroke: new Stroke({
color: 'red',
lineDash: [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>
2.2 需求更新2
新需求:
- 确定的两个顶点之间变为实线
- 取消跟随鼠标的Point,影响定位
- 取消绘制时的填充
分析:
这里主要是styleFunction的灵活使用
实现:
<template>
<div id="map" class="map"></div>
</template>
<script setup lang="ts">
import { Map, View } from 'ol';
import { get } from 'ol/proj';
import { Style } from 'ol/style';
import Draw from 'ol/interaction/Draw.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 } from 'ol/geom';
const projection = get('EPSG:4326');
const source = new VectorSource();
const map = ref();
const draw = ref();
onMounted(() => {
initMap();
initDraw();
});
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 initDraw = () => {
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);
};
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>
存在问题:
- 在点击鼠标后并且鼠标有移动时,前一段虚线才会变成实线,并且顶点加上Point,因为只有鼠标移动才会有新的坐标点加入到绘制,因为openlayers没有提供绘制过程中的钩子函数,所以只能是当前效果
- 有需要时drawStyleFunction可以和styleFuntion合并成一个