Adding fill animation to svg pie chart
I want to animate a pie chart with dynamic and unknown value on load. Let's say I get the value as soon as possible and convert it to a rounded percentage:
var percentage = Math.round(sum * 100 / total);
Then I put my value:
<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 felt like I had to just mess around with the CSS rules .pie.animated
, but so far I haven't been able to animate to my dynamic value, only a full circle.
Basically, if my value is 42%, I try to grow my circle to 42% SVG. But the problem is that I cannot give a dynamic value to my CSS animation. I might need to use inline CSS, but I'm not sure if this is possible for keyframe frames.
JSFiddle here
source to share
I played around with my JQuery part of your JSFiddle and this is what I ended up with.
<div class="pie">60%</div>
<div class="pie">90%</div>
<div class="pie">12%</div>
The idea is simple. I am using a javascript interval timer to call the counting 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();
source to share