HTML5 Canvas Listening False Performance Tip
If you have a lot of shapes on the canvas and you don't need to detect events for some of them,
you can set listening to false to improve performance.
When listening = false, the shape will be ignored from event detection (like mouseover, drag and drop, click, etc).
This can significantly improve performance for complex applications.
Below is a demo showing the performance difference between listening and non-listening shapes:
- Vanilla
- React
- Vue
import Konva from 'konva';
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
});
const layer = new Konva.Layer();
stage.add(layer);
// Create many circles with listening enabled
for (let i = 0; i < 100; i++) {
const circle = new Konva.Circle({
x: Math.random() * stage.width(),
y: Math.random() * stage.height(),
radius: 20,
fill: 'blue',
opacity: 0.5,
// Enable event detection (default)
listening: true,
});
// Add hover effect
circle.on('mouseover', function() {
this.fill('red');
});
circle.on('mouseout', function() {
this.fill('blue');
});
layer.add(circle);
}
// Create many circles with listening disabled
for (let i = 0; i < 1000; i++) {
const circle = new Konva.Circle({
x: Math.random() * stage.width(),
y: Math.random() * stage.height(),
radius: 20,
fill: 'green',
opacity: 0.5,
// Disable event detection for better performance
listening: false,
});
layer.add(circle);
}
// Add text explanation
const text = new Konva.Text({
x: 10,
y: 10,
text: 'Blue circles (100) have event listeners (hover them)\nGreen circles (1000) have no listeners (better performance)',
fontSize: 16,
fill: 'black',
});
layer.add(text);
import { Stage, Layer, Circle, Text } from 'react-konva';
import { useState } from 'react';
// Generate circles data
const listeningCircles = Array.from({ length: 100 }, (_, i) => ({
id: i,
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
}));
const nonListeningCircles = Array.from({ length: 1000 }, (_, i) => ({
id: i + 100,
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
}));
const App = () => {
const [hoveredId, setHoveredId] = useState(null);
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
{/* Circles with event listeners */}
{listeningCircles.map((circle) => (
<Circle
key={circle.id}
x={circle.x}
y={circle.y}
radius={20}
fill={hoveredId === circle.id ? 'red' : 'blue'}
opacity={0.5}
onMouseEnter={() => setHoveredId(circle.id)}
onMouseLeave={() => setHoveredId(null)}
/>
))}
{/* Circles without event listeners */}
{nonListeningCircles.map((circle) => (
<Circle
key={circle.id}
x={circle.x}
y={circle.y}
radius={20}
fill="green"
opacity={0.5}
listening={false}
/>
))}
<Text
x={10}
y={10}
text={"Blue circles (100) have event listeners (hover them)\nGreen circles (1000) have no listeners (better performance)"}
fontSize={16}
fill="black"
/>
</Layer>
</Stage>
);
};
export default App;
<template>
<v-stage :config="stageSize">
<v-layer>
<!-- Circles with event listeners -->
<v-circle
v-for="circle in listeningCircles"
:key="circle.id"
:config="getListeningCircleConfig(circle)"
@mouseenter="handleMouseEnter(circle.id)"
@mouseleave="handleMouseLeave"
/>
<!-- Circles without event listeners -->
<v-circle
v-for="circle in nonListeningCircles"
:key="circle.id"
:config="getNonListeningCircleConfig(circle)"
/>
<v-text :config="textConfig" />
</v-layer>
</v-stage>
</template>
<script setup>
import { ref } from 'vue';
const stageSize = {
width: window.innerWidth,
height: window.innerHeight
};
const hoveredId = ref(null);
// Generate circles data
const listeningCircles = Array.from({ length: 100 }, (_, i) => ({
id: i,
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
}));
const nonListeningCircles = Array.from({ length: 1000 }, (_, i) => ({
id: i + 100,
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
}));
const getListeningCircleConfig = (circle) => ({
x: circle.x,
y: circle.y,
radius: 20,
fill: hoveredId.value === circle.id ? 'red' : 'blue',
opacity: 0.5,
});
const getNonListeningCircleConfig = (circle) => ({
x: circle.x,
y: circle.y,
radius: 20,
fill: 'green',
opacity: 0.5,
listening: false,
});
const textConfig = {
x: 10,
y: 10,
text: 'Blue circles (100) have event listeners (hover them)\nGreen circles (1000) have no listeners (better performance)',
fontSize: 16,
fill: 'black',
};
const handleMouseEnter = (id) => {
hoveredId.value = id;
};
const handleMouseLeave = () => {
hoveredId.value = null;
};
</script>