JSFiddle - React, Tailwind, and code Playground

by Shawn Allen

HTML

<canvas width="800" height="600"></canvas>

CSS

canvas {
    border: 1px solid #ccc;
}

JavaScript

var canvas = document.querySelector("canvas")
    context = canvas.getContext("2d"),
    lines = [],
    mouse = null,
    grid = 1;

canvas.addEventListener("mousedown", function(e) {
  mouse = getPosition(e);
  canvas.addEventListener("mousemove", move);
});

window.addEventListener("mouseup", function() {
  canvas.removeEventListener("mousemove", move);
});

canvas.addEventListener("dblclick", clear);

function draw() {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.save();
  lines.forEach(drawLine);
  context.restore();
}

function drawLine(line, i) {
  context.save();
  context.beginPath();

  context.fillStyle = "hsl(" + [i, "85%", "50%"] + ")";

  // move to (x, y)
  context.translate(line.start.x, line.start.y);
  // rotate by the line's angle
  context.rotate(angle(line.start, line.end));
  // draw a rectangle
  var w = distance(line.start, line.end),
      h = 1 + w / 200 * 20;
  context.rect(0, -h / 2, w, h);

  context.arc(0, 0, h / 2, 0, Math.PI * 2);
  context.fill();
  context.arc(w, 0, h / 2, 0, Math.PI * 2);
  context.fill();

  context.closePath();
  context.fill();
  // context.stroke();
  context.restore();
}

function move(e) {
  var pos = getPosition(e),
      line = {
        start: mouse,
        end: pos
      };
  mouse = pos;
  lines.push(line);
  drawLine(line, lines.length);
}

function clear() {
  lines = [];
  draw();
}

function getPosition(e) {
  return {
    x: e.offsetX,
    y: e.offsetY,
    time: Date.now()
  };
}

function round(n) {
  return grid * Math.round(n / grid);
}

function distance(a, b) {
  var dx = b.x - a.x,
      dy = b.y - a.y;
  return Math.sqrt(dx * dx + dy * dy);
}

function angle(a, b) {
  return Math.atan2(b.y - a.y, b.x - a.x);
}