How Konva.js Uses Random Colors for Precise Canvas Hit Detection
Konva.js detects whether a point lies inside a shape by assigning each shape a unique random color key, rendering a hidden hitCanvas with these colors, and then reading the pixel color at the click position to identify the corresponding shape, supporting up to 16.7 million objects.
This article is the third in a series on Canvas point‑in‑shape detection. The first two introduced geometric detection with Fabric.js and opacity‑based detection with Create.js. This piece focuses on using random colors for detection with Konva.js.
Konva.js generates a unique random color value (colorKey) for every shape on the canvas. During rendering, besides the visible sceneCanvas , an off‑screen hitCanvas is created where each shape is drawn with its colorKey instead of its visual fill. When the user clicks, the color of the pixel at the click location on the hitCanvas is read; this colorKey maps back to the original shape, allowing precise hit detection.
The hitCanvas uses the same size and position attributes as the sceneCanvas, but with the special colorKey fills. Because a 24‑bit hex color provides 16,777,216 possible values, Konva.js can theoretically support that many distinct shapes for hit testing, which is sufficient for most applications.
Konva.js generates random color keys with the following constructor code:
<code>constructor(config) {
super(config);
// set colorKey
let key;
while (true) {
// generate random color
key = Util.getRandomColor();
if (key && !(key in shapes)) {
break;
}
}
this.colorKey = key;
// window.Konva.shapes
shapes[key] = this;
}</code>And determines whether a point lies inside a shape using:
<code>_getIntersection(pos) {
const ratio = this.hitCanvas.pixelRatio;
const p = this.hitCanvas.context.getImageData(Math.round(pos.x * ratio), Math.round(pos.y * ratio), 1, 1).data;
const p3 = p[3];
// fully opaque pixel
if (p3 === 255) {
const colorKey = Util._rgbToHex(p[0], p[1], p[2]);
const shape = shapes[HASH + colorKey];
// found corresponding shape
if (shape) {
return { shape: shape };
}
return { antialiased: true };
} else if (p3 > 0) {
// antialiased pixel
return { antialiased: true };
}
// empty pixel
return {};
}</code>When multiple shapes overlap, this method only returns the topmost shape. For cases where all intersecting shapes are needed, Konva.js provides
getAllIntersections(pos), which works similarly to Create.js by rendering each shape to a temporary canvas and checking opacity, though it can impact performance.
getAllIntersections(pos): get all shapes that intersect a point. Note: because this method must clear a temporary canvas and redraw every shape inside the container, it should only be used for special situations because it performs very poorly. Please use the Konva.Stage#getIntersection method if at all possible because it performs much better.
KooFE Frontend Team
Follow the latest frontend updates
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.