GetBBox of SVG when hidden
Asked Answered
D

3

7

I'm trying to solve this problem for more than one day now, but I can't find an answer. My problem is that I need to scale an SVG image (responsive design). I need to manipulate the SVG code on the client side, so embedding it via img tag is not an option. Therefore I tried to use an inline image instead. However, to scale it properly it seems that I need to set the viewBox property. The SVG files are generated by some software which can't set the bounding box on it's own, so my idea was to use JavaScript for that purpose.

The problem is that my software uses various tab controls from a library which I can't modify. I can't just get the bounding box, because it's not rendered initially and therefore I just get back zeros (in Chrome) or error messages (in Firefox).

What I need is a way to get the size of the bounding box without actually rendering the object. It is not possible to manipulate the display parameter, which the library uses to show and hide tabs.

Any ideas?

One idea was to copy the SVG into another, visible div, but I don't know if that would solve the problem. And I don't know how to do it.

Best regards

Dislike answered 2/2, 2015 at 16:31 Comment(5)
Why can't you wait until the tab control has rendered before sizing your viewBox?Iolite
Because there seems to be no view state changed event for the SVG and the possibilities of my tab library are quite limited.Alessandro
I solved my problem by searching the right svg image via it's id using JQuery.Alessandro
Could you clarify your solution, I don't understand. I have a similar problem.Agog
Well, I added an ID tag to each inline svg and selected this ID via jQuery. But I can't remember the details.Alessandro
K
5

Based on the previous answers, I monkeypatched getBBox on my app init so it will transparently apply the hack.

Now I can call getBBox directly on any element, whether it's attached or not.

_getBBox = SVGGraphicsElement.prototype.getBBox;   
SVGGraphicsElement.prototype.getBBox = function() {
  var bbox, tempDiv, tempSvg;
  if (document.contains(this)) {
    return _getBBox.apply(this);
  } else {
    tempDiv = document.createElement("div");
    tempDiv.setAttribute("style", "position:absolute; visibility:hidden; width:0; height:0");
    if (this.tagName === "svg") {
      tempSvg = this.cloneNode(true);
     } else {
      tempSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      tempSvg.appendChild(this.cloneNode(true));
    }
    tempDiv.appendChild(tempSvg);
    document.body.appendChild(tempDiv);
    bbox = _getBBox.apply(tempSvg);
    document.body.removeChild(tempDiv);
    return bbox;
  }
};
Katusha answered 2/8, 2017 at 15:40 Comment(6)
This does not work. This method is not called when I call getBBox() on svg elementMaltz
@EugeneMala it's been working for us for a few years 🤷‍♂️Katusha
It is not working for dynamically created svg elements: element = document.createElementNS("http://www.w3.org/2000/svg", 'path');element.getBBox() // does not workMaltz
@EugeneMala that works fine for me. See jsfiddle.net/diegose/aodstg9b/6 (the path needs to have something in it, of course)Katusha
@EugeneMala sorry, this is the right version: jsfiddle.net/diegose/aodstg9b/7. Look at the console on the right. JSON.stringify seems to ignore all the fields.Katusha
Sorry, my mistake. In my code I was modifying SVGGraphicsElement prototype after getBBox() calculation.Maltz
S
2

you can clone it to a visible svg and then getBBox.

Add into you html:

<div style="position:absolute;left:-9999cm;top:-9999cm;visibility:hidden;">
  <svg id="svg1" xmlns="http://www.w3.org/2000/svg"></svg>
</div>

Add into your javascript:

function getBBox(elem){
    var svg1 = document.getElementById('svg1'), e = elem.cloneNode(true);
    e.style.display = "inline";
    svg1.appendChild(e);
    var b = e.getBBox();
    svg1.removeChild(e);
    return b;
}
Schwartz answered 15/1, 2016 at 9:4 Comment(0)
S
2

cuixiping's answer as a function:

function svgBBox (svgEl) {
  let tempDiv = document.createElement('div')
  tempDiv.setAttribute('style', "position:absolute; visibility:hidden; width:0; height:0")
  document.body.appendChild(tempDiv)
  let tempSvg = document.createElementNS("http://www.w3.org/2000/svg", 'svg')
  tempDiv.appendChild(tempSvg)
  let tempEl = svgEl.cloneNode(true)
  tempSvg.appendChild(tempEl)
  let bb = tempEl.getBBox()
  document.body.removeChild(tempDiv)
  return bb
}
Shaw answered 15/6, 2017 at 9:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.