em
are scalable units which are translated by the browser into pixel values. For a base font size of 10px
, a value of 1em
is translated into 10px
. 2em
into 20px
. And so on.
By computing the ratio between the width taken by a label and the available width, we can use that value as an em
unit and resize the label to fit the available space.
xxxxxxxxxx
<style>
.bubble-chart {
font: 24px "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.bubble-chart .node text {
text-anchor: middle;
}
.bubble-chart .node circle {
fill: #ccc;
}
.bubble-chart .node:hover circle {
fill: orange;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var bleed = 100,
width = 960,
height = 760;
var pack = d3.layout.pack()
.sort(null)
.size([width, height + bleed * 2])
.padding(2);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "bubble-chart")
.append("g")
.attr("transform", "translate(0," + -bleed + ")");
d3.json("data.json", function(error, json) {
if (error) throw error;
var node = svg.selectAll(".node")
.data(pack.nodes(flatten(json))
.filter(function(d) { return !d.children; }))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.append("circle")
.attr("r", function(d) { return d.r; });
node.append("text")
.text(function(d) { return d.name; })
.style("font-size", adaptLabelFontSize)
.attr("dy", ".35em");
});
function adaptLabelFontSize(d) {
var xPadding, diameter, labelAvailableWidth, labelWidth;
xPadding = 8;
diameter = 2 * d.r;
labelAvailableWidth = diameter - xPadding;
labelWidth = this.getComputedTextLength();
// There is enough space for the label so leave it as is.
if (labelWidth < labelAvailableWidth) {
return null;
}
/*
* The meaning of the ratio between labelAvailableWidth and labelWidth equaling 1 is that
* the label is taking up exactly its available space.
* With the result as `1em` the font remains the same.
*
* The meaning of the ratio between labelAvailableWidth and labelWidth equaling 0.5 is that
* the label is taking up twice its available space.
* With the result as `0.5em` the font will change to half its original size.
*/
return (labelAvailableWidth / labelWidth) + 'em';
}
// Returns a flattened hierarchy containing all leaf nodes under the root.
function flatten(root) {
var nodes = [];
function recurse(node) {
if (node.children) node.children.forEach(recurse);
else nodes.push({name: node.name, value: node.size});
}
recurse(root);
return {children: nodes};
}
</script>
https://d3js.org/d3.v3.min.js