javascriptjqueryjquery-waypointswaypoint

Waypoints counter counts up (then down) and doesn't execute script when div is in immediate view


I have a number ticker which counts up. For demo purposes, this is how the counter is meant to work. It counts up and then stops.

Now, I'm trying to get the ticker script to execute when the #ticker is in view. To do this, I'm using waypoints. However, I'm having the following issues:

  1. The script isn't executing as soon as the #ticker is in view. In fact, I have to scroll past it and then when I scroll up, it starts to count.
  2. The counter is counting up, hitting the end number and then counting down? I just want it count up and stop on the end number plus string (in this case being 16,000+).

Why is this happening?

Demo:

$(document).ready(function() {

  $('#ticker').waypoint(function() {
    $('.count').each(function() {
      const initial = $(this).text()
      const format = formatter(initial)
      $(this).prop('Counter', 0).animate({
        Counter: format.value
      }, {
        duration: 3000,
        easing: 'swing',
        step: function(now) {
          $(this).text(format.revert(Math.ceil(now)));
        }
      });
    });
  });

})

function formatter(str) {
  // const delimeter = '-'
  const char = 'x'
  const template = str.replace(/\d/g, char)
  const value = str.replace(/\D/g, '')

  function revert(val) {
    // need better solution
    const valStr = val.toString()
    let result = ''
    let index = 0
    for (let i = 0; i < template.length; i++) {
      const holder = template[i]
      if (holder === char) {
        result += valStr.slice(index, index + 1)
        index++
      } else {
        result += holder
      }
    }
    return result
  }
  return {
    template: template,
    value: value,
    revert: revert
  }
}
.gap{
  background: lightgrey;
  height: 600px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js"></script>

<div class="gap"></div>
<div id="ticker">
  <span class="count counter">16,000+</span>
</div>
<div class="gap"></div>


Solution

  • Waypoint plugin has an option offset which determines at which position should the handler be triggered, which is by default 0. This means that your handler will only be triggered when your element reaches the top edge of browser and it will be triggered everytime your element reaches top edge of the browser.

    This is whats happening in your case, you just need to pass offset to the Waypoint and it will be fixed.

    $(document).ready(function() {
      $('#ticker').waypoint({
        handler: function() {
          $('.count').each(function() {
            const initial = $(this).text()
            const format = formatter(initial)
            $(this).prop('Counter', 0).animate({
              Counter: format.value
            }, {
              duration: 3000,
              easing: 'swing',
              step: function(now) {
                $(this).text(format.revert(Math.ceil(now)));
              }
            });
          });
        },
        offset: '100%'
      });
    })
    
    function formatter(str) {
      // const delimeter = '-'
      const char = 'x'
      const template = str.replace(/\d/g, char)
      const value = str.replace(/\D/g, '')
    
      function revert(val) {
        // need better solution
        const valStr = val.toString()
        let result = ''
        let index = 0
        for (let i = 0; i < template.length; i++) {
          const holder = template[i]
          if (holder === char) {
            result += valStr.slice(index, index + 1)
            index++
          } else {
            result += holder
          }
        }
        return result
      }
      return {
        template: template,
        value: value,
        revert: revert
      }
    }
    .gap{
      background: lightgrey;
      height: 600px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js"></script>
    
    <div class="gap"></div>
    <div id="ticker">
      <span class="count counter">16,000+</span>
    </div>
    <div class="gap"></div>