我正试图在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度。显然我的旋转公式在某处被抛弃但我无法弄清楚如何。
答案 0 :(得分:2)
您可以手动实施transformation matrix。这允许您为读取和写入设置矩阵,然后将其应用于返回具有新实际值的绝对点的点,而无需为每个用例创建特殊代码。
使用3x3矩阵的(2D仿射)公式为:
或简化为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
现在您需要将矩阵与另一个矩阵相乘以添加旋转,平移,缩放等。这样做的常见方法是这样 - 假设我们有一个对象保存我们的值,您可以这样做:
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;
}
}
设置核心后,您现在可以添加方法来执行旋转:
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);
}
依赖于您的需求等等。请注意,这些将与普通的canvas / SVG矩阵一样累积。重置为标识以删除所有变换。
现在你需要做的就是在设置转换后输入你的点以获得绝对点 - 假设我们有一个100x100的盒子,我们想要在中心旋转:
将其添加到原型中:
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
}
}
将允许我们这样做:
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));
红色框是原始坐标,蓝色是我们现在可以访问的转换点:
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>
如果您不想自己实施,或想要更广泛的解决方案,请随时查看我的(免费)matrix solution here。
上下文中的future will give us currentTransform
(目前仅在Chrome中可用,Firefox与bug斗争)返回SVGMatrix
object,您可以使用与上述实现完全相同的方式