Mat*_*hew 1 javascript html5 canvas
我正在测试鼠标是否位于对象上.问题是对象已被转换.我有对象图,主要是相机,然后是滑块对象,最后是形状对象.我需要能够看到鼠标坐标是否在相对于形状对象的指定矩形内.
在这里,我有我的游戏循环,它会转换清除画布,然后转换相机.然后我进入for循环并循环遍历调用其特定"draw"方法的所有对象,传入已转换的上下文.
Game.prototype.gameLoop = function()
{
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].update();
this.objects[i].draw(this.context);
}
this.context.restore();
}
Run Code Online (Sandbox Code Playgroud)
这是绘制方法的对象之一.该对象称为Slider.它被成功调用并根据它的x,y和旋转值执行转换.
Slider.prototype.draw = function(ctx)
{
ctx.save();
ctx.translate(this.x,this.y);
ctx.rotate(this.rotate);
this.pointer.draw(ctx);
ctx.fillStyle = "black";
ctx.beginPath();
ctx.moveTo(-(this.width/2),0);
ctx.lineTo((this.width/2),0);
ctx.lineTo((this.width/2),5);
ctx.lineTo(-(this.width/2),5);
ctx.fill();
ctx.restore();
}
Run Code Online (Sandbox Code Playgroud)
最后我得到了Shape的draw方法,该方法被成功调用并再次转换上下文.
Shape.prototype.draw = function(ctx)
{
ctx.save();
ctx.translate(this.x,this.y);
ctx.rotate(this.rotate);
if(this.isMouseOver)
ctx.fillStyle = this.color;
else
ctx.fillStyle = this.mouseOverFillColor;
ctx.fill(this.shape);
ctx.restore();
}
Run Code Online (Sandbox Code Playgroud)
最后,这是当鼠标移动时调用的方法"mouseEventListener".我需要能够转换坐标以查看它们相对于形状.
Shape.prototype.mouseEventListener = function(evt,type)
{
console.log(evt.clientX+" "+evt.clientY);
}
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?如果需要,我可以创建一个父指针对象,并使形状指向滑块,滑块指向相机以访问每个父级的x,y,旋转值.
我正在寻找相当于Android的mappoints方法,它根据矩阵转换点.在这种情况下,上下文已被多次转换,我需要一种方法来捕获每个对象的状态,然后转换一些点.
我还想在没有任何其他库的情况下轻松完成所有这些工作.
谢谢.
在写这个答案时,我注意到标准刚刚改变了.HTML标准文档2016年11月28日
现在有两个对canvas 2D API的新调用
ctx.getTransform()ctx.resetTransform()GetTransform返回的a DOMMatrix与返回a 的现有currentTransform不同SVGMatrix.
目前我还不知道采用和使用这两个新的(最受欢迎和需要的)电话.
现在回到我的常规交战回答.
在完美的世界中,你会使用
var mat = ctx.currentTransform;
var mat = ctx.getTransform();
Run Code Online (Sandbox Code Playgroud)
它返回一个DOMMatrix,然后你得到它的逆矩阵.SVGMatrix
var invMat = mat.inverse();
mat.invertSelf();
Run Code Online (Sandbox Code Playgroud)
然后从屏幕坐标转换为世界坐标
我现在猜测DOMMatrix有a,b,c,d,e,f但我知道它们是否是2D,因为DOMMatrix是一个3D矩阵.
var wX = screenX * invMat.a + screenY * invMat.c + invMat.e;
var wY = screenX * invMat.b + screenY * invMat.d + invMat.f;
Run Code Online (Sandbox Code Playgroud)
就是这样.
但由于某些原因,浏览器似乎认为没有这个标准对象我们的生活会变得更好.写大量的慢速javascript更好.
ctx.currentTransform隐藏在前缀(moz)和标志(chrome实验画布API)后面并忽略IE(不知道Edge会做什么??)
要解决您的问题,您需要用自己的转换替换所有转换,以便跟踪当前转换.有很多JS库可以帮到你.请注意,大多数人都不知道静态内存/对象池,并且可能会在代码中添加过度的性能命中.我现在不会支持任何lib.
矩阵数学模块的示例
var matrixMath =( function(){
var _a,_b,_c,_d,_e,_f;
var xdx,xdy;
var stack = [];
var stackPos = 0;
var API = {
// matrix = create() // creates identity matrix 1,0,0,1,0,0
// matrix = create([1,0,0,1,0,0]); // creates from array
// matrix = create(matrix); // creates from matrix (copy)
// matrix = create(x, y, scale, rotate); // creates from x,y uniform scale and rotation
// matrix = create(x, y, scaleX, scaleY, rotate); // creates from x,y, scaleX,scaleY, rotation
// matrix = create(a,b,c,d,e,f);
create : function(a,b,c,d,e,f){
var mat = {};
if(a === undefined){
mat.a = mat.d = 1;
mat.b = mat.c = mat.e = mat.f = 0;
return mat;
}
if(Array.isArray(a)){
mat.a = a[0];
mat.b = a[1];
mat.c = a[2];
mat.d = a[3];
mat.e = a[4];
mat.f = a[5];
return mat;
}
if(a.a !== undefined){
mat.a = a.a;
mat.b = a.b;
mat.c = a.c;
mat.d = a.d;
mat.e = a.e;
mat.f = a.f;
return mat
}
if(f === undefined){
mat.e = a;
mat.f = b;
if(e === undefined){
mat.d = mat.a = Math.cos(d) * c;
mat.c = -(mat.b = Math.sin(d) * c);
return mat;
}
mat.d = (mat.a = Math.cos(e)) * d;
mat.c = -(mat.b = Math.sin(e)) * d;
mat.a *= c;
mat.b *= c;
return mat;
}
mat.a = a;
mat.b = b;
mat.c = c;
mat.d = d;
mat.e = e;
mat.f = f;
return mat
},
// point = matrixMultPoint(matrix,x,y,returnPoint) // returnPoint is optional.
matrixMultPoint : function(mA,x,y,point){
if(point === undefined){
point = {};
}
point.x = x * mA.a + y * mA.c + mA.e;
point.y = x * mA.b + y * mA.d + mA.f;
return point;
},
// C = A * B
// resultMatrix = matrixMult(matrixA, matrixB, returnMatrix); // returnMatrix is optional
matrixMult : function(mA,mB,mat){ // mat = mA * mB
if(mat === undefined){
mat = {};
}
mat.a = mA.a * mB.a + mA.c * mB.b;
mat.b = mA.b * mB.a + mA.d * mB.b;
mat.c = mA.a * mB.c + mA.c * mB.d;
mat.d = mA.b * mB.c + mA.d * mB.d;
mat.e = mA.a * mB.e + mA.c * mB.f + mA.e;
mat.f = mA.b * mB.e + mA.d * mB.f + mA.f;
return mat;
},
transform : function(mA,a,b,c,d,e,f){ // mat = mA * mB
_a = mA.a * a + mA.c * b;
_b = mA.b * a + mA.d * b;
_c = mA.a * c + mA.c * d;
_d = mA.b * c + mA.d * d;
mA.e = mA.a * e + mA.c * f + mA.e;
mA.f = mA.b * e + mA.d * f + mA.f;
mA.a = _a;
mA.b = _b;
mA.c = _c;
mA.d = _d;
return mA;
},
setTransform : function(mA,a,b,c,d,e,f){ // mat = mA * mB
mA.a = a;
mA.b = b;
mA.c = c;
mA.d = d;
mA.e = e;
mA.f = f;
return mA;
},
resetStack : function(){ // in case you do not match save and restores
// because you have re inited the 2D context
stackPos = 0;
stack.length = 0;
},
save : function(mA){
var mat;
if(stack.length <= stackPos){
stack[stackPos++] = API.create(mA);
return;
}
mat = stack[stackPos++];
mat.a = mA.a;
mat.b = mA.b;
mat.c = mA.c;
mat.d = mA.d;
mat.e = mA.e;
mat.f = mA.f;
},
restore : function(mA){
var mat;
if(stackPos > 0){
stackPos -= 1;
mat = stack[stackPos];
mA.a = mat.a;
mA.b = mat.b;
mA.c = mat.c;
mA.d = mat.d;
mA.e = mat.e;
mA.f = mat.f;
}
return mA;
},
identity : function(mA){
mA.a = mA.d = 1;
mA.b = mA.c = mA.e = mA.f = 0;
return mA;
},
translate : function(mA, x,y){ // mat = mat * translate(x,y)
mA.e = mA.a * x + mA.c * y + mA.e;
mA.f = mA.b * x + mA.d * y + mA.f;
return mA;
},
rotate : function(mA,rotate){
xdx = Math.cos(rotate);
xdy = Math.sin(rotate);
_a = mA.a * xdx + mA.c * xdy;
_b = mA.b * xdx + mA.d * xdy;
_c = mA.c * xdx - mA.a * xdy;
_d = mA.d * xdx - mA.b * xdy;
mA.a = _a;
mA.b = _b;
mA.c = _c;
mA.d = _d;
return mA;
},
// Scales mA
// matrix = scale(mA,scale); // uniform scale
// matrix = scale(mA,scaleX,scaleY); // scaleX,scaleY
scale : function(mA,scaleX,scaleY){
if(scaleY === undefined){
scaleY = scaleX;
}
mA.a *= scaleX;
mA.b *= scaleX;
mA.c *= scaleY;
mA.d *= scaleY;
return mA;
},
// invert(matrix,returnMatrix); // returnMatrix is optional
invert : function(mA,mat){
if(mat === undefined){
mat = {};
}
var d = mA.a * mA.d - mA.b * mA.c;
mat.a = mA.d / d;
mat.b = -mA.b / d;
mat.c = -mA.c / d;
mat.d = mA.a / d;
mat.e = (mA.c * mA.f - mA.d * mA.e) / d;
mat.f = -(mA.a * mA.f - mA.b * mA.e) / d;
return mat;
},
getRotate : function(mA,fromY){
return !fromY ? Math.atan2(mA.b,mA.a) : Math.atan2(mA.d,mA.c) ;
},
getScale : function(mA,fromY){
return !fromY ? Math.sqrt(mA.b * mA.b + mA.a * mA.a) : Math.sqrt(mA.c * mA.c + mA.d * mA.d) ;
},
getOrigin : function(mA,point){
if(point === undefined){
point = {};
}
point.x = mA.e;
point.y = mA.f;
return point;
},
}
return API;
})();Run Code Online (Sandbox Code Playgroud)
使用上面的代码镜像所有转换
// do once only
var cMatrix = matrixMath.create(); // create default identity matrix
var cIMatrix = matrixMath.create(); // create a matrix to hold the inverse
var worldP = {x:0,y:0}; // to hold world coordinates.
// in main loop
matrixMath.identity(cMatrix); // resets to default transform.
matrixMath.translate(cMatrix,x,y); // same as ctx.translate
matrixMath.rotate(cMatrix,angle); // same as ctx.rotate
matrixMath.scale(cMatrix,scaleX,scaleY); // same as ctx.scale.. Has variant see code.
matrixMath.transform(cMatrix,a,b,c,d,e,f); // same as ctx.transform
matrixMath.setTransform(cMatrix,a,b,c,d,e,f); // same as ctx.setTransform
matrixMath.save(cMatrix); // save and restores to matrixMath internal stack
matrixMath.restore(cMatrix); // NOTE very simple stack look at code to understand its function.
// set the context to the transform
ctx.setTransfrom(cMatrix.a, cMatrix.b, cMatrix.c, cMatrix.d, cMatrix.e, cMatrix.f);
// Draw what you need.
To get the world coordinates
cIMatrix = matrixMath.invert(cMatrix,cIMatrix);
// screenX,screenY are the screen position you wish to covert to world.
worldP = matrixMath.matrixMultPoint(cIMatrix,screenX,screenY,worldP);
// worldP.x and worldP.y are now in transformed space.
Run Code Online (Sandbox Code Playgroud)
请注意,该
matrixMath对象只是针对此答案编写的,未经测试.虽然已经通过了基本的解析测试,但它可能包含一些拼写错误.它仅用作矩阵数学的How To示例.
| 归档时间: |
|
| 查看次数: |
987 次 |
| 最近记录: |