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 教程中,我们已经讨论了变换。