Last active
August 16, 2017 12:03
-
-
Save souljorje/e6ce8dd955bd646314f0ecd258c431c1 to your computer and use it in GitHub Desktop.
d3 animated donut chart with labels
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: gpl-3.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.diagram { | |
font-family: sans-serif; | |
height: 355px; | |
max-width: 570px; | |
margin: 80px auto 0; | |
} | |
.diagram svg { | |
fill: transparent; | |
} | |
.diagram svg .label { | |
opacity: 0; | |
fill: #000b38; | |
font-size: 18px; | |
font-weight: 400; | |
-webkit-animation: diagram 0.5s; | |
animation: diagram 0.5s; | |
-webkit-animation-fill-mode: forwards; | |
animation-fill-mode: forwards; | |
} | |
.diagram svg .label:nth-child(1) { | |
-webkit-animation-delay: 0.15s; | |
animation-delay: 0.15s; | |
} | |
.diagram svg .label:nth-child(2) { | |
-webkit-animation-delay: 0.3s; | |
animation-delay: 0.3s; | |
} | |
.diagram svg .label:nth-child(3) { | |
-webkit-animation-delay: 0.45s; | |
animation-delay: 0.45s; | |
} | |
.diagram svg .label:nth-child(4) { | |
-webkit-animation-delay: 0.6s; | |
animation-delay: 0.6s; | |
} | |
.diagram svg .label:nth-child(5) { | |
-webkit-animation-delay: 0.75s; | |
animation-delay: 0.75s; | |
} | |
.diagram svg .label:nth-child(6) { | |
-webkit-animation-delay: 0.9s; | |
animation-delay: 0.9s; | |
} | |
.diagram svg .line { | |
opacity: 0; | |
fill: none; | |
stroke: #00547e; | |
stroke-width: 1px; | |
-webkit-animation: diagram 0.5s; | |
animation: diagram 0.5s; | |
-webkit-animation-fill-mode: forwards; | |
animation-fill-mode: forwards; | |
} | |
.diagram svg .line:nth-child(1) { | |
-webkit-animation-delay: 0.15s; | |
animation-delay: 0.15s; | |
} | |
.diagram svg .line:nth-child(2) { | |
-webkit-animation-delay: 0.3s; | |
animation-delay: 0.3s; | |
} | |
.diagram svg .line:nth-child(3) { | |
-webkit-animation-delay: 0.45s; | |
animation-delay: 0.45s; | |
} | |
.diagram svg .line:nth-child(4) { | |
-webkit-animation-delay: 0.6s; | |
animation-delay: 0.6s; | |
} | |
.diagram svg .line:nth-child(5) { | |
-webkit-animation-delay: 0.75s; | |
animation-delay: 0.75s; | |
} | |
.diagram svg .line:nth-child(6) { | |
-webkit-animation-delay: 0.9s; | |
animation-delay: 0.9s; | |
} | |
@-webkit-keyframes diagram { | |
0% { | |
opacity: 0; | |
-webkit-transform: translateY(-20px); | |
transform: translateY(-20px); | |
} | |
100% { | |
opacity: 1; | |
-webkit-transform: translateY(0); | |
transform: translateY(0); | |
} | |
@keyframes diagram { | |
0% { | |
opacity: 0; | |
-webkit-transform: translateY(-20px); | |
transform: translateY(-20px); | |
} | |
100% { | |
opacity: 1; | |
-webkit-transform: translateY(0); | |
transform: translateY(0); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Animated donut chart with labels D3 v4</title> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<link rel="stylesheet" href="index.css"> | |
<script src="index.js"></script> | |
</head> | |
<body> | |
<div class="diagram"></div> | |
<script> | |
var dataset = [ | |
{ label:'<tspan x="300" dy="-0.3em">Lorem</tspan><tspan x="300" dy="1.4em">impsum dolor – 52%.</tspan>', color: '#21b5ff', count: 52 }, | |
{ label:'<tspan x="300" dy="0.5em">Sit amet – 37%.</tspan>', color: '#59c8ff', count: 37 }, | |
{ label:'Consectetur adipiscing – 3%.', color: '#7ad3ff', count: 3 }, | |
{ label:'<tspan x="300" dy="-0.3em">Elit – 2%.</tspan>', color: '#9cdeff', count: 2 }, | |
{ label:'<tspan x="300" dy="-0.7em">Suspendisse finibus</tspan><tspan x="300" dy="1.4em">quis lorem – 4%.</tspan>', color: '#c4ebff', count: 4}, | |
{ label:'<tspan x="300" dy="0.3em">Suspendisse non – 2%.</tspan>', color: '#d4f1ff', count: 2} | |
]; | |
var svg = d3.select('.diagram').append('svg') | |
.attr("width", '100%') | |
.attr("height", '100%') | |
.attr('viewBox','0 -20 555 340') | |
.attr('preserveAspectRatio','xMinYMin') | |
.append("g") | |
var color = d3.scaleOrdinal() | |
.range(["#21b5ff", "#59c8ff", "#7ad3ff", "#9cdeff", "#c4ebff", "#d4f1ff"]); | |
var outerRadius = 120-65; | |
var innerRadius = 120; | |
svg.append('g').attr('class', 'slices').attr('transform', 'translate(120,120) rotate(180)'); | |
svg.append('g').attr('class', 'labels'); | |
svg.append('g').attr('class', 'lines').attr('transform', 'translate(120,120) rotate(180)'); | |
var arc = d3.arc() | |
.innerRadius(innerRadius) | |
.outerRadius(outerRadius); | |
var pie = d3.pie() | |
.value(function(d) { return d.count; }) | |
.sort(null); | |
var delaySpec = function(d, i) { | |
if (i==0) { return 0}; | |
if (i==1) { return 520}; | |
if (i==2) { return 890}; | |
if (i==3) { return 920}; | |
if (i==4) { return 940}; | |
if (i==5) { return 1000} | |
}; | |
var durationSpec = function(d) { | |
return d.data.count * 10 | |
}; | |
var path = svg.select('.slices') | |
.datum(dataset).selectAll('path') | |
.data(pie(dataset)) | |
.enter().append('path') | |
.attr('class', 'slice') | |
.attr('d', arc) | |
.transition().ease(d3.easeLinear).delay(delaySpec).duration(durationSpec) | |
.attrTween('d', function(d) { | |
var i = d3.interpolate(d.startAngle, d.endAngle); | |
return function(t) { | |
d.endAngle = i(t); | |
return arc(d); | |
} | |
}) | |
.attr('fill', function(d, i) { | |
return color(d.data.color); | |
}); | |
var text = svg.select(".labels").selectAll("text") | |
.data(pie(dataset)); | |
text.enter() | |
.append("text") | |
.attr("class", "label") | |
.html(function(d) { | |
return (d.data.label); | |
}) | |
.attr('x', 300) | |
.attr('y', function(d, i) { | |
return (i*58); | |
}); | |
var polyline = svg.select('.lines').selectAll('polyline') | |
.data(pie(dataset)) | |
.enter().append('polyline') | |
.attr ('class', 'line') | |
.attr('points', function(d, i) { | |
if (i==0) { | |
return '4,116 -162,116' | |
} | |
if (i==1) { | |
return '-81,59 -162,59' | |
} | |
if (i==2) { | |
return '-42,-60 -141,8 -162,8' | |
} | |
if (i==3) { | |
return '-37,-79 -139,-43 -162,-43' | |
} | |
if (i==4) { | |
return '-21,-86 -139,-106 -162,-106' | |
} | |
if (i==5) { | |
return '-5,-99 -140,-169 -162,-169' | |
} | |
}) | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://www.npmjs.com/package/innersvg-polyfill | |
/** | |
* innerHTML property for SVGElement | |
* Copyright(c) 2010, Jeff Schiller | |
* | |
* Licensed under the Apache License, Version 2 | |
* | |
* Works in a SVG document in Chrome 6+, Safari 5+, Firefox 4+ and IE9+. | |
* Works in a HTML5 document in Chrome 7+, Firefox 4+ and IE9+. | |
* Does not work in Opera since it doesn't support the SVGElement interface yet. | |
* | |
* I haven't decided on the best name for this property - thus the duplication. | |
*/ | |
(function() { | |
var serializeXML = function(node, output) { | |
var nodeType = node.nodeType; | |
if (nodeType == 3) { // TEXT nodes. | |
// Replace special XML characters with their entities. | |
output.push(node.textContent.replace(/&/, '&').replace(/</, '<').replace('>', '>')); | |
} else if (nodeType == 1) { // ELEMENT nodes. | |
// Serialize Element nodes. | |
output.push('<', node.tagName); | |
if (node.hasAttributes()) { | |
var attrMap = node.attributes; | |
for (var i = 0, len = attrMap.length; i < len; ++i) { | |
var attrNode = attrMap.item(i); | |
output.push(' ', attrNode.name, '=\'', attrNode.value, '\''); | |
} | |
} | |
if (node.hasChildNodes()) { | |
output.push('>'); | |
var childNodes = node.childNodes; | |
for (var i = 0, len = childNodes.length; i < len; ++i) { | |
serializeXML(childNodes.item(i), output); | |
} | |
output.push('</', node.tagName, '>'); | |
} else { | |
output.push('/>'); | |
} | |
} else if (nodeType == 8) { | |
// TODO(codedread): Replace special characters with XML entities? | |
output.push('<!--', node.nodeValue, '-->'); | |
} else { | |
// TODO: Handle CDATA nodes. | |
// TODO: Handle ENTITY nodes. | |
// TODO: Handle DOCUMENT nodes. | |
throw 'Error serializing XML. Unhandled node of type: ' + nodeType; | |
} | |
} | |
// The innerHTML DOM property for SVGElement. | |
Object.defineProperty(SVGElement.prototype, 'innerHTML', { | |
get: function() { | |
var output = []; | |
var childNode = this.firstChild; | |
while (childNode) { | |
serializeXML(childNode, output); | |
childNode = childNode.nextSibling; | |
} | |
return output.join(''); | |
}, | |
set: function(markupText) { | |
// Wipe out the current contents of the element. | |
while (this.firstChild) { | |
this.removeChild(this.firstChild); | |
} | |
try { | |
// Parse the markup into valid nodes. | |
var dXML = new DOMParser(); | |
dXML.async = false; | |
// Wrap the markup into a SVG node to ensure parsing works. | |
sXML = '<svg xmlns=\'http://www.w3.org/2000/svg\'>' + markupText + '</svg>'; | |
var svgDocElement = dXML.parseFromString(sXML, 'text/xml').documentElement; | |
// Now take each node, import it and append to this element. | |
var childNode = svgDocElement.firstChild; | |
while(childNode) { | |
this.appendChild(this.ownerDocument.importNode(childNode, true)); | |
childNode = childNode.nextSibling; | |
} | |
} catch(e) { | |
throw new Error('Error parsing XML string'); | |
}; | |
} | |
}); | |
// The innerSVG DOM property for SVGElement. | |
Object.defineProperty(SVGElement.prototype, 'innerSVG', { | |
get: function() { | |
return this.innerHTML; | |
}, | |
set: function(markupText) { | |
this.innerHTML = markupText; | |
} | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment