Canvas 的分层渲染

941次阅读  |  发布于3年以前

在 Photoshop 中有个概念叫图层,图层就像堆叠在一起的透明纸,组合到一起展示出图片的效果。在 Canvas 的应用中,为了优化渲染性能,也会采用类似的分层机制。本文会对 Canvas 分层做一些介绍。

基本原理

在某些应用程序中,可能会需要经常移动或更改画布中的某些对象,而画布中其他的内容则保持相对静态。在这种情况下,可以在项目中使用分层机制来做优化。

比如,在游戏或动画场景中,背景发生变化的频率比较低,而主要角色的发生变化的频率是比较高的。如果不做任何处理的话,每次画布上出现任意的变化,需要把画布所有的内容都重新绘制一次,代码如下所示。

<canvas id="canvas" />

const canvas = document.getElementById('canvas');

function draw(){
  drawPeopleAction(canvas);
  drawBackground(canvas);
  requestAnimationFrame(draw);
}

很显然,全量绘制是没有必要的,比较理想的情况是,只渲染发生变化的内容。这里可以根据不同的变化频率做分层,把低频和高频渲染的内容归到不同的图层中,每次变化的时候只把需要把对应的图层重新渲染即可,这样可以降低渲染的开销。

Canvas 画布自身并不支持分层,为了实现分层需要我们引入多个 <canvas /> 元素。每个 <canvas /> 元素就是一个分层,这些 <canvas /> 元素的长宽以及位置都是相同的,最终会完全是重叠在一起的。通过 z-index 可以对图层重叠的顺序进行调整。

可以将上面的代码进行分层优化:

<canvas id="backgroundCanvas" />
<canvas id="peopleActionCanvas" />
const peopleActionCanvas = document.getElementById('peopleActionCanvas');
const backgroundCanvas = document.getElementById('backgroundCanvas');

function draw(){
  drawPeopleAction(peopleActionCanvas);
  if (needDrawBackground) {
    drawBackground(backgroundCanvas);
  }
  requestAnimationFrame(draw);
}

相关应用

Fabric.js 支持用户在画布上进行选择、拖拽等交互操作,这些交互功能的实现用到了分层技术。Fabric.js 会创建两个 canvas / 元素,所有交互操作和事件处理相关的逻辑会放在了一个图层中(upper-canvas);而具体展示的内容会在另一个图层中 (lower-canvas)完成渲染。如果画布中的内容不需要与用户交互,对于这种单纯的静态展示的场景,Fabric.js 不做分层,只用一个 canvas / 进行绘制,具体细节可以参考fabric.StaticCanvas 方法。

<div>
  <canvas class="lower-canvas"></canvas>
  <canvas class="upper-canvas"></canvas>
</div>

Konva.js 支持开发人员添加和组织图层 (Konva.Layer),相对来说可以更加方便、灵活地使用图层。值得注意的是,Konva.js 给出了一条建议:要控制图层的数量,最多不超过 3 ~ 5 个。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8