Accepted answer

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:

      .attr("transform",(d:any,i:any)=> {return "translate("+(i*this.width/","+(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):

  .attr("transform",(d:any,i:any)=> {return "translate("+(i*this.width/","+(this.height+35)+")"; })
  .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

More Query from same tag