rotate x axis text in d3
I am new to d3 and svg coding and am looking for a way to rotate text on the xAxis of a chart. My problem is that typically the xAxis titles are longer than the bars in the bar chart are wide. So I'm looking to rotate the text to run vertically (rather than horizontally) beneath the xAxis.
I've tried adding the transform attribute: .attr("transform", "rotate(180)")
But when I do that, the text disappears altogether. I've tried increasing the height of the svg canvas, but still was unable to view the text.
Any thoughts on what I'm doing wrong would be great. Do I need to also adjust the x and y positions? And, if so, by how much (hard to troubleshoot when I can see it in Firebug).
Solution 1:
If you set a transform of rotate(180), it rotates the element relative to the origin, not relative to the text anchor. So, if your text elements also have an x and y attribute set to position them, it’s quite likely that you’ve rotated the text off-screen. For example, if you tried,
<text x="200" y="100" transform="rotate(180)">Hello!</text>
the text anchor would be at ⟨-200,100⟩. If you want the text anchor to stay at ⟨200,100⟩, then you can use the transform to position the text before rotating it, thereby changing the origin.
<text transform="translate(200,100)rotate(180)">Hello!</text>
Another option is to use the optional cx and cy arguments to SVG’s rotate transform, so that you can specify the origin of rotation. This ends up being a bit redundant, but for completeness, it looks like this:
<text x="200" y="100" transform="rotate(180,200,100)">Hello World!</text>
Solution 2:
Shamelessly plucked from elsewhere, all credit to author.
margin included only to show the bottom margin should be increased.
var margin = {top: 30, right: 40, bottom: 50, left: 50},
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
Solution 3:
One problem with this rotating D3 axis labels is that you have to re-apply this logic each time you render the axis. This is because you do not have access to the enter-update-exit selections that the axis uses to render the ticks and labels.
d3fc is a component library that has a decorate pattern allowing you to gain access to the underling data join used by components.
It has a drop-in replacement for the D3 axis, where axis label rotation is performed as follows:
var axis = fc.axisBottom()
.scale(scaleBand)
.decorate(function(s) {
s.enter()
.select('text')
.style('text-anchor', 'start')
.attr('transform', 'rotate(45 -10 10)');
});
Notice that the rotation is only applied on the enter selection.
You can see some other possible uses for this pattern on the axis documentation page.