I've got a list of colors and I'd like to have a method that given a list of colors it can linearly interpolate across them with an evenly distributed stops per color, so for example if there's four colors: color one to two would interpolate from 0-0.25, color two to three from 0.25-0.5 and so on.
In my rudimentary example I'm currently using an approximation of the value of the sine to trigger the next color in the array but as can be expected the index gets called more than once, causing it to skip colors. Furthermore I can't find the formula that allows me to spread the colors values evenly so I can transition them all at once from the normalized value of the cycle.
I know CSS can easily transition colors and there's libraries that can do similar things but I'd like to know the math to do this and implement in Javascript using Canvas API without any third party libraries.
const rgbColors = [
[255, 0, 0],
[0, 255, 0],
[255, 0, 0],
[0, 255, 255]
];
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const lerp = (x, y, a) => x * (1 - a) + y * a;
let start = performance.now();
let currentIndex = 0;
function getColorLERP(colorA, colorB, progress) {
const r = Math.round(lerp(colorA[0], colorB[0], progress) * 10) / 10;
const g = Math.round(lerp(colorA[1], colorB[1], progress) * 10) / 10;
const b = Math.round(lerp(colorA[2], colorB[2], progress) * 10) / 10;
return [r, g, b];
}
const loop = (now) => {
window.requestAnimationFrame(loop);
const delta = Math.round(now - start);
const yoyoRate = delta * 0.0005;
const yoyo = Math.abs(Math.sin(yoyoRate));
const [r, g, b] = getColorLERP(
rgbColors[currentIndex],
rgbColors[(currentIndex + 1) % rgbColors.length],
yoyo
);
ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
ctx.fillRect(0, 0, 200, 200);
ctx.fillStyle = "#000";
if (yoyo > 0.9999) {
currentIndex++;
if (currentIndex > rgbColors.length - 1) {
currentIndex = 0;
}
}
};
loop();
<canvas width=200 height=200></canvas>
I'd just use CSS to do the math for me. You didn't mention any restrictions on technologies...
const colors = ['red', 'green', 'red', 'cyan'];
let colorIndex = 0;
setInterval(() => {
document.querySelector('.box').classList.remove(colors[colorIndex++ % 4]);
document.querySelector('.box').classList.add(colors[colorIndex % 4]);
}, 1000);
.red {
background-color: rgb(255,0,0);
}
.green {
background-color: rgb(0,255,0);
}
.cyan {
background-color: rgb(0,255,255);
}
.box {
transition: background-color 1000ms linear;
width: 200px;
height: 200px;
}
<div class="box red"></div>