1

I'm using a combination of AngularJS and D3.js to dynamically draw line graphs based on data retrieved from an API.

Below is a picture of my y-axis. As you can see, I have a drawn a black vertical line representing 0 to 100%. I have 5 tick marks labelled with their associated percentages.

enter image description here

Here is the code that generates this:

    var yScaleIntervals = 4;
    var yMaxlabel = 100;
    for (var i = 0; i <= yScaleIntervals; i++) {
      var tickY = self.yBottom - (self.yPixSpan  * (i/yScaleIntervals));
      var tickLabel = ((100 * i)/yScaleIntervals).toString() + '%';
      console.log("tickY = ", tickY);
      self.svgContainer.append("line")
        .attr("x1", self.yScaleX - 2)
        .attr("y1", tickY)
        .attr("x2", self.yScaleX)
        .attr("y2", tickY)
        .attr("stroke-width", 1)
        .attr("stroke", "black");

      var YfontOffset = 30;
      var XfontOffset = 4;
      var label = self.svgContainer.append("text")
        .attr("x", yScaleX - YfontOffset)
        .attr("y", tickY + XfontOffset)
        .text(tickLabel)
        .attr("font-family", "Courier New")
        .attr("font-weight", "bold")
        .attr("font-size", "10px");
        .attr("fill", "black");

    }

As you can see, I have hardcoded YfontOffset and XfontOffset to re-position the text to appear somewhat adjacent to those tick marks.

But this is not what I really want. I want each text label to appear the same number of pixels to to the left of their associated tick marks. And I want the tick marks to be exactly horizontally in the middle of the text. Thus the x and y attributes of each label must be computed based on the bounding box of the text. How can I get the dimensions of those bounding boxes before the text is drawn on the canvas so I can use them to in those attributes?

Saqib Ali
  • 11,931
  • 41
  • 133
  • 272

2 Answers2

3

How can I get the dimensions of those bounding boxes before the text is drawn on the canvas?

In short, you don't. Just change your order of operations, draw them and then move them:

  var YfontOffset = 30;
  var XfontOffset = 4;
  var label = self.svgContainer.append("text")
    .text(tickLabel)
    .attr("font-family", "Courier New")
    .attr("font-weight", "bold")
    .attr("font-size", "10px");
    .attr("fill", "black")
    // using translate, so I can set the 
    // x/y in one attr call
    .attr("transform", function(d){
       var bb = this.getBBox();
       return "translate(" + fancyCalcX() + "," + fancyCalcY() + ")";
    });
Saqib Ali
  • 11,931
  • 41
  • 133
  • 272
Mark
  • 106,305
  • 20
  • 172
  • 230
0

Skip bounding boxes altogether and use text-anchor

https://developer.mozilla.org/en/docs/Web/SVG/Attribute/text-anchor

.style("text-anchor", "end");
mgraham
  • 6,147
  • 1
  • 21
  • 20
  • But I have to change the Y position of the text, not just the X. "text-anchor" seems to only change the X positioning. Also, I don't just need it at the text-anchor "end" position. I need to be shifted further to the left. – Saqib Ali Mar 21 '16 at 03:19
  • To be shifted further to the left, just keep your little XFontOffset value. For the y-positioning use the css property `alignment-baseline` or if it has to be for IE too, use the `dy` attr and a `em` unit. http://stackoverflow.com/questions/12250403/vertical-alignment-of-text-element-in-svg – mgraham Mar 21 '16 at 09:38