我正在尝试在 JavaScript 中围绕其中心旋转一个正方形。虽然在本例中我使用 Canvas 来绘制正方形,但我需要一种旋转正方形的功能方法以供其他地方使用,因此仅旋转 Canvas 是 Not Acceptable 。这就是我到目前为止所拥有的
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();`
方向是 -90-90 度之间的值。此代码开始旋转正方形,但正方形继续“挤压”,直到完全旋转 90 度。显然我的旋转公式在某个地方被抛弃了,但我不知道如何。
最佳答案
您可以手动实现 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 的盒子,我们想要在中心旋转:
将其添加到原型(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
}
}
将允许我们做:
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您可以按照与上述实现几乎相同的方式使用它。
关于javascript - 在javascript中旋转一个正方形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30577269/