Search code examples
javascriptanimationscrollcounterviewport

How can I stop the counter animation?


Hello I'm trying to start a counter animation when the class is in the viewport, but this continue make the counter animation each time that I scrolling

How can I stop the animation?, just need this counter one time when I scroll until the section that have the numbers counter

thanks

https://codesandbox.io/s/k51wlj7xx7

function linear(duration, range, current) {
  return ((duration * 2) / Math.pow(range, 2)) * current;
}

//counter animation
//Linear easing
function linear(duration, range, current) {
  return ((duration * 2) / Math.pow(range, 2)) * current;
}


function animateValue(id, start, duration, easing) {
  var end = parseInt(document.getElementById(id).textContent, 10);
  var range = end - start;
  var current = start;
  var increment = end > start ? 1 : -1;
  var obj = document.getElementById(id);
  var startTime = new Date();

  var step = function() {
    current += increment;
    obj.innerHTML = current;

    if (current !== end) {
      setTimeout(step, easing(duration, range, current));
    } else {
      console.log("Easing: ", easing);
      console.log("Elapsed time: ", new Date() - startTime);
      console.log("");
    }
  };

  setTimeout(step, easing(duration, range, start));
}

const counterViewport = function() {
  let elems;
  let windowHeight;
  function init() {
    elems = document.querySelectorAll(".numbers-stats");
    windowHeight = window.innerHeight;
    addEventHandlers();
    checkPosition();
  }
  function addEventHandlers() {
    window.addEventListener("scroll", checkPosition);
    window.addEventListener("resize", init);
  }
  function checkPosition() {
    for (var i = 0; i < elems.length; i++) {
      var positionFromTop = elems[i].getBoundingClientRect().top;
      if (positionFromTop - windowHeight <= 0) {
        animateValue("counterNumberFiba", 0, 2000, linear);
        animateValue("counterNumberFiba2", 0, 1400, linear);
        animateValue("counterNumberFiba3", 0, 700, linear);
      }
    }
  }
  return {
    init: init
  };
};
counterViewport().init();

Solution

  • After your counter has run once, you just need to call another function which will remove your Event listeners. below is the updated code:

    <html>
    <body>
    <section>
        <div class="content-max-width our-solution flex flex-wrap padding-mobile justify-between">
    
    
            <div class="w-full md:w-6c md:pt-4 ">
                <h4>Our Solution</h4>
                <p>
                    Genius Sports’ partnership with FIBA began back in 2004 with the development of FIBA Organizer,
                    a digital system for the management of any basketball competition format.
                </p>
                <p>
                    After four years of successful cooperation, FIBA requested the development of a tool that would enable it to
                    centralise its data through the real-time collection of statistics. Genius Sports subsequently launched FIBA
                    LiveStats, giving leagues
                    and federations of all sizes an official data feed that could underpin their relationships with fans, commercial
                    partners and coaches.
                </p>
            </div>
        </div>
    </section>
    <section>
        <div class="content-max-width our-solution flex flex-wrap padding-mobile justify-between">
    
    
            <div class="w-full md:w-6c md:pt-4 ">
                <h4>Our Solution</h4>
                <p>
                    Genius Sports’ partnership with FIBA began back in 2004 with the development of FIBA Organizer,
                    a digital system for the management of any basketball competition format.
                </p>
                <p>
                    After four years of successful cooperation, FIBA requested the development of a tool that would enable it to
                    centralise its data through the real-time collection of statistics. Genius Sports subsequently launched FIBA
                    LiveStats, giving leagues
                    and federations of all sizes an official data feed that could underpin their relationships with fans, commercial
                    partners and coaches.
                </p>
            </div>
        </div>
    </section>
    <section>
        <div class="content-max-width our-solution flex flex-wrap padding-mobile justify-between">
    
    
            <div class="w-full md:w-6c md:pt-4 ">
                <h4>Our Solution</h4>
                <p>
                    Genius Sports’ partnership with FIBA began back in 2004 with the development of FIBA Organizer,
                    a digital system for the management of any basketball competition format.
                </p>
                <p>
                    After four years of successful cooperation, FIBA requested the development of a tool that would enable it to
                    centralise its data through the real-time collection of statistics. Genius Sports subsequently launched FIBA
                    LiveStats, giving leagues
                    and federations of all sizes an official data feed that could underpin their relationships with fans, commercial
                    partners and coaches.
                </p>
            </div>
        </div>
    </section>
    <div class="numbers-stats">
        <div class="content-max-width mx-auto mt-4 flex flex-wrap justify-between">
            <div class="w-6c md:w-full">
                <h2 class="counter-number" id="counterNumberFiba">80</h2><span class="million-text">+</span>
                <h5>MATCHES PER YEAR POWERED BY FIBA LIVESTATS</h5>
            </div>
            <div class="w-6c md:w-full">
                <h2 class="counter-number" id="counterNumberFiba2">25</h2><span class="million-text">m+</span>
                <h5>BASKETBALL FANS GLOBALLY USINHG LIVESTATS' GAMECENTRES</h5>
            </div>
            <div class="w-6c mt-2 md:w-full">
                <h2 class="counter-number" id="counterNumberFiba3">200</h2><span class="million-text">+</span>
                <h5>LEAGUES AND FEDERATIONS BENEFITTING FROM THIS LANDMARK PARTNERSHIP</h5>
            </div>
        </div>
    </div>
    <style>
    .numbers-stats {
      h2.counter-number, .million-text {
        font-size: 5rem;
        color: $GREEN;
        font-weight: 300;
        display: inline;
    
        @screen md {
          font-size: 9.1rem;
        }
      }
    
      h5 {
        color: $TEXT-GRAY;
        text-transform: uppercase;
      }
    }
    </style>
    <script>
    //counter animation
    //Linear easing
    function linear(duration, range, current) {
      return ((duration * 2) / Math.pow(range, 2)) * current;
    }
    
    //Quadratic easing
    function animateValue(id, start, duration, easing) {
      var end = parseInt(document.getElementById(id).textContent, 10);
      var range = end - start;
      var current = start;
      var increment = end > start ? 1 : -1;
      var obj = document.getElementById(id);
      var startTime = new Date();
    
      var step = function() {
        current += increment;
        obj.innerHTML = current;
    
        if (current !== end) {
          setTimeout(step, easing(duration, range, current));
        } else {
          console.log("Easing: ", easing);
          console.log("Elapsed time: ", new Date() - startTime);
          console.log("");
        }
      };
    
      setTimeout(step, easing(duration, range, start));
    }
    
    const counterViewport = function() {
      let elems;
      let windowHeight;
      function init() {
        elems = document.querySelectorAll(".numbers-stats");
        windowHeight = window.innerHeight;
        addEventHandlers();
        checkPosition();
      }
      function addEventHandlers() {
        window.addEventListener("scroll", checkPosition);
        window.addEventListener("resize", init);
      }
      function checkPosition() {
        for (var i = 0; i < elems.length; i++) {
          var positionFromTop = elems[i].getBoundingClientRect().top;
          if (positionFromTop - windowHeight <= 0) {
            animateValue("counterNumberFiba", 0, 2000, linear);
            animateValue("counterNumberFiba2", 0, 1400, linear);
            animateValue("counterNumberFiba3", 0, 700, linear);
            removeHandlers();
          }
        }
      }
      function removeHandlers(){
        window.removeEventListener("scroll", checkPosition);
        window.removeEventListener("resize", init);
    
    }
    
      return {
        init: init
      };
    };
    counterViewport().init();
    
    </script>
    </body>
    </html>
    

    Hope this is what you're looking for.