I created two graphs in d3js: a bar chart and a donut chart. These two graphs use the same json object for data and share an input range and the radio button.
This is the code:
<html lang='en'>
<head>
<meta charset='utf-8'>
<style>
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
.arc text {
font: 10px sans-serif;
text-anchor: middle;
}
.arc path {
stroke: #fff;
}
</style>
<title>Donut & Bar charts</title>
<script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
</head>
<body>
<div id='year-selector-container'>
<input id='year-slider' class='year-range' type='range' min='2000' max='2005' value='2004'>
Year: <span id='year-span'>2004</span>
</div>
<div id='type-selector-container'>
<form id='type-selector'>
<input type='radio' name='type-selector' id='rb-1' value='type1' checked />
<label for='rb-1'>Type 1</label>
<input type='radio' name='type-selector' id='rb-2' value='type2' />
<label for='rb-2'>Type 2</label>
<input type='radio' name='type-selector' id='rb-3' value='type3' />
<label for='rb-3'>Type 3</label>
</form>
</div>
<div id='barchart'></div>
<div id='donutchart'></div>
<script>
/////////////////////////////////////////////////
// SHARED CODE
/////////////////////////////////////////////////
var data = [
{"year": 2000, "type1": 30, "type2": 40, "type3": 30},
{"year": 2001, "type1": 75.5, "type2": 4.5, "type3": 30},
{"year": 2002, "type1": 0, "type2": 90, "type3": 10},
{"year": 2003, "type1": 15, "type2": 20, "type3": 65},
{"year": 2004, "type1": 20, "type2": 40, "type3": 40},
{"year": 2005, "type1": 50, "type2": 25, "type3": 25}
];
var updateRadio = function() {
typeSelected = document.querySelector('input[name=type-selector]:checked', '#type-selector').value;
console.log('typeSelected:', typeSelected);
d3.selectAll('rect').remove();
drawBar(getDataFromType(typeSelected));
}
var updateSlider = function() {
var slider = document.getElementById('year-slider');
var output = document.getElementById('year-span');
yearSelected = slider.value;
output.innerHTML = yearSelected;
console.log('yearSelected:', yearSelected);
d3.selectAll('.svgG').remove();
drawDonut(getDataFromYear(yearSelected));
}
d3.select('#type-selector').on('change', updateRadio);
d3.select('#year-slider').on('input', updateSlider);
var yearSelected = d3.select('#year-span').text();
var typeSelected = document.querySelector('input[name=type-selector]:checked', '#type-selector').value;
console.log('yearSelected:', yearSelected);
console.log('typeSelected:', typeSelected);
/////////////////////////////////////////////////
// BAR
/////////////////////////////////////////////////
var svgBar = d3.select("#barchart").append("svg").attr("width", 450).attr("height", 200);
var marginBar = {top: 20, right: 20, bottom: 30, left: 40};
var widthBar = +svgBar.attr("width") - marginBar.left - marginBar.right;
var heightBar = +svgBar.attr("height") - marginBar.top - marginBar.bottom;
var xBar = d3.scaleBand().rangeRound([0, widthBar]).padding(0.1);
var yBar = d3.scaleLinear().rangeRound([heightBar, 0]);
createBar(data);
function createBar(data) {
var g = svgBar.append("g").attr('id', 'gBar').attr("transform", "translate(" + marginBar.left + ", " + marginBar.top + ")");
xBar.domain(data.map(function(d) {
return d.year;
}));
yBar.domain([0, d3.max(data, function(d) {
if(typeSelected == 'type1') return d.type1;
if(typeSelected == 'type2') return d.type2;
if(typeSelected == 'type2') return d.type3;
})]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + heightBar + ")")
.call(d3.axisBottom(xBar));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(yBar).ticks(10, "%"))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end");
var initialData = getDataFromType('type1');
drawBar(initialData, heightBar);
}
// return the right data
function getDataFromType(type) {
var arr = [];
data.forEach(function(item) {
if(type == 'type1') arr.push({"year": item.year, "value": item.type1});
if(type == 'type2') arr.push({"year": item.year, "value": item.type2});
if(type == 'type3') arr.push({"year": item.year, "value": item.type3});
});
return arr;
}
// draw barchart
function drawBar(mydata, height) {
d3.select('#gBar').selectAll(".bar")
.data(mydata)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return xBar(d.year);
})
.attr("y", function(d) {
return yBar(d.value);
})
.attr("width", xBar.bandwidth())
.attr("height", function(d) {
return heightBar - yBar(d.value);
});
} // end draw
/////////////////////////////////////////////////
// DONUT
/////////////////////////////////////////////////
var widthDonut = 400;
var heightDonut = 200;
var radiusDonut = Math.min(widthDonut, heightDonut) / 2;
var colorDonut = d3.scaleOrdinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var arcDonut = d3.arc()
.outerRadius(radiusDonut - 10)
.innerRadius(radiusDonut - 60);
var pieDonut = d3.pie()
.sort(null)
.value(function(d) {
return d.value;
});
var svgDonut = d3.select("#donutchart").append("svg")
.attr("width", widthDonut)
.attr("height", heightDonut);
var dataNestDonut = d3.nest()
.key(function(d) {
return d.year;
})
.object(data);
createDonut();
function createDonut() {
var initialData = getDataFromYear(yearSelected);
drawDonut(initialData);
}
// return the right data
function getDataFromYear(year) {
var filterData = dataNestDonut[year].slice();
var arr = [{"typeData": "type1", "value": filterData[0].type1}, {"typeData": "type2", "value": filterData[0].type2}, {"typeData": "type3", "value": filterData[0].type3}];
return arr;
}
function drawDonut(data) {
var svgG = svgDonut.append("g")
.attr('class', 'svgG')
.attr("transform", "translate(" + widthDonut / 2 + "," + heightDonut / 2 + ")");
var g = svgG.selectAll(".arc")
.data(pieDonut(data))
.enter()
.append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arcDonut)
.style("fill", function(d) {
return colorDonut(d.data.typeData);
});
g.append("text")
.attr("transform", function(d) {
return "translate(" + arcDonut.centroid(d) + ")";
})
.attr("dy", ".35em")
.text(function(d) {
return d.data.typeData;
});
}
</script>
</body>
</html>
The code works but I think there are smarter ways to organize it.