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');
...