I've made a small js/css/html module which purpose is to fill a pie chart up to a given percentage. Basically it could be used for instance as a filling pie chart that keep tracks of the amount of donations for a non-profit organization.
Let's sum up briefly what it does. Basically I have two svg circles, the base color and the fill color. Javascript will get the fill circle and give it a stroke-dasharray that corresponds to the percentage value (based on the circle area). Basically the fill circle's stroke will animate up to a given value.
The main advantage is that my chart can be customized easily on those parameters : the base pie color, the filling color, the number color, the pie shadow (or its absence) and the dimension of the pie. Also, you can use as many pie charts as you want on a single page, each one only need a different id/class as you see fit.
The percentage to which the pie will fill is stocked in a html data-id. So it's very easy to use with something like PHP. Also, there is no need to write a single line in javascript, mostly everything is in the SCSS file (you still need to enter 2 values in the html for the svg circles dimensions).
The problem is I'm not that good at writing javascript so I'm pretty sure it could be more efficient. Also, the SCSS might be better, I'd like to know your opinion on that.
So if you want to review only the javascript or only the SCSS, that's very fine by me. Maybe even the whole concept of my module is flawed, if you want to comment on the big picture
Here is my codepen to see the pie chart in action and fiddle with the code
Here is the html
<figure id="pie" data-percentage="75" data-behavior="pie-chart">
<svg>
<!-- Radius has to be svg diameter divided by 4 -->
<!-- Cx and cy have to be svg diameter divided by 2 -->
<circle r="50" cx="100" cy="100"/>
<circle r="50" cx="100" cy="100"/>
</svg>
<div class="receiver"></div>
</figure>
Here is the SCSS, as you can see I tried my best to stay modular. It's made so you can create any number of pie charts
// Base styles for every pie chart
%pie-base {
position: relative;
display: inline-block;
margin: 0 auto;
vertical-align: middle;
border-radius: 50%;
svg {
display: block;
margin: 0 auto;
transform: rotate(-90deg);
shape-rendering: geometricPrecision;
}
circle {
shape-rendering: geometricPrecision;
}
// This is where the percentage is shown
.receiver {
position: absolute;
top: 0;
font-family: Helvetica;
font-size: 2rem;
text-align: center;
&:after {
content: '%';
}
}
}
// Custom styles for pie charts, 5 parameters are required
@mixin pie($base-color, $fill-color, $number-color, $shadow, $diameter) {
$easing: 2000ms cubic-bezier(0.215, 0.61, 0.355, 1);
$pi: 3.14159;
@extend %pie-base;
width: $diameter;
box-shadow: $shadow;
circle:nth-child(1) {
fill: $base-color;
stroke: $base-color;
stroke-width: $diameter / 2 - 0.5;
stroke-dasharray: ($pi * 2 * $diameter / 4) ($pi * 2 * $diameter / 4);
}
circle:nth-child(2) {
transition: stroke-dasharray $easing;
fill: $base-color;
stroke: $fill-color;
stroke-width: $diameter / 2;
stroke-dasharray: 0 ($pi * 2 * $diameter / 4);
}
svg {
width: $diameter + px;
height: $diameter + px;
}
.receiver {
width: $diameter + px;
height: $diameter + px;
line-height: $diameter + px;
color: $number-color;
}
}
// Declaring the pie parameters
$pie-param: (
'base-color': hsl(210, 40%, 50%),
'fill-color': hsl(90, 40%, 61%),
'number-color': hsl(0, 0%, 100%),
'shadow': 2px 2px 10px 0px rgba(0, 0, 0, 0.36),
'diameter': 200
);
// Calling the pie
#pie {
@include pie($pie-param...);
}
Now for the JS, as you can see it's made so any number of pie charts will be ok
'use strict';
/* global jQuery */
/**
* Animated pie chart
* @require jQuery v1.7+
* @require jQuery-numerator v0.2+
*/
(function($) {
// Custom easing
$.easing.jswing = $.easing.swing;
$.extend($.easing, {
easeOutCubic: function(x, t, b, c, d) {
return c * ((t = t / d - 1) * t * t + 1) + b;
}
});
// Numbering animation
function numerate(elem, value) {
$(elem).numerator({
easing: 'easeOutCubic',
duration: 2000,
delimiter: ' ',
rounding: 0,
toValue: value
});
};
// Main function
function makePieChart(elem) {
// Local variables
var percentage = $(elem).data('percentage');
var $filling = $('circle:nth-child(2)', elem);
var total = 2 * Math.PI * $(elem).width() / 4;
// Converting the percentage
function numberFixer(value) {
var result = ((value * total) / 100);
return result;
};
// Filling function
function setPieChart(value) {
var fixedNumber = numberFixer(value);
var result = fixedNumber + ' ' + total;
$filling.css('stroke-dasharray', result);
};
// Fill the chart to the given percentage
setPieChart(percentage);
// Animate the number to the given percentage
numerate($('.receiver', elem), percentage)
};
// Call animation on dom element(s)
$(document).ready(function() {
$('*[data-behavior="pie-chart"]').each(function(i) {
makePieChart($(this));
});
});
})(jQuery);