在使用HTML5 Canvas进行绘图操作时,translate
、rotate
、scale
等变换操作是通过Canvas的2D上下文(CanvasRenderingContext2D
)提供的变换方法实现的。这些变换会影响后续绘制的所有图形,直到你通过调用save
和restore
来保存和恢复变换状态。
save
和 restore
的作用
save()
:将当前的变换矩阵和其他属性(如填充颜色、字体等)保存到一个栈中。restore()
:从栈中恢复最近一次保存的状态,包括变换矩阵和其他属性。
变换操作的影响范围
所有的变换操作(如translate
、rotate
、scale
)都会修改当前的变换矩阵,并且这些修改是累积的。这意味着如果你不使用save
和restore
来管理变换状态,变换会一直影响后续的绘图操作,直到显式地重置变换矩阵。
示例代码
基本变换操作示例
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 平移画布中心到(100, 100)
ctx.translate(100, 100);
// 旋转45度
ctx.rotate(Math.PI / 4); // 45度转换为弧度
// 缩放x轴和y轴各放大2倍
ctx.scale(2, 2);
// 绘制一个矩形
ctx.fillStyle = 'blue';
ctx.fillRect(-50, -50, 100, 100);
在这个例子中,所有变换都是累积的,最终绘制的矩形会受到平移、旋转和缩放的影响。
使用 save
和 restore
管理变换状态
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 保存当前状态
ctx.save();
// 平移画布中心到(100, 100)
ctx.translate(100, 100);
// 旋转45度
ctx.rotate(Math.PI / 4); // 45度转换为弧度
// 缩放x轴和y轴各放大2倍
ctx.scale(2, 2);
// 绘制一个矩形
ctx.fillStyle = 'blue';
ctx.fillRect(-50, -50, 100, 100);
// 恢复之前保存的状态
ctx.restore();
// 再次绘制一个矩形,这次不受之前的变换影响
ctx.fillStyle = 'red';
ctx.fillRect(150, 150, 100, 100);
在这个例子中,第一个矩形受到了平移、旋转和缩放的影响,而第二个矩形则没有受到影响,因为它是在调用restore
之后绘制的。
变换操作是否受 save
和 restore
控制
是的,translate
、rotate
、scale
等变换操作是受save
和restore
控制的。具体来说:
save()
:保存当前的变换矩阵以及其他绘图状态(如填充颜色、字体等),并将它们压入栈中。restore()
:从栈中弹出最近一次保存的状态,并恢复这些状态,包括变换矩阵。
因此,当你需要临时应用一些变换并在之后恢复原始状态时,可以使用save
和restore
来管理这些变换。
进一步说明
-
变换矩阵的累积性:
- 每次调用
translate
、rotate
、scale
等方法都会修改当前的变换矩阵,并且这些修改是累积的。也就是说,如果你连续调用这些方法,它们的效果会叠加在一起。
- 每次调用
-
重置变换矩阵:
- 如果你不使用
save
和restore
,也可以通过调用setTransform(1, 0, 0, 1, 0, 0)
来重置变换矩阵,使其恢复到默认状态。
- 如果你不使用
-
嵌套变换:
- 你可以嵌套使用
save
和restore
来管理不同层次的变换。例如,在一个较大的变换块中嵌套一个小的变换块,这样可以确保小块内的变换不会影响外部的变换。
- 你可以嵌套使用
复杂示例:嵌套变换
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 第一组变换
ctx.save();
ctx.translate(100, 100);
ctx.rotate(Math.PI / 4); // 45度
ctx.scale(2, 2);
// 绘制一个蓝色矩形
ctx.fillStyle = 'blue';
ctx.fillRect(-50, -50, 100, 100);
// 第二组变换(嵌套)
ctx.save();
ctx.translate(50, 50);
ctx.rotate(Math.PI / 6); // 30度
ctx.scale(1.5, 1.5);
// 绘制一个绿色矩形
ctx.fillStyle = 'green';
ctx.fillRect(-25, -25, 50, 50);
// 恢复第二组变换前的状态
ctx.restore();
// 再次绘制一个黄色矩形,只受第一组变换影响
ctx.fillStyle = 'yellow';
ctx.fillRect(25, 25, 50, 50);
// 恢复第一组变换前的状态
ctx.restore();
// 绘制一个红色矩形,不受任何变换影响
ctx.fillStyle = 'red';
ctx.fillRect(150, 150, 100, 100);
在这个复杂示例中,我们展示了如何嵌套使用save
和restore
来管理不同层次的变换。每个嵌套块内的变换仅影响该块内的绘图操作,而不会影响外部的绘图操作。