当前位置: 首页 > news >正文

Opnelayers:向某个方向平移指定的距离

一、需求分析

我想要封装一个平移方法,这个方法的功能是可以让视图向某个方向平移一定的距离。除了基础的能力外,我还希望有以下的功能:

  1. 可以自定义动画持续时间
  2. 可以自定义平移结束后的回调
  3. 可以自定义移动的方向,如:上、下、左、右等。
  4. 可以自定义移动距离的单位,如:米、像素等。

二、思路梳理

首先肯定还是基于veiw.animate()方法实现平移的功能。因此就需要计算出平移后的视图中心点坐标。

接下来就需要解决以下的几个问题:

① 如何根据平移的距离和平移的方向计算我们目标位置的坐标?

这个很简单,其实就是坐标正算

坐标正算是指根据已知点的坐标、已知边长及该边的坐标方位角,计算未知点的坐标。简单来说,就是已知起点坐标、两点间的距离和方位角,求终点坐标。

它的公式如下:


② 如何实现自定义移动方向?

移动方向本质上就是方位角,我可以预设一些固定的方位值(例如,向上是0度角)也以一个数字作为方位角。

‘top’  -   表示 0° 方位角

180  -  表示 180° 方位角


③ 如何兼容多种距离单位?

想要兼容多种距离单位就需要在计算目标点坐标时进行单位转换,统一各个数值的单位。我计划平移方法支持 米、千米、像素 三种单位,并最终全部转换为像素单位。转换的方法如下:

像素 = 米 / 分辨率

像素 = ( 千米 * 1000 ) / 分辨率

因为分辨率就表示图上一个像素所对应的实地距离,因此可以利用分辨率将移动距离由米转换为像素。


具体的实现步骤如下:

  1. 获取平移起点的坐标(即视图中心点坐标)
  2. 将起点坐标由地理空间坐标(以米或度为单位)转换为屏幕坐标(以像素为单位)
  3. 将移动距离的单位全部转换为像素
  4. 计算平移的方位角
  5. 根据起点坐标、平移距离、方位角计算终点距离
  6. 将终点坐标由屏幕坐标(以像素为单位)转换为地理空间坐标(以米或度为单位)
  7. 执行veiw.animate()方法

三、成果展示

平移方法

 

/*** @abstract 向某个方向平移一段距离* @param {*} map* @param {number} distance 要平移的距离* @param { 'top' | 'bottom' | 'left' | 'right'  | 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | number } direction 要平移的方向  如果参数为一个数字则表示方位角(以度为单位)* @param { 'px' | 'm' | 'km' } unit 距离的单位* @param {number} duration 动画持续时间* @param {function} done 动画结束后的回调函数*/
export const pan = (map,{ distance, direction, unit = "m", duration = 1000 },done = () => {}
) => {// 获取当前视图中心点坐标const view = map.getView();const center = view.getCenter();const resolution = view.getResolution();// 将中心点坐标转换为像素坐标const centerPixel = map.getPixelFromCoordinate(center);// 将需要移动的距离转换为像素距离let finalDistance = distance;if (unit === "km") {finalDistance =(distance * 1000) /(resolution * view.getProjection().getMetersPerUnit());} else if (unit === "m") {finalDistance =distance / (resolution * view.getProjection().getMetersPerUnit());}// 计算方位角let alpha;if (typeof direction === "number") {alpha = direction * (Math.PI / 180);} else {switch (direction) {case "top":alpha = 270 * (Math.PI / 180);break;case "bottom":alpha = 90 * (Math.PI / 180);break;case "left":alpha = 180 * (Math.PI / 180);break;case "right":alpha = 0;break;case "top-left":alpha = 225 * (Math.PI / 180);break;case "top-right":alpha = 135 * (Math.PI / 180);break;case "bottom-left":alpha = 315 * (Math.PI / 180);break;case "bottom-right":alpha = 45 * (Math.PI / 180);break;default:return;}}// 通过坐标正算计算平移后的中心点坐标let newCenterPixel = [];newCenterPixel[0] = centerPixel[0] + finalDistance * Math.cos(alpha);newCenterPixel[1] = centerPixel[1] + finalDistance * Math.sin(alpha);// 将新的中心点坐标转换为地理坐标const newCenter = map.getCoordinateFromPixel(newCenterPixel);// 执行平移动画view.animate({center: newCenter,duration: duration,},done);
};

四、要点分析

1.空间坐标与屏幕坐标的转换

在OpenLayers中可以通过内置的方法实现空间坐标与屏幕坐标的转换

view.getPixelFromCoordinate(coordinate)  // 空间坐标 => 屏幕坐标view.getCoordinateFromPixel(pixel)       // 屏幕坐标 => 空间坐标

2.注意地理坐标系统对分辨率的影响

我们需要通过分辨率来实现地理单位(km,m)与 像素单位(px)的转换。但是分辨也是会受当前地图的地理坐标系统的影响:

  • projection:'EPSG:4326' (地理坐标系),则分辨率的单位是度。
  • projection:'EPSG:3857'(投影坐标系),则分辨率的单位是米。

因此如果当前地图使用的是像'EPSG:4326'这样的地理坐标系,就需要将分辨率的单位由度转换为米,这样才能使用分辨率正确的计算出要平移的距离。

可以通过projection.getMetersPerUnit()方法来获取当前坐标系下1个单位长度所对应的米数。

因此在考虑了地理坐标系统的影响后,将平移距离的单位转换为像素的公式就可以这样写:

像素 = 米 / ( 分辨率 * 当前坐标系每单位对应米数 )

像素 = ( 千米 * 1000 ) / ( 分辨率 * 当前坐标系每单位对应米数 )

对应到代码中就是这样:

// m => px
distance_px = distance_m / (resolution * view.getProjection().getMetersPerUnit());// km => px
distance_px = (distance_m * 1000) / (resolution * view.getProjection().getMetersPerUnit());

3.注意在屏幕坐标系下的角度

当我们将点和距离都转换为像素单位后,坐标就需要遵循屏幕坐标系,屏幕坐标系是以屏幕左上角为原点,向右为x周正方形,向下位y轴的正方向。

因此在计算方位角时就要以从左向右的这条线为零度线进行计算。

在屏幕坐标系下各个方向所对应的方位角如下:

方向

方位角(度)

270°

90°

180°

左上

225°

右上

315°

右下

45°

左下

135°

参考资料

  1. OpenLayers v10.5.0 API - Class: Map
  2. OpenLayers v10.5.0 API - Class: Projection
  3. Canvas学习系列二:Canvas的坐标系统 - 六小登登 - 博客园
http://www.xdnf.cn/news/181963.html

相关文章:

  • 7.14 GitHub命令行工具测试实战:从参数解析到异常处理的全链路测试方案
  • 视觉导航中的回环检测技术解析
  • Gentex EDI 需求分析
  • 封装成帧的学习
  • 软考-软件设计师中级备考 2、计算机系统组成、指令系统
  • 【JavaScript】二十七、用户注册、登陆、登出
  • Ldap高效数据同步- MirrorMode双主复制模式配置详解(上)
  • 【KWDB创作者计划】_企业级多模数据库实战:用KWDB实现时序+关系数据毫秒级融合(附代码、性能优化与架构图)
  • OpenGl ES 3.0 笔记一:初步概念
  • 4.27 JavaScript核心语法+事件监听
  • 小球在摆线上下落的物理过程MATLAB代码
  • NL2SQL调研
  • 抗体品牌及产品介绍
  • 【三大特性】对象模型
  • 前端开发资源缓存策略
  • 全球城市范围30米分辨率土地覆盖数据(1985-2020)
  • 信奥赛之c++基础(常用数学函数)
  • 显存在哪里看 分享查看及优化方法
  • Milvus如何实现关键词过滤和向量检索的混合检索
  • 文本向量化
  • 深入解析Promise:从基础原理到async/await实战
  • 4月27日星期日今日早报简报微语报早读
  • 牟乃夏《ArcGIS Engine地理信息系统开发教程》学习笔记3-地图基本操作与实战案例
  • 二叉树遍历(C语言版)
  • 解决升级WIN11(WINSERVER2025)后 远程桌面内 部分内容 显示 花屏 替换文件
  • 【Luogu】动态规划六
  • Python中数据切片操作详解和代码示例
  • AI实战SEO关键词优化法
  • 【视频生成模型】通义万相Wan2.1模型本地部署和LoRA微调
  • 初中级前端面试全攻略:自我介绍模板、项目讲解套路与常见问答