By using the center part of the chart, this example demonstrates one way to show information in the scenarios of pie or donut charts. We could also perform interactions between these charts by hovering or clicking.
forked from erichoco's block: Interactive Donut Charts
xxxxxxxxxx
<meta charset="utf-8">
<style type="text/css">
body {
font-size: 100%;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
}
#refresh-btn {
float: right;
font-size: 12px;
border-radius: 0;
}
</style>
<body>
<h4>
<a href="https://bl.ocks.org/erichoco/6694616">forked from erichoco/6694616</a>
</h4>
<button type="button" id="refresh-btn">Refresh data</button>
<div id="donut-charts"></div>
<script src="https://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
$(function() {
var donutData = genData();
var donuts = new DonutCharts();
donuts.create(donutData);
$('#refresh-btn').on('click', function refresh() {
donuts.update(genData);
});
});
function DonutCharts() {
var charts = d3.select('#donut-charts');
var chart_m,
chart_r,
color = d3.scale.category20();
var getCatNames = function(dataset) {
var catNames = new Array();
for (var i = 0; i < dataset[0].data.length; i++) {
catNames.push(dataset[0].data[i].cat);
}
return catNames;
}
var createLegend = function(catNames) {
var legends = charts.select('.legend')
.selectAll('g')
.data(catNames)
.enter().append('g')
.attr('transform', function(d, i) {
return 'translate(' + (i * 150 + 50) + ', 10)';
});
legends.append('circle')
.attr('class', 'legend-icon')
.attr('r', 6)
.style('fill', function(d, i) {
return color(i);
});
legends.append('text')
.attr('dx', '1em')
.attr('dy', '.3em')
.text(function(d) {
return d;
});
}
var createCenter = function(pie) {
var eventObj = {
'mouseover': function(d, i) {
d3.select(this)
.transition()
.attr("r", chart_r * 0.65);
},
'mouseout': function(d, i) {
d3.select(this)
.transition()
.duration(500)
.ease('bounce')
.attr("r", chart_r * 0.6);
},
'click': function(d, i) {
var paths = charts.selectAll('.clicked');
pathAnim(paths, 0);
paths.classed('clicked', false);
resetAllCenterText();
}
}
var donuts = d3.selectAll('.donut');
// The circle displaying total data.
donuts.append("svg:circle")
.attr("r", chart_r * 0.6)
.style("fill", "#E7E7E7")
.on(eventObj);
donuts.append('text')
.attr('class', 'center-txt type')
.attr('y', chart_r * -0.16)
.attr('text-anchor', 'middle')
.style('font-weight', 'bold')
.text(function(d, i) {
return d.type;
});
donuts.append('text')
.attr('class', 'center-txt value')
.attr('text-anchor', 'middle');
donuts.append('text')
.attr('class', 'center-txt percentage')
.attr('y', chart_r * 0.16)
.attr('text-anchor', 'middle')
.style('fill', '#A2A2A2');
}
var setCenterText = function(thisDonut) {
var sum = d3.sum(thisDonut.selectAll('.clicked').data(), function(d) {
return d.data.val;
});
thisDonut.select('.value')
.text(function(d) {
return (sum)? sum.toFixed(1) + d.unit
: d.total.toFixed(1) + d.unit;
});
thisDonut.select('.percentage')
.text(function(d) {
return (sum)? (sum/d.total*100).toFixed(2) + '%'
: '';
});
}
var resetAllCenterText = function() {
charts.selectAll('.value')
.text(function(d) {
return d.total.toFixed(1) + d.unit;
});
charts.selectAll('.percentage')
.text('');
}
var pathAnim = function(path, dir) {
switch(dir) {
case 0:
path.transition()
.duration(500)
.ease('bounce')
.attr('d', d3.svg.arc()
.innerRadius(chart_r * 0.7)
.outerRadius(chart_r)
);
break;
case 1:
path.transition()
.attr('d', d3.svg.arc()
.innerRadius(chart_r * 0.7)
.outerRadius(chart_r * 1.08)
);
break;
}
}
var updateDonut = function() {
var eventObj = {
'mouseover': function(d, i, j) {
pathAnim(d3.select(this), 1);
var thisDonut = charts.select('.type' + j);
thisDonut.select('.value').text(function(donut_d) {
return d.data.val.toFixed(1) + donut_d.unit;
});
thisDonut.select('.percentage').text(function(donut_d) {
return (d.data.val/donut_d.total*100).toFixed(2) + '%';
});
},
'mouseout': function(d, i, j) {
var thisPath = d3.select(this);
if (!thisPath.classed('clicked')) {
pathAnim(thisPath, 0);
}
var thisDonut = charts.select('.type' + j);
setCenterText(thisDonut);
},
'click': function(d, i, j) {
var thisDonut = charts.select('.type' + j);
if (0 === thisDonut.selectAll('.clicked')[0].length) {
thisDonut.select('circle').on('click')();
}
var thisPath = d3.select(this);
var clicked = thisPath.classed('clicked');
pathAnim(thisPath, ~~(!clicked));
thisPath.classed('clicked', !clicked);
setCenterText(thisDonut);
}
};
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.val;
});
var arc = d3.svg.arc()
.innerRadius(chart_r * 0.7)
.outerRadius(function() {
return (d3.select(this).classed('clicked'))? chart_r * 1.08
: chart_r;
});
// Start joining data with paths
var paths = charts.selectAll('.donut')
.selectAll('path')
.data(function(d, i) {
return pie(d.data);
});
paths
.transition()
.duration(1000)
.attr('d', arc);
paths.enter()
.append('svg:path')
.attr('d', arc)
.style('fill', function(d, i) {
return color(i);
})
.style('stroke', '#FFFFFF')
.on(eventObj)
paths.exit().remove();
resetAllCenterText();
}
this.create = function(dataset) {
var $charts = $('#donut-charts');
chart_m = $charts.innerWidth() / dataset.length / 2 * 0.14;
chart_r = $charts.innerWidth() / dataset.length / 2 * 0.85;
charts.append('svg')
.attr('class', 'legend')
.attr('width', '100%')
.attr('height', 50)
.attr('transform', 'translate(0, -100)');
var donut = charts.selectAll('.donut')
.data(dataset)
.enter().append('svg:svg')
.attr('width', (chart_r + chart_m) * 2)
.attr('height', (chart_r + chart_m) * 2)
.append('svg:g')
.attr('class', function(d, i) {
return 'donut type' + i;
})
.attr('transform', 'translate(' + (chart_r+chart_m) + ',' + (chart_r+chart_m) + ')');
createLegend(getCatNames(dataset));
createCenter();
updateDonut();
}
this.update = function(dataset) {
// Assume no new categ of data enter
var donut = charts.selectAll(".donut")
.data(dataset);
updateDonut();
}
}
/*
* Returns a json-like object.
*/
function genData() {
var type = ['Users', 'Avg Upload', 'Avg Files Shared'];
var unit = ['M', 'GB', ''];
var cat = ['Google Drive', 'Dropbox', 'iCloud', 'OneDrive', 'Box'];
var dataset = new Array();
for (var i = 0; i < type.length; i++) {
var data = new Array();
var total = 0;
for (var j = 0; j < cat.length; j++) {
var value = Math.random()*10*(3-i);
total += value;
data.push({
"cat": cat[j],
"val": value
});
}
dataset.push({
"type": type[i],
"unit": unit[i],
"data": data,
"total": total
});
}
console.log(JSON.stringify(dataset, null, 2));
return dataset;
}
</script>
</body>
Modified http://code.jquery.com/jquery-1.10.1.min.js to a secure url
Modified http://d3js.org/d3.v3.min.js to a secure url
https://code.jquery.com/jquery-1.10.1.min.js
https://d3js.org/d3.v3.min.js