40 openlayers setCenter 之后 绘制了Overlay 地图定位异常

前言

这是之前在 生产环境碰到的一个问题

这个其实就是 业务上一个地图点击点位展示详情, 然后再点击另外一个点位 展示详情, 切换中心店的这个过程 

其主要的问题是 使用 openlayers 的 Map.View.setCenter() 了之后, 整个地图的中心点切换到了一个莫名其妙的地方 

然后 经过大量的事件排查, 我们发现 在我们复现问题的操作的过程中总共有两个地方在进行中心点的切换 

第一个是我们业务上的 map.getView().setCenter(), 然后另外一个是 openlayers 的 Overlay 元素的重新绘制 的过程中的一个中心点的切换

然后 正常的业务情况是 先执行 Overlay 的相关业务绘制, 然后再执行 map.getView().setCenter()

然后 在我们这里测试出了某一个情况下 业务代码这边先执行的 map.getView().setCenter() 然后再执行的 Overlay 的相关业务绘制, 然后导致 地图上面看不到数据, 产生了一个 bug, 就是 我点击了目标点位, 期望地图上面能够展示这个点, 以及这个点位的详情信息, 但是实际情况是 地图上面展示的是空的

我们这里 便是来看一下 这个问题 

测试用例

<template><div style="width: 1920px; height:1080px;" ><div class="olMapUsageClass"></div><div class="overdelay1" ref="overdelay1" >this is over delay1</div></div></template><script>import Map from 'ol/Map'import View from 'ol/View'import DragPan from 'ol/interaction/DragPan'import MouseWheelZoom from 'ol/interaction/MouseWheelZoom'import PointerInteraction from 'ol/interaction/Pointer'import GeoJSON from 'ol/format/GeoJSON'import {Tile as TileLayer} from 'ol/layer'import {Vector as VectorLayer} from 'ol/layer'import {Image as ImageLayer} from 'ol/layer'import {Vector as VectorSource} from 'ol/source'import {Feature as Feature} from 'ol'import Point from 'ol/geom/Point'import LineString from 'ol/geom/LineString'import Polygon from 'ol/geom/Polygon'import CircleGeo from 'ol/geom/Circle'import XYZ from "ol/source/XYZ"import ImageStatic from "ol/source/ImageStatic"import {Circle, Fill, Icon, RegularShape, Stroke, Style, Text} from 'ol/style'import Overlay from 'ol/Overlay'import {transformExtent, transform} from "ol/proj"export default {name: "olMapUsage",components: {},props: {},data() {return {map: null,tdtImgLayer: null,labelLayer: null,overlay: null,};},computed: {},watch: {},created() {},mounted() {this.initMap()this.test12SetCenterThenAddOverlay()},methods: {initMap() {let center = [105.065735, 30.659462]let projection = "EPSG:4326"let zoom = 10let minZoom = 5let maxZoom = 20const layer = []const view = new View({...(this.viewOptions || {}),projection,center,zoom,minZoom,maxZoom})this.map = new Map({...(this.mapOptions || {}),layers: [].concat(layer),view: view,target: this.$el,controls: [],interactions: [new DragPan(),new MouseWheelZoom(),new PointerInteraction({handleEvent: this.handleEvent})]})},test06AddCircleLayer(coord, color) {color = color || 'green'let style = new Style({image: new Circle({radius:20,fill: new Fill({color: color})})})let feature = new Feature({geometry: new Point(coord)})feature.setStyle(style)let source = new VectorSource()source.addFeature(feature)let layer = new VectorLayer({source: source})this.map.addLayer(layer);},test10SetCenter(coord, color) {this.map.getView().setCenter(coord)this.test06AddCircleLayer(coord, color)},test11AddOverlay(coord) {this.overlay && this.map.removeOverlay(this.overlay)this.overlay = new Overlay({element: this.$refs.overdelay1,position: coord,positioning: "bottom-center",offset: [0, 0],autoPan: true,autoPanMargin: 200,autoPanAnimation: {duration: 1000},map: this.map})this.map.addOverlay(this.overlay)},test12SetCenterThenAddOverlay() {// refer cyclethis.test06AddCircleLayer([10.265735, 10.659462], "#007f5a")this.test06AddCircleLayer([105.565735, 30.759462], "#0039ff")let _this = this// use this for map.addOverlay's animation updatesetTimeout(function() {_this.test11AddOverlay([10.065735, 10.459462])_this.test10SetCenter([10.065735, 10.459462], "yellow")}, 2000)// the core case, normal or exception or compensatedsetTimeout(function() {// case1. function of addOverlay_this.test11AddOverlay([105.065735, 30.259462])// case2. normal case// _this.test11AddOverlay([105.065735, 30.259462])// _this.test10SetCenter([105.065735, 30.259462], "red")// case3. exception case// _this.test10SetCenter([105.065735, 30.259462], "red")// _this.test11AddOverlay([105.065735, 30.259462])// case4. compensated case// _this.test10SetCenter([105.065735, 30.259462], "red")// setTimeout(function() {//   _this.test11AddOverlay([105.065735, 30.259462])// }, 1000)}, 5000)},}};
</script><style lang="scss">.olMapUsageClass {}.overdelay1 {position: absolute;border: 1px greenyellow solid;width: 200px;height: 50px;}
</style>

map.addOverlay 的绘制和计算 

这里使用 上面的 case1 的相关代码 来查看

整个测试用例分为了三次状态, 第一个是初始状态, 第二个是 切换到 [10.065735, 10.459462] 附近, 第三个是切换到 [105.065735, 30.259462] 附近 

我们这里 着重关注 第三次切换

我们上面配置的 Overlay 的 autopan 相关配置为 margin 为 200, duration 为 1s, 我们这里是从做下切换到右上, 因此 overlay1 是距离右上 200px, 然后整个切换的耗时为 1s

注意这里 Overlay 的 autopan 切换的中心点不是将 Overlay 放在正中间, 只需要满足 autopanMargin 的配置即可 

我们可以将 autopanMargin 配置调整下, 再看下一个大概的情况, autoPan 只需要确保给定的元素在页面上能够找到即可 

然后 autopan 目标中心点计算方式如下 

这里 newCenterPx 的计算涉及到两个变量, 其一是 center, 即 map.getView().getCenter 为当前的 [10.065735, 10.459462]

另外一个 delta 计算结果为 [68617, -14213]

delta 的计算依赖于 overlayRect, 值为 [70137, -13923, 70337, -13873]

然后最终 计算出来新的中心点为 [104.29, 29.85]

保证的是 center 切换到新的中心点的时候 可以看到 [105.065735, 30.259462] 的 Overlay

正常绘制 以及 切换中心点的情况

这里切换到 case2 来执行 

会先执行 Overlay 然后再执行 map.getView().setCenter

Overlay 的 autopan 这个阶段, 可以看到和上面是一样的, 然后设置中心点为 [104.29, 29.85], 以及动画切换 

然后接着是 setCenter 的处理, 设置中心点为 [105.065735, 30.259462] 然后渲染 

这样最终的效果如下, center 为 点位的位置, 以及 overlay所在的位置 

异常绘制 以及 切换中心点的情况

这里切换到 case3 来执行 

会先执行 map.getView().setCenter 然后再 执行 Overlay

map.getView().setCenter

map.getView().setCenter 之后, 设置了 map 的中心点的字段为 [105.065735, 30.259462]

然后接下来的 applyTargetState 才会开始真实的数据的渲染, 切换 

Overlay 的 autopan 这个阶段

然后 autopan 目标中心点计算方式如下 

这里 newCenterPx 的计算涉及到两个变量, 其一是 center, 即 map.getView().getCenter 为当前的 [105.065735, 30.259462]

另外一个 delta 计算结果为 [68617, -14213]

delta 的计算依赖于 overlayRect, 值为 [70137, -13923, 70337, -13873]

可以看到 和上面正常的 Overlay 加载的时候会存在一些问题 

第一 center 变化了, 拿到的 overlayRect 还是 [10.065735, 10.459462] 状态下的 overlayRect, 然后计算出的偏移也是 [10.065735, 10.459462] 相比于 [105.065735, 30.259462] 的偏移 

然后 导致了计算中心点存在问题, 最终 autopan 切换到目标中心点之后, 切换到了一个错误的中心点, 导致页面看不到数据 

然后 我们大致推导一下 这个新的中心点

从上面 map.addOverlay 中我们可以看到 delta 对应的经纬度偏移大致为 [104.29-10.06, 29.85-10.45], 即为 [94.23, 19.4]

然后 大致的新的中心点位为 [105.065735+94.23, 30.259462+19.4] 为 [199.29, 49.65]

可以看到 和我们的推导一样

综上 核心问题就是, map.getView().setCenter 之后先切换了 map.view 的中心点的数据 

但是 View.applyTargetState 的过程是异步的 

Overlay 的Overlay.panIntoView 中 this.getRect(element, [outerWidth(element),outerHeight(element),]); 获取到的元素状态为 中心点为 [10.065735, 10.459462] 的状态下面的元素状态

然后一个是 最新的中心点位, 一个是基于 旧的中心点位元素状态计算的偏移, 然后 最终得到了一个 错误的结果

如何先切换中心点 然后再绘制 Overlay

然后 这里的一个 曲线救国的调整方式就是, 在 setCenter 渲染结束了之后, 在添加 Overlay, 调整的方式如下 

// case4. compensated case
_this.test10SetCenter([105.065735, 30.259462], "red")
setTimeout(function() {_this.test11AddOverlay([105.065735, 30.259462])
}, 1000)

然后 我们这里看一下 我们这里的 Overlay 的添加情况, 这会是 另外的一个状态

切换了中心点之后, 然后再执行 test11AddOverlay 的时候, 会发现 Overlay 的坐标在当前上下文的区域内, 不用进行 autopan, 直接跳过了 autopan 的流程 

完 

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

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

相关文章

MySQL多表联查会重复查找记录

在做尚上优选项目时&#xff0c;根据商品id查询商品参加的活动信息。需要根据skuid&#xff08;商品id&#xff09;对商品信息表、活动表、活动规则表进行多表联查。 但是发现&#xff0c;查询出来的数据会重复&#xff0c;如下图所示&#xff1a; 后把sql语句放在navicat中进…

web集群-lvs-DR模式基本配置

目录 环境&#xff1a; 一、配置RS 1、安装常见软件 2、配置web服务 3、添加vip 4、arp抑制 二、配置LVS 1、添加vip 2、安装配置工具 3、配置DR 三、测试 四、脚本方式配置 1、LVS-DR 2、LVS-RS 环境&#xff1a; master lvs 192.168.80.161 no…

opencv函数使用查找

opencv官方文档地址&#xff1a;https://docs.opencv.org/4.x/index.html 先选对应的版本opencv-python 以这个函数为例子 model cv2.face.LBPHFaceRecognizer.create() 点开后找face类的LBP里面就有create函数的用法

什么是智能物联网关?有哪些作用?

随着物联网技术的不断发展和普及&#xff0c;智能物联网关已经成为连接物理世界与数字世界的桥梁&#xff0c;成为实现万物互联的重要枢纽。那么&#xff0c;什么是智能物联网关&#xff1f;它又有哪些价值呢&#xff1f;今天&#xff0c;就让我们一起走进HiWoo Box的世界&…

5、双亲委派机制

双亲委派机制指的是&#xff1a;当一个类加载器接收到加载类的任务时&#xff0c;会自底向上查找是否加载过&#xff0c; 再由顶向下进行加载。 详细流程&#xff1a; 每个类加载器都有一个父类加载器。父类加载器的关系如下&#xff0c;启动类加载器没有父类加载器&#xff1…

Python将字符串转换为datetime

有这样一些字符串&#xff1a; 1710903685 20240320110125 2024-03-20 11:01:25 要转换成Python的datetime 代码如下&#xff1a; import functools import re from datetime import datetime, timedelta from typing import Union# pip install python-dateutil from date…

鸿蒙一次开发,多端部署(十五)常见问题

如何查询设备类型 设备类型分为default&#xff08;默认设备&#xff09;、tablet、tv、wearable、2in1等&#xff0c;有多种查询设备类型的方式。 通过命令行的方式查询设备类型。 通过命令行查询指定系统参数&#xff08;const.product.devicetype&#xff09;进而确定设备…

Linux(Centos)安装mysql 8 并且使用systemctl管理服务

1.下载mysql包 地址 MySQL :: Download MySQL Community Server (Archived Versions) 注&#xff1a;下载我圈住的减压之后里面会有tar.gz 再次减压才会是软件主体 2.安装和准备 yum -y install numactl 安装numactl tar -xvf mysql-8.0.30-el7-x86_64.tar 拆分 …

逆向爬虫技术的进阶应用与实战技巧

前言 在互联网的海洋中&#xff0c;数据是无价的财富。爬虫技术作为获取这些数据的重要手段&#xff0c;一直备受关注。然而&#xff0c;随着网站反爬虫机制的日益完善&#xff0c;简单的爬虫程序已经很难满足我们的需求。因此&#xff0c;掌握爬虫逆向技术&#xff0c;突破反爬…

【计算机网络篇】数据链路层(3)差错检测

文章目录 &#x1f95a;误码&#x1f354;两种常见的检错技术⭐奇偶校验⭐循环冗余校验&#x1f388;例子 &#x1f95a;误码 误码首先介绍误码的相关概念 &#x1f354;两种常见的检错技术 ⭐奇偶校验 奇校验是在待发送的数据后面添加1个校验位&#xff0c;使得添加该校验…

NVIDIA最新 Blackwell架构简介

NVIDIA Blackwell架构简介 在AI和大型语言模型&#xff08;LLMs&#xff09;迅速发展的领域中&#xff0c;追求实时性能和可扩展性至关重要。从医疗保健到汽车行业&#xff0c;组织正深入探索生成性AI和加速计算解决方案的领域。对生成性AI解决方案的需求激增&#xff0c;促使企…

【前端寻宝之路】学习和使用表单标签和表单控件

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-cR8zvB8CkpxTk485 {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

Linux——生产者消费者模型

为何要使用生产者消费者模型 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯&#xff0c;而通过阻塞队列来进行通讯&#xff0c;所以生产者生产完数据之后不用等待消费者处理&#xff0c;直接扔给阻塞队列&#xff0c;…

MUNIK第二届功能安全及自动驾驶研讨会将在沪召开

2024年4月26日,由上海秒尼科技术服务有限公司(以下简称“Munik”)联合Parosoft主办的“第二届功能安全及自动驾驶研讨会”将在上海虹桥隆重开幕。 据了解,本次功能与自动驾驶安全研讨会,将聚焦在ISO 26262标准体系下,自动驾驶新形势下各个零部件供应商如何满足功能安全等相关重…

论文解读:Relational Embedding for Few-Shot Classification

文章汇总 问题 最近的方法通过元学习一个深度嵌入函数来解决小样本问题&#xff0c;使得嵌入空间上图像之间的距离符合它们的语义距离。然而&#xff0c;学习到的嵌入函数经常会过度拟合到不相关的特征[4,9,14]&#xff0c;从而无法迁移到训练中尚未观察到的新类。 动机 与…

web自动化--元素定位之xpath和css

元素定位 xpath绝对路径相对路径案例xpath策略&#xff08;路径&#xff09;案例xpath策略&#xff08;层级、扩展&#xff09;属性层级与属性层级与属性拓展层级与属性综合 csscss选择器&#xff08;id、类、标签、属性&#xff09;id选择器类选择器标签选择器属性选择器案例-…

重看Spring聚焦BeanFactory分析

目录 一、理解BeanFactory &#xff08;一&#xff09;功能性理解 &#xff08;二&#xff09;BeanFactory和它的子接口 &#xff08;三&#xff09;BeanFactory的实现类 二、BeanFactory根接口 &#xff08;一&#xff09;源码展示和理解 &#xff08;二&#xff09;基…

增强现实(AR)在广告中的力量

The Power of AR in Advertising 写在前面 增强现实&#xff08;AR -Augmented Reality&#xff09;是指借助软件、应用程序和智能手机、平板电脑或耳机等设备&#xff0c;为日常生活添加视觉和音频元素的技术。如今&#xff0c;品牌和广告商可以在营销活动中使用AR&#xff0…

IT运维服务规范标准与实施细则

一、 总则 本部分规定了 IT 运维服务支撑系统的应用需求&#xff0c;包括 IT 运维服务模型与模式、 IT 运维服务管理体系、以及 IT 运维服务和管理能力评估与提升途径。 二、 参考标准 下列文件中的条款通过本部分的引用而成为本部分的条款。凡是注日期的引用文件&#xff0c…

Python通过Ctypes调用C++类,实测有效

文章目录 前言创建vs dll工程添加外部库编辑代码编译测试参考 前言 在软件开发中&#xff0c;有时候需要Python与C相结合&#xff0c;以充分发挥两者的优势 。Python作为一种高级编程语言&#xff0c;具有简洁易读的特点&#xff0c;适用于快速开发和原型设计。而C则是一种性能…