最佳化 canvas

<canvas> 元素是 Web 上渲染 2D 圖形最廣泛使用的工具之一。然而,當網站和應用程式將 Canvas API 推向極限時,效能就會開始下降。本文提供了最佳化 canvas 元素使用方法的建議,以確保您的圖形效能良好。

效能提示

以下是提高 Canvas 效能的技巧集合。

在離屏 Canvas 上預先渲染相似的圖元或重複的物件

如果您發現自己在每個動畫幀中重複執行相同的繪圖操作,請考慮將其解除安裝到離屏 Canvas。然後,您可以根據需要將離屏影像渲染到主 Canvas 上,而無需不必要地重複最初生成它的步驟。

js
myCanvas.offscreenCanvas = document.createElement("canvas");
myCanvas.offscreenCanvas.width = myCanvas.width;
myCanvas.offscreenCanvas.height = myCanvas.height;

myCanvas.getContext("2d").drawImage(myCanvas.offScreenCanvas, 0, 0);

避免使用浮點數座標,而是使用整數

當您在 Canvas 上繪製沒有整數值的物件時,會發生亞畫素渲染。

js
ctx.drawImage(myImage, 0.3, 0.5);

這會迫使瀏覽器進行額外的計算來建立抗鋸齒效果。為避免這種情況,請確保使用 Math.floor() 等方法對呼叫 drawImage() 時使用的所有座標進行四捨五入。

不要在 drawImage 中縮放影像

在載入影像時,將其快取為不同大小並放在離屏 Canvas 上,而不是在 drawImage() 中反覆縮放。

為複雜場景使用多個分層 Canvas

在您的應用程式中,您可能會發現有些物件需要頻繁移動或更改,而其他物件則相對靜態。在這種情況下,一種可能的最佳化方法是使用多個 <canvas> 元素來分層您的專案。

例如,假設您有一個遊戲,頂部是 UI,中間是遊戲動作,底部是靜態背景。在這種情況下,您可以將遊戲分成三個 <canvas> 層。UI 只會在使用者輸入時更改,遊戲層會在每一幀更改,而背景通常保持不變。

html
<div id="stage">
  <canvas id="ui-layer" width="480" height="320"></canvas>
  <canvas id="game-layer" width="480" height="320"></canvas>
  <canvas id="background-layer" width="480" height="320"></canvas>
</div>
css
#stage {
  width: 480px;
  height: 320px;
  position: relative;
  border: 2px solid black;
}

canvas {
  position: absolute;
}
#ui-layer {
  z-index: 3;
}
#game-layer {
  z-index: 2;
}
#background-layer {
  z-index: 1;
}

為大型背景影像使用純 CSS

如果您有靜態背景影像,可以使用 CSS 的 background 屬性將其繪製到一個普通的 <div> 元素上,並將其放置在 Canvas 下方。這樣可以避免在每一幀都將背景渲染到 Canvas 上。

使用 CSS 變換縮放 Canvas

CSS 變換 由於使用 GPU,因此速度更快。最佳情況是不要縮放 Canvas,或者使用較小的 Canvas 並放大,而不是使用較大的 Canvas 並縮小。

js
const scaleX = window.innerWidth / canvas.width;
const scaleY = window.innerHeight / canvas.height;

const scaleToFit = Math.min(scaleX, scaleY);
const scaleToCover = Math.max(scaleX, scaleY);

stage.style.transformOrigin = "0 0"; // Scale from top left
stage.style.transform = `scale(${scaleToFit})`;

關閉透明度

如果您的應用程式使用 Canvas 且不需要透明背景,請在透過 HTMLCanvasElement.getContext() 建立繪圖上下文時將 alpha 選項設定為 false。瀏覽器可以在內部使用此資訊來最佳化渲染。

js
const ctx = canvas.getContext("2d", { alpha: false });

為高解析度顯示屏縮放

您可能會發現 Canvas 元素在高解析度顯示屏上看起來有些模糊。雖然可能存在許多解決方案,但一個簡單的第一步是同時使用 Canvas 的屬性、樣式及其上下文的 scale 來放大和縮小 Canvas。

js
// Get the DPR and size of the canvas
const dpr = window.devicePixelRatio;
const rect = canvas.getBoundingClientRect();

// Set the "actual" size of the canvas
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;

// Scale the context to ensure correct drawing operations
ctx.scale(dpr, dpr);

// Set the "drawn" size of the canvas
canvas.style.width = `${rect.width}px`;
canvas.style.height = `${rect.height}px`;

更多技巧

  • 將 Canvas 呼叫批次化。例如,繪製折線而不是多條單獨的線。
  • 避免不必要的 Canvas 狀態更改。
  • 僅渲染螢幕差異,而不是整個新狀態。
  • 儘可能避免使用 shadowBlur 屬性。
  • 儘可能避免 文字渲染
  • 嘗試不同的清除 Canvas 的方法(clearRect() vs. fillRect() vs. 調整 Canvas 大小)。
  • 對於動畫,請使用 Window.requestAnimationFrame() 而不是 setInterval()
  • 小心使用沉重的物理庫。