JSFiddle - React, Tailwind, and code Playground

by warriormole

HTML

<h4>Click to add a circle<br>Drag to move a circle.</h4>
<canvas id="canvas" width=400 height=300></canvas>

CSS

body {
    background-color: ivory;
}
#canvas {
    border:1px solid red;
}

JavaScript

// canvas related variables
// references to canvas and its context and its position on the page
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas.scrollLeft();
var scrollY = $canvas.scrollTop();
var cw = canvas.width;
var ch = canvas.height;

// flag to indicate a drag is in process
// and the last XY position that has already been processed
var isDown = false;
var lastX;
var lastY;

// the radian value of a full circle is used often, cache it
var PI2 = Math.PI * 2;

// variables relating to existing circles
var circles = [];
var stdRadius = 10;
var draggingCircle = -1;

// clear the canvas and redraw all existing circles
function drawAll() {
    ctx.clearRect(0, 0, cw, ch);
    for (var i = 0; i < circles.length; i++) {
        var circle = circles[i];
        ctx.beginPath();
        ctx.arc(circle.x, circle.y, circle.radius, 0, PI2);
        ctx.closePath();
        ctx.fillStyle = circle.color;
        ctx.fill();
    }
}

function handleMouseDown(e) {
    // tell the browser we'll handle this event
    e.preventDefault();
    e.stopPropagation();

    // save the mouse position
    // in case this becomes a drag operation
    lastX = parseInt(e.clientX - offsetX);
    lastY = parseInt(e.clientY - offsetY);

    // hit test all existing circles
    var hit = -1;
    for (var i = 0; i < circles.length; i++) {
        var circle = circles[i];
        var dx = lastX - circle.x;
        var dy = lastY - circle.y;
        if (dx * dx + dy * dy < circle.radius * circle.radius) {
            hit = i;
        }
    }

    // if no hits then add a circle
    // if hit then set the isDown flag to start a drag
    if (hit < 0) {
        circles.push({
            x: lastX,
            y: lastY,
            radius: stdRadius,
            color: randomColor()
        });
       ...