问题
https://jsfiddle.net/swoq9g3f/1/
I am having a problem where a simple SVG is drawn incorrectly in Internet Explorer (v11.0.9600.17728) after I change a xlink:href
with javascript.
If you render just the SVG in IE you get two concentric circles. The javascript sets the xlink:href
value for a <use>
element to #def1
, which is the value it was previously. After this IE renders only the larger circle, with the smaller circle hidden behind it. The smaller circle is later in the svg document meaning that it should always render on top of the larger circle. I also included some calls to forceRedraw()
, but they fail to correct the issue.
This problem does not happen in Chrome or Firefox. What is causing this? Is there a way to work around the problem?
SVG:
<svg id="svg_element" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400">
<defs>
<svg id="def1" width="300" height="300">
<g>
<circle cx="150" cy="150" r="100" />
<circle cx="150" cy="150" r="50" />
</g>
</svg>
<svg id="def2">
<use id="use_element" xlink:href="#def1" />
</svg>
</defs>
<g fill="white" stroke="black" >
<use xlink:href="#def2" />
</g>
</svg>
Javascript:
document.getElementById("use_element").setAttributeNS('http://www.w3.org/1999/xlink','href','#def1')
document.getElementById("def1").forceRedraw()
document.getElementById("def2").forceRedraw()
document.getElementById("svg_element").forceRedraw()
回答1:
I found a workaround for the problem.
https://jsfiddle.net/swoq9g3f/9/
It seems that changing things in the <defs>
does not always trigger a full repaint, so I then have to trick it into doing a repaint afterwards. In this example I found changing the <use>
in the <g>
in the top level of the SVG correctly triggered a repaint.
SVG:
<svg id="svg_element" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400">
<defs>
<svg id="def1" width="300" height="300">
<g>
<circle cx="150" cy="150" r="100" />
<circle cx="150" cy="150" r="50"/>
</g>
</svg>
<svg id="def2">
<use id="use_element" xlink:href="#def1" />
</svg>
</defs>
<g fill="white" stroke="black">
<use id="use_element_2" xlink:href="#def2" />
</g>
</svg>
Javascript:
document.getElementById("use_element").setAttributeNS('http://www.w3.org/1999/xlink','href','#def1')
document.getElementById("use_element_2").setAttributeNS('http://www.w3.org/1999/xlink','href','#def2')
回答2:
This happens in IE when updating xlink:href="..."
, but also when updating clip-path=url(...)
. The problem is that the DOM isn't up to date and needs to be refreshed, which can be forced manually.
To force an update (an immediate, synchronous reflow or relayout), you can read an element property like offsetTop
. This forces the browser to repaint the element before it can give you the offsetTop
value.
This is mentioned in this talk: Faster HTML and CSS: Layout Engine Internals for Web Developers (at 37:10)
I use this function, and whenever I have changed an svg I call this.
function repaintThisElement(element){
var tmp = 0;
if (navigator.appName == 'Microsoft Internet Explorer'){
tmp = elementOnShow.parentNode.offsetTop + 'px';
}else{
tmp = elementOnShow.offsetTop;
}
}
来源:https://stackoverflow.com/questions/30127078/internet-explorer-draws-svg-incorrectly-when-updating-xlinkhref-for-a-use-ele