跳到主要内容

使用 Konva 提高 HTML5 Canvas 性能

Canvas 性能取决于场景复杂度、重绘频率、像素数量和命中检测。请优化实测瓶颈,不要只关注节点数量。

请在有代表性的设备上使用浏览器性能工具。记录真实场景的帧时间、内存使用量和交互延迟。

效果显著的 Konva 改进

  • 将静态内容和变化内容放在不同的图层上。
  • 对不接收事件的节点或图层设置 listening(false)
  • 如果场景很大,请隐藏可见区域外的节点。
  • 如果测量结果显示缓存有绘制优势,请缓存复杂且稳定的节点。
  • 如果阴影、滤镜和大型透明区域占用大量帧时间,请减少使用这些效果。
  • 仅在数据变化后绘制。Konva 会自动批量执行图层绘制。

不要缓存每个节点。每个缓存都会占用内存,并在内容变化时产生额外工作。

分离交互图层

此示例在一个图层上放置 2,000 个非交互圆形。因为 listening 为 false,所以这个图层不绘制命中 Canvas。

第二个图层包含一个可拖动图形。

import Konva from 'konva';

const stage = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: 420,
});

const backgroundLayer = new Konva.Layer({ listening: false });
const interactionLayer = new Konva.Layer();
stage.add(backgroundLayer, interactionLayer);

for (let index = 0; index < 2000; index += 1) {
  backgroundLayer.add(
    new Konva.Circle({
      x: Math.random() * stage.width(),
      y: Math.random() * stage.height(),
      radius: 2 + Math.random() * 4,
      fill: Konva.Util.getRandomColor(),
      opacity: 0.55,
      perfectDrawEnabled: false,
    })
  );
}

const handle = new Konva.Circle({
  x: stage.width() / 2,
  y: stage.height() / 2,
  radius: 36,
  fill: '#ff922b',
  stroke: '#7c2d12',
  strokeWidth: 3,
  draggable: true,
});

const label = new Konva.Text({
  x: 16,
  y: 16,
  text: 'The orange circle stays interactive',
  fontSize: 18,
  fill: '#111827',
});

interactionLayer.add(handle, label);

分离图层会产生开销,因为每个图层都会创建场景 Canvas 和命中 Canvas。请使用少量图层,并为每个图层定义明确的更新模式。

请阅读所有 Konva 性能提示,了解动画、缓存、像素比和特定图形的指导。