Canvas Color-Based Object Tracking Utility
canvas-color-tracker is a utility library (current stable version 1.3.2) designed to facilitate interaction with dynamically rendered objects on an HTML5 canvas, where native object-specific mouse events are not available. It provides a system for tracking canvas elements by assigning each a unique, invisible color key on a 'shadow' or off-screen canvas. Developers render their objects on this shadow canvas with these unique colors, then use `mousemove` events on the main canvas to sample the pixel color under the mouse pointer. This color is then used to look up the associated object in the `canvas-color-tracker` registry. A key feature is its checksum encoding mechanism for color keys, which enhances lookup reliability by accounting for pixel anti-aliasing and color mutations at object boundaries. The library focuses solely on the registry aspect: generating keys, registering objects, and performing lookups. It enables effective object identification and interaction for complex canvas applications, supporting up to approximately 262,000 objects with default settings.
Common errors
-
Object not found for sampled color (or `lookup` returns `null`/`undefined`)
cause The sampled pixel color from the shadow canvas does not exactly match a registered object's unique key, potentially due to anti-aliasing or an incorrect color format being passed to `lookup`.fixEnsure the color passed to `lookup` is either a hex string (e.g., `'#RRGGBB'`) or an `[r, g, b]` array (e.g., `ImageData.data` sliced to the first three values). Verify that your shadow canvas drawing precisely matches the object's registered color. The internal checksum usually handles minor anti-aliasing discrepancies. -
`myTracker.register(myObject)` returns `null` instead of a color string.
cause The internal object registry has reached its maximum capacity, preventing new objects from being added.fixReview the number of objects being tracked. If it exceeds approximately 262,000 (default `checksum_bits=6`), you may need to instantiate `ColorTracker` with a lower `checksum_bits` value (e.g., `new ColorTracker(4)` for ~1 million objects), accepting a slightly higher theoretical risk of checksum collisions.
Warnings
- gotcha The `checksum_bits` parameter, configurable during `ColorTracker` instantiation, directly impacts the maximum number of objects the registry can store. Higher `checksum_bits` reduce the chance of anti-aliasing-induced color collisions but decrease the total capacity. The maximum objects are `2^(24 - checksum_bits) - 1`. The default of 6 bits supports approximately 262,000 objects.
- gotcha The `register()` method returns `null` if the object registry is full and cannot store any more unique objects. This can lead to silent failures if not handled.
- gotcha Canvas anti-aliasing on object boundaries can produce blended pixel colors, which might not precisely match the unique color key assigned by the tracker. `canvas-color-tracker` mitigates this with checksum encoding, but extreme anti-aliasing or certain rendering contexts could still lead to lookup failures.
Install
-
npm install canvas-color-tracker -
yarn add canvas-color-tracker -
pnpm add canvas-color-tracker
Imports
- ColorTracker
const ColorTracker = require('canvas-color-tracker');import ColorTracker from 'canvas-color-tracker';
- ColorTracker
<script src="//cdn.jsdelivr.net/npm/canvas-color-tracker"></script>
Quickstart
import ColorTracker from 'canvas-color-tracker';
// Assume a canvas context is available for pixel data
const canvas = document.createElement('canvas');
canvas.width = 800; canvas.height = 600;
const context = canvas.getContext('2d', { willReadFrequently: true });
const shadowCanvas = document.createElement('canvas');
shadowCanvas.width = canvas.width; shadowCanvas.height = canvas.height;
const shadowCtx = shadowCanvas.getContext('2d', { willReadFrequently: true });
// Create a new ColorTracker instance
// Default checksum_bits (6) allows ~262k objects. Use `new ColorTracker(4)` for ~1M objects.
const myTracker = new ColorTracker();
// Register an object and get its unique color key
const myObject = { id: 1, name: 'Red Square', x: 50, y: 50, size: 20 };
const myObjectColor = myTracker.register(myObject);
if (myObjectColor) {
// Draw the actual object on the main canvas
context.fillStyle = 'red';
context.fillRect(myObject.x, myObject.y, myObject.size, myObject.size);
// Draw the object with its unique shadow color on the hidden shadow canvas
shadowCtx.fillStyle = myObjectColor;
shadowCtx.fillRect(myObject.x, myObject.y, myObject.size, myObject.size);
}
// Simulate a mouse hover event
const hoverX = 55; // Inside the red square
const hoverY = 55;
// Get the pixel color from the shadow canvas at the hover position
const pixel = shadowCtx.getImageData(hoverX, hoverY, 1, 1).data; // Returns a Uint8ClampedArray: [r, g, b, a]
const hoverColor = [pixel[0], pixel[1], pixel[2]]; // Only RGB is used for lookup
// Look up the object using the color data
const hoveredObject = myTracker.lookup(hoverColor);
if (hoveredObject) {
console.log('Hovered over:', hoveredObject.name);
// Expected: Hovered over: Red Square
} else {
console.log('No object found at this position.');
}
// Example of registry full scenario (highly simplified, usually needs many registrations)
// For demonstration, let's assume we force it to be full or hit null return
// myTracker.register(someObject) could return null if capacity exceeded.