需求
用户绘制图形确定一定的范围或者位置后,可以进行二次修改。改变范围大小或者移动图形位置。
实现过程
实现非常简单,通过给地图增加一个new ol.interaction.Modify({source})
,传入用户绘制的图层资源即可。
知识点
ol.interaction.Modify({})
的condition
参数,进行编辑的触发条件,默认点击左键。ol.interaction.Modify({})
的deleteCondition
参数,删除端点的条件,默认是alt+鼠标左键点击端点,端点就被删除了。ol.interaction.Modify({})
的insertVertexCondition
参数,插入端点的条件,就是在直线中间进行编辑,能否拉出来一个新的端点。默认是可以,可设置成组合键,也可以根据业务自行设置,最后返回true或者false即可。ol.interaction.Modify({})
的style
参数,编辑过程中鼠标的样式。ol.interaction.Modify({})
的实例可以通过on
绑定modifyend
事件,此事件在每次编辑结束后触发,事件内通过evt.features
可以拿到编辑后的图形。feature.setStyle({})
的zIndex
可调整图形的显示的层级。
代码HTML+CSS+JS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/ol.min.css" integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<title>编辑图形</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body,
#app,
.app-map {
height: 100%;
height: 100%;
}
.app-btns {
position: fixed;
right: 10px;
top: 10px;
background-color: #fff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
width: 210px;
padding: 25px;
text-align: center;
border-radius: 5px;
display: flex;
flex-direction: column;
z-index: 2;
}
.app-btns button {
font-size: 18px;
border: none;
padding: 12px 20px;
border-radius: 4px;
color: #fff;
background-color: #409eff;
border-color: #409eff;
cursor: pointer;
border: 1px solid #dcdfe6;
margin-bottom: 5px;
}
.app-btns button:hover {
background: #66b1ff;
border-color: #66b1ff;
}
.app-btns button.active {
background-color: #07c160;
}
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<div class="app-map" id="app-map"></div>
<div class="app-btns">
<button type='button' :class="{active: item.id === currentId}" v-for='item in drawTypes' @click='handleClickDraw(item)'>{{item.text}}</button>
<button type='button' @click='handleClickExit' style="background-color: #808080;">退出绘制</button>
<button type='button' @click='handleClickDelete' style="background-color: #ff0000;">删除所有图形</button>
<button type='button' @click='verifyMode = !verifyMode' :style="{'background-color': verifyMode ? '#ff0000' : '#409eff'}" title="开启验证问题模式后,先在地图上绘制一个图形,记住图形边或者端点的位置。点击删除图形,鼠标靠近记住的边或者点的位置">验证删除图形问题</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/dist/ol.min.js" integrity="sha512-xXS2hdEzrUC2BFO0fIJ+d/bwScOLgN+W7psE4XXq6xULXjKFCskUNe8QOVVUsB7vtYRI5ZS0Ie4EgS4VzJQBkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.14/vue.global.prod.min.js" integrity="sha512-huEQFMCpBzGkSDSPVAeQFMfvWuQJWs09DslYxQ1xHeaCGQlBiky9KKZuXX7zfb0ytmgvfpTIKKAmlCZT94TAlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const drawingStyle = 'data:image/png;base64,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';
const attributions = '<a href="https://ditu.amap.com/" target="_blank">© 地图版权归高德地图所有</a>';
const { createApp } = Vue;
const userType = 0;
let zIndex = 1;
const vm = createApp({
data() {
return {
map: {}, // 地图实例
drawSource: {}, // 绘制图形的图层资源
draw: null, // 绘制实例
modify: null,
currentId: -1, // 当前绘制类型id
features: [], // 绘制的图形数组
drawTypes: [{
type: 'Point',
text: '打点',
id: 2
}, {
type: 'Circle',
text: '画圆',
id: 1
}, {
type: 'Polygon',
text: '画多边形',
id: 3
}, {
type: 'LineString',
text: '画折线',
id: 5
}, {
type: 'Circle',
text: '正方形',
geometryFunction: ol.interaction.Draw.createRegularPolygon(4),
id: 7
}, {
type: 'Circle',
text: '矩形',
geometryFunction: ol.interaction.Draw.createBox(),
id: 6
}],
verifyMode: false
}
},
methods: {
// 初始化地图
initMap() {
// 创建放置用户绘制的feature的图层
this.drawSource = new ol.source.Vector();
const layer = new ol.layer.Vector({
source: this.drawSource
});
// 高德地图瓦片地址
const mianLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
attributions: attributions,
url: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
})
});
// 初始化地图
this.map = new ol.Map({
target: 'app-map',
layers: [mianLayer, layer],
view: new ol.View({
projection: 'EPSG:3857',
center: ol.proj.transform([111.8453154, 32.7383500], 'EPSG:4326', 'EPSG:3857'),
zoom: 5
}),
controls: ol.control.defaults.defaults({
attribution: true, // 地图版权信息工具
attributionOptions: {
collapsed: false, // 默认折叠
collapsible: true // 是否可折叠,显示折叠按钮
}
})
});
// 绑定地图事件
this.bindMapEvt();
// 创建modify
this.createModify();
},
// 绑定地图事件
bindMapEvt() {
// 监听鼠标点击
this.map.on('click', (evt) => {
const coordinate = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')
console.log('当前点击坐标为 : ' + coordinate[0].toFixed(7) + ',' + coordinate[1].toFixed(7));
});
},
// 创建modify
createModify(deltetFirst) {
// 删除feature后,将Modify也删除
if (deltetFirst) {
this.map.removeInteraction(this.modify);
};
console.log('重新创建了,Modify');
// 创建Modify
this.modify = new ol.interaction.Modify({
source: this.drawSource,
// 进行编辑的触发条件,默认点击左键。
condition: (event) => {
// 鼠标左键即可编辑
return ol.events.condition.primaryAction(event);
// 按住shift键+鼠标左键进行编辑
// return ol.events.condition.shiftKeyOnly(event) && ol.events.condition.primaryAction(event);
},
// 删除端点的条件,默认是alt+鼠标左键点击端点,端点就被删除了
deleteCondition: function(event) {
// 双击端点,将端点删除
return ol.events.condition.doubleClick(event);
},
// 插入端点的条件,就是在直线中间进行编辑,能否拉出来一个新的端点。默认是可以,可设置成组合键,也可以根据业务自行设置,最后返回true或者false即可
insertVertexCondition: function(event) {
// 鼠标左键即可插入新的端点
return ol.events.condition.primaryAction(event);
// 用户类型是0的,可插入新的端点
// return userType === 0;
// ctrl+鼠标左键可插入新的端点
// return ol.events.condition.platformModifierKey(event) && ol.events.condition.primaryAction(event);
},
});
// 绑定修改结束的事件
this.modify.on('modifyend', (evt) => {
console.log('编辑结束了,modifyend', evt);
evt.features.forEach(feature => {
this.setFeatureStyle(feature);
})
});
// 将Modify添加到地图
this.map.addInteraction(this.modify);
},
// 点击绘制各种图形
handleClickDraw(item) {
const { type, geometryFunction, id } = item;
// 同一种类型点击,不处理
if (this.currentId === id) {
return;
}
this.currentId = id;
// 根据 type 创建交互
this.draw = new ol.interaction.Draw({
source: this.drawSource,
type: type,
geometryFunction: geometryFunction,
style: new ol.style.Style({
image: new ol.style.Icon({
src: drawingStyle,
scale: 0.2,
// anchor: [0.5, 0.5],
rotateWithView: true,
rotation: 0,
opacity: 1
}),
stroke: new ol.style.Stroke({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 })
})
});
// 将交互添加到地图
this.map.addInteraction(this.draw);
// 监听绘制完成的事件
this.draw.on('drawend', (event) => {
// 存储绘制的feature
this.features.push(event.feature);
// 设置随机颜色样式
this.setFeatureStyle(event.feature);
// 结束此次绘制
this.map.removeInteraction(this.draw);
// 恢复按钮状态
this.currentId = -1;
});
},
// 设置feature样式 为随机颜色
setFeatureStyle(feature) {
feature.setStyle(new ol.style.Style({
stroke: new ol.style.Stroke({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8) }),
stroke: new ol.style.Stroke({
color: '#' + Math.random().toString(16).slice(2, 8),
width: 2
})
}),
// 保证编辑的结束后处于上层
zIndex: ++zIndex
}));
},
// 退出绘制
handleClickExit() {
this.currentId = -1;
this.draw && this.map.removeInteraction(this.draw);
this.draw = null;
},
// 点击删除图形
handleClickDelete() {
// 删除用户创建的feature
for (let i = 0; i < this.features.length; i++) {
this.drawSource.removeFeature(this.features[i]);
};
this.features = [];
// 将Modify删除,再重新创建Modify
!this.verifyMode && this.createModify(true);
}
},
mounted() {
this.initMap();
}
}).mount('#app')
</script>
</body>
</html>
备注
在鼠标靠近图形的边或者端点时,图形最近的点会出现一个吸附点,此时按下鼠标即可进行编辑。存在一个问题,在删除图形后,鼠标靠近图形原位置时(此时图形已经没有了),依然会出现编辑吸附点,且可以拖动这些吸附点。似乎是编辑模块Modify
未能及时更新可编辑的feature
的状态。查了写资料,没找到更新Modify
的方法。目前的解决办法是,在删除图形后,移除现有的Modify
交互,并重新创建一个新的Modify
交互。