JS图形编辑器场景坐标视口坐标的相互转换

目录
  • 图形编辑器坐标系
  • 视口坐标转换为场景坐标
  • 场景坐标转换为视口坐标

图形编辑器坐标系

图形编辑器的坐标系有两种。

一个是场景(scene)坐标系,一个是 视口(viewport)坐标系。视口就是场景的一个子区域。

假设我们的视口的原点,离场景原点的坐标水平和垂直距离分别为 scrollX 和 scrollY。

先 不考虑缩放,假设我们在视口坐标上的某个地方点击了一下,这个坐标是 (x, y)。这个坐标在场景坐标系中,就是:

const sceneX = scrollX + x;
const sceneY = scrollY + y;

挺简单。

视口坐标转换为场景坐标

下面我们引入画布缩放,即画布可以缩小和放大,对应的一个比例值 zoom。

视口中的某个坐标 (x, y) 在场景坐标系,则是 :

function viewportCoordsToSceneCoords(x, y, scrollX, scrollY, zoom) {
  return {
  x: scrollX + x / zoom,
  y: scrollY + y / zoom
  }
}

之所以要用 x 除以 zoom,是因为此时视口中展示的是缩放后的图形,里面的坐标都是缩放后的值。所以需要先转换为 zoom 值为 1 对应的真实值。

场景坐标转换为视口坐标

然后我们反过来,如何从场景坐标 (x, y) 转换为视口坐标?将前面的公式做等式变换即可:

function sceneCoordsToViewportCoords(x, y, scrollX, scrollY, zoom) {
  return {
  x: (x - scrollX) * zoom,
  y: (y - scrollY) * zoom
  };
}

我们通常是使用按键加滚轮的方式让画布以光标为中心进行缩放,或按按钮进行缩放,

为了让缩放后的场景还能对上缩放前光标的位置,我们需要计算缩放后的 scrollX 和 scrollY,进行校准。

核心思路是 保持缩放前点到视口左上角距离(视口坐标系)相同

function calScrollVal(cx, cy, prevZoom, zoom, scrollX, scrollY) {
  // 先计算目标点的场景坐标(这里 cx 和 cy 是基于视口坐标系的)
  const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords(cx, cy, prevZoom, scrollX, scrollY);
  // 缩放后画布缩放比变成了 zoom,距离视口左上角的距离变成了 cx / zoom
  // 减去这个距离,就是新的 scrollX 了。
  const newScrollX = sceneX - cx / zoom;
  const newScrollY = sceneY - cy / zoom;
  return {
    x: newScrollX,
    y: newScrollY
  };
}

再说点别的。

可能会有这么一种情况,就是实际的视口区域的原点坐标有一些偏移,偏移了 offsetX 和 offsetY,见下图。

我们只需要将前面代码中的 scrollX 变成 (scrollX + offsetX),scrollY 变成 (scrollY + offsetY),其他不变。

就这些了。

总结一下,视口坐标是场景坐标平移并缩放后的结果,所以视口转场景,需要除以 zoom 再加上偏移值。在图形编辑器中,会有相当多的坐标系转换逻辑,这两个坐标系的关系需要好好消化理解,更多关于JS场景视口坐标转换的资料请关注我们其它相关文章!

(0)

相关推荐

  • JavaScript实现捕获鼠标坐标

    本文实例为大家分享了JavaScript实现捕获鼠标坐标的具体代码,供大家参考,具体内容如下 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件对象</title> <style> .box1{ width: 300px; height: 100px; border: 1px solid #

  • JavaScript使用canvas绘制坐标和线

    本文实例为大家分享了JavaScript使用canvas绘制坐标和线的具体代码,供大家参考,具体内容如下 具体代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>在指定位置画多个点</title> <style> canvas{ border: 1px dashed gray; } &

  • 基于JavaScript实现数值型坐标轴刻度计算算法(echarts的y轴刻度计算)

    目录 前言 算法描述 代码 ts版本(2021/3/10补充) 结语 前言 因实习的公司是做大数据的,而我的工作刚好又是需要绘制一些数据图表的.绘制图表有许多现成的组件可以使用,但是要想达到产品所需要的效果,只靠组件内部的一些功能是不太够的.一些细腻的要求必须在掌握组件原理方法的情况下,自己去写算法来完成.例如,本文要说的这个刻度计算算法,开始正文之前,我先描述遇到的问题.echarts自身的刻度计算有时候并不好用,例如有时候你希望让图表只有5条刻度线,即分成4段,echarts提供了一个参数叫

  • JavaScript 空间坐标的使用

    基础知识 首先参考画布分为视口(窗口)与文档的含义 网页很多都是多屏,所以文档尺寸一般大于视口尺寸 视口尺寸不包括浏览器工具条.菜单.标签.状态栏等 当打开控制台后,视口尺寸相应变小 文档像 position 定位,视口类似 fixed 定位 文档坐标在页面滚动时不发生改变 视口坐标的操作需要考虑滚动条的位置 视口文档 视口坐标需要知道滚动条位置才可以进行计算,有以下几种方式获取滚动位置 方法 说明 注意 window.innerWidth 视口宽度 包括滚动条(不常用) window.inne

  • js中火星坐标、百度坐标、WGS84坐标转换实现方法示例

    本文实例讲述了js中火星坐标.百度坐标.WGS84坐标转换实现方法.分享给大家供大家参考,具体如下: //定义一些常量 var x_PI = 3.14159265358979324 * 3000.0 / 180.0; var PI = 3.1415926535897932384626; var a = 6378245.0; var ee = 0.00669342162296594323; /** * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换 * 即 百度 转 谷歌.高德

  • 如何利用js根据坐标判断构成单个多边形是否合法

    目录 安装 代码 测试 总结 前言 需求:在高德地图中判断用户绘制的围栏是否合法. 核心解决点:倒序依次判断如果是相邻的二根线段,判断是否有交点,非相邻的线段不相交. 安装 npm install @turf/helpers @turf/line-intersect 代码 /** * geometric 几何工具库 * @author maybe * @license https://gitee.com/null_639_5368 */ import * as turf from "@turf/

  • JavaScript offset实现鼠标坐标获取和窗口内模块拖动

    offset offset 即偏移量,使用 offset 系列相关属性可以 动态的 获取该元素的位置(偏移).大小等,如: 元素距离带有定位父元素的位置 获取元素自身的大小(宽度高度) 注:返回的数值不带单位 offset 系列常用的属性包括:     element.offsetParent     返回作为该元素带有定位的父级元素,如果父级元素没有定位,则返回 body     注意,parentNode 和 offsetParent 还是有本质上的区别的:parentNode 返回的是直接

  • JS图形编辑器场景坐标视口坐标的相互转换

    目录 图形编辑器坐标系 视口坐标转换为场景坐标 场景坐标转换为视口坐标 图形编辑器坐标系 图形编辑器的坐标系有两种. 一个是场景(scene)坐标系,一个是 视口(viewport)坐标系.视口就是场景的一个子区域. 假设我们的视口的原点,离场景原点的坐标水平和垂直距离分别为 scrollX 和 scrollY. 先 不考虑缩放,假设我们在视口坐标上的某个地方点击了一下,这个坐标是 (x, y).这个坐标在场景坐标系中,就是: const sceneX = scrollX + x; const 

  • js 公式编辑器 - 自定义匹配规则 - 带提示下拉框 - 动态获取光标像素坐标

    引言 前段时间发了一个编辑器的插件,忙完后自己再次进行了详细的测试,然后心里冒出一句:"这谁写的这么奇葩的插件?完全没什么luan用啊!" 自己做了让自己不满意的事,咋整?男人不怕累,花了时间重写(为世界上所有像我一样勤劳的男人点赞)~ 思维导图 在小生看来,在开发每一个新功能的时候都应该做到心中有一张思维导图:功能实现逻辑和实现功能大致的方法.当然我们不可能在还没动手 前就考虑得面面俱到,但在正式开发之前心里对整个流程有个清晰的印象肯定会让我们在动手时愈加流畅(喝口娃哈哈美滋滋,看图

  • 图形编辑器中JS实现防误操作之拖拽阻塞

    目录 图形编辑器中 代码改造 结尾 图形编辑器中 在图形编辑器中,想象这么一个场景,我们撤销了一些重要的操作,然后想选中一个图形,看看它的属性.你点了上去,然后你发现你再也无法重做了. 你以为你点了一下,但其实你点击的时候,鼠标还是小小移动了一点,飘了一个像素点.对编辑器来说,它识别到让图形移动一个像素点的操作,就生成了一个新的版本,然后重做栈(redoStack)被清空了,你退回前的操作就没了. 为了解决这类用户微小操作的问题,我们可以巧妙地给拖拽行为加一个 阻塞阈值.具体就是就是按下鼠标后,

  • javascript获取文档坐标和视口坐标

    元素的位置是以像素度量的,向右代表X坐标的增加,向下代表Y坐标的增加,但是,有两个不同的点作为坐标系的原点:元素的X和Y坐标可以相对于文档的左上角或者相对于在职中显示文档的视口的左上角. 在定级窗口和标签页中,"视口"只是实际显示文档内容的浏览器的一部分:它不包括浏览器的"外壳"(如菜单.工具条和标签页). 针对框架也中显示的文档,是口试定了框架页的<iframe>元素.无论在何种情况下,当讨论元素的位置是,必须弄清楚所使用的坐标是文档坐标还是视口坐标.

  • js模拟3D场景效果代码打包

    要在二维空间模拟出三维的效果,就需要把三维的坐标转换成二维坐标.一个最基本依据是:东西越远,看到大小就越小,坐标越往消失点靠拢. 透视公式: scale = fl / (fl + z); scale是大小的比例值,0.0到1.0之间,fl是观察点到成像面的距离,通常这个值是固定,z就是物件的三维空间中的z轴. 在写这些代码之前,我喜欢用面向对象来描述我写的这些东西,比如我需要一个场景,场景是个空间,空间内是可以容纳各种物件的,物件是个对象,物件是是x,y,z三个维度的,场景可以插入任意多的物件,

  • JS模仿编辑器实时改变文本框宽度和高度大小的方法

    本文实例讲述了JS模仿编辑器实时改变文本框宽度和高度大小的方法.分享给大家供大家参考.具体如下: 这里演示JS模仿编辑器中实时改变文本框大小,包括宽度和高度的方法,在一些在线编辑器,比如eWebEditor中,就有一个功能,让文本框不断的增大或减小,以适应页面的大小,这个功能是如何实现的呢?请您参考一下这个程序,相信你会从中获益. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-editor-cha-width-height-codes/

  • js内存泄漏场景、如何监控及分析详解

    目录 前言 哪些情况会引起内存泄漏 1. 意外的全局变量 2. 遗忘的定时器 3. 使用不当的闭包 4. 遗漏的 DOM 元素 5. 网络回调 如何监控内存泄漏 如何分析内存泄漏,找出有问题的代码 实例分析 总结 前言 Q:什么是内存泄漏? 字面上的意思,申请的内存没有及时回收掉,被泄漏了 Q:为什么会发生内存泄漏? 虽然前端有垃圾回收机制,但当某块无用的内存,却无法被垃圾回收机制认为是垃圾时,也就发生内存泄漏了 而垃圾回收机制通常是使用标志清除策略,简单说,也就是引用从根节点开始是否可达来判定

  • 如何利用JS检查元素是否在视口内

    前言 分享两个监测元素是否在视口内的方法 1. 位置计算 使用 Element.getBoundingClientRect() 方法返回元素相对于视口的位置 const isElementVisible = (el) => { const rect = el.getBoundingClientRect(); }; 获取浏览器窗口的宽高 const isElementVisible = (el) => { const rect = el.getBoundingClientRect(); cons

  • js 获取坐标 通过JS得到当前焦点(鼠标)的坐标属性

    通过JS得到当前焦点的坐标 如下是得到当前焦点的坐标: 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head

  • Js和JQuery获取鼠标指针坐标的实现代码分享

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> <ti

随机推荐