优化 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()
  • 小心使用沉重的物理库。