Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly get text width to center labels above graph bars?

I currently have a graph that has associated bar values displaying above each bar, but I'm having difficulty centering the value labels, due to not being able to fetch each text element's width.

This is how my graph is drawing at the moment:

enter image description here

All I need to do is to subtract half of each text element's width, but I can't seem to do so with the following Coffeescript:

    #Drawing value labels   
    svg.selectAll("rect")
        .data(data)
        .enter()
        .append("text")
        .text((d)-> d.Total)
        .attr("width", x.rangeBand())
        .attr("x", (d)->
            textWidth = d3.selectAll("text").attr("width")

            x(d.Year) + (x.rangeBand() / 2) - (textWidth / 2)
        )
        .attr("y", (d)-> y(d.Total) - 5)
        .attr("font-size", "10px")
        .attr("font-family", "sans-serif")

    #Drawing bars       
    svg.selectAll("rect")
        .data(data)
        .enter().append("rect")
        .attr("class", "bar")
        .attr("x", (d)-> x(d.Year))
        .attr("width", x.rangeBand())
        .attr("y", (d)-> y(d.Total))
        .attr("height", (d)-> height - y(d.Total))

Is there a way that I can access each text element's width attribute to set a value to offset?

like image 798
SCS Avatar asked Mar 22 '13 18:03

SCS


People also ask

How do you put data labels on top of a bar?

On the Layout tab, in the Labels group, click Data Labels, and then click the option that you want. For additional data label options, click More Data Label Options, click Label Options if it's not selected, and then select the options that you want.


2 Answers

A perhaps simpler way is to use a text-anchor of middle with x set to the left side of the bar plus half the width of the bar:

svg.selectAll(".bar-label")
  .data(data)
.enter().append("text")
  .text((d)-> d.Total)
  .attr("class", "bar-label")
  .attr("text-anchor", "middle")
  .attr("x", (d)-> x(d.Year) + x.rangeBand()/2)
  .attr("y", (d)-> y(d.Total) - 5)
like image 67
Drew Goodwin Avatar answered Oct 05 '22 23:10

Drew Goodwin


You can get the bounding box of the text and use those values to apply a transform to center it. An example for getting the bounding box is here. The code would look something like

.text(function(d) { return d.Total; })
.attr("x", function(d) {
   return x(d.Year) + (x.rangeBand() / 2) - (this.getBBox().width / 2);
}
...
like image 40
Lars Kotthoff Avatar answered Oct 06 '22 01:10

Lars Kotthoff