Javascript 获取变换元素的局部坐标中的接触位置

Javascript 获取变换元素的局部坐标中的接触位置,javascript,cross-browser,css-transforms,mathjs,Javascript,Cross Browser,Css Transforms,Mathjs,我有一个元素,它已经用矩阵x3d进行了转换,以提供透视图。它代表手持设备的屏幕 有一个背景图像显示了手持设备本身,并且没有转换。保存此内容的元素已定位,屏幕元素绝对位于其内部,位于左侧:0;排名:0,然后进行转换,原点位于容器的左上角。对我来说,这是将其与背景图像完美对齐的最简单的方法(我曾经制作过矩阵),它将屏幕元素从角落移开 我希望能够通过鼠标和触摸事件与屏幕交互。要做到这一点,在点击或触摸事件中,我需要找到屏幕元素的本地坐标系中的坐标——也就是说,转换发生之前的坐标。换句话说,当单击手持设

我有一个元素,它已经用
矩阵x3d
进行了转换,以提供透视图。它代表手持设备的屏幕

有一个背景图像显示了手持设备本身,并且没有转换。保存此内容的元素已定位,屏幕元素绝对位于其内部,位于
左侧:0;排名:0,然后进行转换,原点位于容器的左上角。对我来说,这是将其与背景图像完美对齐的最简单的方法(我曾经制作过矩阵),它将屏幕元素从角落移开

我希望能够通过鼠标和触摸事件与屏幕交互。要做到这一点,在点击或触摸事件中,我需要找到屏幕元素的本地坐标系中的坐标——也就是说,转换发生之前的坐标。换句话说,当单击手持设备屏幕的左上角(它不是页面边界框的左上角!)时,我想要
[0,0]
,当单击屏幕的右上角时,在这种转换中,屏幕实际上在页面上更高,也更右,我想要
[untransformedWidth,0]

鼠标事件提供了
offsetX
offsetY
,据说正是这两个功能(下面将详细介绍),但触摸事件没有这些属性,因此我需要一种自己计算它们的方法

使用I可以输入转换矩阵并将其反转。我必须得到
transform:matrix3d(…)
规则(如果不需要的话,我不想在我的代码中重复它),我将跳过它——我知道它是有效的,因为数字与CSS匹配

请注意,CSS的矩阵元素是按列顺序排列的,因此
matrix3d(a、b、c、d、e、f、g、h、i、j、k、l、m、n、o、p)
在常规矩阵表示法中如下所示:

┌            ┐
│ a  e  i  m │
│ b  f  j  n │
│ c  g  k  o │
│ d  h  l  p │
└            ┘
同时,math.js希望它的矩阵逐行声明,比如
[[a,e,i,m],[b,f,j,n]…

因此,我从
matrix3d(…)
表达式中的数字元素列表开始,按照CSS顺序,构建并反转矩阵,如下所示:

如果我将一个标记(相对于容器)移动到此点
[x,y]
,它正好出现在我单击的位置。因此我知道这一切都在起作用。然后我将这些坐标的向量乘以逆变换矩阵:

  var vector = math.matrix([x, y, 0, 1]);
  var result = math.multiply(inverseMatrixTransform, vector);
如果我将另一个标记(该标记相对于屏幕元素)移动到结果向量的值
[result.get([0]),result.get([1])
它移动到与上一个标记大致相同的位置,但并不完全正确。似乎距离原点越远,错误越大,直到右边缘和下边缘非常糟糕为止

但是如果我检查一下
offsetX
offsetY
,结果会怎样呢?答案取决于浏览器

在Firefox中,使用偏移量*
找到的坐标与单击的位置也不匹配。它们与我的计算值不完全相同,但只是相差几个像素。它们与真正的单击点的距离与我的计算值一样远

但在Chrome中,用
offset*
找到的坐标是完美的

这是一个例子


我的计算有什么地方做错了吗?我有没有办法模仿Chrome的结果,但没有偏移量属性?

我对这个理论不是很确定,我在处理类似问题时读到过这个,但我发现了。矩阵的乘法(3d变换矩阵-齐次坐标和光标位置)产生除x和y之外的另外两个值。第一个是z,另一个是w,用于将3d对象投影到2d平面上

如果将向量的x和y值除以w坐标,则可以获得笛卡尔平面上光标的正确位置/贴图

因此,我将用以下代码替换您小提琴中的代码,第69-70行:

var x = result.get([0]);
var y = result.get([1]);
var w = result.get([3]);
screenCrosshair.style.left = x / w + 'px';
screenCrosshair.style.top = y / w + 'px';
以下是更新提琴:

然后不需要浏览器的
offsetX
offsetY
值来找到正确的位置

有关更多信息,请阅读以下文章:


我怀疑Firefox和Chrome中的
event.offset*
之间的不匹配可能是一个bug。我已经找到了。但是如果它是Firefox bug,我的代码中也存在相同的bug,我想找到它。这个bug似乎在Firefox版本50.0.2中得到了修复,尽管我仍然对这里的实际解决方案感兴趣。更正:我可以确认这个bug仍然存在这里,我的测试是错误的。如果这个问题得到解决,那就太好了。非常令人沮丧,不是吗?我的计算对你来说正确吗?我想知道这是否可能是数学中的某种错误。js…但更可能是我做错了。@tremby你找到解决方案或解决方法了吗?就是这样!非常感谢!看起来Mozilla有了解决方案他们的代码中有完全相同的错误,所以我将引导他们找到您的解决方案。
  var vector = math.matrix([x, y, 0, 1]);
  var result = math.multiply(inverseMatrixTransform, vector);
var x = result.get([0]);
var y = result.get([1]);
var w = result.get([3]);
screenCrosshair.style.left = x / w + 'px';
screenCrosshair.style.top = y / w + 'px';