我想告诉你 how and why,所以写了个原理向的小 demo,如果代码还是有疑惑,留言让我知道 (^ ^)
transform2d
const matrixHelper = {
translate(tx, ty) {
return [1, 0, 0, 0, 1, 0, tx, ty, 1];
},
rotate(angle) {
const cos = Math.cos(angle);
const sin = Math.sin(angle);
return [cos, -sin, 0, sin, cos, 0, 0, 0, 1];
},
scale(sx, sy) {
return [sx, 0, 0, 0, sy, 0, 0, 0, 1];
},
mult(a, b) {
const ret = [];
for (let y = 0; y < 3; y++) {
for (let x = 0; x < 3; x++) {
let sum = 0;
for (let i = 0; i < 3; i++) {
sum += b[i + y * 3] * a[x + i * 3];
}
ret[x + y * 3] = sum;
}
}
return ret;
},
setTransform(ctx, m) {
ctx.setTransform(m[0], m[1], m[3], m[4], m[6], m[7]);
},
};
function translateImage(canvas, image, deg, scale = 0.5) {
const ctx = canvas.getContext("2d");
const width = image.width;
const height = image.height;
const angle = (deg / 180) * Math.PI;
let m = matrixHelper.scale(scale, scale);
m = matrixHelper.mult(m, matrixHelper.rotate(angle));
m = matrixHelper.mult(m, matrixHelper.translate(-width >> 1, -height >> 1));
const translate = (x, y) => ({
x: x * m[0] + y * m[3] + 1 * m[6],
y: x * m[1] + y * m[4] + m[7],
});
const upLeft = translate(0, 0);
const upRight = translate(width, 0);
const downLeft = translate(0, height);
const downRight = translate(width, height);
const newWidth =
Math.max(upLeft.x, upRight.x, downLeft.x, downRight.x) -
Math.min(upLeft.x, upRight.x, downLeft.x, downRight.x);
const newHeight =
Math.max(upLeft.y, upRight.y, downLeft.y, downRight.y) -
Math.min(upLeft.y, upRight.y, downLeft.y, downRight.y);
[canvas.width, canvas.height] = [newWidth, newHeight];
m = matrixHelper.translate(newWidth >> 1, newHeight >> 1);
m = matrixHelper.mult(m, matrixHelper.scale(scale, scale));
m = matrixHelper.mult(m, matrixHelper.rotate(angle));
m = matrixHelper.mult(m, matrixHelper.translate(-width >> 1, -height >> 1));
matrixHelper.setTransform(ctx, m);
ctx.drawImage(image, 0, 0);
}
async function bootstrap() {
const canvas = document.createElement("canvas");
document.body.appendChild(canvas);
const image = new Image();
image.src =
"https://c-ssl.duitang.com/uploads/item/201702/17/20170217101328_L4zQj.thumb.1000_0.jpeg";
await new Promise((resolve) => (image.onload = resolve));
let deg = 0;
setInterval(() => {
translateImage(canvas, image, deg++, 0.5);
}, 100);
}
bootstrap();