Search code examples
javascriptjqueryparallax

Counting continusly with scroll, speed varies


My boss asked me to mimic this site:

http://mailchimp.com/2013/#by-the-numbers

I've been able to figure out every piece except for the white numbers. The really cool (but tricky) effect is that the speed of the count accelerates/decelerates depending on the data-count attribute, even though the distance between sections is the same.

It looks like they used waypoints.js to differentiate between sections. I searched for a plug-in that would adjust speed depending on the data inputs, but I could only find ones like countTo.js which trigger then count, rather than continuously count up and down as the user scrolls.

Any help would be greatly appreciated!


Solution

  • This intrigued me, so I gave it a shot.

    As far as I know, waypoints.js only fires when an element hits the edge of the viewport. I don't think you could use it for this kind of thing, because you need to continually update your counter. So I wrote this without any jQuery plugin.

    Disclaimer: This code may or may not work for you, either way, please regard it as nothing more than a sketch of a solution, it still needs to be improved in several places to be used for a production site.

    var current = $('.step').first();
    
    $('.step').each(function() {
      var start = $(this).data('count'),
        end = $(this).next().data('count'),
        height = $(this).height(),
        offset = $(this).offset().top,
        increment = end ? height / (end - start) : 0; //after how many pixels of scrolling do we need to incremwent our counter? Set to 0 for last element, just in case
    
      // just adding the count as text, so it gets displayed
      $(this).text(start);
    
      //store increment and offset, we need those in our scrollListener
      $(this).data({
        increment: increment,
        offset: offset
      });
    });
    
    $(document).on('scroll', function() {
      var scrollpos = $(window).scrollTop(),
        elementscrollpos,
        counter;
    
      //check if scrolled to the next element
      if (current.next().data('offset') < scrollpos) {
        current = current.next();
      } else if (current.data('offset') > scrollpos) {
        current = current.prev();
      }
    
      //calculate the current counter value;
      elementscrollpos = scrollpos - current.data('offset');
      counter = Math.floor(current.data('count') + elementscrollpos / current.data('increment'));
    
      $('.counter').text(counter);
    });
    body {
      margin: 0;
    }
    .counter {
      position: fixed;
      top: 0;
      left: 0;
    }
    .step {
      height: 100vh;
      text-align: center;
      font-size: 40px;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    
    <div class="counter"></div>
    <div class="step" data-count="0"></div>
    <div class="step" data-count="1"></div>
    <div class="step" data-count="2"></div>
    <div class="step" data-count="8"></div>
    <div class="step" data-count="100"></div>
    <div class="step" data-count="110240"></div>
    <div class="step" data-count="110250"></div>