6

I am trying to use SVG markup in my HTML in order to render some graphics. The problem was very tricky because I just realized that the issue is when generating the SVG programmatically.

The markup

What I want to end up in my page is this fragment of code:

<svg>
  <circle cx="20" cy="20" r="15"></circle>
</svg>

If you take this and paste it inside a page, all is fine and the a black circle is rendered!

Creating the SVG dynamically

But I want to create this content using Javascript, so I have this:

var container = document.createElement("div");
var svg = document.createElement("svg");

var circle = document.createElement("circle");
circle.setAttribute("cx", "20");
circle.setAttribute("cy", "20");
circle.setAttribute("r", "15");

svg.appendChild(circle);
container.appendChild(svg);
document.body.appendChild(container);

Well, try to execute this in fiddle or in your browser and you'll see it will not be rendered. When you inspect the HTML, you see that the circle is not taking any space.

What is the problem?

Andry
  • 16,172
  • 27
  • 138
  • 246
  • Possible duplicate of [How do I manipulate the SVG DOM and create elements?](http://stackoverflow.com/questions/8320002/how-do-i-manipulate-the-svg-dom-and-create-elements) –  Dec 15 '16 at 09:57

3 Answers3

15

you have to use "document.createElementNS("http://www.w3.org/2000/svg", "svg");" to create svg elements

var container = document.createElement("div");
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");

var circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", "20");
circle.setAttribute("cy", "20");
circle.setAttribute("r", "15");

svg.appendChild(circle);
container.appendChild(svg);
document.body.appendChild(container);
Azad
  • 5,144
  • 4
  • 28
  • 56
  • I tried in `svg` but I thought that it was not needed in `circle`... I see thanks. But why is it needed in `circle`? The `xmlns` in `svg` is a globally included ns, so it should work on all nested elements... – Andry Dec 15 '16 at 10:04
  • 1
    you have to create svg dom elements from svg namespace (`"http://www.w3.org/2000/svg"`) by calling `document.createElementNS` instead of `document.createElement` – Azad Dec 15 '16 at 10:07
  • Yes I understand that. So, what I tried is invoking the `createElementNS` on the `svg` element only. It did not work as it looks like, by your answer, that I also need `createElementNS` on the `circle` element as well. Well, my question is: why is it not enough only on `svg`? When you use `xmlns` on the svg element, everything inside that element will see the schema, so no need to specify `xmlns` on `circle` as well... – Andry Dec 15 '16 at 10:11
  • @Andry the namespace of an element is set on creation and is not altera ble afterwards. – Robert Longson Dec 15 '16 at 10:17
  • see this answer http://stackoverflow.com/questions/32637811/how-can-i-add-a-svg-graphic-dynamically-using-javascript-or-jquery – Azad Dec 15 '16 at 10:21
  • In 2018, is it still required that we use the name space "http://www.w3.org/2000/svg". When rendering in HTML I do not need to, it just seems messy and expensive. – Andrew S May 18 '18 at 21:36
  • @Andry, please see my answer below, I solved it without calling `createElementNS()` on child elements. – Levon May 06 '21 at 08:30
2

While you have to use document.createElementNS("http://www.w3.org/2000/svg", "svg"); to create the parent svg element, you are not strictly required to use that method for the child elements to get a functioning graphic on your page. Calling createElementNS() for each child could become especially cumbersome if you are using a more complex image, with multiple paths, defs, style, title, etc, for example something exported from a drawing program.

A quicker way that worked well for me, is to create the parent svg element, and then add all its contents in one go as innerHTML. Your specific example could be solved like so:

var container = document.createElement("div");
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
var svgContent = '<circle cx="20" cy="20" r="15"></circle>';

svg.innerHTML = svgContent;
container.appendChild(svg);
document.body.appendChild(container);
Levon
  • 1,681
  • 2
  • 18
  • 40
-2

<svg>
  <circle cx="20" cy="20" r="15"></circle>
</svg>
  • what is this? the asker wants it to be generated dynamically, this is wrong – I_love_vegetables Jul 09 '21 at 08:38
  • This appears to be nothing more than copying part of the question and does not answer anything. It is also missing the mandatory XML namespace declaration to be a correct solution. – penguin359 Jul 09 '21 at 09:47