Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set y-axis of d3 chart to fit widest label?

I'm drawing line charts with d3 and it all works fine. However, I have to leave enough margin on the left of the chart area to fit whatever I think might be the widest y-axis text label. I'd like to adjust this space for each chart, depending on the widest label.

Initially I thought I could find the maximum y value, create a hidden text object, work out how wide that is, and use that value for the left margin when creating the chart. A bit nasty, but it gets me a value.

However, if the maximum y value is, say "1598.538" the top-most y-axis label might be "1500"... ie, a lot narrower.

So I guess I want to find the width of whatever will actually be the top-most label. But I can't think how to do that without drawing the chart and axis, measuring that width, and drawing it again for real. Which sounds nasty! Is there a non-nasty way to do this?

UPDATE

Here's part of my code, using Lars' suggestion, just to show where it fits in:

// I did have
// `.attr("transform", "translate(" + margin.left + "," + margin.top ")")`
// on the end of this line, but I've now moved that to the bottom.
var g = svg.select("g");

// Add line paths.
g.selectAll(".line").data(data)
    .enter()
    .append("path")
    .attr("d", line);

// Update the previously-created axes.
g.select(".axis-x")
    .attr("transform", "translate(0," + yScale.range()[0] + ")"))
    .call(xAxis);
g.select(".axis-y")
    .call(yAxis);

// Lars's suggestion for finding the maximum width of a y-axis label:
var maxw = 0;
d3.select(this).select('.axis-y').selectAll('text').each(function(){
  if (this.getBBox().width > maxw) maxw = this.getBBox().width;
});

// Now update inner dimensions of the chart.
g.attr("transform", "translate(" + (maxw + margin.left) + "," + margin.top + ")");
like image 333
Phil Gyford Avatar asked Jun 14 '13 13:06

Phil Gyford


1 Answers

You can put everything inside a g element and set transform based on the max width. Something along the lines of

var maxw = 0;
yAxisContainer.selectAll("text").each(function() {
    if(this.getBBox().width > maxw) maxw = this.getBBox().width;
});
graphContainer.attr("transform", "translate(" + maxw + ",0)");
like image 142
Lars Kotthoff Avatar answered Sep 21 '22 20:09

Lars Kotthoff