Last active
March 5, 2018 19:15
-
-
Save timproDev/990395af116b4c650f577215d5340e61 to your computer and use it in GitHub Desktop.
Donut Chart with Radio Buttons
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
document.addEventListener("DOMContentLoaded", function(){ | |
// set global variables | |
var path = ''; | |
var dataFile = 'placeholder-dataset.csv'; | |
var dataFileTwo = 'placeholder-two.csv'; | |
var elemContainer = ['#donutChart', '#donutChartTwo']; | |
var uiEl = '.chart-ui-container input'; | |
var cssFile = 'donut-chart.css'; | |
var strNumHeaders = ['header_two_amount','header_three_amount']; // to convert to numbers | |
// instantiate constructor methods | |
var donutChart = new DonutChart({ | |
elem:document.querySelector(elemContainer[0]), | |
dataCount:'header_two_amount', | |
data: path + dataFile, | |
transSpeed:350 | |
}); | |
// instantiate constructor methods | |
var donutChartTwo = new DonutChart({ | |
elem:document.querySelector(elemContainer[1]), | |
dataCount:'header_two_amount', | |
data: path + dataFileTwo, | |
transSpeed:350 | |
}); | |
// fire chart and events | |
chartInit(donutChart, '#donutChart', dataFile); | |
chartInit(donutChartTwo, '#donutChartTwo', dataFileTwo); | |
styleLink(); | |
function chartInit(chartInst, elem, dataFile){ | |
d3.csv((path + dataFile), function(data) { | |
// convert defined header values to number | |
data.forEach(function(d) { | |
for (var i = 0; i < strNumHeaders.length; i++) { | |
d[strNumHeaders[i]] = +d[strNumHeaders[i]] || 0; | |
} | |
}); | |
chartInst.setData(data); | |
var inputs = document.querySelectorAll(elem + ' ' + uiEl); | |
for (var i = 0; i < inputs.length; i++) { | |
inputs[i].addEventListener('click', function(){ | |
var value = this.value; | |
chartInst.setDataCount(value); | |
}); | |
} | |
}); | |
} | |
// include resize event | |
d3.select(window).on('resize', function(){ | |
donutChart.resize(); | |
donutChartTwo.resize(); | |
}); | |
// inject custom chart css | |
function styleLink(){ | |
var linkElem = document.createElement('link'); | |
document.getElementsByTagName('head')[0].appendChild(linkElem); | |
linkElem.rel = 'stylesheet'; | |
linkElem.type = 'text/css'; | |
linkElem.href = (path + cssFile); | |
} | |
}); |
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
* { | |
font-family: arial, verdana, sans-serif; | |
color:#808080; | |
-webkit-font-smoothing: antialiased; | |
-moz-osx-font-smoothing: grayscale; | |
} | |
line { | |
shape-rendering: crispEdges; | |
} | |
.tooltip { | |
box-shadow: 0 2px 4px 0px rgba(0, 0, 0, 0.5); | |
border-radius: 2px; | |
background-color: #fff; | |
top: -1000px; | |
position: fixed; | |
padding: .65rem; | |
pointer-events: none; | |
max-width: 25%; | |
z-index: 500; | |
} | |
.tooltip-info { | |
padding: 0; | |
margin: 0; | |
display: block; | |
width: 100%; | |
} | |
.tooltip-hidden { | |
opacity: 0; | |
transition: all .3s; | |
transition-delay: .1s; | |
} | |
.chart-ui-container { | |
display: block; | |
width: 200px; | |
margin:0 auto; | |
padding: 2rem 0 0 0; | |
} | |
.chart-ui-container .chart-form__radio {} | |
.chart-ui-container .chart-form__radio-label { | |
display: inline-block; | |
padding: 0 .5rem; | |
border-radius: 3px; | |
font-size: .8rem; | |
} | |
.chart-ui-container .chart-form__radio-input { | |
margin-right: .75rem; | |
cursor: pointer; | |
outline:none; | |
} | |
.legend text { | |
font-size:.65rem; | |
} |
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
var DonutChart = function(opts){ | |
this.transSpeed = opts.transSpeed; | |
this.data = opts.data; | |
this.dataCount = opts.dataCount; | |
this.colorScheme = d3.schemeCategory20b || this.colorScheme; // set up customize | |
this.element = opts.elem.querySelector('.plot-wrap.w-svg'); | |
this.draw(); | |
} | |
DonutChart.prototype.setData = function(newData){ | |
this.data = newData; | |
this.draw(); | |
} | |
DonutChart.prototype.setDataCount = function(newData){ | |
this.dataCount = newData; | |
this.updateData(); | |
} | |
DonutChart.prototype.draw = function(){ | |
var self = this | |
this.margin = { | |
top:0, | |
left:0, | |
right:0, | |
bottom:0 | |
}; | |
this.width = this.element.offsetWidth - this.margin.left - this.margin.right; | |
this.width = parseInt(d3.select(this.element).style('width'), 10); | |
this.height = this.width / 2 - (this.margin.top - this.margin.bottom); | |
this.element.innerHTML = ''; | |
var svg = d3.select(this.element).append('svg'); | |
svg.attr('width', this.width + (this.margin.left + this.margin.right)); | |
svg.attr('height', (this.height + this.margin.top + this.margin.bottom)); | |
this.plot = svg.append('g') | |
.attr("transform", "translate(" + this.width / 2 + "," + this.height / 2 + ")"); | |
this.createDonut() | |
} | |
DonutChart.prototype.createDonut = function() { | |
var self = this | |
this.radius = Math.min(this.width, this.height) / 2; | |
this.ringSize = this.height / 5; | |
this.colorRange = d3.scaleOrdinal(this.colorScheme); | |
this.color = d3.scaleOrdinal() | |
.range(this.colorRange.range()); | |
this.arc = d3.arc() | |
.innerRadius(this.radius) | |
.outerRadius(this.radius - this.ringSize); | |
this.outerArc = d3.arc() | |
.innerRadius(this.radius * 0.9) | |
.outerRadius(this.radius * 0.9); | |
this.pie = d3.pie() | |
.value(function(d,i) {return d[self.dataCount];}) | |
.sort(null); | |
this.path = this.plot.selectAll("path.slice") | |
.data(this.pie(this.data)); | |
this.path | |
.enter() | |
.append("path") | |
.attr("class", "slice") | |
.attr("fill", function(d, i) { return self.color(i); }) | |
.attr('d', this.arc) | |
.each(function(d){this._current = d;}); | |
this.text = this.plot.selectAll("text") | |
.data(this.pie(this.data)) | |
.enter() | |
.append("text") | |
.attr("dy", ".35em") | |
.style("opacity", function(d){ | |
return d.data[self.dataCount] <= 0 ? "0" : "1"; | |
}) | |
.text(function(d) { | |
return d.data['header_one_name']; | |
}) | |
.each(function(d) { | |
this._current = d; | |
}) | |
.transition().duration(this.transSpeed) | |
.attrTween("transform", function(d) { | |
var interpolate = d3.interpolate(this._current, d); | |
var _this = this; | |
return function(t) { | |
var d2 = interpolate(t); | |
_this._current = d2; | |
var pos = self.outerArc.centroid(d2); | |
pos[0] = self.radius * (self.midAngle(d2) < Math.PI ? 1 : -1); | |
return "translate("+ pos +")"; | |
}; | |
}) | |
.styleTween("text-anchor", function(d){ | |
var interpolate = d3.interpolate(this._current, d); | |
return function(t) { | |
var d2 = interpolate(t); | |
return self.midAngle(d2) < Math.PI ? "start":"end"; | |
}; | |
}); | |
this.polyline = this.plot.selectAll("polyline") | |
.data(this.pie(this.data)) | |
.enter() | |
.append("polyline") | |
.style("opacity", function(d){ | |
return d.data[self.dataCount] <= 0 ? "0" : "1"; | |
}) | |
.attr('fill','none') | |
.attr('stroke-width','1') | |
.attr('stroke','#bfbfbf') | |
.transition().duration(this.transSpeed) | |
.attrTween("points", function(d){ | |
this._current = this._current || d; | |
var interpolate = d3.interpolate(this._current, d); | |
this._current = interpolate(0); | |
return function(t) { | |
var d2 = interpolate(t); | |
var pos = self.outerArc.centroid(d2); | |
pos[0] = self.radius * 0.95 * (self.midAngle(d2) < Math.PI ? 1 : -1); | |
return [self.arc.centroid(d2), self.outerArc.centroid(d2), pos]; | |
}; | |
}); | |
this.midAngle = function(d){ | |
return d.startAngle + (d.endAngle - d.startAngle)/2; | |
} | |
} | |
DonutChart.prototype.updateData = function(opts, elem){ | |
var self = this | |
//this.data = opts.data; | |
//this.element = document.querySelector(elem).querySelector('.plot-wrap.w-svg'); | |
this.plot = d3.select(this.element).select('svg').select('g'); | |
//this.dataCount = opts.dataCount; // here pie will reference the new data | |
this.path = this.plot.selectAll('path.slice').data(this.pie(this.data)); | |
this.path | |
.transition().duration(this.transSpeed) | |
.attrTween("d", function(d) { | |
this._current = this._current || d; | |
var interpolate = d3.interpolate(this._current, d); | |
this._current = interpolate(0); | |
return function(t) { | |
return self.arc(interpolate(t)); | |
}; | |
}); | |
this.newText = this.plot.selectAll("text") | |
.data(this.pie(this.data)) | |
.transition().duration(this.transSpeed) | |
.attrTween("transform", function(d) { | |
var interpolate = d3.interpolate(this._current, d); | |
var _this = this; | |
return function(t) { | |
var d2 = interpolate(t); | |
_this._current = d2; | |
var pos = self.outerArc.centroid(d2); | |
pos[0] = self.radius * (self.midAngle(d2) < Math.PI ? 1 : -1); | |
return "translate("+ pos +")"; | |
}; | |
}) | |
.style("opacity", function(d){ | |
return d.data[self.dataCount] <= 0 ? "0" : "1"; | |
}) | |
.styleTween("text-anchor", function(d){ | |
var interpolate = d3.interpolate(this._current, d); | |
return function(t) { | |
var d2 = interpolate(t); | |
return self.midAngle(d2) < Math.PI ? "start":"end"; | |
}; | |
}); | |
this.newPolyline = this.plot.selectAll("polyline") | |
.data(this.pie(this.data)) | |
.attr('fill','none') | |
.attr('stroke-width','1') | |
.attr('stroke','#bfbfbf') | |
.transition().duration(this.transSpeed) | |
.style("opacity", function(d){ | |
return d.data[self.dataCount] <= 0 ? "0" : "1"; | |
}) | |
.attrTween("points", function(d){ | |
this._current = this._current || d; | |
var interpolate = d3.interpolate(this._current, d); | |
this._current = interpolate(0); | |
return function(t) { | |
var d2 = interpolate(t); | |
var pos = self.outerArc.centroid(d2); | |
pos[0] = self.radius * 0.95 * (self.midAngle(d2) < Math.PI ? 1 : -1); | |
return [self.arc.centroid(d2), self.outerArc.centroid(d2), pos]; | |
}; | |
}); | |
} | |
DonutChart.prototype.resize = function(){ | |
this.width = parseInt(d3.select(this.element).style('width'), 10); | |
this.draw(); | |
} |
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 class="no-js" lang="en"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="x-ua-compatible" content="ie=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Donut Chart</title> | |
</head> | |
<body> | |
<div style="text-align: center;"> | |
<section style="width:40%; margin:5rem 0; display: inline-block;"> | |
<div class="mx-dv-container" id="donutChart"> | |
<div class="plot-wrap w-svg"></div> | |
<div class="plot-wrap no-svg"> | |
<!-- <img src="assets/d3-bundles/horiz-barchart.png"> --> | |
</div> | |
<form class="chart-ui-container"> | |
<div class="chart-form__radio"> | |
<label class="chart-form__radio-label"><input class="chart-form__radio-input" type="radio" name="dataset" value="header_two_amount" checked>Header Two Amount</label> | |
</div> | |
<div class="chart-form__radio"> | |
<label class="chart-form__radio-label"><input class="chart-form__radio-input" type="radio" name="dataset" value="header_three_amount">Header Three Amount</label> | |
</div> | |
</form> | |
</div> | |
</section> | |
<section style="width:40%; margin:5rem 0; display: inline-block;"> | |
<div class="mx-dv-container" id="donutChartTwo"> | |
<div class="plot-wrap w-svg"></div> | |
<div class="plot-wrap no-svg"></div> | |
<form class="chart-ui-container"> | |
<div class="chart-form__radio"> | |
<label class="chart-form__radio-label"><input class="chart-form__radio-input" type="radio" name="dataset" value="header_two_amount" checked>Header Two Amount</label> | |
</div> | |
<div class="chart-form__radio"> | |
<label class="chart-form__radio-label"><input class="chart-form__radio-input" type="radio" name="dataset" value="header_three_amount">Header Three Amount</label> | |
</div> | |
</form> | |
</div> | |
</section> | |
</div> | |
<script src="donut-chart.js"></script> | |
<script src="donut-chart-init.js"></script> | |
<script src="https://rawgit.com/timproDev/d3-first-timer/master/js/d3v4-473-jetpack.js"></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
header_one_name | header_two_amount | header_three_amount | header_four_text_string | header_five_date | |
---|---|---|---|---|---|
Glazed | 50 | faucibus | 30/04/2013 | ||
Chocolate | 64 | 444 | viverra | 20/11/2017 | |
Cinnamon Sugar | 30 | 76 | purus | 15/11/2015 | |
Jelly | 73 | sed | 27/01/2015 | ||
Marble Frosted | 95 | 495 | amet | 17/02/2015 | |
Apple Crumb | 97 | 367 | tellus | 27/11/2013 |
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
header_one_name | header_two_amount | header_three_amount | header_four_text_string | header_five_date | |
---|---|---|---|---|---|
Apples | 12 | faucibus | 30/04/2013 | ||
Bananas | 88 | 144 | viverra | 20/11/2017 | |
Grapes | 54 | 376 | purus | 15/11/2015 | |
Pears | 21 | sed | 27/01/2015 | ||
Carrots | 33 | 299 | amet | 17/02/2015 | |
Celery | 11 | 245 | tellus | 27/11/2013 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment