8

I have an SVG page with some complex diagrams; I'm trying to add code that inserts even more complexity via an Ajax call on demand. This is mostly working, but the inserted nodes don't behave properly. In particular getBBox() fails on some elements, in Firefox the error is something like this:

uncaught exception: [Exception... "Component returned failure code: 0x80004005  (NS_ERROR_FAILURE) [nsIDOMSVGLocatable.getBBox]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: http://localhost:1555/svg-scripts.js :: addBackground :: line 91"  data: no]

The problem seems to be related to this one: https://bugzilla.mozilla.org/show_bug.cgi?format=multiple&id=612118 but in my case the objects are definitely rendered, I can see them.

Any insight or workarounds appreciated. Unfortunately I can't easily point to an example since this relies on a server interaction.

Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
mtraven
  • 179
  • 1
  • 7
  • An Example would be advantageous. Wouldn't it be possible to reproduce this bug by simply simulating the async environment via `setTimeout`? – basecode Nov 18 '12 at 22:56

2 Answers2

8

See https://bugzilla.mozilla.org/show_bug.cgi?id=612118 (SVGLocatable.getBBox() fails unless the SVG element it is applied to is attached and rendered).

You must put your element to SVG and style.display must be non-"none".

See also SVG 'getBBox' fails in a jQueryUI tab

I workaround issue by placing text at invisible area ([-1000; -1000]):

function SVGlibText(x, y, text) {
    this.value = document.createElementNS(SVGlibBase.svgNS, "text");
    this.value.setAttribute("x", x);
    this.value.setAttribute("y", y);
    this.value.textContent = text;
}
SVGlibText.prototype.moveTo = function(x, y) {
    this.value.setAttribute("x", x);
    this.value.setAttribute("y", y);
    return this;
}
SVGlibText.prototype.getW = function() {
    return this.value.getBBox().width;
}
SVGlibText.prototype.getH = function() {
    return this.value.getBBox().height;
}

var text = new SVGlibText(-1000, -1000, "Hello world!");

getting width/height:

var textW = text.getW();
var textH = text.getH();

and placing text to necessary position after calculation with width/height (which require width/height in order to determine position of text):

text.moveTo(off, off + textH);
Community
  • 1
  • 1
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • 1
    the SVG element should be rendered by the broswer first and then the api getBBox().width can be available,so @gavenkoa post the right answer. – LightStalker Apr 30 '14 at 08:39
  • 2
    The key for me was that the svg element cannot have the style.display none. – cw24 Jun 11 '14 at 22:53
0

The NS_ERROR_FAILURE error message, or

Exception { message: "", result: 2147500037, name: "NS_ERROR_FAILURE", ...}`)

also occurs if you try to calculate the bounding box of an SVGElement which is attached directly to the HTML DOM and does not have a parent SVGSVGElement. Examples (you can run the code in Scratchpad, Shift+F4 in Firefox):

text directly attached to body

This fails because <html><body><g></g></body></html> is not allowed.

var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
document.body.appendChild(text)
text.getBBox()
/*
Exception: [Exception... "Failure"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: "JS frame :: Scratchpad/2 :: <TOP_LEVEL> :: line 3"  data: no]
*/

text attached to svg

This works.

var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
svg.appendChild(text);
document.body.appendChild(svg)
text.getBBox()
/*
[object SVGRect]
*/
Simon A. Eugster
  • 4,114
  • 4
  • 36
  • 31