Reputation: 949
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
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