Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3.js: Align text labels between ticks on the axis

Is there an easy way to align text labels between ticks?

Here is my time axis with labels above the ticks:
enter image description here

I would like to place these labels like here:
enter image description here

like image 441
oluckyman Avatar asked Jul 09 '13 09:07

oluckyman


3 Answers

I ended up with one of the Lars Kotthoff's advices.

Every time when I call(axis) I also adjust text labels.
Here is simplified code:

function renderAxis() {
    axisContainer
        .transition().duration(300)
        .call(axis)                  // draw the standart d3 axis
        .call(adjustTextLabels);     // adjusts text labels on the axis 
}

function adjustTextLabels(selection) {
    selection.selectAll('.major text')
        .attr('transform', 'translate(' + daysToPixels(1) / 2 + ',0)');
}

// calculate the width of the days in the timeScale
function daysToPixels(days, timeScale) {
    var d1 = new Date();
    timeScale || (timeScale = Global.timeScale);
    return timeScale(d3.time.day.offset(d1, days)) - timeScale(d1);
}

Update:
BTW, here is a calendar demo with I ended up: http://bl.ocks.org/oluckyman/6199145

enter image description here

like image 195
oluckyman Avatar answered Nov 02 '22 23:11

oluckyman


There is no easy (i.e. built-in) way of doing this, but you can still achieve it. There are a few options. The most straightforward one is probably to use the tickFormat function to specify a format with a suitable number of spaces in front/after the numbers. This would need to be hand-tuned for each application though.

Alternatively, you could select the label elements after they have been drawn and add a suitable transform attribute that shifts them accordingly. Again, this would have to be hand-tuned.

Your third option is to have two different axes, one for the ticks and one for the labels. The idea is that the axis that provides the ticks has no labels and the other one no ticks. You would need to set the tick values appropriately, but at least you wouldn't have to guess the right offset.

like image 7
Lars Kotthoff Avatar answered Nov 02 '22 23:11

Lars Kotthoff


You might want to consider using D3FC, which has a drop-in replacement for the D3 axis component that supports this feature.

Here's an example which substitutes the D3 axis d3.axisBottom, for the D3FC equivalent fc.axisBottom:

const axis = fc.axisBottom(linear)
  .tickCenterLabel(true);

The tickCenterLabel centres the axis labels as requested.

Here's what the axis looks like with tickCenterLabel = false:

enter image description here

And here with the tickCenterLabel = true:

enter image description here

Full disclosure - I'm a maintainer and contributor to D3FC

like image 3
ColinE Avatar answered Nov 02 '22 21:11

ColinE