JSFiddle - React, Tailwind, and code Playground
by Jeremy Gillick
HTML
<form>
<p>
<label>From</label>
<input type="number" id="from-r" value="255" />
<input type="number" id="from-g" value="0" />
<input type="number" id="from-b" value="0" />
</p>
<p>
<label>To</label>
<input type="number" id="to-r" value="0" />
<input type="number" id="to-g" value="255" />
<input type="number" id="to-b" value="0" />
</p>
<p>
<label>Time</label>
<input type="number" id="time" value="1500" />
</p>
<p>
<button type="button">
Go
</button>
</p>
</form>
<div id="preview">
</div>
<ul id="frames">
</ul>
CSS
body {
font-family: helvetica neue;
}
label {
display: inline-block;
min-width: 3em;
text-align: right;
}
input[type=number] {
width: 4em;
}
#preview {
height: 100px;
width: 100px;
border: 1px solid #000;
margin: 15px auto;
}
#frames {
list-style-type: none;
margin: 15px;
padding: 0;
}
#frames li {
height: 10px;
width: 10px;
display: inline-block;
border: 1px solid #000;
}
JavaScript
/**
Fading a color using the current Disco Dance Controller fade algorithm, with exponential color shifting (vs linear).
*/
(function(){
var animateTimer;
var increments = [];
function fadeIncrements(fromColor, toColor, duration) {
increments = [0, 0, 0];
if (duration > 0) {
for (let i = 0; i < 3; i++) {
let diff = toColor[i] - fromColor[i];
if (diff != 0) {
increments[i] = diff / duration;
}
}
}
return increments;
}
function getNaturalColor(color) {
return Math.round(Math.exp(Math.log(255) * color / 255))
}
function getColorCSS(color) {
var cssColor = color.map( (c) => {
return getNaturalColor(c);
});
return 'rgb('+ cssColor.join(',') +')';
}
function colorTick(color, time) {
color = color.slice(0);
color = color.map( (c, i) => {
if (increments[i] == 0) return c;
return c + (increments[i] * time);
});
return color;
}
function buildFrames(from, to, duration) {
var currentColor = from.slice(0),
frameCount = 40,
perFrame = duration / 40,
frameList = $('#frames');
frameList.empty();
for (var i = 0; i < frameCount; i++) {
var li = document.createElement('li');
currentColor = colorTick(currentColor, perFrame);
li.style.backgroundColor = getColorCSS(currentColor);
frameList.append(li);
}
}
function animate(from, to, duration) {
var preview = $('#preview'),
lastFade = (new Date()).getTime(),
currentColor = from.slice(0),
targetColor = to.slice(0),
timeLeft = duration;
clearTimeout(animateTimer);
function run() {
let now = (new Date()).getTime(),
diff = now - lastFade;
if (diff > 1) {
timeLeft -= diff;
lastFade = now;
// Increment color
currentColor = colorTick(currentColor, diff);
// Done, reverse fade
if...