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:
- How to load SVG from a file using svg.js?
- 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