Robyk62
Robyk62

Reputation: 3

Loading svg using innerHTML

I'm trying to inject SVG gradient definitions from external file using 'innerHTML' to keep my HTML clean.

It works fine in Chrome but not in Safari or Mobile Safari. Any idea or workaround?

Here is a simplified example (the second gradient in injected, in the real word the html is requested from server):

<html>
  <body>
    <svg width="0" height="0">
      <defs>
        <linearGradient id="grad1" x2="0" y2="1"> <stop offset="0" stop-color="#ffff00"/><stop offset="1" stop-color="#ff0000"/> </linearGradient>
      </defs>
    </svg>
    <svg width="0" height="0" id="svg-grad"></svg>    
    <script>
      function inject_svg() {
        var gr2=document.getElementById('svg-grad');
        html='<defs><linearGradient id="grad2"><stop offset="0"  stop-color="#ffff00"/><stop offset="1" stop-color="#ff0000"/> </linearGradient></defs>';
        gr2.innerHTML=html;
      }
    </script>    
    <svg width="200" height="200">
       <rect fill="url(#grad1)" x="20" y="20" width="50" height="150"/>
       <rect fill="url(#grad2)" x="100" y="20" width="50" height="150"/>
    </svg>
    <button onclick="inject_svg();">inject</button>
  </body>
</html>

In jsfiddle: http://jsfiddle.net/wPL4n/

Upvotes: 0

Views: 3900

Answers (2)

Robert Longson
Robert Longson

Reputation: 124299

It's probably adding things in the html namespace rather than the SVG namespace. Try using DOMParser instead and also setting an explicit namespace for the data (i.e. xmlns="http://www.w3.org/2000/svg" on the root element of the data).

<svg width="0" height="0" id="svg-grad"></svg>

<script>
  function inject_svg() {
    var gr2=document.getElementById('svg-grad');
    html='<defs xmlns="http://www.w3.org/2000/svg"><linearGradient id="grad2"><stop offset="0"  stop-color="#ffff00"/><stop offset="1" stop-color="#ff0000"/> </linearGradient></defs>';
    var xmlDoc = new DOMParser().parseFromString(html, "text/xml");
    gr2.appendChild(xmlDoc.documentElement);
  }
</script>

<svg width="200" height="200">
   <rect fill="url(#grad1)" x="20" y="20" width="50" height="150"/>
   <rect fill="url(#grad2)" x="100" y="20" width="50" height="150"/>
</svg>
<button onclick="inject_svg();">inject</button>

Upvotes: 3

dnozay
dnozay

Reputation: 24344

older webkit

You can use the innersvg.js polyfill.

Based on webkit bug tracker: https://bugs.webkit.org/show_bug.cgi?id=136903, this problem is caused by different implementations of the DOM spec; specifically, innerHTML/outerHTML is defined on HTMLElement and SVGElement is not a subclass.

webkit r176637+

2014-12-02 : This issue should be fixed :)

The patch r176630 changes that behavior and moves the definition up one level so they can be shared across HTMLElement and SVGElement and have a behavior closer to competing browsers/rendering engines.

If you live on the edge, you can get the new nightly build, e.g. webkit r176637 (note: I have not tried it out yet).

Upvotes: 1

Related Questions