Skip to content

Instantly share code, notes, and snippets.

@SteveBate
Last active April 26, 2016 15:26
Show Gist options
  • Save SteveBate/1476137306f499b1840c38708a82edbf to your computer and use it in GitHub Desktop.
Save SteveBate/1476137306f499b1840c38708a82edbf to your computer and use it in GitHub Desktop.
Example D3 bubble chart based on the one in 'Facts Are Sacred' book on page 52
var dataset = {
"dispatched": {
"CCE018 - Acme Glass Division": "42",
"CCE033 - Cold Shopper Marketing": "730",
"CCE034 - Home Shopper Marketing": "31",
"CCE035 - T C C C Portfolio": "10",
"CCE036 - Portfolio X Franchise": "21",
"CCE037 - Cold Operations Trading": "500",
"CCE038 - Home Operations Trading": "9",
"CCE039 - Field Sales Operations": "2702",
"All Divisions": "4045"
}
};
function processData(data, col) {
var obj = data[col];
var newDataSet = [];
for(var prop in obj) {
newDataSet.push({name: prop, className: prop.toUpperCase(), size: obj[prop]});
}
return {children: newDataSet};
}
function renderBubble(target, diameter){
var svg = d3.select(target).append('svg').attr('width', diameter).attr('height', diameter);
// prepare an area that can pack circle together
var bubble = d3.layout.pack()
.sort(function(a, b) {return -(a.value - b.value);})
.size([diameter, diameter])
.padding(30) // padding between adjacent circles
.value(function(d) {return d.size;}); // new data will be loaded to bubble layout
var node = svg.selectAll(".node")
.data(bubble.nodes(processData(dataset, "dispatched"))
.filter(function(d) { return !d.children; }))
.enter()
.append("g")
.attr("class", "node")
.attr("data-x", function(d){return d.x;})
.attr("data-y", function(d){return d.y;})
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("circle")
.attr("r", function(d) { return d.r; })
.style("fill", function(d, i) { return "rgb(138, " + i*10 + ", 175)"; })
.on("click", function(d){console.log(d);})
.on("mouseenter", function(d) {
// scale the circle
d3.select(this)
.transition()
.ease('cubic-in-out')
.duration(200)
.attr('r', d.r+5);
// scale the text
var text = d3.select(this.parentNode.lastChild);
text
.transition()
.ease('cubic-in-out')
.duration(200)
.style('font-size', text.attr('font-size')/0.8);
})
.on("mouseout", function(d) {
// scale the circle
d3.select(this)
.transition()
.ease('cubic-in-out')
.duration(200)
.attr('r', d.r);
// scale the text
var text = d3.select(this.parentNode.lastChild);
text
.transition()
.ease('cubic-in-out')
.duration(200)
.style('font-size', text.attr('font-size'));
});
// find the circle representing the total value of all circles combined
var index = node[0].length-1;
var totalCircle = node[0][index].childNodes[0];
// draw lines from the center of the current circle to the center of the target circle
node.append("line")
.attr("x1", function(d){return 0;})
.attr("x2", function(d, i){return totalCircle.parentNode.getAttribute("data-x")-d.x;})
.attr("y1", function(d){return 0;})
.attr("y2", function(d, i){return (totalCircle.parentNode.getAttribute("data-y")-d.y);})
.attr("stroke", function(d,i) { return "rgb(138, " + i*10 + ", 175)"; })
.attr("stroke-width", 5);
// add text displaying the total number of orders dispatched. Set the font size according to the circle size.
node.append("text")
.attr("dy", ".3em")
.attr("font-family", "sans-serif")
.attr("font-size", function(d, i){
var val = node[0][i].childNodes[0].r.baseVal.value;
return val < 45 ? val*0.6 : val*0.5;
})
.attr("fill", "#FFF")
.attr("font-weight", "bold")
.attr("text-anchor", "middle")
.text(function(d) { return d.value.toLocaleString(); });
}
renderBubble("#chart1", 550);
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div id="chart1" />
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment