save与restore

save()主要用来保存目前Canvas的状态,例如lineWidthfillStylelineJoin等,
通过save()函数它会将目前Canvas的状态推到绘图堆栈中;
restore()函数就是从绘图堆栈中弹出上一个Canvas的状态。

通过save-restore组合把代码包裹起来,实质上是把save()方法和restore()方法之间的样式包裹起来,这样一来,他们就不影响后面绘制的图形。
save()方法和restore()方法都可以被调用任意多次,并且可以嵌套。
save()方法和restore()方法总是成对出现,每次调用restore()方法,都是恢复到最近一次调用save()方法时栈的状态,
并用该栈顶所保存的状态进行绘制。

save与restore的使用

下面是一个例子
首先,现在body标签中创建一张画布<canvas width="600" height="600"></canvas>
然后执行下方的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const cv = document.querySelector("canvas");
const c = cv.getContext("2d");

c.fillStyle = "red";
c.fillRect(10, 10, 180, 180);
c.fill();

c.save();                 // ① 栈: "red"
c.fillStyle = "green";
c.fillRect(30, 30,140,140);

c.save();                 // ② 栈: "red","green"
c.fillStyle = "blue";
c.fillRect(50, 50, 100,100);

c.restore();               // 恢复到 ② 的状态, 栈: "red","green"
c.beginPath();
c.fillRect(70, 70, 60, 60);   // 用栈顶的状态绘图,填充"green"

c.restore();               // 恢复到 ① 的状态, 栈: "red"
c.fillRect(90, 90, 20, 20); // 用栈顶的状态绘图,填充" red "
c.fill();

运行结果如图

Canvas-note-save-and-restore

上述代码中,首先绘制第一个红色的矩形。
接着调用第一个save()方法,把第一个红色矩形的状态压栈,此时栈中只有一个元素”red”,记为 ①。
然后把状态设置为”green”,绘制第二个矩形,此时绘制出的是绿色矩形。
接着调用第二个save()方法,把第二个绿色矩形的状态压栈,此时栈中有两个元素”red”,”green”,栈顶元素为”green”,记为 ②。
接着绘制第三个蓝色矩形,此处没有调用save()方法,栈的状态不变。
接着调用restore()方法,恢复到 ② 的状态,绘制第四个矩形,此时栈顶元素为”green”,故绘制出绿色矩形。
接着再调用restore()方法,恢复到 ① 的状态,绘制第五个矩形,此时栈顶元素为”red”,故绘制出红色矩形。

save与restore的继承问题

代码从上往下覆盖执行,因此所有未加beginpath进行隔断的图形样式都会继承上最新设置定义的样式,类似污染
对于下方的代码可自行调试,实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
c.moveTo(50,100);
c.lineTo(50,200);
c.stroke();

c.lineWidth = 10;
c.strokeStyle = 'red';
c.moveTo(100,100);
c.lineTo(100,200);
c.stroke();

c.save();//保存 将上方设置的样式在释放的下方进行应用

c.beginPath();//进行重置隔断,可理解为划分作用域,不会相互污染

c.strokeStyle = 'green';
c.lineWidth = 20;
c.moveTo(150,100);
c.lineTo(150,200);
c.stroke();

c.restore();//释放 在beginpath的上下方都不影响

c.beginPath();//进行重置隔断

//c.lineWidth = 30;
//c.strokeStyle = 'pink';
c.moveTo(200,100);
c.lineTo(200,200);
c.stroke();

c.moveTo(250,100);
c.lineTo(250,200);
c.stroke();
× 请我吃糖~
打赏二维码