在javascript中旋转一个正方形 [英] rotating a square in javascript
问题描述
我试图在javascript中围绕它的中心旋转一个正方形。虽然在这种情况下,我使用画布来绘制正方形,我需要有一个旋转正方形的功能方法在其他地方使用,所以只是旋转画布是不能接受的。这是我到目前为止
var thecanvas = this.myCanvas;
var canvaswidth = thecanvas.width;
tlx =(0 - ((canvaswidth * 0.6)/ 2));
tly =(0 - ((canvaswidth * 0.6)/ 2));
trx =(0 +((canvaswidth * 0.6)/ 2));
tryy =(0 - ((canvaswidth * 0.6)/ 2));
blx =(0 - ((canvaswidth * 0.6)/ 2));
bly =(0 +((canvaswidth * 0.6)/ 2));
brx =(0 +((canvaswidth * 0.6)/ 2));
bry =(0 +((canvaswidth * 0.6)/ 2));
tlx =((tlx)*(this._cosD(orientation))) - ((tly)*(this._sinD(orientation))));
tly =((tlx)*(this._sinD(orientation))+(tly)*(this._cosD(orientation)))
trx =((trx)*(this._cosD(orientation))) - ((tryy)*(this._sinD(orientation))));
tryy =((trx)*(this._sinD(orientation))+(tryy)*(this._cosD(orientation)));
blx =((blx)*(this._cosD(orientation)) - (bly)*(this._sinD(orientation)));
bly =((blx)*(this._sinD(orientation))+(bly)*(this._cosD(orientation)))
brx =((brx)*(this._cosD(orientation)) - (bry)*(this._sinD(orientation)));
bry =((brx)*(this._sinD(orientation))+(bry)*(this._cosD(orientation)))
tlx =(tlx +(canvaswidth / 2));
tly =(tly +(canvaswidth / 2));
trx =(trx +(canvaswidth / 2));
tryy =(tryy +(canvaswidth / 2));
blx =(blx +(canvaswidth / 2));
bly =(bly +(canvaswidth / 2));
brx =(brx +(canvaswidth / 2));
bry =(bry +(canvaswidth / 2));
var c2 = thecanvas.getContext('2d');
c2.fillStyle ='#f00';
c2.beginPath();
c2.moveTo(tlx,tly);
c2.lineTo(trx,tryy);
c2.lineTo(brx,bry);
c2.lineTo(blx,bly);
c2.closePath();
c2.fill();`
orientation是从-90-90度。此代码开始旋转正方形,但正方形继续挤压,直到它完全消失90度。显然我的旋转公式抛弃了某个地方,但我不能弄清楚如何。
您可以手动实现。
未来将给予我们 currentTransform
上下文(目前仅在Chrome中可用,Firefox遇到错误)会返回 SVGMatrix
object ,你可以使用与上面的实现几乎相同的方式。
I am trying to rotate a square about its center in javascript. Although in this case I am using canvas to draw the square, I need to have a functional method of rotating the square for use elsewhere so just rotating the canvas is not acceptable. This is what I have so far
var thecanvas = this.myCanvas;
var canvaswidth = thecanvas.width;
tlx = (0 - ((canvaswidth * 0.6) / 2));
tly = (0 - ((canvaswidth * 0.6) / 2));
trx = (0 + ((canvaswidth * 0.6) / 2));
tryy = (0 - ((canvaswidth * 0.6) / 2));
blx = (0 - ((canvaswidth * 0.6) / 2));
bly = (0 + ((canvaswidth * 0.6) / 2));
brx = (0 + ((canvaswidth * 0.6) / 2));
bry = (0 + ((canvaswidth * 0.6) / 2));
tlx = (((tlx) * (this._cosD(orientation))) - ((tly) * (this._sinD(orientation))));
tly = ((tlx) * (this._sinD(orientation)) + (tly) * (this._cosD(orientation)));
trx = (((trx) * (this._cosD(orientation))) - ((tryy) * (this._sinD(orientation))));
tryy = ((trx) * (this._sinD(orientation)) + (tryy) * (this._cosD(orientation)));
blx = ((blx) * (this._cosD(orientation)) - (bly) * (this._sinD(orientation)));
bly = ((blx) * (this._sinD(orientation)) + (bly) * (this._cosD(orientation)));
brx = ((brx) * (this._cosD(orientation)) - (bry) * (this._sinD(orientation)));
bry = ((brx) * (this._sinD(orientation)) + (bry) * (this._cosD(orientation)));
tlx = (tlx + (canvaswidth / 2));
tly = (tly + (canvaswidth / 2));
trx = (trx + (canvaswidth / 2));
tryy = (tryy + (canvaswidth / 2));
blx = (blx + (canvaswidth / 2));
bly = (bly + (canvaswidth / 2));
brx = (brx + (canvaswidth / 2));
bry = (bry + (canvaswidth / 2));
var c2 = thecanvas.getContext('2d');
c2.fillStyle = '#f00';
c2.beginPath();
c2.moveTo(tlx, tly);
c2.lineTo(trx, tryy);
c2.lineTo(brx, bry);
c2.lineTo(blx, bly);
c2.closePath();
c2.fill();`
orientation is a value from -90-90 in degrees. This code starts to rotate the square but the square continues to "squish" until it is completely gone by 90 degrees. Obviously my formula for rotation is thrown off somewhere but I cant figure out how.
You could manually implement a transformation matrix. This allows you to set up the matrix for both read and write, then apply it to the points returning absolute points with the new actual values without the need or hassle to make special code for each use-case.
The formula for the (2D affine) using a 3x3 matrix would be:
or simplified in JavaScript:
var newX = x * a + y * c + e, // e (or tx) x 1 => e
newY = x * b + y * d + f; // f (or ty) x 1 => f
Now you would need to multiply the matrix with another to add rotation, translation, scale etc. The common way of doing this is this way - assume we have an object holding our values, you could do:
function Matrix() {
this.a = 1; // 1,0,0,1,0,0 = identity matrix (untransformed)
this.b = 0;
this.c = 0;
this.d = 1;
this.e = 0;
this.f = 0;
}
Matrix.prototype = {
// we need to be able to multiply matrices to accumulate values:
transform: function(a2, b2, c2, d2, e2, f2) {
var a1 = this.a,
b1 = this.b,
c1 = this.c,
d1 = this.d,
e1 = this.e,
f1 = this.f;
/* matrix order (canvas compatible):
* ace
* bdf
* 001
*/
this.a = a1 * a2 + c1 * b2;
this.b = b1 * a2 + d1 * b2;
this.c = a1 * c2 + c1 * d2;
this.d = b1 * c2 + d1 * d2;
this.e = a1 * e2 + c1 * f2 + e1;
this.f = b1 * e2 + d1 * f2 + f1;
}
}
With the core set up you can now add methods to do for example rotation:
rotate: function(angle) {
var cos = Math.cos(angle),
sin = Math.sin(angle);
this.transform(cos, sin, -sin, cos, 0, 0);
}
scale:
scale: function(sx, sy) {
this.transform(sx, 0, 0, sy, 0, 0);
}
translate:
translate: function(tx, ty) {
this.transform(1, 0, 0, 1, tx, ty);
}
and so forth depending on your needs. Note that these will accumulate as with the ordinary canvas/SVG matrix. Reset to identity to remove all transforms.
All you need to do now is to feed your points after settings transformation to get the absolute points - lets say we have a box of 100x100 we want to rotate at center:
Adding this to the prototype:
applyToPoint: function(p) {
return {
x: p.x * this.a + p.y * this.c + this.e,
y: p.x * this.b + p.y * this.d + this.f
}
}
will allow us to do:
var m = new Matrix();
m.translate(50, 50);
m.rotate(0.3);
m.translate(-50, 50);
var points = [
{x: 0, y: 0}, // upper-left
{x: 100, y: 0}, // upper-right
{x: 100, y: 100}, // bottom-right
{x: 0, y: 100} // bottom-left
],
result = [],
i = 0, p;
// transform points
while(p = points[i++]) result.push(m.applyToPoint(p));
Demo
Red box is original coordinates, blue is the transformed points which we now have access to:
function Matrix() {
this.a = 1; // identity matrix
this.b = 0;
this.c = 0;
this.d = 1;
this.e = 0;
this.f = 0;
}
Matrix.prototype = {
applyToPoint: function(p) {
return {
x: p.x * this.a + p.y * this.c + this.e,
y: p.x * this.b + p.y * this.d + this.f
}
},
transform: function(a2, b2, c2, d2, e2, f2) {
var a1 = this.a,
b1 = this.b,
c1 = this.c,
d1 = this.d,
e1 = this.e,
f1 = this.f;
/* matrix order (canvas compatible):
* ace
* bdf
* 001
*/
this.a = a1 * a2 + c1 * b2;
this.b = b1 * a2 + d1 * b2;
this.c = a1 * c2 + c1 * d2;
this.d = b1 * c2 + d1 * d2;
this.e = a1 * e2 + c1 * f2 + e1;
this.f = b1 * e2 + d1 * f2 + f1;
},
rotate: function(angle) {
var cos = Math.cos(angle),
sin = Math.sin(angle);
this.transform(cos, sin, -sin, cos, 0, 0);
},
scale: function(sx, sy) {
this.transform(sx, 0, 0, sy, 0, 0);
},
translate: function(tx, ty) {
this.transform(1, 0, 0, 1, tx, ty);
}
};
// apply some transformation:
var m = new Matrix(); // our manual transformation-matrix
m.translate(50, 50); // center of box
m.rotate(0.3); // some angle in radians
m.translate(-50, -50); // translate back
var points = [
{x: 0, y: 0}, // upper-left
{x: 100, y: 0}, // upper-right
{x: 100, y: 100}, // bottom-right
{x: 0, y: 100} // bottom-left
],
result = [], i = 0, p;
// transform points
while(p = points[i++]) result.push(m.applyToPoint(p));
// draw boxes to canvas:
var ctx = document.querySelector("canvas").getContext("2d");
ctx.translate(30, 30); // give some room for rotation for this demo
drawPolygon(points, "red");
drawPolygon(result, "blue");
drawCoord(points[0]); // plot old point
drawCoord(result[0]); // plot resulting point
// Compare using ordinary canvas: -------------------
ctx.translate(150, 0); // give some space
ctx.fillText("Regular canvas:", 0, -20);
drawPolygon(points, "red");
ctx.translate(50, 50); // center of box
ctx.rotate(0.3); // some angle in radians
ctx.translate(-50, -50); // translate back
drawPolygon(points, "blue");
// plot result:
function drawPolygon(pts, color) {
ctx.beginPath();
ctx.strokeStyle = color;
ctx.moveTo(pts[0].x, pts[0].y);
for(var i = 1, p; p = pts[i++];) ctx.lineTo(p.x, p.y);
ctx.closePath();
ctx.stroke();
}
function drawCoord(p) {
ctx.fillStyle = "#0c0"; ctx.fillRect(p.x - 2, p.y - 2, 4, 4);
ctx.fillStyle = "#000";
ctx.fillText(p.x.toFixed(1) + "," + p.y.toFixed(1), p.x, p.y - 2);
}
<canvas><canvas>
If you don't want to implement this yourselves, or want a more extensive solution, feel free to check out my (free) matrix solution here.
The future will give us currentTransform
on the context (currently only available in Chrome, Firefox struggles with a bug) returning a SVGMatrix
object which you can use in pretty much the same way as the above implementation.
这篇关于在javascript中旋转一个正方形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!