OpenLayers:封装Overlay的方法
平时在使用OpenLayers的Overlay时常感觉不便,于是最近我便封装了一些Overlay增删改查的方法,以提高可用性。这边文章中我会介绍我封装的方法,同时记录这个过程中踩的一些坑。
添加Overlay
/*** @abstract 添加overlay* @param {*} map* @param {object} options overlay的配置项* @param {string} options.id overlay的id,可以用来唯一标识overlay* @param {string} options.groupId overlay的组名,可以用来批量操作overlay* @param {boolean} options.visibility overlay的初始可见性* options中的其它参数参考 ol/Overlay的构造函数参数*/
export const addOverlay = (map, options) => {let {groupId = "default",positioning = "center-center",visibility = true,element,...other} = options;// 将DOMstring转换为DOM元素if (!(element instanceof HTMLElement)) {const container = document.createElement("div");container.innerHTML = element;element = container.firstChild;}// 创建overlayconst overlay = new Overlay({element,positioning,...other,});// 设置额外的属性overlay.setProperties({groupId,visibility,});// 设置初始的可见性overlay.on("change:map", () => {if (!visibility) {setTimeout(() => {overlay.getElement().parentElement.style.display = "none";}, 0);}});// 添加到地图map.addOverlay(overlay);
};
addOverlay方法的特别之处
我封装的添加Overlay的方法,主要的改造是三个地方。
第一,对Overlay的element属性做了一个封装。
在我第一次使用Overlay的时候我就犯了一个错误,我给element属性传递了一个DOMString(比如`<div class="test-overlay pink">粉色overlay</div>`),结果就出现了类似于下面的报错。这是因为Overlay的element属性只能接收一个DOM元素。

现在经过我的封装后,我的addOverlay方法允许传入的element属性是一个DOMString。
第二,给Overlay添加一些额外的属性,这些属性会在后续帮助我去实现一些对Overlay的操作。
// 设置额外的属性overlay.setProperties({groupId,visibility,});
第三,给Overlay设置了初始的可见性,如果传入的visibility参数为false,就会暂时先将overlay隐藏。(我还考虑后续或许可以通过这个来实现popup)
// 设置初始的可见性
overlay.on("change:map", () => {if (!visibility) {setTimeout(() => {overlay.getElement().parentElement.style.display = "none";}, 0);}
});
查询Overlay
/*** @abstract 查找overlay* @param {*} map* @param {object} condition 筛选条件* @param {string} condition.id overlay的id筛选需要操作的overlay* @param {string} condition.groupId overlay的groupId筛选需要操作的overlay* @param {function} condition.condition 自定义条件函数,筛选需要操作的overlay,返回true则操作,false则忽略* @returns {Array} 符合条件的overlay数组*/
export const findOverlay = (map, { id, groupId, condition }) => {const targetOverlays = [];const overlays = map.getOverlays().getArray();overlays.forEach(overlay => {const groupId_ = overlay.get("groupId");const id_ = overlay.getId();if (id) {if (id_ === id) {targetOverlays.push(overlay);}}if (groupId) {if (groupId_ === groupId) {targetOverlays.push(overlay);}}if (condition) {if (condition(overlay, id_, groupId_, overlays)) {targetOverlays.push(overlay);}}});return targetOverlays;
};
findOverlay支持的查询方式
我设计的查找Overlay的方法findOverlay支持通过三种方式进行查找:
- 通过
id查找,这个id是创建 Overlay时的参数(我建议在创建overlay时最好都要添加这个参数)
// 查找id为'overlay-1'的overlay
findOverlay( map , { id : 'overlay-1' })
- 通过
groupId查找,这个是我在addOverlay方法中添加的一个额外属性,我的计划是通过groupId实现对Overlay的分组管理,可以同时去操作一组的Overlay。
// 查找所有groupId 为 stationTooltip 的overlay
findOverlay( map , { groupId : 'stationTooltip' })
- 通过一个筛选函数
condition来进行查找,这个就类似于js中Array.prototype.find()方法。我会为地图中绑定的每个overlay都调用condition方法,若condition方法返回true则将Overlay返回,若返回false则Overlay会被忽略。
condition方法将会接收到四个参数:
-
overlay,当前的overlay对象;id,当前的overlay对象的id;groupId,当前overlay对象的groupId;overlays,地图中的所有overlay对象组成的数组
// 查找所有groupId 为 stationTooltip 的overlay
findOverlay( map , { condition:(overlay , id , groupId , overlays)=> groupId == "stationTooltip" })
最后,注意findOverlay方法返回一个包含所有符合条件的Overlay对象的数组。
删除Overlay
/*** @abstract 移除overlay* @param {*} map* @param {object} condition 筛选条件* @param {string} condition.id overlay的id筛选需要操作的overlay* @param {string} condition.groupId overlay的groupId筛选需要操作的overlay* @param {function} condition.condition 自定义条件函数,筛选需要操作的overlay,返回true则操作,false则忽略*/
export const removeOverlay = (map, { id, groupId, condition }) => {const targetOverlays = findOverlay(map, { id, groupId, condition });targetOverlays.forEach(overlay => {map.removeOverlay(overlay);});
};/***@abstract 清除所有overlay* @param {*} map*/
export const clearOverlay = map => {const overlays = map.getOverlays();overlays.clear();
};
我封装了两个删除Overlay的方法removeOverlay和clearOverlay,前者删除符合条件的Overlay,后者清空地图中的所有Overlay。
错误的删除方式
之前我在网上看到下面的这种删除Overlay的方式。也就是边遍历边删除,这种方法是错误的。会有删除不尽的问题。
const overlays = map.getOverlays();overlays.forEach((overlay, index) => {if (overlay.getId() === id) {overlays.removeAt(index);}});
正确的写法是先通过遍历将想要删除Overlay收集到一个数组中,然后再循环数组进行删除.。
const overlays = map.getOverlays();const targetOverlays = []overlays.forEach((overlay, index) => {if (overlay.getId() === id) {targetOverlays.push(overlay)}});targetOverlays.forEach((overlay)=>{map.removeOverlay(overlay) })
显示/隐藏Overlay
/*** @abstract 设置overlay的可见性* @param {*} map* @param {object} condition 筛选条件* @param {string} condition.id overlay的id筛选需要操作的overlay* @param {string} condition.groupId overlay的groupId筛选需要操作的overlay* @param {function} condition.condition 自定义条件函数,筛选需要操作的overlay,返回true则操作,false则忽略* @param {boolean} visible 要设置的可见性*/
export const setOverlayVisibility = (map,{ id, groupId, condition, visible }
) => {const targetOverlays = findOverlay(map, { id, groupId, condition });targetOverlays.forEach(overlay => {overlay.setProperties({visibility: visible,});const element = overlay.getElement();element.parentElement.style.display = visible ? "flex" : "none";});
};/*** @abstract 切换overlay的可见性* @param {*} map* @param {object} condition 筛选条件* @param {string} condition.id overlay的id筛选需要操作的overlay* @param {string} condition.groupId overlay的groupId筛选需要操作的overlay* @param {function} condition.condition 自定义条件函数,筛选需要操作的overlay,返回true则操作,false则忽略*/
export const toggleOverlayVisibility = (map, { id, groupId, condition }) => {const targetOverlays = findOverlay(map, { id, groupId, condition });targetOverlays.forEach(overlay => {const newVisibility = !overlay.get("visibility");overlay.setProperties({visibility: newVisibility,});const element = overlay.getElement();element.parentElement.style.display = newVisibility ? "flex" : "none";});
};
显示/隐藏Overlay的方法我也封装了两个 setOverlayVisibility用于手动的设置显隐,toggleOverlayVisibility用于自动设置显隐。
隐藏Overlay的方法是去修改Overlay的element的父元素的display。我们在创建Overlay的时候传入的element实际上会被用另一个元素包装起来,这个元素(默认class为ol-overlay-container ol-selectable的元素)才是Overlay的根元素。

参考资料
- OpenLayers v10.5.0 API - Class: Overlay
- OpenLayers v10.5.0 API - Class: Collection
- OpenLayers之 OverLay问题汇总_openlayers overlay zindex-CSDN博客
相关文章:
OpenLayers:封装Overlay的方法
平时在使用OpenLayers的Overlay时常感觉不便,于是最近我便封装了一些Overlay增删改查的方法,以提高可用性。这边文章中我会介绍我封装的方法,同时记录这个过程中踩的一些坑。 添加Overlay /*** abstract 添加overlay* param {*} map* param…...
软件重构与项目进度的矛盾如何解决
软件重构与项目进度之间的矛盾可以通过明确重构目标与范围、采用渐进式重构策略、优化项目管理流程、提高团队沟通效率、建立重构意识文化等方式解决。其中,采用渐进式重构策略尤为关键。渐进式重构是指在日常开发过程中,以小步骤持续进行重构࿰…...
Mysql+Demo 获取当前日期时间的方式
记录一下使用Mysql获取当前日期时间的方式 获取当前完整的日期时间有常见的四种方式,获取得到的默认格式(mysql的格式标准)是 %Y-%m-%d %H:%i:%s其它格式 %Y-%m-%d %H:%i:%s.%f方式一:now()函数 select now();mysql> select now(); -------------…...
数智化时代下开源AI大模型驱动的新型商业生态构建——基于AI智能名片与S2B2C商城小程序的融合创新研究
摘要 数字技术的指数级发展推动物理世界向数智化网状结构加速转型,传统商业逻辑面临系统性重构。本文以"开源AI大模型AI智能名片S2B2C商城小程序"为研究主体,采用案例分析与技术验证相结合的方法,揭示技术融合对商业生态的重塑机制…...
Spring Cloud Alibaba 技术全景与实战指南
简介: Spring Cloud Alibaba 是阿里巴巴开源的微服务解决方案,基于 Spring Cloud 标准构建,提供了一站式分布式系统开发能力。它深度整合阿里云生态组件,为企业级微服务架构提供高可用、高性能的技术支撑。 核心特性 全栈微服务能…...
回归预测 | Matlab实现NRBO-Transformer-BiLSTM多输入单输出回归预测
回归预测 | Matlab实现NRBO-Transformer-BiLSTM多输入单输出回归预测 目录 回归预测 | Matlab实现NRBO-Transformer-BiLSTM多输入单输出回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.【JCR一区级】Matlab实现NRBO-Transformer-BiLSTM多变量回归预测…...
了解 PoE 握手协议在网络配电中的重要性
在现代网络领域,以太网供电(PoE)已成为一项革命性的技术,通过在一根以太网电缆上集成电力和数据传输,简化了网络连接设备的部署和管理。这种无缝操作的核心是 PoE 握手 —— 一个促进支持PoE 的设备之间的通信、确保高效供电和保护网络基础设…...
小智机器人相关函数解析,BackgroundTask::Schedule (***)将一个回调函数添加到后台任务队列中等待执行
以下是对 BackgroundTask::Schedule 函数代码的详细解释: void BackgroundTask::Schedule(std::function<void()> callback) {std::lock_guard<std::mutex> lock(mutex_);if (active_tasks_ > 30) {int free_sram heap_caps_get_free_size(MALLOC_…...
基于Python设计的TEQC数据质量可视化分析软件
标题:基于Python设计的TEQC数据质量可视化分析软件 内容:1.摘要 本文旨在设计一款基于Python的TEQC数据质量可视化分析软件。随着全球导航卫星系统(GNSS)的广泛应用,数据质量的评估变得至关重要。TEQC(TransEditQualityCheck&…...
人月神话:如何有效的避免Bug的产生
bug的来源有很多种,一般的小bug很好修复,最头疼的是哪些致命且难以察觉的Bug。这些bug从哪来的? 在人月神话书中说:假设的不匹配是大多数致命和难以察觉的bug的主要来源。 假设来源于各个组成部分的开发者对概念的理解不一致。 为…...
Git的基础使用方法
本文最终功能: 1.从终端直接传输代码给仓库 2.用终端从仓库克隆文件 基本概念 我们先来理解下 Git 工作区、暂存区和版本库概念: 工作区:就是你在电脑里能看到的目录。 暂存区:英文叫 stage 或 index。一般存放在 .git 目录下的…...
轮胎厂相关笔记
一、术语 图解:https://news.yiche.com/hao/wenzhang/38498703/ 1、胚胎 在轮胎制造行业中,“胎胚”(也称“生胎”或“未硫化轮胎”)是指轮胎在硫化(高温高压固化)之前的半成品形态。它是轮胎成型的中间…...
Java常用异步方式总结
使用建议 完整代码见https://gitee.com/pinetree-cpu/parent-demon 提供了postMan调试json文件于security-demo/src/main/resources/test_file/java-async.postman_collection.json 可导入postMan中进行调试 Java异步方式以及使用场景 继承Thread类 新建三个类继承Thread&…...
【Easylive】视频在线人数统计系统实现详解 WebSocket 及其在在线人数统计中的应用
【Easylive】项目常见问题解答(自用&持续更新中…) 汇总版 视频在线人数统计系统实现详解 1. 系统架构概述 您实现的是一个基于Redis的视频在线人数统计系统,主要包含以下组件: 心跳上报接口:客户端定期调用以…...
tomcat 目录结构组成
文章目录 背景文件结构层级一些常用的路径 背景 现在非常多的 java web 服务部署在 linux 服务器中,我们服务器中的 tomcat 会有各种文件路径,看下它有哪些文件 文件结构层级 ├── bin/ # 核心脚本和启动文件 ├── conf/ # …...
苍穹外卖day12
课程内容 工作台 Apache POI 导出运营数据Excel报表 功能实现:工作台、数据导出 工作台效果图: 数据导出效果图: 在数据统计页面点击数据导出:生成Excel报表 1. 工作台 1.1 需求分析和设计 1.1.1 产品原型 工作台是系统运…...
Unity Final IK:下一代角色动画与物理交互的技术解析
引言:角色动画的范式转移 在传统游戏开发中,角色动画主要依赖于 前向动力学(Forward Kinematics, FK) 和预烘焙动画。然而,这种方法的局限性在开放世界、物理交互和VR等场景中愈发明显: 环境适应性差&…...
前端开发时的内存泄漏问题
目录 🔍 什么是内存泄漏(Memory Leak)?🚨 常见的内存泄漏场景1️⃣ 未清除的定时器(setInterval / setTimeout)2️⃣ 全局变量(变量未正确释放)3️⃣ 事件监听未清除4️⃣…...
【Feign】⭐️使用 openFeign 时传递 MultipartFile 类型的参数参考
💥💥✈️✈️欢迎阅读本文章❤️❤️💥💥 🏆本篇文章阅读大约耗时三分钟。 ⛳️motto:不积跬步、无以千里 📋📋📋本文目录如下:🎁🎁&a…...
Linux中动静态库的制作
1.什么是库 库是写好的现有的,成熟的,可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个⼈的代码都从零开始,因此库的存在意义非同寻常。 本质上来说库是⼀种可执⾏代码的⼆进制形式,可以被操作系统…...
Docker部署sprintboot后端项目
创建Docker网络 docker network create icjs 部署Redis docker run -d \--network icjs \--name redis \-p 6379:6379 \redis:latest数据持久化 docker run --restartalways --network icjs -p 6379:6379 --name redis -v /opt/docker/redis/redis.conf:/etc/redis/redis.c…...
forms实现连连看
说明: forms实现连连看 效果图: step1:C:\Users\wangrusheng\RiderProjects\WinFormsApp2\WinFormsApp2\Form1.cs using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms;namespace …...
多视图几何--立体校正--Fusiello方法
1. 坐标系对齐与正交基构造 目标:构建新坐标系基向量 { e 1 , e 2 , e 3 } \{ \mathbf{e}_1, \mathbf{e}_2, \mathbf{e}_3 \} {e1,e2,e3},使成像平面共面且极线水平对齐。 (1) 基线方向 e 1 \mathbf{e}_1 e1 基线向量由左右相机光心平移向量…...
鸿蒙开发踩坑记录 - 2024S2
wrapBuilder如果想View和ObservedV2做绑定 必须要用 ComponentV2 Param 和 区别 退出两层循环 Builder的传入的参数及时是Trace修饰的也无法刷新组件 折叠屏展开后键盘无法点击 vm是公用的,组件生命周期问题导致 监听键盘高度变化失效 原因:分享面…...
【学Rust写CAD】21 2D 点(point.rs)
源码 //matrix/point.rs use std::ops::Mul; use super::algebraic_units::{Zero, One}; use super::generic::Matrix;/// 点坐标结构体 #[derive(Debug, Clone, Copy, PartialEq)] pub struct Point<X, Y>(Matrix<X, Y, One, Zero, Zero, One>);impl<X, Y>…...
0基础入门scrapy 框架,获取豆瓣top250存入mysql
一、基础教程 创建项目命令 scrapy startproject mySpider --项目名称 创建爬虫文件 scrapy genspider itcast "itcast.cn" --自动生成 itcast.py 文件 爬虫名称 爬虫网址 运行爬虫 scrapy crawl baidu(爬虫名) 使用终端运行太麻烦了,而且…...
鸿蒙NEXT小游戏开发:井字棋
1. 引言 井字棋是一款经典的两人对战游戏,简单易懂,适合各个年龄段的玩家。本文将介绍如何使用鸿蒙NEXT框架开发一个井字棋游戏,涵盖游戏逻辑、界面设计及AI对战功能。 2. 开发环境准备 电脑系统:windows 10 开发工具:…...
deep-sync开源程序插件导出您的 DeepSeek 与 public 聊天
一、软件介绍 文末提供下载 deep-sync开源程序插件导出您的 DeepSeek 与 public 聊天,这是一个浏览器扩展,它允许用户公开、私下分享他们的聊天对话,并使用密码或过期链接来增强 Deepseek Web UI。该扩展程序在 Deepseek 界面中添加了一个 “…...
4. 理解Prompt Engineering:如何让模型听懂你的需求
引言:当模型变成“实习生” 想象一下,你新招的实习生总把“帮我写份报告”理解为“做PPT”或“整理数据表”——这正是开发者与大模型对话的日常困境。某金融公司优化提示词后,合同审查准确率从72%飙升至94%。本文将用3个核心法则+5个行业案例,教你用Prompt Engineering让…...
网络编程—网络概念
目录 1 网络分类 1.1 局域网 1.2 广域网 2 常见网络概念 2.1 交换机 2.2 路由器 2.3 集线器 2.4 IP地址 2.5 端口号 2.6 协议 3 网络协议模型 3.1 OSI七层模型 3.2 TCP/IP五层模型 3.3 每层中常见的协议和作用 3.3.1 应用层 3.3.2 传输层 3.3.3 网络层 3.3.4…...
