
本教程详细讲解了在html5 canvas中如何精确控制单个图形(如矩形)的旋转,而不影响画布上的其他元素。核心方法是利用`ctx.save()`和`ctx.restore()`来隔离变换,并结合`ctx.rotate()`和`ctx.translate()`实现围绕画布原点或图形自身中心的旋转。
在HTML5 Canvas中进行图形绘制时,我们经常需要对特定图形应用变换(如旋转、缩放、平移),同时保持画布上其他元素的原始状态。Canvas的2D渲染上下文(CanvasRenderingContext2D)的变换操作(例如ctx.rotate()、ctx.translate()、ctx.scale())默认是全局性的,这意味着它们会影响后续所有的绘制操作。为了实现对单个图形的局部变换,我们需要巧妙地利用ctx.save()和ctx.restore()方法来管理变换状态。
Canvas 变换上下文与状态管理
Canvas的变换操作会修改当前的坐标系。例如,ctx.rotate()会使后续所有绘制的图形都相对于当前坐标系的原点进行旋转。为了避免这种全局影响,我们需要在应用局部变换之前保存当前的绘制状态,并在变换及绘制完成后恢复到之前的状态。
- ctx.save(): 将当前Canvas的整个状态保存到栈中。这个状态包括当前的变换矩阵、填充样式、描边样式、线宽、字体等所有属性。
- ctx.restore(): 从栈中弹出最近保存的状态,并将其恢复为当前的Canvas状态。这会撤销自上次save()以来所有的变换和样式更改。
通过在需要局部变换的代码块前后分别调用ctx.save()和ctx.restore(),我们可以创建一个“沙盒”环境,确保变换仅作用于沙盒内的绘制操作。
示例一:围绕画布原点旋转单个矩形
假设我们有一个蓝色的矩形,需要围绕画布的左上角(即坐标系原点 (0,0))旋转,而不影响其他红色的矩形。
立即学习“前端免费学习笔记(深入)”;
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 设置Canvas为全屏(示例目的)
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 绘制需要旋转的蓝色矩形
ctx.save(); // 保存当前Canvas状态
// 围绕 (0,0) 旋转 30 度(Math.PI / 6 弧度)
ctx.rotate(Math.PI / 6);
ctx.fillStyle = "blue";
ctx.fillRect(0, 0, canvas.width / 3, canvas.height / 3);
ctx.restore(); // 恢复之前保存的Canvas状态
// 绘制其他不旋转的红色矩形
ctx.fillStyle = "red";
ctx.fillRect(canvas.width / 3, canvas.height / 3, canvas.width / 3, canvas.height / 3);
ctx.fillRect(canvas.width * 2 / 3, canvas.height * 2 / 3, canvas.width / 3, canvas.height / 3);在这个例子中,ctx.rotate(Math.PI / 6) 只影响了 ctx.fillRect(0, 0, ...) 这条绘制蓝色矩形的指令,因为它们被包裹在 ctx.save() 和 ctx.restore() 之间。其他红色矩形的绘制则不受影响。
示例二:围绕矩形自身中心旋转单个矩形
更常见的需求是让图形围绕其自身的中心点进行旋转。由于ctx.rotate()默认是围绕当前坐标系的原点旋转,我们需要结合ctx.translate()来调整旋转的中心点。
基本思路是:
- 保存Canvas状态。
- 将坐标系原点平移到矩形的中心。
- 执行旋转操作。
- 绘制矩形,此时矩形的坐标需要调整为相对于新的原点(即其中心点)。
- 恢复Canvas状态。
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 设置Canvas为全屏(示例目的)
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 绘制需要旋转的蓝色矩形
ctx.save(); // 保存当前Canvas状态
const rectWidth = canvas.width / 3;
const rectHeight = canvas.height / 3;
// 将画布原点平移到矩形的中心
ctx.translate(rectWidth / 2, rectHeight / 2);
// 围绕新的原点(矩形中心)旋转 30 度
ctx.rotate(Math.PI / 6);
ctx.fillStyle = "blue";
// 绘制矩形,使其中心位于新的原点 (0,0)
ctx.fillRect(-rectWidth / 2, -rectHeight / 2, rectWidth, rectHeight);
ctx.restore(); // 恢复之前保存的Canvas状态
// 绘制其他不旋转的红色矩形
ctx.fillStyle = "red";
ctx.fillRect(canvas.width / 3, canvas.height / 3, canvas.width / 3, canvas.height / 3);
ctx.fillRect(canvas.width * 2 / 3, canvas.height * 2 / 3, canvas.width / 3, canvas.height / 3);在这个例子中,ctx.translate(rectWidth / 2, rectHeight / 2) 将坐标系的原点从 (0,0) 移动到了蓝色矩形的中心。然后 ctx.rotate() 就在这个新的原点上执行旋转。最后,ctx.fillRect(-rectWidth / 2, -rectHeight / 2, rectWidth, rectHeight) 绘制了一个以 (0,0) 为中心、宽度为 rectWidth、高度为 rectHeight 的矩形,这正是我们想要的围绕自身中心旋转的效果。
总结与注意事项
- 隔离变换的关键:ctx.save() 和 ctx.restore() 是在Canvas中实现局部变换的基石。它们确保了变换只作用于特定的绘制指令,而不会影响画布的整体状态。
-
变换顺序:当需要同时应用平移和旋转时,变换的顺序至关重要。通常,为了实现围绕对象中心旋转,正确的顺序是:
- ctx.save()
- ctx.translate()(将原点移动到旋转中心)
- ctx.rotate()
- 绘制图形(坐标需相对于新的原点)
- ctx.restore()
- 旋转单位:ctx.rotate() 方法的参数是弧度(radians),而不是角度(degrees)。一个完整的圆是 2 * Math.PI 弧度,即 360 度。因此,30 度可以通过 Math.PI / 6 计算得到。
- 坐标调整:当使用 ctx.translate() 改变原点后,所有后续的绘制指令(如 ctx.fillRect()、ctx.arc() 等)都需要根据新的坐标系来调整其参数。如果原点移到了图形中心,那么图形的绘制起点通常会变成负值。
通过掌握 ctx.save()、ctx.restore() 和基本的变换方法,您就可以在HTML5 Canvas中灵活地控制单个图形的运动和姿态,为开发互动性更强的应用和游戏打下坚实的基础。










