旋转/平移和恢复后获取画布上的位置

Chr*_*gel 5 html javascript math mouse canvas

好吧,事情变得复杂了......

给定情况:
我有一个尺寸为 800x600 的画布。
我的鼠标位于画布位置 100x200(例如)。

我保存我的画布状态。
现在我旋转并平移画布,绘制一个正方形。
我恢复画布状态。

有什么方法可以确定我的鼠标是否位于方块上?
我想我也必须向相反的方向平移/旋转我的鼠标位置,但我该怎么做呢?

ben*_*ich 4

您可以通过递归应用以下公式来获取对象的世界位置/旋转:

worldX = parentX + x * Math.cos( parentR ) - y * Math.sin( parentR );
worldY = parentY + x * Math.sin( parentR ) + y * Math.cos( parentR );
worldR = parentR + r;
Run Code Online (Sandbox Code Playgroud)

一个 JavaScript 实现是:

var deg2rad, rad2deg, getXYR;

deg2rad = function ( d ) { return d * Math.PI / 180 };
rad2deg = function ( r ) { return r / Math.PI * 180 };

getXYR = function ( node ) {
  var x, y, r,
      parentXYR, pX, pY, pR,
      nX, nY;

  x = y = r = 0;

  if ( node ) {
    parentXYR = getXYR( node.parent );
    pX = parentXYR.x;
    pY = parentXYR.y;
    pR = deg2rad( parentXYR.r );
    nX = node.x;
    nY = node.y;

    x = pX + nX * Math.cos( pR ) - nY * Math.sin( pR );
    y = pY + nX * Math.sin( pR ) + nY * Math.cos( pR );
    r = rad2deg( pR + deg2rad( node.r ) );
  }

  return { x:x, y:y, r:r };
};
Run Code Online (Sandbox Code Playgroud)

使用这些对象尝试一下:

el1 = {x:3,y:0,r:45};
el2 = {x:0,y:0,r:45};
el1.parent = el2;
getXYR(el1);
Run Code Online (Sandbox Code Playgroud)

不久之后,您就会想要计算两个对象之间的最短角度,如果您获得两个对象之间的 deltaX (x2-x1) 和 deltaY (y2-y1),您可以使用此函数获得角度:

var getAngle = function ( dx, dy ) {
  var r = Math.atan2( dy, dx ) * 180 / Math.PI;
  return ( r > 180 )  ? r-360 :
         ( r < -180 ) ? r+360 :
         r;
}
Run Code Online (Sandbox Code Playgroud)

从长远来看,最好使用矩阵来学习。获得世界 pos/rot 的等价物是一个世界矩阵。这里有一些关于矩阵的好信息(在 SVG 文档中,但它不相关):http://www.w3.org/TR/SVG/coords.html#NestedTransformations

这是使用矩阵(以及 gl-matrix lib https://github.com/toji/gl-matrix)的方法:

var getWorldMatrix = function ( node ) {
    var parentMatrix;

    if ( !node )
        return mat4.identity();

    parentMatrix = getWorldMatrix( node.parent );
    return mat4.multiply( parentMatrix, node.matrix );
};
Run Code Online (Sandbox Code Playgroud)

哦,我忘了,现在要最终注册一次单击,您只需获取鼠标的屏幕坐标并将它们与对象位置+画布视口偏移进行比较。