Question

I found this great piece of code on jsfiddle for fading between two colors onScroll using jQuery and the Color plugin. What I would like to do is be able to fade three or more colors onScroll down the page. I have tried (failing miserably) to edit the code myself but am just too new to JS and jQuery. Help please?

$(document).ready(function(){

//** notice we are including jquery and the color plugin at 
//** http://code.jquery.com/color/jquery.color-2.1.0.js

var scroll_pos = 0;
var animation_begin_pos = 0; //where you want the animation to begin
var animation_end_pos = 1000; //where you want the animation to stop
var beginning_color = new $.Color( 'rgb(210,50,98)' ); //we can set this here, but it'd probably be better to get it from the CSS; for the example we're setting it here.
var ending_color = new $.Color( 'rgb(0,197,209)' ); ;//what color we want to use in the end
$(document).scroll(function() {
    scroll_pos = $(this).scrollTop();
    if(scroll_pos >= animation_begin_pos && scroll_pos <= animation_end_pos ) { 
       // console.log( 'scrolling and animating' );
        //we want to calculate the relevant transitional rgb value
        var percentScrolled = scroll_pos / ( animation_end_pos - animation_begin_pos );
        var newRed = beginning_color.red() + ( ( ending_color.red() - beginning_color.red() ) * percentScrolled );
        var newGreen = beginning_color.green() + ( ( ending_color.green() - beginning_color.green() ) * percentScrolled );
        var newBlue = beginning_color.blue() + ( ( ending_color.blue() - beginning_color.blue() ) * percentScrolled );
        var newColor = new $.Color( newRed, newGreen, newBlue );
        //console.log( newColor.red(), newColor.green(), newColor.blue() );
        $('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 { }
});

});

Here is the fiddle: http://jsfiddle.net/cgspicer/V4qh9/

Was it helpful?

Solution

Similar to Sterling's answer, my first attempt was to kind of insert another checkpoint for the third color. This process, as in Sterling's solution, begins to precipitate the necessity of sub-functions. See it here: http://jsfiddle.net/5uU6y/1/

A better and more complete solution, in which you can declare multiple colors, can be achieved by creating an array which stores your beginning, ending, and color values that you can check against when the window is scrolled.

Here's that solution ( see it in action here: http://codepen.io/cgspicer/pen/tomvq/ )

$(document).ready(function(){ 
/**
requires http://code.jquery.com/color/jquery.color-2.1.0.js
*/

var colorsNPoints = [
  { 'begin' : 0, 'end': 100, 'color': 'rgb(220,20,60)' },
  { 'begin' : 100, 'end': 110, 'color': 'rgb(0,0,0)' },
  { 'begin' : 110, 'end': 210, 'color': 'rgb(50,205,50)' },
  { 'begin' : 210, 'end': 310, 'color': 'rgb(255,215,0)' },
  { 'begin' : 310, 'end': 410, 'color': 'rgb(220,20,60)' },
  { 'begin' : 410, 'end': 420, 'color': 'rgb(0,0,0)' },
  { 'begin' : 420, 'end': 520, 'color': 'rgb(50,205,50)' },
  { 'begin' : 520, 'end': 620, 'color': 'rgb(255,215,0)' },
  { 'begin' : 620, 'end': 720, 'color': 'rgb(220,20,60)' },
  { 'begin' : 720, 'end': 730, 'color': 'rgb(0,0,0)' },
  { 'begin' : 730, 'end': 830, 'color': 'rgb(50,205,50)' },
  { 'begin' : 830, 'end': 930, 'color': 'rgb(255,215,0)' }
];

$(document).scroll(function() {
  var scrollPosition = $(this).scrollTop();
  var currentRange = checkRange( scrollPosition, colorsNPoints );

  if ( currentRange !== undefined ) {
    console.log( currentRange );
    var newColor = recalcColor( currentRange.prevColor, currentRange.nextColor, currentRange.progress );
    $('body').css({ backgroundColor: newColor }, 0);
  } else {
    // do nothing, we're not within any ranges
  }
});

// sub-functions
/**
* checks which, if any, of the scroll ranges the window is currently on
* returns an object containing necessary values
*/
function checkRange( yValue, rangesObj ) {
  // loop over the object containing our ranges
  for ( var i=0; i < rangesObj.length; i++ ) {
    var rangeToCheck = rangesObj[i];
    // check to see if we are within said range
    if ( yValue >= rangeToCheck.begin && yValue <= rangeToCheck.end ) {
      // set up a new object for refinement and return
      var currentRangeObj = {};

      currentRangeObj.prevColor = rangesObj[i-1] ? rangesObj[i-1].color : rangeToCheck.color; // store old color, falls back to range's color if no previous color exists
      currentRangeObj.nextColor = rangeToCheck.color; // store new color
      currentRangeObj.progress = calcPercentScrolled( rangeToCheck.begin, rangeToCheck.end, yValue ); //calculate the progress within the current range
      return currentRangeObj;
    } else {
    }
  }

}

/**
* calculates current percent scrolled
**/
function calcPercentScrolled( begin, end, current ) {
  return (current - begin) / ( end - begin );
}
/**
* calculates new color
**/
function recalcColor( begin, end, factor ) {

    var begin = $.Color( begin ),
        end = $.Color( end );
    var newRed = begin.red() + ( ( end.red() - begin.red() ) * factor );
    var newGreen = begin.green() + ( ( end.green() - begin.green() ) * factor );
    var newBlue = begin.blue() + ( ( end.blue() - begin.blue() ) * factor );
    return $.Color( newRed, newGreen, newBlue );
}
});

Hope this helps!

OTHER TIPS

Try this. It's the same idea as the original code with a couple of minor additions. You can try to do it for n colors using the same idea using an array of start positions, end positions, and starting colors if you want some practice with Javascript. (And a better implementation)

Fiddle

$(document).ready(function(){ 
    //** notice we are including jquery and the color plugin at 
    //** http://code.jquery.com/color/jquery.color-2.1.0.js
    var body_end = $(document).height() / ;
    var animation_begin_pos = 0; //where you want the animation to begin
    var animation_middle_pos = body_end / 3;
    var animation_end_pos = body_end / (3/2); //where you want the animation to stop

    var beginning_color = new $.Color( 'rgb(210,50,98)' ); //we can set this here, but it'd probably be better to get it from the CSS; for the example we're setting it here.
    var middle_color = new $.Color('rgb(255,0,0)');
    var ending_color = new $.Color( 'rgb(0,197,209)' ); ;//what color we want to use in the end
    /* */
    function getPercentScrolled(scroll_pos, beginning_pos, end_pos){
        return (scroll_pos - beginning_pos) / (end_pos - beginning_pos);
    }

    function getNewRGB(start_color, end_color, percentScrolled){
        var newRed = start_color.red() + ( ( end_color.red() - start_color.red() ) * percentScrolled );
        var newGreen = start_color.green() + ( ( end_color.green() - start_color.green() ) * percentScrolled );
        var newBlue = start_color.blue() + ( ( end_color.blue() - start_color.blue() ) * percentScrolled );        
        console.log(newRed, newGreen, newBlue);
        console.log(percentScrolled);
        newRed = ((newRed > 0.0) ? newRed : 0.0);
        newGreen = ((newGreen > 0.0) ? newGreen : 0.0);
        newBlue = ((newBlue > 0.0) ? newBlue : 0.0);

    return {red: newRed, green: newGreen, blue: newBlue};
    }
    $(document).scroll(function() {
        var scroll_pos = $(this).scrollTop(); 

        if(scroll_pos >= animation_begin_pos && scroll_pos <= animation_middle_pos ) { 
            //we want to calculate the relevant transitional rgb value
            var percentScrolled = getPercentScrolled(scroll_pos, animation_begin_pos, animation_end_pos);
        var updatedColor = getNewRGB(beginning_color, middle_color, percentScrolled);
            var newColor = new $.Color( updatedColor['red'], updatedColor['green'], updatedColor['blue'] );
            $('body').animate({ backgroundColor: newColor }, 0);
        }
        else if ( scroll_pos >= animation_middle_pos && scroll_pos < animation_end_pos) {
            percentScrolled = getPercentScrolled(scroll_pos, animation_middle_pos, animation_end_pos);
            updatedColor = getNewRGB(middle_color, ending_color, percentScrolled);
            newColor = new $.Color( updatedColor['red'], updatedColor['green'], updatedColor['blue'] );
            $('body').animate({ backgroundColor: newColor }, 0);
        }       
        else if ( scroll_pos > animation_middle_pos ) {
             $('body').animate({ backgroundColor: ending_color }, 0);
        } 
        else if ( scroll_pos < animation_begin_pos ) {
             $('body').animate({ backgroundColor: beginning_color }, 0);
        }
    });
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top