Load an SVG image where the elements become part of the DOM

Consider this simple page:

<html>
<body>
   <svg width="250" height="250">
      <g>
         <path id="foo" d="M20,230 Q40,205 50,230 T90,230" stroke="red" stroke-width="3" fill="none" onclick="setBlue()" />
      </g>
   </svg>
   <script>
      function setBlue() {
         document.getElementById("foo").setAttribute("stroke", "blue");
      }
   </script>
</body>
</html>

It will display a red squiggly line. If you click on the line, it will turn blue. This demonstrates that JavaScript functionality is working inside this SVG object and also that the path element foo was added to the DOM itself.

Now instead load a static SVG that a browser could cache:

<img width="250" height="250" src="images/somesvg.svg" />

The embedded JavaScript does not hit. Asking the DOM for foo via JavaScript or jQuery returns nothing.

Does this mean the only way to name elements inside the SVG or to add JavaScript functionality is via rendering the SVG inside the HTML itself? I could shorten a page up significantly if I could add IDs to paths in an SVG file and then access them.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

If it is an external *.svg file, A native Web Component <load-file> can fetch it and inject it in the DOM; either in shadowDOM or replacing the <load-file> Element, thus becoming part of the DOM you can access and style with CSS.

customElements.define("load-file", class extends HTMLElement {

  // declare default connectedCallback as async so await can be used
  async connectedCallback(
    // call connectedCallback with parameter to *replace* SVG (of <load-file> persists)
    src = this.getAttribute("src"),
    // attach a shadowRoot if none exists (prevents displaying error when moving Nodes)
    shadowRoot = this.shadowRoot || this.attachShadow({mode:"open"})
  ) {
      // load SVG file from src="" async, parse to text, add to shadowRoot.innerHTML
    shadowRoot.innerHTML = await (await fetch(src)).text()

    // append optional <tag [shadowRoot]> Elements from inside <load-svg> after parsed <svg>
    shadowRoot.append(...this.querySelectorAll("[shadowRoot]"))

    // if "replaceWith" attribute 
    // then replace <load-svg> with loaded content <load-svg>
    // childNodes instead of children to include #textNodes also
    this.hasAttribute("replaceWith") && this.replaceWith(...shadowRoot.childNodes)
  }
})

Full explanation in Dev.To post: 〈load-file〉Web Component, add external content to the DOM

Method 2

As @diopside and @RobertLongson mention in the comments, the question was asked a different way here: Do I use <img>, <object>, or <embed> for SVG files?

The solution was to use <object> and embed the SVG in that. Now I can interact with it yet the browser doesn’t need to reload the image each time the page loads.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x