10

I have a SVG in my document and I add a symbol to it with JavaScript like this:

var myScene =document.getElementById('myScene');
var useSVG = document.createElement('use');
useSVG.setAttribute('xlink:href','spriteSheet.svg#mySymbol');
useSVG.setAttribute('x','10');
useSVG.setAttribute('y','30');
useSVG.setAttribute('width','10');
useSVG.setAttribute('height','10');
myScene.appendChild(useSVG);

The symbol does not show up whereas the resulting code is exactly the same as another node written in HTML which is displayed correctly.

Code shown in debugger:

<svg id="myScene" width="200px" height="200px">
    <use xlink:href="spriteSheet.svg#mySymbol" x="5" y="50" width="10" height="10"></use>
    <!-- this one was in html, it is visible -->
    <use xlink:href="spriteSheet.svg#mySymbol" x="10" y="30" width="10" height="10"></use>
    <!-- this one is added with javascript. it is not displayed -->
</svg>
Jason Aller
  • 3,541
  • 28
  • 38
  • 38
bokan
  • 3,601
  • 2
  • 23
  • 38
  • 1
    the answer below is not enough but points to the right direction. Here you also have to use `document.createElementNS` instead of `document.createElement` to create the `use` element. This [answer](http://stackoverflow.com/questions/16488884/add-svg-element-to-existing-svg-using-dom) solved the similar problem. – King King Sep 20 '14 at 10:41
  • I've tried everything, I can't make it work. Can't find a working example neither. My solution is to give an ID to the hard coded USE tag and duplicate it with node.cloneNode(). Still looking for a working example. – bokan Sep 20 '14 at 12:23

4 Answers4

15

You need to use createElementNS() to create SVG elements. The basic createElement() creates elements in the HTML namespace. So you basically have been creating <html:use> elements instead of <svg:use> ones.

var myScene =document.getElementById('myScene');
var useSVG = document.createElementNS('http://www.w3.org/2000/svg', 'use');
useSVG.setAttributeNS('http://www.w3.org/1999/xlink','href','spriteSheet.svg#mySymbol');
useSVG.setAttribute('x','10');
useSVG.setAttribute('y','30');
useSVG.setAttribute('width','10');
useSVG.setAttribute('height','10');
myScene.appendChild(useSVG);

Demo here

Update

I have just realised there is a second problem with your code. You are using an external reference in your href (it's referenceing a symbol in another file). It seems IE doesn't support external references.

I found more info, and a possible workaround, here: http://css-tricks.com/svg-use-external-source/

Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • Thank you... but it works in Chrome and Firefox, but not in IE 10. Do you have an Idea why ? – bokan Sep 20 '14 at 14:35
  • You might need to do `useSVG.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href','spriteSheet.svg#mySymbol');` on IE. Try that. If it still doesn't work, please post a jsfiddle so we can see your code. – Paul LeBeau Sep 20 '14 at 20:00
  • Still doesn't work. Maybe it's because I use a SVG symbol, I,ll try later with groups – bokan Sep 21 '14 at 10:57
3

I am not sure to 100% but I think you need to set the xlink:href Attribute using setAttributeNS() like this:

useSVG.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', 'spriteSheet.svg#mySymbol');

Also make sure that the namespace is declared within your document.

<html xmlns:xlink="http://www.w3.org/1999/xlink">

<!-- or if standalone svg -->

<svg xmlns:xlink="http://www.w3.org/1999/xlink">

However, this way I solved the same issue within an xhtml document, probably that will work for html5 or standalone SVG, too.

xlink specification

good luck!

philipp
  • 15,947
  • 15
  • 61
  • 106
  • 1
    Just tried it, it doesn't work ;( Thank you anyway. It does write href attribute without the 'xlink' of xlink:href. – bokan Sep 20 '14 at 09:22
0

In general, to create SVG elements you must use createElementNS(), not createElement(). But even then, createElementNS() won't properly create an SVG "use" element. It appears to work, but the resulting "use" won't be displayed.

Workaround 1: clone an existing "use" element, then modify it via setAttributeNS(). (In my experience, setAttribute() also works on SVG elements.)

var useSVG = another_useSVG.cloneNode(true);
myScene.appendChild(useSVG);
useSVG.setAttribute('xlink:href','spriteSheet.svg#mySymbol');

Workaround 2: create a group element, then assign it's innerHTML to get the desired "use" element.

var myScene = document.getElementById('myScene');
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
group.innerHTML = "<use xlink:href='spriteSheet.svg#mySymbol' x='10' y='30' width='10' height='10'/>";
Kevin Sterns
  • 76
  • 1
  • 4
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 14 '21 at 12:00
0

I had exactly the same problem and I just figured it out! When creating the svg element with document.createElement("svg"), you just have to use the correct namespace. And it works even with other elements like path, line, rect etc

So this

document.createElement("svg");

Becomes that

document.createElementNS("http://www.w3.org/2000/svg","svg");

And this

document.createElement("use");

Becomes that

document.createElementNS("http://www.w3.org/2000/svg","use");

In case you wondering, you don't have to use element.setAttributeNS, element.setAttribute will work

MiftikCZ
  • 21
  • 4