JSFiddle - React, Tailwind, and code Playground

by Christian Sonne

HTML

<canvas id="c"></canvas>

CSS

html, body {
  margin: 0;
  padding: 0;
  line-height: 0;
}

JavaScript

let labels = [];

function Label(y) {
	this.y = this.anchor = y;
}

let W = c.width = window.innerWidth;
let H = c.height = window.innerHeight;
let ctx = c.getContext("2d");
ctx.textBaseline="middle";

c.addEventListener("click", function(e) {
	labels.push(new Label(e.clientY));
}, false);

function mutate() {
	for (let ia = 0; ia < labels.length -1 ; ia++) {
  	let a = labels[ia];
  	for (let ib = ia + 1; ib < labels.length; ib++) {
    	let b = labels[ib];
    	if (a != b) {
      	let dist = a.y - b.y;
        if (dist == 0) {
        	a.y += 1;
        }
      	if (Math.abs(dist) < 10) {
        	a.y += Math.sign(dist);
          b.y -= Math.sign(dist);
        }
        if (
        	(a.anchor < b.anchor && a.y > b.y) || 
          (a.anchor > b.anchor && a.y < b.y)) {
        	let t = a.anchor;
          a.anchor = b.anchor;
          b.anchor = t;
        }
      }
    }
  }
}

function draw() {
	mutate();
  ctx.clearRect(0, 0, W, H);
  for (let label of labels) {
  	ctx.beginPath();
    ctx.moveTo(0, label.anchor);
    ctx.lineTo(18, label.y);
    ctx.stroke();
  	ctx.fillText("Label at "+label.anchor, 20, label.y);
  }
  window.requestAnimationFrame(draw);
}

window.requestAnimationFrame(draw);