Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to work with jquery and Svg directly (no plugins)?

I'm trying to work with Jquery and Svg together. But I don´t want to use any plugin.

The problem I am dealing now is that when I try to work using the traditional append mode to add a child to the svg document, the object is not rendered. Let´s check out what I tried to do:

/* Creating the svg container using pure JS */
var container = document.getElementById("svg_space");
mySvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
mySvg.setAttribute("version", "1.2");
mySvg.setAttribute("baseProfile", "tiny");
container.appendChild(mySvg);

/* Adding a child and setting attributes to the SVG container using pure JS */
Circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
Circle.setAttribute("cx", "60");
Circle.setAttribute("cy", "30");
Circle.setAttribute("r", "13");
Circle.setAttribute("class", "class1");
    mySvg.appendChild(Circle); /* After this, the circle is rendered */

/* Then, I tried to use jQuery to perform the same action... */
$(mySvg).append("<circle />");
$(mySvg).find("circle").attr("cx","160");
$(mySvg).find("circle").attr("cy","70");
$(mySvg).find("circle").attr("r","30");
$(mySvg).find("circle").attr("class","class1" );

...but after this action, the circle does not render. I check if at least the circle was really appended to the DOM tree in the Developers Tool Inspector, and I found out that both element exist, with the proper attributes previously set, but the circle created with jQuery was as if it were a html descendant, not as a svg descendant. This means that the constructors, prototypes and other methods related to a svg circle element was not part of the this 'jquery' circle, but instead the related to a pure html tag.

Is there a way to create svg elements as svg descendants using jquery, or is better the use of pure javascript despite the loss of productivity?

like image 804
Jesufer Vn Avatar asked May 27 '11 06:05

Jesufer Vn


2 Answers

Haven't been able to try, but I bet this would work. Instead of

$(mySvg).append("<circle />");

Do

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

If you plan on doing this more than once, maybe

function svgEl(tagName) {
    return document.createElementNS("http://www.w3.org/2000/svg", tagName);
}

$(mySvg).append(svgEl("circle"));

This is the same as the old trick of getting better performance via $(document.createElement("div")) instead of $("<div />").

like image 60
Domenic Avatar answered Nov 19 '22 14:11

Domenic


This works in Chrome 11. Haven't tried in other browsers.

$(mySvg).append("<svg><circle /></svg>");
$(mySvg).find("circle").unwrap();
$(mySvg).find("circle").attr("cx","160");
$(mySvg).find("circle").attr("cy","70");
$(mySvg).find("circle").attr("r","30");
$(mySvg).find("circle").attr("class","class1" );

As I understand it, jQuery parses html by passing the string to the browser's native HTML parser. The HTML parsing rules assign a namespace to the element based on its name and its ancestor elements, so to get the circle element into the svg namespace it needs to be parsed inside an svg element.

So here, it is parsed and appended inside the <svg> element and then unwrap is called to remove the extra svg element created. This append-and-unwrap pattern is somewhat ugly, and I expect that someone with better jQuery knowledge can find a more elegant solution, but the concept is clear enough.

like image 4
Alohci Avatar answered Nov 19 '22 14:11

Alohci