Trigger jQuery function only when in viewport?

Viewed 179

I have this simple jQuery Counter on my website. The only issue I face, that the counter starts or even has finished before you get to the section where the html code is embedded.

Any help is much appreciated!

<script> 
 var isInViewport = function(elem) {
 var distance = elem.getBoundingClientRect();
 return (distance.top >= 0 && distance.left >= 0 && distance.bottom <= (window.innerHeight || document.documentElement.clientHeight) && distance.right <= (window.innerWidth || document.documentElement.clientWidth));
}
// then in your code ..
 if(isInViewPort) {
 $.fn.jQuerySimpleCounter = function( options ) {
        var settings = $.extend({
            start:  0,
            end:    100,
            easing: 'swing',
            duration: 400,
            complete: ''
        }, options );

        var thisElement = $(this);

        $({count: settings.start}).animate({count: settings.end}, {
            duration: settings.duration,
            easing: settings.easing,
            step: function() {
                var mathCount = Math.ceil(this.count);
                thisElement.text(mathCount);
            },
            complete: settings.complete
        });
    };
$('#number1').jQuerySimpleCounter({end: 52,duration: 5000});
$('#number2').jQuerySimpleCounter({end: 35,duration: 3000});
$('#number3').jQuerySimpleCounter({end: 998,duration: 6000});
}</script>

1 Answers

There are multiple ways of doing this

Vanilla JS: https://gomakethings.com/how-to-test-if-an-element-is-in-the-viewport-with-vanilla-javascript/ jQuery plugin: https://github.com/zeusdeux/isInViewport

Updated Vanilla version as pseudoCode for directional purposes - Can be optimized tremendously.

 var isInViewport = function(elem) {
 var distance = elem.getBoundingClientRect();
 return (distance.top >= 0 && distance.left >= 0 && distance.bottom <= (window.innerHeight || document.documentElement.clientHeight) && distance.right <= (window.innerWidth || document.documentElement.clientWidth));
}



 $.fn.jQuerySimpleCounter = function( options ) {
        var settings = $.extend({
            start:  0,
            end:    100,
            easing: 'swing',
            duration: 400,
            complete: ''
        }, options );

        var thisElement = $(this);

        $({count: settings.start}).animate({count: settings.end}, {
            duration: settings.duration,
            easing: settings.easing,
            step: function() {
                var mathCount = Math.ceil(this.count);
                thisElement.text(mathCount);
            },
            complete: settings.complete
        });
 }

        
 function startCounters() { 
 if(isInViewport($('#number1').get(0))) $('#number1').jQuerySimpleCounter({end: 52,duration: 5000});
 if(isInViewport($('#number2').get(0))) $('#number2').jQuerySimpleCounter({end: 52,duration: 5000});
 if(isInViewport($('#number3').get(0))) $('#number3').jQuerySimpleCounter({end: 52,duration: 5000});
}
$(document).ready(function(){
    startCounters() 
})
$(window).on("scroll",function(){
startCounters()
})

You can improve it with the following updates 1.Instead of the selectors #number1, #number2 etc. just use a class so your code is cleaner, imagine a future of #number99. 2. Should the counter stall at where it was last left or reset?

Related