JSFiddle - React, Tailwind, and code Playground
by Rajesh Danabal
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Canvas Interaction Manager</title>
<style>
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
// --- Shape Class ---
class Shape {
constructor({ x, y, width, height, color }) {
Object.assign(this, { x, y, width, height, color });
}
draw(ctx) {
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
hitTest(x, y) {
return (
x >= this.x && x <= this.x + this.width &&
y >= this.y && y <= this.y + this.height
);
}
}
// --- Layer Class ---
class Layer {
constructor(id) {
this.id = id;
this.shapes = [];
}
addShape(shape) {
this.shapes.push(shape);
}
draw(ctx) {
this.shapes.forEach(shape => shape.draw(ctx));
}
hitTest(x, y) {
for (let i = this.shapes.length - 1; i >= 0; i--) {
if (this.shapes[i].hitTest(x, y)) {
return { type: 'shape', target: this.shapes[i], layer: this };
}
}
return { type: 'layer', target: this };
}
}
// --- InteractionManager Class ---
class InteractionManager {
constructor(canvas, layers = []) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.layers = layers;
this.plugins = {
shape: [],
layer: [],
container: []
};
this._bindEvents();
}
register(type, plugin) {
if (this.plugins[type]) {
this.plugins[type].push(plugin);
}
}
_bindEvents() {
this.canvas.addEventListener('click', (e) => this._handleEvent(e, 'click'));
this.canvas.addEventListener('contextmenu', (e) => {
e.preventDefault();
this._handleEvent(e, 'contextmenu');
...