Adding a fill animation to a svg pie chart

2019-08-17 04:42发布

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

1条回答
做自己的国王
2楼-- · 2019-08-17 04:54

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();
查看更多
登录 后发表回答