Automatic Redraws — Do You Need draw() or batchDraw()?
Short answer: no. Since Konva 8, you do not need to call draw() or
batchDraw() after changing a shape.
// This is enough. Konva schedules the redraw itself.
rect.fill('red');
rect.x(120);
// Both of these are redundant.
layer.draw();
layer.batchDraw();
Setting any attribute marks the layer as dirty, and Konva redraws it once on
the next animation frame. Changing ten attributes in a row still produces one
redraw, so calling batchDraw() yourself adds nothing — the batching already
happened.
You will still see layer.draw() in older tutorials, in answers written before
2021, and in code that AI assistants generate, because that is what the corpus
is full of. It is harmless, just unnecessary. Deleting those calls will not
change what you see on screen.
When you do still need a manual redraw
Auto-draw reacts to Konva changes. If something changes outside Konva's knowledge, nothing marks the layer dirty and you have to say so yourself.
The usual case is a Konva.Image backed by a source that mutates on its own —
a <video> element, an animated GIF, or a raw canvas another library draws
into:
// 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();
}
For video, prefer Konva.Animation,
which redraws every frame for you. There is a worked example in
Video on canvas and
GIF on canvas.
Turning batching off
Konva.autoDrawEnabled = false restores the old behaviour, where nothing is
drawn until you ask. It is worth it only if you are driving the render loop
yourself and want exact control over when frames happen. With it off,
batchDraw() becomes useful again: it collapses many calls into one redraw per
frame, instead of redrawing on every one.
The demo below turns auto-draw off so batchDraw() has something to do. The
rectangle rotates on mousemove, an event that can fire far more often than the
screen refreshes.
Instructions: Move your mouse over the stage to spin the rectangle
- Vanilla
- React
- Vue
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', () => {
// rotate rectangle on mouse move
rect.rotate(5);
// auto-draw is off, so ask for a batched redraw
layer.batchDraw();
});
import { Stage, Layer, Rect } from 'react-konva';
import { useRef, useEffect } from 'react';
// Turned off on purpose, so batchDraw has a job to do
Konva.autoDrawEnabled = false;
const App = () => {
const rectRef = useRef(null);
const layerRef = useRef(null);
useEffect(() => {
const stage = rectRef.current.getStage();
stage.on('mousemove', () => {
// rotate rectangle on mouse move
rectRef.current.rotate(5);
// auto-draw is off, so ask for a batched redraw
layerRef.current.getLayer().batchDraw();
});
}, []);
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer ref={layerRef}>
<Rect
ref={rectRef}
x={window.innerWidth / 2 - 50}
y={window.innerHeight / 2 - 25}
width={100}
height={50}
fill="green"
stroke="black"
strokeWidth={4}
/>
</Layer>
</Stage>
);
};
export default App;
<template>
<v-stage :config="stageSize" @mousemove="handleMouseMove">
<v-layer ref="layerRef">
<v-rect :config="rectConfig" ref="rectRef" />
</v-layer>
</v-stage>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import Konva from 'konva';
// Turned off on purpose, so batchDraw has a job to do
Konva.autoDrawEnabled = false;
const stageSize = {
width: window.innerWidth,
height: window.innerHeight
};
const rectConfig = ref({
x: window.innerWidth / 2 - 50,
y: window.innerHeight / 2 - 25,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
const layerRef = ref(null);
const rectRef = ref(null);
const handleMouseMove = () => {
// rotate rectangle on mouse move
rectRef.value.getNode().rotate(5);
// auto-draw is off, so ask for a batched redraw
layerRef.value.getNode().batchDraw();
};
</script>