最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Get position on canvas AFTER rotatingtranslating and restoring - Stack Overflow

programmeradmin1浏览0评论

Okay, this is getting plicated...

Given situation:
I have a canvas with the dimensions of 800x600.
My mouse is at canvas position 100x200 (for example).

I save my canvas state.
Now I rotate and translate the canvas, I draw a square.
I restore my canvas state.

Is there any way to determine if my mouse is over the square?
I think I would have to translate/rotate my mouse position as well - in the opposite direction, but how would I do this?

Okay, this is getting plicated...

Given situation:
I have a canvas with the dimensions of 800x600.
My mouse is at canvas position 100x200 (for example).

I save my canvas state.
Now I rotate and translate the canvas, I draw a square.
I restore my canvas state.

Is there any way to determine if my mouse is over the square?
I think I would have to translate/rotate my mouse position as well - in the opposite direction, but how would I do this?

Share Improve this question asked Jan 13, 2012 at 0:51 Christian EngelChristian Engel 3,7785 gold badges31 silver badges45 bronze badges 2
  • Do you have objects correlating to what you draw? Do you have a scenegraph? Do every object have a matrix? If not, how do you save position and rotation of what you draw? – bennedich Commented Jan 13, 2012 at 1:13
  • Yes, the square is also present as an object with the values x, y, w, h, r. The point where its getting plicated is that an object also can have children which inherit the parents position and rotation and are themselves positioned and rotated based on the parents origin. – Christian Engel Commented Jan 13, 2012 at 1:17
Add a ment  | 

2 Answers 2

Reset to default 4

You can get hold of an objects world position/rotation by recursively applying this formula:

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

A javascript implementation would be:

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

Try it out with these objects:

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

It won't be long before you want to calculate the shortest angle between two objects, if you get the deltaX (x2-x1) and deltaY (y2-y1) between the two objects you can get the angle with this function:

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

In the long run it's better to learn using matrices instead. The equivalence of getting the world pos/rot is a world matrix. Here's some good info about matrices (in the SVG doc, but it's not relevant): http://www.w3/TR/SVG/coords.html#NestedTransformations

This is how you would do it with matrices (and the gl-matrix lib https://github./toji/gl-matrix):

var getWorldMatrix = function ( node ) {
    var parentMatrix;

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

    parentMatrix = getWorldMatrix( node.parent );
    return mat4.multiply( parentMatrix, node.matrix );
};

Oh, i forgot, now to finally register a click you just get the screen coordinates of the mouse and pare them to the objects position + the canvas viewport offset.

Yes you have to either translate the mouse coordinates or retain a second set of coordinates for your shape. I remend keeping a second set of coordinates as you will move the mouse more times than you transform the object. Try using an object like so

Box

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
    }
}
发布评论

评论列表(0)

  1. 暂无评论