15

I am trying to use the pie chart from Chart.js (http://www.chartjs.org/docs/#pieChart-exampleUsage). Everything works smooth, but the animation happens as soon as the page loads, but since the user has to scroll down to see the chart, they won't see the animation. Is there anyway I can make the animation to start only when scrolled to that position? Also if possible, is it possible to animate everytime when that chart becomes into view?

My code is as follows:

<canvas id="canvas" height="450" width="450"></canvas>
    <script>
        var pieData = [
                {
                    value: 30,
                    color:"#F38630"
                },
                {
                    value : 50,
                    color : "#E0E4CC"
                },
                {
                    value : 100,
                    color : "#69D2E7"
                }

            ];

    var myPie = new Chart(document.getElementById("canvas").getContext("2d")).Pie(pieData);

    </script>
Suthan Bala
  • 3,209
  • 5
  • 34
  • 59

6 Answers6

18

You can combine the check for whether something is viewable with a flag to keep track of whether the graph has been drawn since it appeared in the viewport (though doing this with the plugin bitiou posted would be simpler):

http://jsfiddle.net/TSmDV/

var inView = false;

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemTop <= docViewBottom) && (elemBottom >= docViewTop));
}

$(window).scroll(function() {
    if (isScrolledIntoView('#canvas')) {
        if (inView) { return; }
        inView = true;
        new Chart(document.getElementById("canvas").getContext("2d")).Pie(data);
    } else {
        inView = false;  
    }
});
Jason P
  • 26,984
  • 3
  • 31
  • 45
  • In your jsfiddle example, everytime I scroll off and scroll back to the element, it gets bigger and bigger. And this doesn't work with Radar Chart. – Yannis Dran Mar 02 '14 at 18:05
  • If you have several canvas on your website, it would be better to pass a class name instead of an ID. – Avatar Sep 26 '22 at 15:06
4

Best to use deferred plugin

https://chartjs-plugin-deferred.netlify.com/

<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-deferred@1"></script>

new Chart(ctx, {
  // ... data ...
  options: {
    // ... other options ...
    plugins: {
      deferred: {
        xOffset: 150,   // defer until 150px of the canvas width are inside the viewport
        yOffset: '50%', // defer until 50% of the canvas height are inside the viewport
        delay: 500      // delay of 500 ms after the canvas is considered inside the viewport
      }
    }
  }
});
sierra.charli3
  • 205
  • 2
  • 22
2

Using IntersectionObserver is the more modern approach, and gives you the ability to choose how much of the element must be visible before triggering an event.

A threshold of 0 means it will trigger if any part of the element is visible, while a threshold of 1 means the entire element must be visible.

It performs better than listening to scroll, and will only fire once when the element transitions from hidden to visible, even while you are continuously scrolling. And it also works if the page content changes due to other events, such as other content being hidden/shown, or window resize, etc.

This is how I made a radial chart that animates every time at least 20% of it appears into view:

const options = {
    series: [75],
    chart: {
        type: 'radialBar',
    },
};
const chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();

const observer = new IntersectionObserver(function(entries) {
    if (entries[0].isIntersecting === true) {
        chart.updateSeries([0], false); // reset data to 0, then
        chart.updateSeries([75], true); // set original data and animate
        // you can disconnect the observer if you only want this to animate once
        // observer.disconnect();
    }
}, { threshold: [0.2] });

observer.observe(document.querySelector("#chart"));
Paul
  • 86
  • 6
1

I don't know if you could do that, I had the same issue and resolved it without any plugin in this simple way, check out:

$(window).bind("scroll", function(){            
    $('.chartClass').each(function(i){ 
        var dougData = [
            {value: 100, color:"#6abd79"},
            {value: 20, color:"#e6e6e6"}
        ];
        var graphic = new Chart(document.getElementById("html-charts").getContext("2d")).Doughnut(dougData, options);
        $(window).unbind(i);
    });
});
Uri Agassi
  • 36,848
  • 14
  • 76
  • 93
1

I had the same problem with Chart.js and found a really great solution. There is a package on GitHub that is called ChartNew.js by FVANCOP. He expanded it and added several functions.

Look at the sample, the charts are drawn by scrolling down.

Responsible is the statement

dynamicDisplay : true
Holger
  • 11
  • 1
-1

This is what you want:

Check if element is visible after scrolling

Next time please check if there's already an answer ;)

Alternatively: jquery.appear

Community
  • 1
  • 1
bitoiu
  • 6,893
  • 5
  • 38
  • 60
  • Well it will work for the first time, and suppose the user scrolls down further and then coming back up, the animation wouldn't occur. – Suthan Bala Sep 12 '13 at 19:20
  • are you calling this on the scroll event? also, have you tried the jquery plugin, easier usage. – bitoiu Sep 12 '13 at 19:29