ttmt
ttmt

Reputation: 4984

D3 - Rotate text individually

I have a plunker here - https://plnkr.co/edit/eh5DlisXGTqKt9bGtuMT?p=preview

I'm creating a stacked bar chart that will show a trend over months.

The months are on the x axis.

I want to show the type of each column with text underneath the column and rotated 90 degrees.

I have the text showing but if I try to rotate it, it rotates all the text as block and not each text individually.

How can I rotate each text block 90 degrees separatley.

this.layersBar.append('text')
  .text((d:any, i:any)=>{
    return d[i].data.type
  })
  .attr('x', (d:any, i:any)=>{
        return (i * this.width/this.data.length)+5;
    })
    .attr('y', this.height+15)
    .style('fill', 'black')
    .classed('trend-type', true)
    .style("text-anchor", "middle")
    .attr("transform", "rotate(-20)") 

}

Upvotes: 1

Views: 947

Answers (1)

Andrew Reid
Andrew Reid

Reputation: 38151

Rotation is relative to an element's parent origin:

the rotate is about the origin of the current user coordinate system.(source)

unless specifying a rotational point. Since all your text shares the same coordinate system (that of the parent g), they all get rotated together, as a block as you note. And they are rotated around [0,0] of the parent g, not around their anchor or any point related to where the text lies.

Instead of appending text directly to the chart's g, you could append each label to its own g. If each of these g elements are transformed so that their origins correspond to text locations, rotation becomes easy.

Using your example, I append a g with a translate similar to where you position your labels:

this.layersBar.append('g')
      .attr("transform",(d:any,i:any)=> {return "translate("+(i*this.width/this.data.length+5)+","+(this.height+35)+")"; })

Now I can append the text (no need to set x,y because 0,0 is now where I want the text):

this.layersBar.append('g')
  .attr("transform",(d:any,i:any)=> {return "translate("+(i*this.width/this.data.length+5)+","+(this.height+35)+")"; })
  .append("text")
  .text((d:any, i:any)=>{ return d[i].data.type })
  .style('fill', 'black')
  .classed('trend-type', true)
  .style("text-anchor", "middle")
  .attr("transform", "rotate(-20)");

Each label is now rotated around the origin of it's g, and each origin is positioned according to where the label should be:

enter image description here

Upvotes: 5

Related Questions