akinuri akinuri - 7 months ago 38
HTML Question

Continuous Color Transition

I'm trying to create an infinite color transition. Changing an element's background continuously and make a smooth transition between the colors.

I couldn't figure out how to write the

shift
function. Checking all r, g, b values and matching the current color to the next color...

Can anyone help me on this? Or let me know if there's a better approach to it than this?

function switchColor(id) {
var elm = document.getElementById(id);

// getting elm's current rgb values
var elmColor = window.getComputedStyle(elm).getPropertyValue("background");
var startIndex = elmColor.indexOf("(");
var finishIndex = elmColor.indexOf(")");
var elmRGB = elmColor.substring(startIndex + 1, finishIndex);
var currentColor = elmRGB.split(",");
for (var i = 0; i<3; i++) { currentColor[i] = currentColor[i].trim(); }

// generating a random color => [r, g, ,b]
var nextColor = [];
for (var i = 0; i < 3; i++) {
nextColor[i] = Math.floor(Math.random()*250);
}

// function to convert rgb array to hex color => [r, g, b] = #rgb
function rgbToHex(clr) {
var rgb = clr;
var hex;
var hex1 = rgb[0].toString(16);
var hex2 = rgb[1].toString(16);
var hex3 = rgb[2].toString(16);
if (hex1.length < 2) { hex1 = "0" + hex1; }
if (hex2.length < 2) { hex2 = "0" + hex2; }
if (hex3.length < 2) { hex3 = "0" + hex3; }
return hex = "#" + hex1 + hex2 + hex3;
}

// checking if nextColor rgb values are greater than current rgb's
// so we can increase or decrease for smooth transition
var status = [];
for (var i = 0; i < 3; i++) {
if (nextColor[i] > currentColor[i]) { status.push(1); }
else { status.push(0); }
}

// this isn't part of the code, just testing
elm.style.background = rgbToHex(nextColor);

function shift() {
// shift between colors
// modify currentColor's rgb values and apply it to the elm
// elm.style.background = rgbToHex(currentColor);
}
var handler = setInterval(shift, 100);
}
setInterval(function() { switchColor("sandbox"); }, 2000);


FIDDLE

Answer

JSFiddle

/* ==================== Required Functions ==================== */
function getElementBG(elm) {
    var bg  = getComputedStyle(elm).backgroundColor;
        bg  = bg.match(/\((.*)\)/)[1];
        bg  = bg.split(",");
    for (var i = 0; i < bg.length; i++) {
        bg[i] = parseInt(bg[i], 10);
    }
    if (bg.length > 3) { bg.pop(); }
    return bg;
}

function generateRGB(min, max) {
    var min     = min || 0;
    var max     = max || 255;
    var color   = [];
    for (var i = 0; i < 3; i++) {
        var num = Math.floor(Math.random() * max);
        while (num < min) {
            num = Math.floor(Math.random() * max);
        }
        color.push(num);
    }
    return color;
}

function calculateDistance(colorArray1, colorArray2) {
    var distance = [];
    for (var i = 0; i < colorArray1.length; i++) {
        distance.push(Math.abs(colorArray1[i] - colorArray2[i]));
    }
    return distance;
}

function calculateIncrement(distanceArray, fps, duration) {
    var fps         = fps || 30;
    var duration    = duration || 1;
    var increment   = [];
    for (var i = 0; i < distanceArray.length; i++) {
        increment.push(Math.abs(Math.floor(distanceArray[i] / (fps * duration))));
        if (increment[i] == 0) {
            increment[i]++;
        }
    }
    return increment;
}

function rgb2hex(colorArray) {
    var hex = [];
    for (var i = 0; i < colorArray.length; i++) {
        hex.push(colorArray[i].toString(16));
        if (hex[i].length < 2) { hex[i] = "0" + hex[i]; }
    }
    return "#" + hex.join("");
}

/* ==================== Setup ==================== */
var fps             = 30;
var duration        = 3;
var transElement    = document.body;
var currentColor    = getElementBG(transElement);

var targetColor     = generateRGB();
var distance        = calculateDistance(currentColor, targetColor);
var increment       = calculateIncrement(distance, fps, duration);

var intervalHandler = null;

startTransition();

/* ==================== Transition Initiator ==================== */
function startTransition() {
    clearInterval(intervalHandler);

    targetColor = generateRGB();
    distance    = calculateDistance(currentColor, targetColor);
    increment   = calculateIncrement(distance, fps, duration);

    intervalHandler = setInterval(function() {
        transition();
    }, 1000/fps);
}

/* ==================== Transition Calculator ==================== */
function transition() {
    // checking R
    if (currentColor[0] > targetColor[0]) {
        currentColor[0] -= increment[0];
        if (currentColor[0] <= targetColor[0]) {
            increment[0] = 0;
        }
    } else {
        currentColor[0] += increment[0];
        if (currentColor[0] >= targetColor[0]) {
            increment[0] = 0;
        }
    }

    // checking G
    if (currentColor[1] > targetColor[1]) {
        currentColor[1] -= increment[1];
        if (currentColor[1] <= targetColor[1]) {
            increment[1] = 0;
        }
    } else {
        currentColor[1] += increment[1];
        if (currentColor[1] >= targetColor[1]) {
            increment[1] = 0;
        }
    }

    // checking B
    if (currentColor[2] > targetColor[2]) {
        currentColor[2] -= increment[2];
        if (currentColor[2] <= targetColor[2]) {
            increment[2] = 0;
        }
    } else {
        currentColor[2] += increment[2];
        if (currentColor[2] >= targetColor[2]) {
            increment[2] = 0;
        }
    }

    // apply the new modified color
    transElement.style.backgroundColor = rgb2hex(currentColor);

    // transition ended. start a new one
    if (increment[0] == 0 && increment[1] == 0 && increment[2] == 0) {
        startTransition();
    }
}