donut
by phloe
JavaScript
var donut = (function (doc) {
var doublePI = Math.PI * 2;
function create (size, thickness, data, spacing) {
var ns = "http://www.w3.org/2000/svg";
var sum = 0;
var offset = 0;
var outerRadius = size / 2;
var innerRadius = outerRadius - thickness;
data.forEach(function (d) {
sum += d.value;
});
spacing = spacing || 0;
var svg = doc.createElementNS(ns, "svg");
svg.setAttribute("width", size + "px");
svg.setAttribute("height", size + "px");
var path = doc.createElementNS(ns, "path");
data.forEach(function (d) {
var _path = path.cloneNode(true);
_path.setAttribute("d", wedge(outerRadius, innerRadius, d.value, sum, offset, spacing));
if (d.color) {
_path.setAttribute("fill", d.color);
}
svg.appendChild(_path);
offset += d.value;
});
return svg;
}
function wedge (or, ir, value, sum, offset, spacing) {
var op = [or, 0];
var ip = [or, or - ir];
var flip = 0;
// if wedge is larger than 180 degrees large-arc-flag needs to be flipped
if (value / sum > 0.5) {
flip = 1;
}
// calculate correct spacing offset for outer and inner edges
var os = 0;
var is = 0;
if (spacing) {
var s = spacing / 2;
os = (Math.asin(s / or) / doublePI) * sum;
is = (Math.asin(s / ir) / doublePI) * sum;
}
// concatenate path value
return [
"M", (offset || spacing) ? rotate(or, or, op, (offset + os) / sum) : op,
"A", or, or, 0, flip, 1, rotate(or, or, op, (value + offset - os) / sum),
"L", rotate(or, or, ip, (value + offset - is) / sum),
"A", ir, ir, 0, flip, 0, (offset || spacing) ? rotate(or, or, ip, (offset + is) / sum) : ip,
...