Firefox -- Dynamically embedding <svg> element in SVG
I am trying dynamically to append an <svg>
element to an existing SVG island on an XHTML page (Firefox 3.6.3). And it is crashing the browser.
Done manually, this works as expected:
<svg xmlns="http://www.w3.org/2000/svg">
<svg xmlns="http://www.w3.org/2000/svg">
...
</svg>
</svg>
However, if you dynamically add this element using JavaScript, the browser crashes. Simple example:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SVG island example</title>
<script type="text/javascript"><![CDATA[
function crash( )
{
svgs = document.getElementsByTagNameNS( "http://www.w3.org/2000/svg", "svg" );
for ( var i = 0; i < svgs.length; i++ )
{
var e = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
svgs[i].appendChild( e );
}
}
]]></script>开发者_JAVA技巧;
</head>
<body>
<svg id="mySVG" xmlns="http://www.w3.org/2000/svg">
</svg>
<button onclick="crash()">Crash Firefox</button>
</body>
</html>
Interestingly, if I do a getElementById
, it works fine. Interesting, but not particularly helpful in my situation since I'm storing pointers to SVGDocument
s. Example:
function doesntCrash( )
{
var svg = document.getElementById( "mySVG" );
var e = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
svg.appendChild( e );
}
As far as I can tell, this is a Firefox bug. Does anyone have any insight into this matter?
UPDATED (solution):
As stated below, the issue was the "liveness" of the HTMLCollection
returned by the getElementsByTagNameNS
call which I mistook for a native array (tsk, tsk!) A quick hackaround would be to either store the array length in a variable, if you're only appending. A better solution might be to copy the array contents to a native array, as described here. Here's an updated using that method:
function doesntCrash( )
{
var svgs = document.getElementsByTagNameNS( "http://www.w3.org/2000/svg", "svg" );
// copy contents to native a static, array
svgs = Array.prototype.slice.call( svgs );
for ( var i = 0; i < svgs.length; i++ )
{
var e = document.createElementNS( "http://www.w3.org/2000/svg", "svg" );
svgs[i].appendChild( e );
}
}
Thank you Sergey Ilinsky for your quick response!
The cause to your problem is likely hidden in liveness of the NodeSet returned by the getElementByTagName(NS) method call (which is not the case for querySelectorAll method, for example). So in your code you find all elements with name "svg" from SVG namespace, then start walking through this list and add new "svg" elements to the document that end up added to the collection you are walking too. Teoretically script simply should never exit, but in practice as you see browser crashes.
精彩评论