理解Canvas Context 的save() 和 restore()

19,867 阅读3分钟

🙂简述

之前写过一个基于canvas实现的共享写作画板应用,当时在写这个应用的有画板绘制的“前进”和“后退”功能,当时查了MDN上的Canvas文档,看到了有save()和restore()两个方法。文档上是这样解释的使用 save() 方法保存默认的状态,使用 restore()进行恢复当时寻思着或许可以用这两个方法实现,可是最后哦用的时候却与预期的结果截然相反。这篇文章我们来了解一下Cavas的save() 和 restore();

🙂较规范的restore()和 save()解释

save()和restore()方法只会在有效范围内生效,它是绘制状态的存储器,并不是画布内容的存储器。它是基于状态记录的。
Canvas Context维持着绘制状态的堆栈。区分绘制状态:

  • 当前矩阵变换例如:平移translate(),缩放scale(),以及旋转rotate()等
  • 剪切区域clip()
  • 以下属性值: strokeStyle,fillStyle,globalAlpha,lineWidth,lineCap,lineJoin,miterLimit,shadowOffsetX,shadowOffsetY,shadowBlur,shadowColor,globalCompositeOperation,font,textAlign,textBaseline。
  • 路径和位图不是绘图状态的一部分,使用save()和restore()不会生效。路径是持久的,只能使用beginPath()方法重置,位图是画布的属性,而非上下文。
  • context.save()将当前状态压入堆栈。context.restore()弹出堆栈上的顶级状态,将上下文恢复到该状态。

🙂介绍一下场景吧

✈“ 变换” 场景

一个canvas只有一个2d上下文,save()和restore()的使用场景也很广泛,例如 "变换"状态的用途。
当你执行“变换”操作时,整个上下文的坐标系都将会改变。“变换”之后,我们需要将坐标系恢复到原有正常的状态,这时候就需要使用save()和restore()了。如下图:

效果图

我们看到在调用了restore()绘制的图形并没有发生变化,只是绘制状态发生了变化。因为绘制好的图形并不属于绘制状态。而restore()和save()只作用于绘制状态。 在我的那个基于canvas实现的共享写作画板应用中我想实现撤销恢复绘制内容并没有起作用正式因为这个原因,绘制的内容并不属于绘制状态,所以无法撤销绘制的内容,或者恢复撤销的内容。

😃码字不如堆码

我们不如简单的写一下如何使用save()和restore()的代码。

💻HTML code

<!doctype html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Canvas Test</title>
    </head>
    <body
        <div>
            <canvas id="canvas" width="320" height="200">
                 This text is displayed if your browser does not support HTML5 Canvas.
            </canvas>
        </div>
    </body>
</html>

javscript code

var canvas,ctx;
function init() {
    canvas = document.getElementById("canvas");
    ctx = canvas.getContext("2d");
    draw();
}
function draw() {
    //初始的样式(绘制状态)并绘制矩形
    ctx.fillStyle = '#FA6900';
    ctx.shadowOffsetX = 5;
    ctx.shadowOffsetY = 5;
    ctx.shadowBlur    = 4;
    ctx.shadowColor   = 'rgba(204, 204, 204, 0.5)';
    ctx.fillRect(0,0,15,150);
    ctx.save(); //保存上述设置的绘制状态
    
    //重新定义新的绘制状态,并绘制矩形
    ctx.fillStyle = '#E0E4CD';
    ctx.shadowOffsetX = 10;
    ctx.shadowOffsetY = 10;
    ctx.shadowBlur    = 4;
    ctx.shadowColor   = 'rgba(204, 204, 204, 0.5)';
    ctx.fillRect(30,0,30,150);
    
    //绘制完之后,恢复到初始的绘制状态,继续进行绘画。并绘制圆形,并不会恢复初始状态下绘制的矩形。
    ctx.restore();
    ctx.beginPath();
    ctx.arc(305, 75, 8, 0, Math.PI*2, true);
    ctx.closePath();
    ctx.fill();
    }
    init();

上述代码的效果如下:

效果图
我们发现最后绘制的圆形的填充色和阴影和第一个矩形的保持了一致,这是因为restore之后,使用了初始绘制状态。

😭后话

以上就是对Canvas的save()和restore()的介绍。我也是在阅读了一篇外国作者写的一篇blog才理解过来了这个的真实作用。如果有误或者有更好的理解,不妨留言指出和评论。完结撒花★,°:.☆( ̄▽ ̄)/$:.°★


参考文献:Understanding save() and restore() for the Canvas Context (July 10, 2010 by James Litten)