ZetCode

JavaScript Canvas 恢复教程

最后修改于 2025 年 4 月 3 日

在本文中,我们探讨了 JavaScript 中的 Canvas 保存和恢复方法。这些方法对于管理 HTML Canvas 的绘图状态堆栈至关重要。掌握状态管理对于复杂的绘图和动画至关重要。

基本定义

Canvas 的 save() 和 restore() 方法用于管理绘图状态堆栈。save() 方法将当前状态推送到堆栈。restore() 方法从堆栈中弹出顶部状态。

绘图状态包括样式、变换和剪切路径。这允许进行临时更改,而不会影响后续的绘图。正确进行状态管理是高效 Canvas 编程的关键。

基本保存和恢复

此示例演示了 save 和 restore 方法的基本用法。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Basic Save and Restore</title>
</head>
<body>

<canvas id="myCanvas" width="300" height="200"></canvas>

<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Original state
    ctx.fillStyle = 'blue';
    ctx.fillRect(10, 10, 100, 100);
    
    // Save current state
    ctx.save();
    
    // Change state
    ctx.fillStyle = 'red';
    ctx.fillRect(150, 10, 100, 100);
    
    // Restore original state
    ctx.restore();
    
    // Uses original blue color
    ctx.fillRect(10, 120, 100, 50);
</script>

</body>
</html>

此示例展示了如何保存绘图状态。我们首先绘制一个蓝色矩形,然后在更改填充颜色为红色之前保存状态。

绘制红色矩形后,我们恢复到之前的状态。最后一个矩形使用了原始的蓝色,演示了状态恢复。

嵌套保存和恢复

此示例演示了嵌套的保存和恢复操作。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Nested Save and Restore</title>
</head>
<body>

<canvas id="myCanvas" width="400" height="300"></canvas>

<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Level 0 state
    ctx.fillStyle = 'black';
    ctx.fillRect(10, 10, 100, 100);
    
    // Save Level 0
    ctx.save();
    
    // Level 1 state
    ctx.fillStyle = 'blue';
    ctx.fillRect(150, 10, 100, 100);
    
    // Save Level 1
    ctx.save();
    
    // Level 2 state
    ctx.fillStyle = 'red';
    ctx.fillRect(290, 10, 100, 100);
    
    // Restore to Level 1
    ctx.restore();
    ctx.fillRect(150, 120, 100, 100);
    
    // Restore to Level 0
    ctx.restore();
    ctx.fillRect(10, 120, 100, 100);
</script>

</body>
</html>

此示例展示了嵌套状态管理。我们创建了三个具有不同填充颜色的状态,在更改为下一个状态之前保存了每个状态。

恢复时,我们按照相反的顺序回退到各个状态。这演示了堆栈如何与多个保存操作协同工作。

带有变换的保存和恢复

此示例展示了带有 Canvas 变换的保存/恢复。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Save/Restore with Transformations</title>
</head>
<body>

<canvas id="myCanvas" width="400" height="300"></canvas>

<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Original state
    ctx.fillStyle = 'blue';
    ctx.fillRect(50, 50, 100, 50);
    
    // Save state
    ctx.save();
    
    // Apply transformation
    ctx.translate(200, 100);
    ctx.rotate(Math.PI/4);
    ctx.fillStyle = 'red';
    ctx.fillRect(0, 0, 100, 50);
    
    // Restore original state
    ctx.restore();
    
    // Draw with original state
    ctx.fillRect(50, 150, 100, 50);
</script>

</body>
</html>

此示例演示了保存和恢复变换状态。我们首先在原始坐标系中绘制一个蓝色矩形。

保存状态后,我们平移和旋转 Canvas,然后绘制一个红色矩形。恢复后,后续的绘图将使用原始的未变换坐标。

带有剪切的保存和恢复

此示例展示了带有剪切路径的保存/恢复。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Save/Restore with Clipping</title>
</head>
<body>

<canvas id="myCanvas" width="400" height="300"></canvas>

<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Original drawing
    ctx.fillStyle = 'blue';
    ctx.fillRect(50, 50, 300, 200);
    
    // Save state
    ctx.save();
    
    // Create clipping path
    ctx.beginPath();
    ctx.arc(200, 150, 100, 0, Math.PI * 2);
    ctx.clip();
    
    // Draw with clipping
    ctx.fillStyle = 'red';
    ctx.fillRect(50, 50, 300, 200);
    
    // Restore state (removes clipping)
    ctx.restore();
    
    // Draw without clipping
    ctx.fillStyle = 'green';
    ctx.fillRect(100, 100, 200, 100);
</script>

</body>
</html>

此示例演示了使用 save/restore 管理剪切路径。我们首先绘制一个覆盖整个绘图区域的蓝色矩形。

保存状态后,我们创建一个圆形剪切路径并绘制一个红色矩形(仅在圆内可见)。恢复后,剪切将被移除,我们可以正常进行绘图。

包含多个状态的复杂示例

此示例结合了多个状态更改和 save/restore。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Complex Save/Restore Example</title>
</head>
<body>

<canvas id="myCanvas" width="500" height="400"></canvas>

<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Initial state
    ctx.fillStyle = 'gray';
    ctx.fillRect(0, 0, 500, 400);
    
    // Save state 1
    ctx.save();
    ctx.fillStyle = 'blue';
    ctx.translate(100, 100);
    ctx.fillRect(0, 0, 100, 100);
    
    // Save state 2
    ctx.save();
    ctx.fillStyle = 'red';
    ctx.rotate(Math.PI/4);
    ctx.fillRect(0, 0, 100, 100);
    
    // Save state 3
    ctx.save();
    ctx.fillStyle = 'green';
    ctx.scale(1.5, 1.5);
    ctx.fillRect(50, 50, 100, 100);
    
    // Restore to state 2
    ctx.restore();
    ctx.fillRect(0, 0, 100, 100);
    
    // Restore to state 1
    ctx.restore();
    ctx.fillRect(150, 0, 100, 100);
    
    // Restore to initial state
    ctx.restore();
    ctx.fillRect(300, 100, 100, 100);
</script>

</body>
</html>

这个复杂的示例展示了多次状态更改以及变换。我们从灰色背景开始,然后创建三个嵌套状态。

每个状态都添加了新的变换和样式更改。恢复时,我们回退到每个状态,演示了堆栈的工作方式。最终的矩形使用的是原始的未变换状态。

来源

MDN Canvas save 文档

MDN Canvas restore 文档

在本文中,我们探讨了 Canvas 中的 save 和 restore 方法。这些强大的工具通过保存状态来帮助管理复杂的绘图。正确使用这些方法可以带来更清晰、更易于维护的代码。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 JS Canvas 教程