Internet Explorer draws SVG incorrectly when updating xlink:href for a <use> element

纵饮孤独 提交于 2021-01-27 18:20:33

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!