JSFiddle - React, Tailwind, and code Playground

by Rich Shih

HTML

<canvas id="canvas" width="500" height="500"></canvas>

JavaScript

let canvas = document.getElementById("canvas"),
  context, circles = [];

if (canvas) {
  context = canvas.getContext("2d");
  for (let i = 1; i < 5; i++) {
    let c = new Circle();
    c.quadrant = i;
    circles.push(c);
  }
  draw()
}

function draw() {
  context.clearRect(0, 0, canvas.width, canvas.height)
  circles.forEach(c => {
    c.animate()
  })
  if (!circles.some(c => [Math.abs(c.left), Math.abs(c.right), Math.abs(c.top), Math.abs(c.bottom)].some(_c => _c > c.midpoint))) {
    window.requestAnimationFrame(draw);
  }
}

function animateAll() {
  circles.forEach(c => c.animate());
  window.requestAnimationFrame(animateAll)
}

function Circle() {
  this.x = canvas.width / 2;
  this.y = canvas.height / 2;
  this.midpoint = canvas.width / 4;
  this.quadrant = 4;
  this.left = 0;
  this.right = 0;
  this.top = 0;
  this.bottom = 0;
  this.animate = function() {
    context.beginPath();
    context.strokeStyle = "black";
    //	quadrants go counter clockwise in starting from top right
    switch (this.quadrant) {
      case 1:
        context.arc(this.x + this.right, this.y + this.top, 100, 0, 2 * Math.PI);
        this.right += 10;
        this.top -= 10;
        break;
      case 2:
        context.arc(this.x + this.left, this.y + this.top, 100, 0, 2 * Math.PI);
        this.left -= 10;
        this.top -= 10;
        break;
      case 3:
        context.arc(this.x + this.right, this.y + this.bottom, 100, 0, 2 * Math.PI);
        this.right += 10;
        this.bottom += 10;
        break;
      case 4:
        context.arc(this.x + this.left, this.y + this.bottom, 100, 0, 2 * Math.PI);
        this.left -= 10;
        this.bottom += 10;
        break

    }
    context.stroke();
  }
  this.animate = this.animate.bind(this);
}