Kanchon Gharami
Kanchon Gharami

Reputation: 949

Activate animation after scrolling beyond a specific point in document

I made a count-up counter animation with js, but the counter starts count-up animation when I refresh the page (does not matter where I am, or whether I can see it or not).

I want the counter to start working only when the counter div is in the viewpoint (when I scroll down and see it).

HTML

<div class="content bg-warning">
    <div class="row m-0 py-5 d-flex justify-content-center">
        <div class="counter" data-count="2200" style="color: white; font-size: 32px; font-weight: bold;">0</div>
    </div>
</div>

js

<script type="text/javascript">
    $('.counter').each(function() {
      var $this = $(this),
          countTo = $this.attr('data-count');
      
      $({ countNum: $this.text()}).animate({
        countNum: countTo
      },

      {
        duration: 8000,
        easing:'linear',
        step: function() {
          $this.text(Math.floor(this.countNum));
        },
        complete: function() {
          $this.text(this.countNum);
          //alert('finished');
        }

      });  

    });
</script>

How can I solve this?

Upvotes: 1

Views: 424

Answers (1)

cssyphus
cssyphus

Reputation: 40038

Use $(window).scroll() to monitor the current scroll position (fires once for each pixel scrolled)
Use $(window).scrollTop() to get the current scroll position*
Use $(element).offset() to get the .top and .left coords of the element*
Use $(window).height() to get the height of the viewport

* calculated from top of document

You want to calculate how far below the bottom of the viewport is the element you are scrolling to. That calculation (simplified) is:

element_position - viewport_height = distance below the fold

Important: Note that window.scroll() fires once for each pixel scrolled. This is great, but it can bog down your app. The usual solution is to implement a debouncer. See:

https://davidwalsh.name/javascript-debounce-function

Here is an example:

var st = $(window).scrollTop();
var fin = calcWhenDivInWindow();
var off = 20; //How far counter div must be above bottom of screen before count begins

$(window).scroll(function(){
    st = $(this).scrollTop();
    if (st > fin+off) doCount();
});

function doCount(){
    $('.counter').each(function() {
      var $this = $(this),
          countTo = $this.attr('data-count');

      $({ countNum: $this.text()}).animate({
        countNum: countTo
      },
      {
        duration: 8000,
        easing:'linear',
        step: function() {
          $this.text(Math.floor(this.countNum));
        },
        complete: function() {
          $this.text(this.countNum);
        }
      });  
    });
}
function calcWhenDivInWindow(){
    var tt = $('.content').offset().top;
    var th = $('.content').outerHeight();
    var ww = $(window).height();
    return tt+th-ww;
}
*{font-family:Arial;font-size:1.2rem;}

.stuff1{height:80vh;width:98vw;background:pink;}
.stuff2{height:50vh;width:98vw;background:lightblue;}
.stuff3{height:50vh;width:98vw;background:palegreen;}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/countUp.min.js">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>

<div class="stuff1">Stuff n Nonsense (scroll slowly...)</div>
<div class="stuff2">More Stuff n Nonsense</div>

<div class="content bg-warning">
    <div class="row m-0 py-5 d-flex justify-content-center">
        <div class="counter" data-count="2200" style="color: white; font-size: 32px; font-weight: bold;">0</div>
    </div>
</div>

<div class="stuff3"></div>

Upvotes: 1

Related Questions