HTML5 Canvas 中的变换
最后修改于 2023 年 7 月 17 日
在本篇 HTML5 Canvas 教程中,我们将讨论变换。
仿射变换 由零个或多个线性变换(旋转、缩放或剪切)和翻译(平移)组成。多个线性变换可以组合成一个单一的矩阵。旋转是将刚体围绕一个固定点移动的变换。缩放是放大或缩小对象的变换。缩放因子在所有方向上都是相同的。平移是将每个点在指定方向上移动恒定距离的变换。剪切是将对象沿给定轴垂直移动的变换,在轴的一侧比另一侧具有更大的值。
有一个 transform 方法,它将当前变换与方法参数描述的矩阵相乘。我们可以缩放、旋转、移动和剪切上下文。还有执行特定变换的方法:translate、rotate 和 scale。
平移
以下示例展示了一个简单的平移。
<!DOCTYPE html>
<html>
<head>
<title>HTML5 canvas translation</title>
<style>
canvas {border: 1px solid #bbbbbb}
</style>
<script>
function draw() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'gray';
ctx.translate(canvas.width/2, canvas.height/2);
ctx.beginPath();
ctx.arc(0, 0, 30, 0, 2*Math.PI);
ctx.fill();
}
</script>
</head>
<body onload="draw();">
<canvas id="myCanvas" width="150" height="150">
</canvas>
</body>
</html>
该示例在画布中间绘制一个圆。
ctx.translate(canvas.width/2, canvas.height/2);
translate 方法将坐标系的原点移动到画布的中心。
ctx.beginPath(); ctx.arc(0, 0, 30, 0, 2*Math.PI); ctx.fill();
绘制了一个圆。它的中心点是画布的中心。
旋转
下一个示例演示了旋转。
<!DOCTYPE html>
<html>
<head>
<title>HTML5 canvas rotation</title>
<script>
function draw() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'gray';
ctx.rotate(Math.PI/10);
ctx.fillRect(50, 10, 120, 80);
}
</script>
</head>
<body onload="draw();">
<canvas id="myCanvas" width="200" height="200">
</canvas>
</body>
</html>
该示例对一个矩形执行旋转。
ctx.rotate(Math.PI/10);
rotate 方法执行旋转。角度参数表示顺时针旋转角度,以弧度表示。
缩放
缩放使用 scale 方法完成。该方法接受两个参数:x 缩放因子和 y 缩放因子。
<!DOCTYPE html>
<html>
<head>
<title>HTML5 canvas scaling</title>
<script>
function draw() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'gray';
ctx.fillRect(20, 20, 80, 50);
ctx.save();
ctx.translate(110, 22);
ctx.scale(0.5, 0.5);
ctx.fillRect(0, 0, 80, 50);
ctx.restore();
ctx.translate(170, 20);
ctx.scale(1.5, 1.5);
ctx.fillRect(0, 0, 80, 50);
}
</script>
</head>
<body onload="draw();">
<canvas id="myCanvas" width="300" height="200">
</canvas>
</body>
</html>
在示例中,有一个矩形对象。首先,我们将其缩小,然后将其稍微放大。
ctx.save(); ctx.translate(110, 22); ctx.scale(0.5, 0.5); ctx.fillRect(0, 0, 80, 50); ctx.restore();
变换操作是累加的。为了隔离平移和缩放操作,我们将它们放在 save 和 restore 方法之间。save 方法保存画布的整个状态,restore 方法恢复它。
剪切
剪切是一种变换,它沿着一个或两个轴扭曲对象的形状。与缩放和平移一样,剪切可以沿着一个坐标轴或两个坐标轴进行。
<!DOCTYPE html>
<html>
<head>
<title>HTML5 canvas shearing</title>
<script>
function draw() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.translate(0.5, 0.5);
ctx.setLineDash([2]);
ctx.save();
ctx.strokeStyle = 'green';
ctx.strokeRect(50, 90, 160, 50);
ctx.restore();
ctx.save();
ctx.strokeStyle = 'blue';
ctx.transform(1, 1, 0, 1, 0, 0);
ctx.strokeRect(50, 40, 80, 50);
ctx.restore();
ctx.save();
ctx.strokeStyle = 'red';
ctx.transform(1, 1, 0, 1, 0, -130);
ctx.strokeRect(130, 10, 80, 50);
ctx.restore();
}
</script>
</head>
<body onload="draw();">
<canvas id="myCanvas" width="300" height="300">
</canvas>
</body>
</html>
没有专门用于剪切的方法,我们使用通用的 transform 方法。
ctx.translate(0.5, 0.5);
这一行使得矩形的线更平滑。
ctx.save(); ctx.strokeStyle = 'blue'; ctx.transform(1, 1, 0, 1, 0, 0); ctx.strokeRect(50, 40, 80, 50); ctx.restore();
蓝色矩形是水平剪切(倾斜)的。transform 方法的参数是:水平缩放、水平剪切、垂直剪切、垂直缩放、水平平移和垂直平移。
甜甜圈
在下面的示例中,我们通过旋转一个椭圆来创建一个复杂的形状。
<!DOCTYPE html>
<html>
<head>
<title>HTML5 canvas donut</title>
<script>
function draw() {
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'gray';
ctx.translate(0.5, 0.5);
var x = canvas.width/2;
var y = canvas.height/2;
for (var deg = 0; deg < 360; deg += 5) {
var rad = deg * Math.PI / 180;
ctx.beginPath();
ctx.ellipse(x, y, 30, 130, rad, 0, 2*Math.PI);
ctx.stroke();
}
}
</script>
</head>
<body onload="draw();">
<canvas id="myCanvas" width="300" height="300">
</canvas>
</body>
</html>
该示例使用了 ellipse 方法,在撰写本教程时,该方法尚未得到所有浏览器的支持。该示例在 Chrome 和 Opera 上运行。
var x = canvas.width/2; var y = canvas.height/2;
椭圆的中心点位于画布的中心。
for (var deg = 0; deg < 360; deg += 5) {
var rad = deg * Math.PI / 180;
ctx.beginPath();
ctx.ellipse(x, y, 30, 130, rad, 0, 2*Math.PI);
ctx.stroke();
}
我们创建了 36 个椭圆。这些椭圆被旋转了。ellipse 方法接受以下参数:椭圆中心点的 x 和 y 坐标、椭圆的长半轴、椭圆的短半轴、旋转角度、起始角度和结束角度。
在本篇 Java 2D 教程中,我们已经讨论了变换。