OpenLayers:如何控制Overlay的层级?

news2025/4/13 7:23:10

我最近在使用Overlay的时候遇到了一个问题,我向地图中添加了两种不同的Overlay(下图中的蓝色标牌和粉色标牌),我希望粉色标牌可以显示在最上层,可偏偏蓝色标牌却将其遮挡住了。于是我对Overlay的层级开始起了兴趣,希望可以找到控制Overlay层级顺序的方法。

一、Overlay的原始层级顺序

决定Overlay原始层级的因素

首先得搞清楚一个问题,为什么粉色标牌的层级会比蓝色标牌低呢?

我观察了一番发现原因是因为我是先将蓝色标牌添加到地图中,后将粉色标牌添加到地图中。

如果调换一下代码顺序,先添加粉色标牌,那么就变成了粉色标牌的层级更高了

因此可以得出结论:

决定Overlay原始层级的因素是添加Overlay的先后顺序,先添加到地图中的Overlay层级高,后添加到地图中的Overlay层级低。

为什么是“先高后低”的顺序?

为什么会有这种“先高后低”的层级顺序呢?难道Elment元素就是按照这种顺序排列的吗?

于是我便进行了一次测试,依次插入蓝色、粉色两个元素,这两个元素都脱标且z-index属性值相同,结果发生后插入的粉色元素覆盖了先插入的蓝色元素。

这说明在默认情况下Element元素的层级实际上遵循的是“先低后高”的原则,这个与Overlay的情况是不符的。

于是我查看了一下OpenLayers地图元素中的DOM数据,居然发现粉色标牌的元素在最前面,而蓝色标牌的元素在后面。这说明其实粉色标牌的元素才是先被插入到地图元素中的,这与我们编程的时候使用map.addOverlay插入的顺序是相反的。

那我大概就明白了,OpenLayers的地图中用于存储Overlay的应该是一个栈结构,由于栈结构遵循着“后进先出”的原则,因此在渲染Overlay时,后插入的Overlay会先从存储栈中弹出进行渲染,因此才出现了层级“先高后低”的情况。

我用代码模拟了一下这种方式:

  // 点击添加overlay
 function handleClick(event) {
    // 添加蓝色标牌
    const el_blue = document.createElement("div");
    el_blue.className = "test-overlay blue";
    el_blue.innerHTML = "蓝色overlay";

    addOverlay(el_blue);

    // 添加粉色标牌
    const el_pink = document.createElement("div");
    el_pink.className = "test-overlay pink";
    el_pink.innerHTML = "粉色overlay";

    addOverlay(el_pink);
  }

  //地图的Overlay存储栈
  const overlayStack = [];

  function addOverlay(overlay) {
    //将overlay添加到存储栈中
    overlayStack.push(overlay);

    // 渲染overlay到地图上
    const map = document.getElementById("map");
    for (let i = overlayStack.length - 1; i >= 0; i--) {
      const el = overlayStack[i];

      map.appendChild(el);
    }
  }

二、控制Overlay层级的方法

上面的理论探索纯属个人兴趣,其实我真正要解决的还是如何控制Overlay层级的问题。

当然最简单的方法就是控制添加Overlay的顺序,保证想要展示在上层的Overlay先添加。但是这种方法显得有些“蠢萌”了,在很多复杂的项目中我们是无法保障Overlay的插入顺序的,因此我认为需要找到更加有效的方法。

提到控制显示层级我们很容易就能想到CSS中的z-index属性,这似乎是一个不错的思路,但是z-index属性究竟应该加在哪儿呢?

z-index的错误使用

一开始我想的很简单,我认为只要给每个Overlay所绑定的element设置z-index就可以了。

.test-overlay {
  position: relative;
  padding: 10px;
  cursor: pointer;

  /* 蓝色overlay样式 */
  &.blue {
     z-index: 1;
    background-color: skyblue;
  }
  /* 粉色overlay样式 */
  &.pink {
    z-index: 2; /* 给粉色标牌设置更高的层级 */
    background-color: pink;
  }
}

但是设置之后发现好像没有任何的作用。为什会这样呢?

原因是因为,添加到DOM树中的Overlay的element还会被包装一层,所以我设置z-indexdiv.blue元素和div.pink元素实际上是表兄弟元素(它们的父元素是兄弟元素)

表兄弟元素之间的层级关系就不由它们的z-index属性决定,而是要看它们父元素的层级。也就是说z-index应该设置在div.blue元素和div.pink的父元素也就是Overlay的包装元素上。

如何正确的使用z-index控制Overlay的层级

那么如何给Overlay的包装元素设置z-index属性呢?我找到了两种方法。

方法一,通过Overlay的className属性给包装元素添加一个类名。

首先在创建Overlay时设置className属性,给蓝色标牌和粉色标牌设置不同的类名

// 添加蓝色overlay
positions.forEach((position, index) => {
  addOverlay(window.map, {
    id: `blue-${index}`,
    groupId: "blue",
    element: createBlueElement(),
    position,
    className: "ol-overlay-container ol-selectable blue-container",
  });
});

// 添加粉色overlay
positions
  .filter((_, index) => index % 2 === 0)
  .forEach((position, index) => {
    addOverlay(window.map, {
      id: `pink-${index}`,
      groupId: "pink",
      element: createPinkElement(),
      offset: [20, 20],
      position,
      className: "ol-overlay-container ol-selectable pink-container",
    });
  });

然后再通过类名给不同的Overlay的包装元素设置不同的层级

.blue-container {
  z-index: 1;
}
.pink-container {
  z-index: 2;
}

最终就可以实现粉色标牌不被蓝色标牌遮挡。

方法二,通过:has选择器给包装元素添加样式

:has选择器可以让你在选择元素上更佳灵活,也就是可以让你选中本元素之前的兄弟级别的元素或者是父元素亦或者是祖先元素。

它的使用方法是:当前元素之前的元素:has(当前元素)

因此我们就可以利用:has选择器分别选中div.blue元素和div.pink元素的父元素,然后给它们设置层级。

.ol-overlay-container.ol-selectable:has(>.blue){
  z-index: 1;
}

.ol-overlay-container.ol-selectable:has(>.pink){
  z-index: 2;
}

参考资料

  1. OpenLayers v10.5.0 API - Class: Overlay
  2. OpenLayers之 OverLay问题汇总_openlayers overlay zindex-CSDN博客
  3. :has() - CSS:层叠样式表 | MDN
  4. 伪类选择器中的:has_has选择器-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2328252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Golang高性能网络编程:构建低延迟服务器应用》

在本文中,我们将深入探讨Golang高性能网络编程,帮助您构建低延迟服务器应用。我们将介绍Golang的网络编程特性、优化技巧和实际案例,让您更好地理解和应用Golang在网络编程领域的优势。 高性能网络编程简介 什么是Golang高性能网络编程 高性能…

数据结构C语言练习(设计循环队列)

一、循环队列简介 循环队列是一种线性数据结构,基于 FIFO(先进先出)原则,将队尾连接到队首形成循环。其核心优势是能复用队列之前用过的空间,避免普通队列 “假溢出” 问题。实现时,通常申请 k1 大小的数组…

vscode代码片段的设置与使用

在 Visual Studio Code (VS Code) 中,可以通过自定义**代码片段(Snippets)**快速插入常用代码模板。以下是详细设置步骤: 步骤 1:打开代码片段设置 按下快捷键 Ctrl Shift P(Windows/Linux)或…

uniapp -- 列表垂直方向拖拽drag组件

背景 需要在小程序中实现拖拽排序功能,所以就用到了m-drag拖拽组件,在开发的过程中,发现该组件在特殊的场景下会有些问题,并对其进行了拓展。 效果 组件代码 <template><!-- 创建一个垂直滚动视图,类名为m-drag --><scroll

一款非常小的软件,操作起来非常丝滑!

今天我想给大家分享一款超级实用的小软件&#xff0c;它是一款电脑上用的倒计时和关机助手。 关机助手 帮你自动关机 这款关机助手特别小巧&#xff0c;完全不需要安装&#xff0c;文件大小才60KB&#xff0c;比一个小小的文件还小。你只需要把它下载下来&#xff0c;双击打开…

FrameWork基础案例解析(四)

文章目录 单独拉取framework开机与开机动画横屏Android.mk语法单独编译SDKmake 忽略warning单独修改和编译Camera2单独编译Launcher3Android Studio 导入、修改、编译Settings导入 Android Studio 导入、修改、编译Launcher3android 开机默认进入指定Launcher植入自己的apk到系…

通过 C# 提取PDF文档中的图片

当 PDF 文件中包含有价值的图片&#xff0c;如艺术画作、设计素材、报告图表等&#xff0c;提取图片可以将这些图像资源进行单独保存&#xff0c;方便后续在不同的项目中使用&#xff0c;避免每次都要从 PDF 中查找。本文将介绍如何使用C#通过代码从PDF文档中提取图片&#xff…

国标GB28181视频监控平台EasyCVR保驾护航休闲娱乐“九小场所”安全运营

凭借降低人力资源、节约物资成本的优势&#xff0c;在多个场景得到广泛应用。如今&#xff0c;棋牌室、洗浴中心、酒店这类人员频繁流动和密集的场所&#xff0c;已成为安全管理的重点。​ 尽管部分棋牌室已安装了监控设备&#xff0c;但是设备功能单一&#xff0c;只能实现一…

GoLand 2024.3 中文 GO语言开发工具

GoLand 2024.3 中文 GO语言开发工具 文章目录 GoLand 2024.3 中文 GO语言开发工具一、介绍二、效果三、下载 一、介绍 JetBrains GoLand 2024 &#xff0c;是一款GO语言开发工具&#xff0c;全行代码补全&#xff1a;能使用本地运行的上下文感知深度学习模型&#xff0c;可以自…

CentOS 7 强制升级Docker 24.x终极指南(解决MySQL8镜像兼容性问题)

CentOS 7 强制升级Docker 24.x终极指南&#xff08;解决MySQL8镜像兼容性问题&#xff09; 旧版本&#xff1a; 新版本docker&#xff1a; 一、问题背景与方案选型 1.1 典型报错分析 The designated data directory /var/lib/mysql/ is unusable根本原因&#xff1a;旧版…

【区块链安全 | 第十九篇】类型之映射类型

文章目录 映射类型可迭代映射 映射类型 映射类型使用语法 mapping(KeyType KeyName? > ValueType ValueName?)&#xff0c;映射类型的变量声明使用语法 mapping(KeyType KeyName? > ValueType ValueName?) VariableName。 KeyType 可以是任何内置值类型、bytes、st…

Flask与 FastAPI 对比:哪个更适合你的 Web 开发?

在开发 Web 应用时&#xff0c;Python 中有许多流行的 Web 框架可以选择&#xff0c;其中 Flask 和 FastAPI 是两款广受欢迎的框架。它们各有特色&#xff0c;适用于不同的应用场景。本文将从多个角度对比这两个框架&#xff0c;帮助你更好地选择适合的框架来构建你的 Web 应用…

QT 中的元对象系统(五):QMetaObject::invokeMethod的使用和实现原理

目录 1.简介 2.原理概述 3.实现分析 3.1.通过方法名调用方法的实现分析 3.2.通过可调用对象调用方法的实现分析 4.使用场景 5.总结 1.简介 QMetaObject::invokeMethod 是 Qt 框架中的一个静态方法&#xff0c;用于在运行时调用对象的成员函数。这个方法提供了一种动态调…

【无人机】无人机PX4飞控系统高级软件架构

目录 1、概述&#xff08;图解&#xff09; 一、数据存储层&#xff08;Storage&#xff09; 二、外部通信层&#xff08;External Connectivity&#xff09; 三、核心通信枢纽&#xff08;Message Bus&#xff09; 四、硬件驱动层&#xff08;Drivers&#xff09; 五、飞…

【SPP】蓝牙链路控制(LC)在SPP中互操作性深度解析

在蓝牙协议栈的精密分层体系中&#xff0c;其链路控制&#xff08;Link Control, LC&#xff09;层作为基带层的核心组件&#xff0c;承载着物理信道管理、连接建立与维护等关键任务。其互操作性要求直接决定了不同厂商设备能否实现无缝通信。本文将以蓝牙技术规范中的LC互操作…

算法每日一练 (25)

&#x1f4a2;欢迎来到张翊尘的技术站 &#x1f4a5;技术如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 算法每日一练 (25)四数之和题目描述解题思路解题代码c…

【大模型基础_毛玉仁】6.4 生成增强

目录 6.4 生成增强6.4.1 何时增强1&#xff09;外部观测法2&#xff09;内部观测法 6.4.2 何处增强6.4.3 多次增强6.4.4 降本增效1&#xff09;去除冗余文本2&#xff09;复用计算结果 6.4 生成增强 检索器得到相关信息后&#xff0c;将其传递给大语言模型以期增强模型的生成能…

【GCC警告报错4】warning: format not a string literal and no format arguments

文章主本文根据笔者个人工作/学习经验整理而成&#xff0c;如有错误请留言。 文章为付费内容&#xff0c;已加入原创保护&#xff0c;禁止私自转载。 文章发布于&#xff1a;《C语言编译报错&警告合集》 如图所示&#xff1a; 原因&#xff1a; snprintf的函数原型&#x…

【落羽的落羽 C++】模板简介

文章目录 一、模板的引入二、函数模板1. 函数模板的使用2. 函数模板的原理3. 函数模板的实例化4. 函数模板的匹配 三、类模板 一、模板的引入 假如我们想写一个Swap函数&#xff0c;针对每一种类型&#xff0c;都要函数重载写一次&#xff0c;但它们的实现原理是几乎一样的。在…

USB(通用串行总线)数据传输机制和包结构简介

目录 1. USB的物理连接电缆结构时钟恢复技术 2. USB的数据传输方式包&#xff08;Packet&#xff09; 3. 包的传输规则帧和微帧 4. 包的结构1. 同步字段&#xff08;Sync&#xff09;2. 包标识符字段&#xff08;PID&#xff09;3. 数据字段4. 循环冗余校验字段&#xff08;CRC…