Home > Mobile >  Load SVG from file and display it in existing SVG using svg.js
Load SVG from file and display it in existing SVG using svg.js

Time:02-05

I want to load an SVG from a file and then place it in an existing HTML SVG element (i.e, a group) using svg.js

I am facing two issues:

  1. How to load SVG from a file using svg.js?
  2. Add the loaded SVG to an existing SVG created with svg.js?

Sorry, but I am somehow lost on this task and hope someone is kind enough to help me on that.

CodePudding user response:

No need for a library.

<div>
  <svg viewBox="0 0 500 300">
    <style>
      svg { height: 180px;background:pink  } 
      path { fill: green }
    </style>
    <heart width="250" x="0" y="0"/>
    <australia x="250" y="0" width="250"/>
  </svg>

  <load-svg to="heart" src="//svg-cdn.github.io/heart.svg"></load-svg>
  <load-svg to="australia" src="//svg-cdn.github.io/map-australia.svg"></load-svg>
</div>

<script>
  customElements.define('load-svg', class extends HTMLElement {
    async connectedCallback() {
      this.attachShadow({mode:"open"})
          .innerHTML = await (await fetch(this.getAttribute("src"))).text();
      let svg = this.shadowRoot.querySelector("svg");
      let to = this.getAttribute("to");
      let container = this.parentNode.querySelector(to);
      for(const attr of container.attributes) {
        svg.setAttribute(attr.name,attr.value);
      }
      container.replaceWith(svg);
      this.remove(); // Web Component did its job
    }
  });
</script>

A native JavaScript Web Component is the best solution, because you don't have to worry about when the HTML is parsed or when the Web Component is defined.

  • Existing <load-svg> tags will be upgraded when the Web Component is defined.
  • newly created <load-svg> tags will execute

Alas native JavaScript Web Components only work in the HTML NameSpace,
not in the SVG NameSpace, so

<svg>
  <inject-svg src="...">
</svg>

is not possible.

That means we have to place the <load-svg> Web Component outside the SVG.


this.attachShadow({mode:"open"})
    .innerHTML = await (await fetch(this.getAttribute("src"))).text();

Loads the external SVG file and injects it into the Web Component shadowDOM


let svg = this.shadowRoot.querySelector("svg");
let to = this.getAttribute("to");
let container = this.parentNode.querySelector(to);

Loads a reference to the SVG in shadowDOM.
And a reference to the <heart> or <australia> locations inside our own SVG. Note: These are a HTMLUnknownElement, they don't do anything in HTML (but behave like a DIV), we are just using them as temporary containers.


for(const attr of container.attributes) {
  svg.setAttribute(attr.name,attr.value);
}

Assign all the attributes from our temporary container to the SVG in shadowDOM


container.replaceWith(svg);

Now the SVG in shadowDOM is complete and can take its place in our main SVG


If you inject SVGs with different viewBox settings x and y positioning is a pain,
because x="0" y="0" won't be top-left of the main SVG.
I presume a SVG guru will know a setting for this.

CodePudding user response:

The solution provided is a very complicated approach to a rather simple problem. Just load the svg with Ajax (jquery, axios, fetch) and then use it:

// your group
const group = canvas.group() 
// add svg
SVG(svg string).addTo(group)

The comment to your question also suggests to use the import function

group.svg(svg string)

That will by no means create a new svg but put it into the group

  • Related