天天看點

筆記-Canvas-畫筆的存儲與恢複機制學習

save()和restore()

1.畫筆的兩種狀态方法,儲存和恢複

(
    ()=>{
        //擷取畫布元素
        let canvas = document.getElementById('demo2');
        //擷取畫筆
        let ctx = canvas.getContext('2d');
        //開始繪畫路徑
        ctx.beginPath();
        //2px的紅色直線
        ctx.lineWidth='2';
        ctx.strokeStyle="#f00";
        //長40,y軸上20的水準直線
        ctx.moveTo(20,20);
        ctx.lineTo(60,20);
        //描邊
        ctx.stroke();
        //儲存畫筆的狀态
        ctx.save();
        //然後畫一條線
        ctx.lineTo(60,60);    
        //描邊
        ctx.stroke();
    }
)();
           

這裡是畫完一條紅線之後繼續補充了一條垂直線,雖然save()過了,但是描邊之後,顔色依舊,這樣其實也能看出來,畫筆也是有全局污染的是以我們可以把不同的圖像放到不同的函數中,減少畫筆的全局污染.

(
    ()=>{
        //擷取畫布元素
        let canvas = document.getElementById('demo2');
        //擷取畫筆
        let ctx = canvas.getContext('2d');
        //開始繪畫路徑
        ctx.beginPath();
        //2px的紅色直線
        ctx.lineWidth='2';
        ctx.strokeStyle="#f00";
        //長40,y軸上20的水準直線
        ctx.moveTo(20,20);
        ctx.lineTo(60,20);
        //描邊
        ctx.stroke();
        //儲存畫筆的狀态
        ctx.save();
        //重新定義畫筆的寬度和顔色
        //4px的寬度和綠色
        ctx.lineWidth='4';
        ctx.strokeStyle="#0f0";
        //然後畫一條線
        ctx.lineTo(60,60);    
        //描邊
        ctx.stroke();
    }
)();
           

這裡我忽視了beginPath()的重要性,當我第二次描邊的時候,畫筆講三點兩線都進行了繪制,使得第一條線變成了紅色和綠色的混色

筆記-Canvas-畫筆的存儲與恢複機制學習

是以重新增加ctx.beginPath()之後,

(
    ()=>{
        //擷取畫布元素
        let canvas = document.getElementById('demo2');
        //擷取畫筆
        let ctx = canvas.getContext('2d');
        //開始繪畫路徑
        ctx.beginPath();
        //2px的紅色直線
        ctx.lineWidth='2';
        ctx.strokeStyle="#f00";
        //長40,y軸上20的水準直線
        ctx.moveTo(20,20);
        ctx.lineTo(60,20);
        //描邊
        ctx.stroke();
        //儲存畫筆的狀态
        ctx.save();
        //開始新的繪畫路徑
        ctx.beginPath();
        //起始點
        ctx.moveTo(60,20);
        //重新定義畫筆的寬度和顔色
        //4px的寬度和綠色
        // ctx.lineWidth='4';
        // ctx.strokeStyle="#0f0";
        //然後畫一條線
        ctx.lineTo(60,60);    
        //描邊
        ctx.stroke();
    }
)();
           

save()之後同樣還是2px紅線,然後取消對新畫筆代碼部分的注釋之後,就能得到一條4px的綠色直線.

(
    ()=>{
        //擷取畫布元素
        let canvas = document.getElementById('demo2');
        //擷取畫筆
        let ctx = canvas.getContext('2d');
        //開始繪畫路徑
        ctx.beginPath();
        //2px的紅色直線
        ctx.lineWidth='2';
        ctx.strokeStyle="#f00";
        //長40,y軸上20的水準直線
        ctx.moveTo(20,20);
        ctx.lineTo(60,20);
        //描邊
        ctx.stroke();
        //儲存畫筆的狀态
        ctx.save();
        //開始新的繪畫路徑
        ctx.beginPath();
        //起始點
        ctx.moveTo(60,20);
        //重新定義畫筆的寬度和顔色
        //4px的寬度和綠色
        ctx.lineWidth='4';
        ctx.strokeStyle="#0f0";
        //然後畫一條線
        ctx.lineTo(60,60);    
        //描邊
        ctx.stroke();
        //第三條直線開始繪制
        ctx.beginPath();
        //恢複之前儲存的畫筆樣式
        ctx.restore();
        //起點
        ctx.moveTo(60,60);
        //終點
        ctx.lineTo(20,60);
        //描邊
        ctx.stroke();
    }
)();
           

我在路徑一開始就恢複了之前儲存的畫筆狀态,是以得到了一條2px的紅色直線

嘗試着注釋掉恢複方法,可以看到直線變成了之前的4px綠色直線,

然後再執行一次畫筆樣式的修改和恢複之後

(
    ()=>{
        //擷取畫布元素
        let canvas = document.getElementById('demo2');
        //擷取畫筆
        let ctx = canvas.getContext('2d');
        //開始繪畫路徑
        ctx.beginPath();
        //2px的紅色直線
        ctx.lineWidth='2';
        ctx.strokeStyle="#f00";
        //長40,y軸上20的水準直線
        ctx.moveTo(20,20);
        ctx.lineTo(60,20);
        //描邊
        ctx.stroke();
        //儲存畫筆的狀态
        ctx.save();
        //開始新的繪畫路徑
        ctx.beginPath();
        //起始點
        ctx.moveTo(60,20);
        //重新定義畫筆的寬度和顔色
        //4px的寬度和綠色
        ctx.lineWidth='4';
        ctx.strokeStyle="#0f0";
        //然後畫一條線
        ctx.lineTo(60,60);    
        //描邊
        ctx.stroke();
        //第三條直線開始繪制
        ctx.beginPath();
        //恢複之前儲存的畫筆樣式
        //第一次恢複
        ctx.restore();
        //起點
        ctx.moveTo(60,60);
        //終點
        ctx.lineTo(20,60);
        //描邊
        ctx.stroke();
        //第四條直線開始繪制
        ctx.beginPath();
        //先修改一下樣式,如果能恢複,則會被頂替
        ctx.lineWidth="10";
        ctx.strokeStyle="#00f";
        //恢複之前儲存的畫筆樣式
        //第二次恢複
        ctx.restore();
        //起點
        ctx.moveTo(20,60);
        //終點
        ctx.lineTo(20,20);
        //描邊
        ctx.stroke();

    }
)();
           

我們得到了一條新的10px的藍色直線,然後我們在第三條結束之後,執行ctx.save(),可以發現直線又成了2px的紅色.

是以我們可知恢複操作隻能恢複一次,然後我們來嘗試save(),

根據恢複的結論,我們可以先反推save也隻能儲存一種,最新的會頂替之前的,可以看成是隻有一個位置的隊列,有新人來了,舊的人就離開了隊伍

(
    ()=>{
        //擷取畫布元素
        let canvas = document.getElementById('demo2');
        //擷取畫筆
        let ctx = canvas.getContext('2d');
        //開始繪畫路徑
        ctx.beginPath();
        //2px的紅色直線
        ctx.lineWidth='2';
        ctx.strokeStyle="#f00";
        //長40,y軸上20的水準直線
        ctx.moveTo(20,20);
        ctx.lineTo(60,20);
        //描邊
        ctx.stroke();
        //儲存畫筆的狀态
        ctx.save();
        //開始新的繪畫路徑
        ctx.beginPath();
        //起始點
        ctx.moveTo(60,20);
        //重新定義畫筆的寬度和顔色
        //4px的寬度和綠色
        ctx.lineWidth='4';
        ctx.strokeStyle="#0f0";
        //然後畫一條線
        ctx.lineTo(60,60);    
        //描邊
        ctx.stroke();
        ctx.save();
        //第三條直線開始繪制
        ctx.beginPath();
        //恢複之前儲存的畫筆樣式
        //第一次恢複
        ctx.restore();
        //起點
        ctx.moveTo(60,60);
        //終點
        ctx.lineTo(20,60);
        //描邊
        ctx.stroke();
        //第四條直線開始繪制
        ctx.beginPath();
        //先修改一下樣式,如果能恢複,則會被頂替
        ctx.lineWidth="10";
        ctx.strokeStyle="#00f";
        //恢複之前儲存的畫筆樣式
        //第二次恢複
        ctx.restore();
        //起點
        ctx.moveTo(20,60);
        //終點
        ctx.lineTo(20,20);
        //描邊
        ctx.stroke();
    }
)();
           

…結果有點不盡如人意,畫筆的狀态是一個棧,先進後出,我分别對第一二條線的畫筆做了儲存,然後讀取了兩次恢複,第三條線是綠色的(與第二條線一緻),第四條線是紅色的(與第一條線一緻);

這個換成js的話可以了解為這是一個畫筆狀态的資料,save()執行的就是push()操作,restore()執行的就是pop()操作,是以隻有一次save的時候restore隻能執行一次,因為第二次pop()隻能獲得undefined.

最後我們對這幾條直線進行一個自調用的閉包封裝;

筆記-Canvas-畫筆的存儲與恢複機制學習

看起來友善了一點…

繼續閱讀