OpenLayers选择与编辑:Select+Modify完整方案
做地图应用画完图形后经常需要编辑——拖拽顶点、修改形状、删除要素。OpenLayers提供了Select和Modify两个交互但要把它们串成一个完整的编辑器还需要处理很多细节选中高亮、顶点显示、编辑完成同步、删除功能。这篇文章把完整方案写出来了。一、Select交互点击选中1.1 基本用法importSelectfromol/interaction/SelectconstselectInteractionnewSelect({layers:[drawLayer],// 只在指定图层上选择style:(feature)createFeatureStyle(feature,#409eff,3,rgba(64, 158, 255, 0.3))})map.addInteraction(selectInteraction)1.2 选中事件selectInteraction.on(select,(event){// event.selected - 新选中的要素数组// event.deselected - 取消选中的要素数组if(event.selected.length0){constfeatureevent.selected[0]console.log(选中了:,feature.get(name))}else{console.log(取消选中)}})1.3 限定选择范围// 只在指定图层上选择constselectnewSelect({layers:[drawLayer]})// 只选择特定类型的要素constselectnewSelect({filter:(feature,layer){returnfeature.get(type)polygon}})// 多图层可选constselectnewSelect({layers:[layer1,layer2,layer3]})二、Modify交互顶点拖拽2.1 基本用法importModifyfromol/interaction/ModifyconstmodifyInteractionnewModify({source:drawSource,selectInteraction:selectInteraction,// 关联Selectstyle:newStyle({image:newCircleStyle({radius:6,fill:newFill({color:#409eff}),stroke:newStroke({color:#fff,width:2})})})})map.addInteraction(modifyInteraction)2.2 编辑完成事件modifyInteraction.on(modifyend,(event){event.features.forEach(feature{constidfeature.get(id)constnewGeometryfeature.getGeometry()console.log(要素${id}编辑完成新坐标:,newGeometry.getCoordinates())})})2.3 关联Select的重要性Modify必须关联Select否则没有高亮显示选中状态无法识别要编辑哪个要素顶点不会显示// ✅ 正确关联SelectconstmodifynewModify({source:drawSource,selectInteraction:selectInteraction})// ❌ 错误不关联SelectconstmodifynewModify({source:drawSource// 缺少 selectInteraction})三、完整编辑器封装3.1 初始化letselectInteractionnullletmodifyInteractionnullconstinitEditor(){// 选择交互selectInteractionnewSelect({layers:[drawLayer],style:(feature)createFeatureStyle(feature,#409eff,3,rgba(64, 158, 255, 0.3))})selectInteraction.on(select,(event){selectedFeature.valueevent.selected.length0?event.selected[0]:null})map.value.addInteraction(selectInteraction)// 编辑交互modifyInteractionnewModify({source:drawSource,selectInteraction:selectInteraction,style:newStyle({image:newCircleStyle({radius:6,fill:newFill({color:#409eff}),stroke:newStroke({color:#fff,width:2})})})})modifyInteraction.on(modifyend,(event){// 同步修改到数据event.features.forEach(feature{constidfeature.get(id)constidxdrawnFeatures.value.findIndex(ff.idid)if(idx0){drawnFeatures.value[idx].geometryfeature.getGeometry().clone()}})})map.value.addInteraction(modifyInteraction)}3.2 删除选中要素constdeleteSelected(){if(!selectedFeature.value)returnconstfeatureselectedFeature.valueconstidfeature.get(id)// 从数据源移除drawSource.removeFeature(feature)// 从数据数组移除drawnFeatures.valuedrawnFeatures.value.filter(ff.id!id)// 清空选中状态selectedFeature.valuenull// 更新吸附updateSnapSource()}3.3 销毁onBeforeUnmount((){if(selectInteraction)map.value.removeInteraction(selectInteraction)if(modifyInteraction)map.value.removeInteraction(modifyInteraction)})四、选中高亮样式4.1 不同状态的样式constcreateFeatureStyle(feature,sColor,sWidth,fColor){// 基础样式conststyles[newStyle({fill:newFill({color:fColor}),stroke:newStroke({color:sColor,width:sWidth}),image:newCircleStyle({radius:6,fill:newFill({color:sColor})})})]returnstyles}// Select的高亮样式蓝色selectInteractionnewSelect({style:(feature)createFeatureStyle(feature,#409eff,3,rgba(64, 158, 255, 0.3))})// Modify的顶点样式蓝色圆点modifyInteractionnewModify({style:newStyle({image:newCircleStyle({radius:6,fill:newFill({color:#409eff}),stroke:newStroke({color:#fff,width:2})})})})4.2 样式状态对照状态颜色线宽说明未选中原色如红色2px正常显示选中蓝色#409eff3px高亮显示编辑中蓝色圆点-顶点可拖拽五、SelectModifyDraw协同5.1 三种交互的关系Draw绘制→ 产出Feature Select选择→ 选中Feature Modify编辑→ 修改Feature5.2 交互切换// 进入编辑模式添加Select和ModifyconstenterEditMode(){map.value.addInteraction(selectInteraction)map.value.addInteraction(modifyInteraction)}// 退出编辑模式移除Select和ModifyconstexitEditMode(){map.value.removeInteraction(selectInteraction)map.value.removeInteraction(modifyInteraction)selectedFeature.valuenull}// 进入绘制模式移除Select和ModifyconstenterDrawMode(){exitEditMode()createDrawInteraction()}5.3 互斥设计绘制和编辑不应该同时进行constsetMode(mode){// 先清除所有交互exitEditMode()if(drawInteraction){map.value.removeInteraction(drawInteraction)drawInteractionnull}if(modedraw){createDrawInteraction()}elseif(modeedit){enterEditMode()}}六、踩坑记录坑1Modify不显示顶点现象选中要素后看不到可拖拽的顶点。原因Modify没有关联Select。解决constmodifynewModify({source:drawSource,selectInteraction:selectInteraction// 必须关联})坑2编辑后数据不同步现象拖拽顶点后数据数组还是旧的。原因没有在modifyend事件中同步数据。解决modifyInteraction.on(modifyend,(event){event.features.forEach(feature{constidfeature.get(id)constidxdrawnFeatures.value.findIndex(ff.idid)if(idx0){drawnFeatures.value[idx].geometryfeature.getGeometry().clone()}})})坑3删除要素后还能选中现象删除了要素但点击原位置还能选中。原因Select的内部缓存没有更新。解决删除后调用selectInteraction.getFeatures().clear()constdeleteSelected(){drawSource.removeFeature(selectedFeature.value)selectInteraction.getFeatures().clear()// 清空Select缓存selectedFeature.valuenull}七、总结功能交互关键点点击选中Select({layers, style})限定图层顶点拖拽Modify({source, selectInteraction})必须关联Select选中高亮Select的style参数蓝色高亮编辑完成modifyend事件同步数据删除要素drawSource.removeFeature()清空Select缓存模式切换互斥设计绘制和编辑不同时进行更新日期2026年9月调试版本OpenLayers 10.9.0完整源码参考项目中4.example绘制功能.vue的Select和Modify部分

相关新闻

Prometheus 监控 Hyperf 全栈实战:从协程指标到请求延迟的 Swoole 应用可观测性

Prometheus 监控 Hyperf 全栈实战:从协程指标到请求延迟的 Swoole 应用可观测性

Prometheus 监控 Hyperf 全栈实战:从协程指标到请求延迟的 Swoole 应用可观测性Hyperf 是构建在 Swoole 协程引擎之上的高性能 PHP 微服务框架,支撑着无数高并发 API 和实时通信系统。然而,协程模型下的内存常驻、连接池耗尽、请求延迟抖动、…

2026/9/8 16:56:57 阅读更多 →
OpenLayers弹窗Overlay深度实战

OpenLayers弹窗Overlay深度实战

做地图应用,点击要素弹出信息窗是最常见的交互。但OpenLayers的Overlay API比较底层,直接用会遇到很多问题——弹窗位置偏移、重复创建、关闭按钮事件失效、Vue响应式丢失。这篇文章把两种实现方式(HTML字符串 vs Vue组件)和踩过的…

2026/9/8 16:56:57 阅读更多 →
项目信息提供指南:撰写标题、关键词和摘要的实操方法

项目信息提供指南:撰写标题、关键词和摘要的实操方法

没有问题,我准备好了。请直接按下面的格式提供你的项目信息,我会基于标题内容,为你输出一篇结构完整、干货充足的博主风格实操博文。项目标题: [标题] 项目正文: [通常比较零散、不完整的原始描述,可是任意领域内容] 关键词: [关键…

2026/9/8 16:55:56 阅读更多 →

最新新闻

图的全景解析:从图论算法到工程图纸与前沿应用

图的全景解析:从图论算法到工程图纸与前沿应用

“图”这个字,在程序员、工程师、设计师、数据分析师眼里几乎是四个不同的世界。做后端的人看到“图”想到图论算法,做嵌入式的人想到引脚图和时序图,做前端的人想到轮播图和可视化图表,做测绘的人想到瓦片图和SLAM建图。这篇总结…

2026/9/9 19:59:52 阅读更多 →
SSM+Vue家居租赁系统毕业设计:从数据库到答辩全流程解析

SSM+Vue家居租赁系统毕业设计:从数据库到答辩全流程解析

每年大概三、四月份,就有不少同学开始为毕业设计失眠。如果你正盯着“基于SSM和Vue的家居租赁系统”这个题目发愁,既没有现成代码,也不知道论文从哪下笔,这篇文章可以帮你一条龙理顺思路。这类项目说到底就是一个电商系统的变体&a…

2026/9/9 19:59:52 阅读更多 →
Bruno 开源 API 客户端(Bru 语言 · 离线优先 · Git 协作):以官方俄语 README 为纲的全面技术解读

Bruno 开源 API 客户端(Bru 语言 · 离线优先 · Git 协作):以官方俄语 README 为纲的全面技术解读

Bruno 开源 API 客户端(Bru 语言 离线优先 Git 协作):以官方俄语 README 为纲的全面技术解读 【免费下载链接】bruno Opensource IDE For Exploring and Testing APIs (lightweight alternative to Postman/Insomnia) 项目地址: https://…

2026/9/9 19:59:52 阅读更多 →
Windows批量给文件名加后缀:cmd、PowerShell与批处理脚本实战

Windows批量给文件名加后缀:cmd、PowerShell与批处理脚本实战

Windows 批量给文件名加后缀,是日常办公和开发运维里出现频率很高的操作:导出的日志要追加日期,配置文件要追加环境标识,备份文件要追加 .bak,图片素材要追加批次号。手动按 F2 一个个改,少说几十个文件&am…

2026/9/9 19:59:52 阅读更多 →
扩增子分析全流程解析:从16S/ITS到二三代测序与可视化

扩增子分析全流程解析:从16S/ITS到二三代测序与可视化

引言这年头做微生物组研究,离了扩增子测序几乎是寸步难行。16S和ITS这两个经典的标记基因,在过去十几年里撑起了肠道、土壤、水体、植物根际等无数微生态研究方向的基本盘。但恰恰是这个“基本盘”,这几年正在经历一轮非常明显的技术换挡&…

2026/9/9 19:59:52 阅读更多 →
本地AI辅助测试落地:Copilot当翻译,MCP当司机

本地AI辅助测试落地:Copilot当翻译,MCP当司机

在本地把 AI 辅助测试这事儿真正落地,我们团队折腾了差不多两个季度。最初大家以为 AI 自动化测试就是装个插件点一下生成脚本,实际上手才发现,工具链选型、生成流程设计、基础设施接入、结果兜底,哪一环不掉链子,方案…

2026/9/9 19:58:51 阅读更多 →

日新闻

MHS模型硬件标准:让大模型像调用软件一样控制物理设备

MHS模型硬件标准:让大模型像调用软件一样控制物理设备

让Claude真正看着显微镜说“这个细胞形态不太对”,或者让大模型自己调一版机械臂的运动轨迹,这事儿听上去已经很接近科幻片了。但你真上手试一次就会发现,模型不缺智商,缺的是一个能插进显微镜、机械臂、激光控制器里的“通用插座…

2026/9/9 0:00:11 阅读更多 →
AI五大核心方向详解:从机器学习到大模型,零基础转行选哪条?

AI五大核心方向详解:从机器学习到大模型,零基础转行选哪条?

会有人告诉我,他想转行学AI,但打开招聘网站一看直接傻眼:机器学习、深度学习、自然语言处理、计算机视觉、大模型应用……满屏都是这些词,好像每个都会一点,又好像每个都离自己很远。还有人上来就问“学Python还是学Ja…

2026/9/9 0:00:11 阅读更多 →
从50行最小循环到生产级AI引擎:工程化改造全解析

从50行最小循环到生产级AI引擎:工程化改造全解析

直接说干货。这一章我写的不是那种"hello world跑通某个模型"的教程,而是把AI引擎当做一个真正要上线、要被人调用、要扛流量的系统来聊。从最初只有50行的最小循环,到能够承载生产流量的AI引擎,中间差的不是代码量,而是…

2026/9/9 0:00:11 阅读更多 →

周新闻

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/9 10:51:30 阅读更多 →
超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/9 4:00:10 阅读更多 →
基于CNN的调制信号识别:MATLAB实现时频图分类实战

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/9 7:35:54 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/9 7:36:02 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/9 7:36:09 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/9 7:36:01 阅读更多 →