繪制狀態存儲
1. 前言
canvas 中設置屬性多數都是全局使用的,我們在操作時難免會遇到某個屬性被修改后,當再次使用到這個屬性時必須是默認值的情況,或者我們繪制多個矩形,這些矩形的填充顏色和陰影有一定規律,比如填充顏色為 紅、黃、藍、黃、紅這樣的順序,陰影也是有對應順序,我們應該怎么做呢?本小節我們就來學習如何保存某個繪制狀態和快速地將繪制狀態恢復到上一個階段。
2. 存儲繪制狀態
我們先看一個不使用存儲繪制狀態的案例,這個案例中,我們需要繪制5個矩形,其中第一個和第五個矩形相同,第二個和第四個矩形相同。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>慕課網Wiki</title>
<style>
#imooc{
border:1px solid #ccc;
}
</style>
</head>
<body>
<canvas id="imooc">您的瀏覽器不支持 HTML5 canvas 標簽</canvas>
<script>
const canvas = document.getElementById('imooc');
canvas.width=360;
canvas.height=130;
const ctx = canvas.getContext('2d');
// 繪制第一個矩形
ctx.fillStyle="red"
ctx.shadowBlur=2;
ctx.shadowOffsetX=4;
ctx.shadowOffsetY=4;
ctx.shadowColor="#ccc"
ctx.fillRect(40,40, 40,40)
// 繪制第二個矩形
ctx.fillStyle="yellow"
ctx.shadowBlur=3;
ctx.shadowOffsetX=8;
ctx.shadowOffsetY=8;
ctx.shadowColor="#456795"
ctx.fillRect(100,40, 40,40)
// 繪制第三個矩形
ctx.fillStyle="blue"
ctx.shadowBlur=5;
ctx.shadowOffsetX=5;
ctx.shadowOffsetY=5;
ctx.shadowColor="#222"
ctx.fillRect(160,40, 40,40)
// 繪制第四個矩形
ctx.fillStyle="yellow"
ctx.shadowBlur=3;
ctx.shadowOffsetX=8;
ctx.shadowOffsetY=8;
ctx.shadowColor="#456795"
ctx.fillRect(220,40, 40,40)
// 繪制第五個矩形
ctx.fillStyle="red"
ctx.shadowBlur=2;
ctx.shadowOffsetX=4;
ctx.shadowOffsetY=4;
ctx.shadowColor="#ccc"
ctx.fillRect(280,40, 40,40)
</script>
<body>
</html>
運行結果:

上面案例中,可以看到,繪制第四個正方形的時候,把所有屬性又寫了一遍,但是這個屬性和我們繪制第二個正方形的屬性一樣,第五個正方形和第一個正方形的屬性一樣,這樣我們不僅浪費時間還增加了代碼維護成本,維護成本主要指:假如我們要修改紅色的正方形為其他顏色,我們就得修改兩處代碼。
今天我們就用存儲繪制狀態的方法來優化一下上面代碼,還是上面那個案例,我們換一種寫法。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>慕課網Wiki</title>
<style>
#imooc{
border:1px solid #ccc;
}
</style>
</head>
<body>
<canvas id="imooc">您的瀏覽器不支持 HTML5 canvas 標簽</canvas>
<script>
const canvas = document.getElementById('imooc');
canvas.width=360;
canvas.height=130;
const ctx = canvas.getContext('2d');
// 繪制第一個矩形
ctx.fillStyle="red"
ctx.shadowBlur=2;
ctx.shadowOffsetX=4;
ctx.shadowOffsetY=4;
ctx.shadowColor="#ccc"
ctx.save(); // 這里把當前畫布的屬性做了一個標記,我們稱為:標記一
ctx.fillRect(40,40, 40,40)
// 繪制第二個矩形
ctx.fillStyle="yellow"
ctx.shadowBlur=3;
ctx.shadowOffsetX=8;
ctx.shadowOffsetY=8;
ctx.shadowColor="#456795"
ctx.save(); // 這里把當前畫布的屬性做了第二個標記,我們稱為:標記二
ctx.fillRect(100,40, 40,40)
// 繪制第三個矩形
ctx.fillStyle="blue"
ctx.shadowBlur=5;
ctx.shadowOffsetX=5;
ctx.shadowOffsetY=5;
ctx.shadowColor="#222"
ctx.fillRect(160,40, 40,40)
// 繪制第四個矩形
ctx.restore() // 這里我們讀取了最新的一個標記,也就是讀區了標記二的狀態,標記二被讀取后就消失了。
ctx.fillRect(220,40, 40,40)
// 繪制第五個矩形
ctx.restore(); // 這里我們讀取了最新的一個標記,也就是讀區了標記一的狀態,因為標記二已經消失了
ctx.fillRect(280,40, 40,40)
</script>
<body>
</html>
運行結果:

我們可以看到,運行結果是一樣的,我們把主要代碼拆分講解一下。
-
設置繪制矩形的相關屬性,并調用 save 方法保存一個繪制狀態。
ctx.fillStyle="red" ctx.shadowBlur=2; ctx.shadowOffsetX=4; ctx.shadowOffsetY=4; ctx.shadowColor="#ccc" ctx.save(); // 這里把當前畫布的屬性做了一個標記,我們稱為:標記一 ctx.fillRect(40,40, 40,40)
-
設置第二個矩形的相關屬性,并調用 save 方法保存一個繪制狀態,這個狀態會堆放到上一個狀態的上面,該狀態的存儲符合“?!钡奶匦裕合冗M后出,也就是最先放進去的最后才被拿走。
我們看一個形象的圖片,小孩的玩具。
最下面的大圈是最先放進去的,再取出時它是最后一個被拿出來的。
ctx.fillStyle="yellow" ctx.shadowBlur=3; ctx.shadowOffsetX=8; ctx.shadowOffsetY=8; ctx.shadowColor="#456795" ctx.save(); // 這里把當前畫布的屬性做了第二個標記,我們稱為:標記二 ctx.fillRect(100,40, 40,40)
-
繪制第四個矩形,我們在繪制前先調用
ctx.restore
方法取出一個狀態,取出的狀態會應用到當前畫布上。當前存儲的所有狀態中,最上面的是標簽二,也就是第二個矩形的狀態,所以這里取出來的就是第二個矩形的狀態屬性。ctx.restore() // 取出狀態 ctx.fillRect(220,40, 40,40)
-
繪制第五個矩形,同樣調用
ctx.restore
方法取出一個狀態,當前存儲的狀態中只有標簽一,也就是第一個矩形的狀態,所以這里取出來的就是第一個矩形的狀態屬性。ctx.restore(); // 取出狀態 ctx.fillRect(280,40, 40,40)
特別注意 當存儲的狀態被取完以后,再去取一個狀態,此時會出問題。解決辦法就是:讀取狀態
restore
的次數只能小于等于存儲save
的次數。
3. 方法整理
本小節我們學習了 save
方法和 restore
方法,它們的主要作用是存儲某一個階段的屬性狀態,后面可以快速恢復存儲的狀態。
3.1 存儲狀態 save
save 說明
- save 方法主要目的是存儲 canvas 當前全部狀態,此方法可以多次執行,每次執行都會存儲一次當前狀態。
語法:
ctx.save();
變量說明:
沒有參數。
3.2 存儲狀態 restore
restore 說明
- restore 方法主要是用于取出存儲在 canvas 中的最新狀態,此方法可以多次執行,但是不能超過已存儲狀態的次數。
語法:
ctx.restore();
變量說明:
沒有參數。
4. 總結
本小節我們主要學習了利用 save
和 restore
存儲和拿取畫布狀態的方法,存儲狀態的目的是后面可以快速恢復到上一個繪制狀態。本小節我們只是簡單體會了存儲和拿取的過程,后面小節我們學習了旋轉變形的操作,會頻繁地用到這個操作。