JSFiddle - React, Tailwind, and code Playground

by Christian Sonne

HTML

<script src="https://www.dropbox.com/s/g2c6cc6ffftrtyu/color.js?dl=1"></script>
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></div>
<input type="button" value="Done!" id="done">

CSS

div {
    display: inline-block;
}

JavaScript

function Indicator(parent, type) {
	this.parent = parent;
	this.type = type;
	this.scope = {};
	this.__done = false;
	this.draw = this.draw.bind(this);
	this.canvas = document.createElement("canvas");
	this.canvas.height = "200";
	this.canvas.width = "200";
	this.parent.appendChild(this.canvas);
	this.ctx = this.canvas.getContext("2d");
	window.requestAnimationFrame(this.draw);
	this.gradient = document.createElement("canvas");
	this.gradient.height = 1;
	this.gradient.width = 1000;
	this.gradientctx = this.gradient.getContext("2d");
	var gradient = this.gradientctx.createLinearGradient(0,0,this.gradient.width,0);
	this.colors = ["green", "yellow", "orange", "purple", "blue"];
	for (var i=0; i<=this.colors.length; i++) { // add first color both first and last to get smooth transition
		gradient.addColorStop(i/(this.colors.length), this.colors[i%this.colors.length]);
	}
	this.gradientctx.fillStyle = gradient;
	this.gradientctx.fillRect(0, 0, this.gradient.width, this.gradient.height);
}

Indicator.prototype = {
	time2rgb: function(time) {
		var color = this.gradientctx.getImageData(time%this.gradient.width, 0, 1, 1).data;
		return "rgb("+color[0]+","+color[1]+","+color[2]+")";
	},
	draw: function(timestamp) {
		this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
		var stillRunning = this.types[this.type].bind(this)(timestamp);
		if (stillRunning)
			window.requestAnimationFrame(this.draw);
	},
	types: {
		"triangle": function(timestamp) {
			var position = timestamp/200;
			var phase = -Math.PI/2;
			var size = 15;
			var normalDistance = 20;
			if (!("distance" in this.scope))
				this.scope.distance = normalDistance;
			if (this.__done)
				this.scope.distance = Math.max(0, this.scope.distance-2);
			var scale = 1.2;
			var scales = [];

			for (var i=0; i<3; i++) {
				var angle = (phase+position+i*2*Math.PI/3)%(2*Math.PI);
				if (angle < 2*Math.PI/3)
					scales[i] = 1+(scale-1)*(angle/(2*Math.PI/3));
				else if (angle <...