Here's a JSFiddle: http://jsfiddle.net/8p2yc/ (A slightly modified example from here: http://bl.ocks.org/mbostock/3883245)
As you can see in the JSFiddle tick labels along the y axis do not fit in the svg. I know I can increase the left margin, but the thing is I don't know what the data will be in advance. If I just make the margin very large the chart will look awkward if the numbers are short in length.
Is there a way to precompute the maximum label width when creating the chart to set the margin correctly? Or perhaps there's an entirely different solution?
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 400 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Thanks!
You can do this by appending the text for the largest label, measuring it and removing it immediately afterwards:
var maxLabel = d3.max(data, function(d) { return d.close; }),
maxWidth;
svg.append("text").text(maxLabel)
.each(function() { maxWidth = this.getBBox().width; })
.remove();
Then you can use that width to do the translation of the g
element:
svg.attr("transform", "translate(" + Math.max(margin.left, maxWidth) + "," + margin.top + ")");
Complete example here.
Edit: Getting the maximum length of the actual labels is a bit more involved because you have to generate them (with the right formatting) and measure them all. This is a better way to do it though as you're measuring what's actually displayed. The code is similar:
var maxWidth = 0;
svg.selectAll("text.foo").data(y.ticks())
.enter().append("text").text(function(d) { return y.tickFormat()(d); })
.each(function(d) {
maxWidth = Math.max(this.getBBox().width + yAxis.tickSize() + yAxis.tickPadding(), maxWidth);
})
.remove();
I'm adding the size of the tick line and the padding between tick line and label to the width here. Complete example of that here.
d3 v4 Solution for Lars' Method.
calculateMarginForYScaleTicks() {
let maxWidth = 0;
let textFormatter = d3.format(",");
let tempYScale = d3
.scaleLinear()
.range([0, 0])
.domain([0, d3.max(data, d => d.value)]);
d3
.select("#svg")
.selectAll("text.foo")
.data(tempYScale.ticks())
.enter()
.append("text")
.text(d => textFormatter(d))
.each(function() {
maxWidth = Math.max(this.getBBox().width, maxWidth);
})
.remove();
return maxWidth;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With