0

I want to animate a pie chart with a dynamic and unknown value on load. Let's say I retrieve the value asap and transform it in a rounded percentage :

var percentage = Math.round(sum * 100 / total);

Then I put my value there :

<div class="pie animated" id="pie-get-percentage"></div>

$('#pie-get-percentage').html(percentage);

SVG

$(document).ready(function() {
    $('#pie-get-percentage').html(percentage);

    function $$(selector, context) {
        context = context || document;
        var elements = context.querySelectorAll(selector);
        return Array.prototype.slice.call(elements);
    }

    $$('.pie').forEach(function(pie) {
        var p = parseFloat(pie.textContent);
        var NS = "http://www.w3.org/2000/svg";
        var svg = document.createElementNS(NS, "svg");
        var circle = document.createElementNS(NS, "circle");
        var title = document.createElementNS(NS, "title");

        circle.setAttribute("r", 16);
        circle.setAttribute("cx", 16);
        circle.setAttribute("cy", 16);
        circle.setAttribute("stroke-dasharray", p + " 100");

        svg.setAttribute("viewBox", "0 0 32 32");
        title.textContent = pie.textContent;
        pie.textContent = '';
        svg.appendChild(title);
        svg.appendChild(circle);
        pie.appendChild(svg);
    });

});

CSS

.pie-wrapper {
    .pie {
        width: 100px;
        height: 100px;
        display: inline-block;
        margin: 10px;
        transform: rotate(-90deg);
    }
    svg {
        background: $primary;
        border-radius: 50%;
    }
    circle {
        fill: $primary;
        stroke: $secondary;
        stroke-width: 32;
    }
    @keyframes grow {
        to {
            stroke-dasharray: 100 100
        }
    }
    .pie.animated {
        animation: grow 2s linear;
    }
}

As you can see I thought I had to simply fiddle with the .pie.animated CSS rules but up to now I've been unable to animate up to my dynamic value, only the full circle.

Basically if my value is 42% I'm trying to grow my circle to 42% of the SVG. But the problem is I can't really give a dynamic value to my CSS animation. Perhaps I might need to use inline CSS but I'm not sure it's possible for animation key frames.

The JSFiddle is here

Moslem Ben Dhaou
  • 6,897
  • 8
  • 62
  • 93
Antonin Cezard
  • 2,011
  • 1
  • 17
  • 30

1 Answers1

2

I played with your JQuery part of your JSFiddle, and this is what I ended up.

<div class="pie">60%</div>

<div class="pie">90%</div>

<div class="pie">12%</div>

The idea is simple. I use a javascript interval timer to call the count timer every time. I also added some max-val, inc-val and other related variable to make it work.

function $$(selector, context) {
    context = context || document;
    var elements = context.querySelectorAll(selector);
    return Array.prototype.slice.call(elements);
} 

function count(){
    var isUsed = false;
 $$('.pie').forEach(function(pie) {
    var p = parseFloat(pie.textContent);

    if(pie.maxValue == null){
         pie.maxValue = p;
         pie.incValue = p / 100.0;
         pie.lastValue = 0;
    }
    else
        pie.lastValue = pie.lastValue + pie.incValue;

   if(pie.lastValue <= pie.maxValue){
        var NS = "http://www.w3.org/2000/svg";
        var svg = document.createElementNS(NS, "svg");
        var circle = document.createElementNS(NS, "circle");
        var title = document.createElementNS(NS, "title");

        circle.setAttribute("r", 16);
        circle.setAttribute("cx", 16);
        circle.setAttribute("cy", 16);
        circle.setAttribute("stroke-dasharray", pie.lastValue + " 100");

        svg.setAttribute("viewBox", "0 0 32 32");
        title.textContent = pie.textContent;
        pie.textContent = '';
        svg.appendChild(title);
        svg.appendChild(circle);
        pie.appendChild(svg);

       isUsed = true;
   }

});
    if(isUsed)
        window.setTimeout(function() {  count(); }, 30);
}

window.setTimeout(function() {  count(); }, 30);

count();
Soley
  • 1,716
  • 1
  • 19
  • 33
  • Perhaps someone else offer a better idea. – Soley Nov 12 '15 at 16:17
  • Please copy the jquery codes and html into your own jsfiddle to see the output. – Soley Nov 12 '15 at 16:18
  • thanks that's not bad at all, but there is a distinct "stuttering" on higher values. So I divided the count interval by 10. Is it ok for performance ? – Antonin Cezard Nov 12 '15 at 16:21
  • Yes, I changed that several time to come up with a smooth animation. All numbers are arbitrary :) One thing that you can improve is to use setTimeout instead of setInterval. That is because it will call the count() function, even if they rich to the max value. – Soley Nov 12 '15 at 16:26
  • let me see if I can change it and update the answer ;) – Soley Nov 12 '15 at 16:26
  • yes I think we should stop the function once the value has been reached – Antonin Cezard Nov 12 '15 at 16:27
  • I updated the code. Much better and smooth animation with the current setting. – Soley Nov 12 '15 at 16:31