问题
Okay, this is getting complicated...
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?
回答1:
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.org/TR/SVG/coords.html#NestedTransformations
This is how you would do it with matrices (and the 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 );
};
Oh, i forgot, now to finally register a click you just get the screen coordinates of the mouse and compare them to the objects position + the canvas viewport offset.
回答2:
Yes you have to either translate the mouse coordinates or retain a second set of coordinates for your shape. I recommend 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
}
}
来源:https://stackoverflow.com/questions/8844525/get-position-on-canvas-after-rotating-translating-and-restoring