【问题标题】:Get position on canvas AFTER rotating/translating and restoring旋转/平移和恢复后在画布上获取位置
【发布时间】:2012-02-09 07:11:25
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你有与你所画的东西相关的对象吗?你有场景图吗?每个对象都有矩阵吗?如果没有,你如何保存你所画的位置和旋转?
  • 是的,正方形也作为对象存在,其值为 x、y、w、h、r。它变得复杂的一点是,一个对象也可以有继承父位置和旋转的子对象,并根据父对象的原点进行定位和旋转。

标签: javascript html math canvas mouse


【解决方案1】:

是的,您必须转换鼠标坐标或为您的形状保留第二组坐标。我建议保留第二组坐标,因为您移动鼠标的次数要比变换对象的次数多。尝试使用这样的对象

盒子

function Box(x, y, w, h){
    this.x = x;
    this.y = y;
    this.tx = x;    //transformed x
    this.ty = y;    //transformed y
    this.w = w;
    this.h = h;

    this.mouseover = function(x, y){
        if (this.tx < x && this.tx + this.w > x && this.ty < y && this.ty + this.h > y){
            return true;
        }
        return false;
    }

    this.applyTransformation = function(transformation){
        switch(transformation){
        case 'rotation':
            //update tx/ty to match rotation
            break;
        case 'translation':
            //update tx/ty to match translation
            break;
       default:
            //do nothing or raise exception
    }
}

【讨论】:

    【解决方案2】:

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

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

    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 };
    };
    

    用这些对象试试吧:

    el1 = {x:3,y:0,r:45};
    el2 = {x:0,y:0,r:45};
    el1.parent = el2;
    getXYR(el1);
    

    很快你就会想计算两个物体之间的最短角度,如果你得到两个物体之间的 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;
    }
    

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

    这是使用矩阵(和 gl-matrix 库 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 );
    };
    

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

    【讨论】:

    • 你的回答太棒了!感谢您为帮助我所做的所有努力:) 我直接采用矩阵方式 - 目前似乎有点复杂,但我希望从长远来看它会有所回报。此外,我没有选择使用 gl-matrix 而是 Sylvester.js,因为 gl-matrix 对我的矩阵做了一些奇怪的事情,并且与 ctx.transform() 等待的矩阵格式相差太多。我希望我的大脑不会在矩阵幂x下融化)
    • 很好的答案,另一个问题!这个问题考虑了三个因素,x、y和r;如果考虑所有转换因素会怎样。我的意思是,如果应用了缩放、平移、倾斜和旋转变换,算法会怎样。你的算法的来源是什么。
    • @bennedich 你能看看这个问题吗? stackoverflow.com/questions/10892267/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-12
    • 2022-11-30
    • 2017-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多