jape
jape

Reputation: 2901

Progressive background change - JavaScript

I would like to progressively change the background color 3 times.

For example, I want it to gradually go from blue to grey to purple. Currently, the background transitions as expected from blue to grey.

Trying to illustrate it:

= Blue
==
===
====
===== Grey
====
===
==
= Purple

Could someone please help me make it go from grey to purple after the first transition please?

$(document).ready(function(){
    var scroll_pos = 0;
    var animation_begin_pos = 0;
    var animation_mid_pos = 500;
    var animation_end_pos = 1000;
    var beginning_color = new $.Color( 'rgb(0,156,243)' );
    var middle_color = new $.Color( 'rgb(36,40,47)' );
    var ending_color = new $.Color( 'rgb(97,20,204)' );

    $(document).scroll(function() {
        scroll_pos = $(this).scrollTop(); 
        if( scroll_pos >= animation_begin_pos && scroll_pos < animation_mid_pos ) { 
            var percentScrolled = scroll_pos / ( animation_mid_pos - animation_begin_pos );
            var newRed = beginning_color.red() + ( ( middle_color.red() - beginning_color.red() ) * percentScrolled );
            var newGreen = beginning_color.green() + ( ( middle_color.green() - beginning_color.green() ) * percentScrolled );
            var newBlue = beginning_color.blue() + ( ( middle_color.blue() - beginning_color.blue() ) * percentScrolled );
            var newColor = new $.Color( newRed, newGreen, newBlue );
            $('body').animate({ backgroundColor: newColor }, 0);
            // messes up starting here
        } else if ( scroll_pos >= animation_mid_pos && scroll_pos <= animation_end_pos ) {
            scroll_ps = $(document).height() - $(this).scrollTop() - $(this).height();
            var percentScrolled = scroll_pos / ( animation_end_pos - animation_mid_pos );
            var newRed = middle_color.red() + ( ( ending_color.red() - middle_color.red() ) * percentScrolled );
            var newGreen = middle_color.green() + ( ( ending_color.green() - middle_color.green() ) * percentScrolled );
            var newBlue = middle_color.blue() + ( ( ending_color.blue() - middle_color.blue() ) * percentScrolled );
            var newColor = new $.Color( newRed, newGreen, newBlue );
            $('body').animate({ backgroundColor: newColor }, 0);
        } else if ( scroll_pos > animation_end_pos ) {
             $('body').animate({ backgroundColor: ending_color }, 0);
        } else if ( scroll_pos < animation_begin_pos ) {
             $('body').animate({ backgroundColor: beginning_color }, 0);
        } else { }
    });
});

Upvotes: 1

Views: 630

Answers (2)

Anthony Sherratt
Anthony Sherratt

Reputation: 475

Created a function so that it would work with any amount of listed colors as long as they have an ordered stop value between 0 and 1.

var colorList = [
    { 
        color: new $.Color('rgb(0,156,243)'),
        stop: 0 
    }, { 
        color: new $.Color('rgb(36,40,47)'),
        stop: 0.25
    }, { 
        color: new $.Color('rgb(97,20,204)'),
        stop: 0.5
    }, { 
        color: new $.Color('rgb(36,40,47)'),
        stop: 0.75
    }, { 
        color: new $.Color('rgb(0,156,243)'),
        stop: 1
    }
];

function getGradientColor(colorList, percent) 
{ 
    percent = 0 || percent;  

    if (colorList.length < 1)
    {
       return new $.Color();
    }

    for (var n = colorList.length - 1; n > 0; n--)
    {       
        if (percent >= colorList[n].stop) { break; }
    }

    if (n > colorList.length - 2)
    {
        n = colorList.length - 2;
        f = 1;
    }

    var f = Math.min((percent - colorList[n].stop) / (colorList[n+1].stop - colorList[n].stop), 1);

    var color1 = colorList[n].color;
    var color2 = colorList[n+1].color;

    return new $.Color(
        Math.floor(color1.red()*(1-f) + color2.red()*f),
        Math.floor(color1.green()*(1-f) + color2.green()*f),
        Math.floor(color1.blue()*(1-f) + color2.blue()*f)
    );
}

$(document).scroll(function() {
    var scrollPosition = $(this).scrollTop(); 
    var height =  $('.tall').outerHeight();
    var body_height = $(window).height();

    // Ensure no divide by 0
    var percent = (height > 0 ? scrollPosition / (height - body_height) : 0);

    $("body").css("background", getGradientColor(colorList, percent));
}).trigger("scroll");

https://jsfiddle.net/fse62fpd/

Upvotes: 1

gre_gor
gre_gor

Reputation: 6787

The easiest way would be, if you calculated the scroll position into a number in range from 0 to 1 and have your colors in a list.

With that you can then calculate which two colors to pick (colors[n] and colors[n+1]) and how much you need to mix them (color1*(1-f)+color2*f).

// list of colors
var colors = [
    new $.Color('rgb(0,156,243)'),
    new $.Color('rgb(36,40,47)'),
    new $.Color('rgb(97,20,204)')
];
$(document).scroll(function() {
    // calculate scroll position 0-1
    var scroll_pos = $(document).scrollTop();
    var height =  $(document).outerHeight();
    var body_height = $(window).height();
    var pos = scroll_pos/(height-body_height);

    // calculate which colors to pick and how much to mix them
    pos *= colors.length-1;

    var n = Math.floor(pos);
    var f = pos % 1;

    // prevent getting out of bounds color pick
    if (n > colors.length-2)
    {
        n = colors.length-2
        f = 1
    }

    // pick colors
    var color1 = colors[n]
    var color2 = colors[n+1];

    // mix the two colors
    var color = new $.Color(
          Math.floor(color1.red()*(1-f) + color2.red()*f),
          Math.floor(color1.green()*(1-f) + color2.green()*f),
          Math.floor(color1.blue()*(1-f) + color2.blue()*f)
    );

    // set the background color
    $("body").css("background", color);
});

jsFiddle

Upvotes: 1

Related Questions