Search code examples
javascriptjqueryanimationviewport

How to Execute a chart Script until each chart is in viewport?


This thing is giving me headaches as I just can't find the way to do it. I downloaded a script which helped me make the charts with an animation (jquery.lineProgressbar.js).

The charts works pretty well, but the problem is the animation runs when the page is loaded. I want people to be able to see the animation of each chart. I have a lot of charts in the same page, and I need them all to execute the animation as they enter the viewport.

I know this question has been posted a lot of times, but none of them solves my problem.

I decided to make a Plunker example of my code so you can see better how it works. Here is my Plunker

I tried adding a code before the "Progressing" part in the jquery.lineProgressbar.js, to tell "apply the animation once the div called "progressbar" enter viewport:

$.fn.isOnScreen = function() {
    var win = $(window);
    var viewport = {
      top: win.scrollTop(),
      left: win.scrollLeft()
    };
    viewport.right = viewport.left + win.width();
    viewport.bottom = viewport.top + win.height();

    var bounds = this.offset();
    bounds.right = bounds.left + this.outerWidth();
    bounds.bottom = bounds.top + this.outerHeight();

    return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
};

if($('.progressbar').isOnScreen()) {
   // Progressing
   progressFill.animate(
     etc...
   )
}

...but this isn't working.
I hope someone can help me, thanks in advance!

CODE UPDATE:
I added the functional code, based on troyw1636 answer. Here the new plunker

function TestViewPort(elementID, chartPercentage){
var top_of_element = $("#" + elementID).offset().top;
var bottom_of_element = $("#" + elementID).offset().top + $("#element").outerHeight();
var bottom_of_screen = $(window).scrollTop() + $(window).innerHeight();
var top_of_screen = $(window).scrollTop();

  if ((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)){
    if (!$("#" + elementID).hasClass('on-view')) {
      $("#" + elementID).LineProgressbar({percentage:chartPercentage}).addClass('on-view');
    }
  } 
}

Solution

  • You're on the right track. I've used a different method for determining viewport visiblity, and have wrapped the progress bar call within that. I've also added the same calls within a $(window).scroll() event so that the viewport visibility for all divs is recalculated when the viewport changes.

    I've edited your Plunker: https://plnkr.co/edit/k5aop0cnP9uziTZwDY3Y?p=preview

    function TestViewPort(elementID, chartPercentage) {
        var top_of_element = $("#" + elementID).offset().top;
        var bottom_of_element = $("#" + elementID).offset().top + $("#element").outerHeight();
        var bottom_of_screen = $(window).scrollTop() + $(window).innerHeight();
        var top_of_screen = $(window).scrollTop();
    
        if ((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
            //div is visible so set up chart
            $("#" + elementID).LineProgressbar({
                percentage: chartPercentage
            });
        } else {
            // div not visible
        }
    } 
    

    As a next step, you'd likely want to determine which charts have already been initialised and stop the code within TestViewPort from re-initialising them after a scroll event.