Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript's getBBox() provides a box that is taller than its content text. Why?

I'm using D3.js to draw some text ("100%") on an SVG Container.

Now I'm trying to figure out the dimensions of the bounding box around that text.

This is how I do it:

      var label = svgContainer.append("text")
        .attr("x", 200)
        .attr("y", 200)
        .text("100%")
        .attr("font-family", "Courier New")
        .attr("font-weight", "bold")
        .attr("font-size", "10px")
        .attr("fill", "black");
        .attr("transform", function(d){
            var bb = this.getBBox();
            console.log("bb.width = ", bb.width);
            console.log("bb.height = ", bb.height);
            return "translate(0, 0)";
          }
        );

Not only does this draw the string "100%" on my screen, but in the console.log, it also outputs the width and height of the bounding box (24 & 11.5 respectively!);

Now I want to visualize the aforementioned bounding box on the screen. So before the code above, I prepend the following code:

        var rect = svgContainer.append("rect")
          .attr("x", 200)
          .attr("y", 200-11.5)
          .attr("width", 24)
          .attr("height", 11.5)
          .attr("fill", "pink");

When I run this altered code, I expect to see a pink bounding box around the "100%" string. But I see the following instead!

enter image description here

Why is the pink bounding box taller than the text? I need to get the dimensions of the actual bounding-box of the text -- not something taller than it. How do I do that?

Here is the Plunker: https://plnkr.co/edit/XoVSZwTBNXhdKKJKkYWn

like image 850
Saqib Ali Avatar asked Jan 22 '26 04:01

Saqib Ali


1 Answers

There are two things going on here:

  1. You are only using the height and width fields of the bounding box. You should be also taking into account the x and y attributes of the bounding box - as @Gilsha correctly pointed out. When you do adjust for the x and y, you'll see the box sits a little lower:

var svg = document.getElementById("my_svg_widget");

    
var bbox = svg.getElementById("test").getBBox();

var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", bbox.x);
rect.setAttribute("y", bbox.y);
rect.setAttribute("width", bbox.width);
rect.setAttribute("height", bbox.height);
rect.setAttribute("fill", "rgba(255, 0, 0, 0.5)");
svg.appendChild(rect);
<svg id="my_svg_widget" width="300" height="300" style="border-style:solid;border-color:purple;border-width: 2px;">
  <text id="test" x="100" y="100" font-family="Courier New" font-weight="bold" font-size="50px">100%</text>
</svg>
  1. This brings us to the second reason. The bounding box returned by getBBox() is not the tight bounding box around the glyphs. It includes the full em-box height of the text - including allowance for ascenders (tallest characters in font) and descenders (lowest below baseline).

You can see what I mean if we include some of those characters in the text element.

var svg = document.getElementById("my_svg_widget");

    
var bbox = svg.getElementById("test").getBBox();

var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", bbox.x);
rect.setAttribute("y", bbox.y);
rect.setAttribute("width", bbox.width);
rect.setAttribute("height", bbox.height);
rect.setAttribute("fill", "rgba(255, 0, 0, 0.5)");
svg.appendChild(rect);
<svg id="my_svg_widget" width="300" height="300" style="border-style:solid;border-color:purple;border-width: 2px;">
  <text id="test" x="100" y="100" font-family="Courier New" font-weight="bold" font-size="50px">&#193;100%&#x2563;</text>
</svg>
like image 191
Paul LeBeau Avatar answered Jan 24 '26 19:01

Paul LeBeau



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!