How to properly get text width to center labels ab

2019-04-07 08:28发布

问题:

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:

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?

回答1:

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);
}
...


回答2:

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)