Skip to main content

自动重绘 — 你需要 draw() 还是 batchDraw()?

简短回答:不需要。自 Konva 8 起,更改图形后无需调用 draw()batchDraw()

// This is enough. Konva schedules the redraw itself.
rect.fill('red');
rect.x(120);

// Both of these are redundant.
layer.draw();
layer.batchDraw();

设置任何属性都会将图层标记为脏,Konva 会在下一帧动画中重绘它。连续更改十个属性仍然只会产生一次重绘,因此自行调用 batchDraw() 没有任何作用——批处理已经完成。

你仍然会在较早的教程、2021 年以前编写的回答以及 AI 助手生成的代码中看到 layer.draw(),因为语料库中充斥着这类内容。它没有害处,只是不必要。删除这些调用不会改变屏幕上的显示效果。

仍然需要手动重绘的情况

自动绘制会响应 Konva 的更改。如果某些内容在 Konva 的认知范围之外发生变化,就不会有任何东西将图层标记为脏,你必须自行告知它。

常见情况是 Konva.Image 使用了会自行变化的源——例如一个 <video> 元素、一个动画 GIF,或者另一个库正在向其中绘制的原始 canvas:

// An external library drew a new GIF frame into our canvas.
// Konva has no attribute change to notice, so ask for the redraw.
function onDrawFrame(ctx, frame) {
ctx.drawImage(frame.buffer, 0, 0);
layer.draw();
}

对于视频,建议使用 Konva.Animation,它会为你重绘每一帧。在画布中播放视频在画布中播放 GIF中提供了完整示例。

关闭批处理

Konva.autoDrawEnabled = false 会恢复旧行为,即在你发出请求之前不会进行任何绘制。只有当你自行驱动渲染循环,并且希望精确控制帧的绘制时机时,关闭它才值得。关闭后,batchDraw() 会再次变得有用:它会将同一帧中的多次调用合并为一次重绘,而不是每次调用都进行重绘。

下面的演示会关闭自动绘制,使 batchDraw() 有实际作用。矩形会在 mousemove 上旋转,而此事件的触发频率可能远高于屏幕刷新频率。

说明: 将鼠标移动到舞台上以旋转矩形

import Konva from 'konva';

// Turned off on purpose, so batchDraw has a job to do
Konva.autoDrawEnabled = false;

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

const layer = new Konva.Layer();
stage.add(layer);

const rect = new Konva.Rect({
x: stage.width() / 2 - 50,
y: stage.height() / 2 - 25,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
});

layer.add(rect);

stage.on('mousemove', () => {
// 在鼠标移动时旋转矩形
rect.rotate(5);
// auto-draw is off, so ask for a batched redraw
layer.batchDraw();
});