前言
今天用 canvas 做 H5 的時候遇到了閃屏問題。閃爍效果如下圖:
問題簡介
功能簡介
H5 該部分的功能為:通過點選二級選單,切換圖片的遮罩或者更換背景。
因為功能簡單,所以用了原生 canvas 實現這個功能。但在使用 clearRect
清除畫布的時候會出現閃爍的情況。
程式碼實現(問題程式碼)
以下程式碼即為出現閃屏的關鍵程式碼,省略了圖片的定義與 onload:
// 點選二級選單後,觸發該函式更新畫布
updateCanvas(){
const canvas = document.getElementById('canvas'); // 獲取畫布
const ctx = canvas.getContext('2d');
ctx.clearRect(0,0,1448,750); // 清空畫布
// 開始重繪
ctx.drawImage(bg,0,0); // 背景
... // 省略其他繪製過程
}
複製程式碼
問題分析
經過簡單分析,得出閃屏的原因是 clearRect
清除畫布後,繪製的時間較長導致出現閃屏的現象。
什麼是雙快取
來看一下 microsoft 網站中 雙緩衝圖形 這篇文章對雙快取的解釋:
對圖形進行程式設計時出現閃爍是一個常見問題。 需要多個複雜畫圖操作的圖形操作可導致呈現的影象出現閃爍或具有不可接受的外觀。 為解決這些問題,.NET Framework 提供了雙緩衝功能。
雙緩衝使用內容緩衝來解決與多個畫圖操作相關的閃爍問題。 啟用雙緩衝後,所有畫圖操作會首先呈現到記憶體緩衝而不是螢幕上的繪圖圖面。 所有畫圖操作完成後,記憶體緩衝會直接複製到與之關聯的繪圖圖面。 由於螢幕上僅執行一個圖形操作,因此與複雜畫圖操作相關的影象閃爍可得以消除。
使用雙快取解決問題
以上引用,簡單來說,主要問題就是繪製時間較長導致了閃屏,解決方法就是新建一個 canvas 作為 快取 canvas,通過 快取 canvas 完成繪製過程,繪製完成後,直接將 快取 canvas 複製到原來的 canvas,這樣就可以解決繪製時間過長導致的閃屏問題。
程式碼實現
以下程式碼即為關鍵程式碼,省略了圖片的定義與 onload:
updateCanvas(){
const canvas = document.getElementById('canvas'); // 獲取頁面中的 canvas
const ctx = canvas.getContext('2d');
const tempCanvas = document.createElement('canvas'); // 新建一個 canvas 作為快取 canvas
const tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = 1448; tempCanvas.height = 750; // 設定寬高
// 開始繪製
tempCtx.drawImage(bg,0,0); // 背景
... // 省略其他繪製過程
// 快取 canvas 繪製完成
ctx.clearRect(0,0,1448,750); // 清空舊 canvas
ctx.drawImage(tempCanvas,0,0); // 將快取 canvas 複製到舊的 canvas
}
複製程式碼
效果驗收
可以很明顯的看到閃屏問題解決了!
總結
- 重繪畫布的時候,我們需要使用
clearRect
來清空畫布,此時的畫布是空的,開始重繪後,如果內容較多,時間也就相應的增加,因此視覺出現了空檔期,我們就看到了閃屏的情況; - 解決閃屏,其實就是怎麼解決繪製時間較長的問題;
- 這裡參考了圖形圖象處理程式設計中 雙快取 的概念,將繪製過程交給了 快取 canvas,這樣頁面中的 canvas 就省去了繪製過程,而 快取 canvas 並沒有新增到頁面,所以我們就看不到繪製過程,也就解決了閃屏的問題。
參考連結
- 【H5動畫】談談canvas動畫的閃爍問題:www.cnblogs.com/kenkofox/p/…
- 雙緩衝圖形:docs.microsoft.com/zh-cn/dotne…
更多文章
- 檢視 網易創意部 其他小夥伴的文章:github.com/f2e-netease…
- 檢視我的更多文章:github.com/NalvyBoo/bl…