ZetCode

JavaScript Canvas 保存教程

最后修改于 2025 年 4 月 3 日

在本文中,我们将探讨 JavaScript 中的 Canvas 保存和恢复方法。这些方法对于在处理复杂的 Canvas 图形时管理绘图状态至关重要。掌握状态管理是高效 Canvas 编程的关键。

基本定义

Canvas 的 `save()` 和 `restore()` 方法用于管理绘图状态堆栈。`save()` 方法将当前状态推入堆栈,而 `restore()` 方法从堆栈中弹出最近保存的状态。

绘图状态包括变换、样式、剪裁路径等。这些方法允许进行临时更改,而不会影响后续的绘图。它们在复杂的绘图操作中特别有用。

基本的保存和恢复

此示例演示了保存和恢复方法的_基本用法_。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Basic Canvas Save/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, 50);
    
    // Save state
    ctx.save();
    
    // Modify state
    ctx.fillStyle = 'red';
    ctx.fillRect(130, 10, 100, 50);
    
    // Restore state
    ctx.restore();
    
    // Uses original blue color
    ctx.fillRect(250, 10, 100, 50);
</script>

</body>
</html>

此示例展示了 `save()` 和 `restore()` 如何影响绘图状态。我们首先绘制一个蓝色矩形,然后使用 `save()` 保存当前状态。

在将填充样式更改为红色并绘制另一个矩形后,我们调用 `restore()` 返回到先前的状态。第三个矩形使用了原始的蓝色。

嵌套保存和恢复

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

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

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

<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Initial state
    ctx.fillStyle = 'black';
    ctx.fillRect(10, 10, 100, 50);
    
    // First save
    ctx.save();
    ctx.fillStyle = 'blue';
    ctx.fillRect(130, 10, 100, 50);
    
    // Second save
    ctx.save();
    ctx.fillStyle = 'red';
    ctx.fillRect(250, 10, 100, 50);
    
    // First restore (back to blue)
    ctx.restore();
    ctx.fillRect(10, 80, 100, 50);
    
    // Second restore (back to black)
    ctx.restore();
    ctx.fillRect(130, 80, 100, 50);
</script>

</body>
</html>

此示例展示了保存和恢复操作如何以堆栈(LIFO - 后进先出)顺序工作。我们首先保存黑色填充状态,然后更改为蓝色并再次保存。

更改为红色并绘制后,我们执行两次恢复。第一次恢复返回到蓝色状态,第二次恢复返回到最初的黑色状态。这演示了状态管理的嵌套性质。

结合变换的保存/恢复

此示例展示了保存和恢复如何与 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');
    
    // Draw original rectangle
    ctx.fillStyle = 'blue';
    ctx.fillRect(50, 50, 100, 50);
    
    // Save state
    ctx.save();
    
    // Apply transformation
    ctx.translate(100, 100);
    ctx.rotate(Math.PI/4);
    ctx.fillStyle = 'red';
    ctx.fillRect(50, 50, 100, 50);
    
    // Restore state
    ctx.restore();
    
    // Draw with original transformation
    ctx.fillStyle = 'green';
    ctx.fillRect(200, 50, 100, 50);
</script>

</body>
</html>

此示例演示了保存和恢复不仅影响样式,还影响变换。我们首先在默认状态下绘制一个蓝色矩形。

保存后,我们应用平移和旋转变换并绘制一个红色矩形。恢复后,绘制的绿色矩形_不_受这些变换的影响,这表明状态已正确恢复。

结合剪裁的保存/恢复

此示例演示了如何将保存和恢复与剪裁路径一起使用。

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');
    
    // Draw without clipping
    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 again
    ctx.fillStyle = 'green';
    ctx.fillRect(50, 50, 100, 100);
</script>

</body>
</html>

此示例展示了剪裁路径如何受到保存和恢复的影响。我们首先绘制一个没有剪裁的蓝色矩形。然后我们保存状态。

创建圆形剪裁路径后,我们绘制一个仅在剪裁区域内可见的红色矩形。恢复后,绘制的绿色矩形_没有_剪裁,这表明状态已正确恢复。

高级状态管理

此示例展示了具有多个属性的复杂状态管理。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Advanced State Management</title>
</head>
<body>

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

<script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    
    // Set initial styles
    ctx.fillStyle = 'blue';
    ctx.strokeStyle = 'black';
    ctx.lineWidth = 2;
    ctx.font = '20px Arial';
    
    // Draw with initial state
    ctx.fillRect(50, 50, 100, 50);
    ctx.strokeRect(50, 50, 100, 50);
    ctx.fillText('Initial', 50, 130);
    
    // Save state
    ctx.save();
    
    // Modify multiple properties
    ctx.fillStyle = 'red';
    ctx.strokeStyle = 'green';
    ctx.lineWidth = 5;
    ctx.font = 'italic 16px Times';
    
    // Draw with modified state
    ctx.fillRect(200, 50, 100, 50);
    ctx.strokeRect(200, 50, 100, 50);
    ctx.fillText('Modified', 200, 130);
    
    // Save nested state
    ctx.save();
    
    // Modify again
    ctx.fillStyle = 'yellow';
    ctx.strokeStyle = 'purple';
    ctx.lineWidth = 1;
    
    // Draw with second modified state
    ctx.fillRect(350, 50, 100, 50);
    ctx.strokeRect(350, 50, 100, 50);
    ctx.fillText('Nested', 350, 130);
    
    // Restore to first modified state
    ctx.restore();
    ctx.fillRect(200, 200, 100, 50);
    ctx.strokeRect(200, 200, 100, 50);
    
    // Restore to initial state
    ctx.restore();
    ctx.fillRect(50, 200, 100, 50);
    ctx.strokeRect(50, 200, 100, 50);
</script>

</body>
</html>

这个综合示例演示了保存和恢复如何同时影响多个绘图状态属性。我们在不同级别修改了填充、描边、线宽和字体属性。

该示例展示了嵌套状态管理,包含两次保存操作和相应的恢复。每次恢复都会返回到保存的确切状态,包括所有样式属性和变换。

来源

MDN Canvas 保存文档

在本文中,我们探索了使用保存和恢复方法管理 Canvas 状态的各种技术。这些强大的工具对于 Web 应用程序中复杂的 Canvas 绘图和动画至关重要。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出 所有 JS Canvas 教程