2

Is it possible to create an SVG tag in jQuery like so:

var dragSVG = $('<svg xmlns="http://www.w3.org/2000/svg"></svg>');
dragSVG.append('<rect x="0" y="0" width="20" height="20" style="fill:red"></rect>');

And then if so, how does one get access to the DOM? ie. If it were HTML I'd do the following:

return dragSVG.html();

But as it isn't HTML this throws an exception... Or am I missing something completely fundamental!?

EDIT:

I'll try to explain what I'm try to achieve a bit more clearly; I have a button that represents an SVG 'item' that can be dragged onto a main SVG canvas. When the user starts dragging I want to display the SVG 'item' under the mouse to provide user-feedback. When the user drops this onto the canvas I need to move the 'item' onto the main canvas.

      $('#testBtnDrag').draggable({
          opacity: 0.7,
          revert: 'invalid',
          cursorAt: { top: 0, left: 0},
          helper: function (event) {
              var dragSVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><rect x="0" y="0" width="20" height="20" style="fill:red"></rect></svg>';
              return dragSVG;
          }              
      });

      // I can't attach the droppable to the SVG tag directly, IE / FF don't work with this
      // so we have to attach it to a <div> tag that wraps the <svg>.
      $('#drawArea').droppable({
        accept: '.svg-item',
        drop: function (event, ui) {
          // Get the mouse offset relative to the <svg> canvas
          var posX = event.originalEvent.clientX - $(this).offset().left;
          var posY = event.originalEvent.clientY - $(this).offset().top;

          // Get the dragged element and put it onto the "main" canvas
          var rawSVG = ui.helper.children().html()  // This won't work!
          var mainCanvas = $('#drawArea > svg');
          mainCanvas.append(rawSVG);
        }
      });

  });
Siyfion
  • 979
  • 1
  • 12
  • 32

4 Answers4

5

A <svg>, <path> etc. are SVGAnimatedString objects, and jQuery itself can not produce them, because is using createElement function for tags creation. Simple hack of jQuery looks like:

enter image description here

    // line 526 in jquery-X.X.X.js, in my case it is jquery-1.9.1.js   
    // Single tag
    if ( parsed ) {
        // ----------------------------------------------------
        var xml_html_element;
        if ( parsed[1] == "svg" || parsed[1] == "path" ) {
            xml_html_element = context.createElementNS( "http://www.w3.org/2000/svg", parsed[1] );
        } else {
            xml_html_element = context.createElement( parsed[1] );
        }
        return [xml_html_element];
        // ----------------------------------------------------
        //return [ context.createElement( parsed[1] ) ];

    }

Now, you can use jQuery like:

var $svg = $("<svg>").attr({'version': "1.1"});
var $path = $("<path>").attr({
    'd': 'M' + 10 + ',' + 100 + ' C' + 200 + ',' + 150 + ' ' + 200 + ',' + 170 + ' ' + 300 + ',' + 250,
    'fill': "none",
    'stroke': "rgba(100,100,100,0.9)",
    'stroke-width': "1"
});
var $body = $("body");
$body.append($svg.append($path));

Of course, for your personal necessary you may expand the number of SVG tags in this hack:

parsed[1] == "svg" || parsed[1] == "path" || parsed[1] == "line" || etc. ...   
Ruben Kazumov
  • 3,803
  • 2
  • 26
  • 39
  • 1
    List of all `svg` tags you can see there: https://developer.mozilla.org/en-US/docs/SVG/Element – Ruben Kazumov Feb 20 '13 at 17:04
  • 2
    +1, but something tells me that directly editing jquery source is probably not the best way to solve this. – Wex Feb 19 '14 at 18:20
  • It is just a funny lightweight trick like an experiment and for private usage. It is not for commercial usage of course! – Ruben Kazumov Feb 19 '14 at 23:03
  • I guess in the case of production you'd make a simple function, maybe call it `$svg`, which takes in a SVG tag, creates the SVG DOM element, and then wraps it in a jQuery object. – Wex Feb 20 '14 at 17:42
2

SVG is essentially an XML file format. Try parseXML() instead. If this doesn't work try http://keith-wood.name/svggraphRef.html.

inVader
  • 1,504
  • 14
  • 25
  • ParseXML allows me to use jQuery functions on XML as if it were html, but I don't think it will allow me to get access back to the "raw" DOM will it? See my edit above. – Siyfion Aug 03 '12 at 10:16
  • I'm still a little confused. What you call your SVG canvas is actually a
    and you are drawing your to another
    that gets moved around on the canvas?
    – inVader Aug 03 '12 at 10:21
  • Sorry, I didn't want to confuse the issue by going right down into the nitty-gritty, but I'm using the Raphael SVG library to create the "Main Canvas" inside the
    tag with id "drawArea". So while your answer helps tremendously when it comes to traversing the main canvas element, I still can't see how to get the tag out of the ui.helper
    – Siyfion Aug 03 '12 at 10:25
  • Well, I don't know about the Raphael library but maybe you could just stick to a simpler approach? Have a look here http://www.pnorg.org/index.php?race=2, this is some game I have written. The svg image is directly coded into the webpage. If you move the mouse over the chat messages I do use simple getElementById() to move the bubble image around the track. I'm not sure if any of this will help you, but just have a look. – inVader Aug 03 '12 at 10:29
2

Don't hack JQuery; just create a simple one-line function that creates an SVG element and wrap the returned element in JQuery, then you can use whatever JQuery functions you want on it, viz:

    function createSvg(tagName) {
        return document.createElementNS("http://www.w3.org/2000/svg", tagName);
    }
    function sayHi() { 
        alert('hi'); 
    }
    $(document).ready(function() {
        var svg = $(createSvg("svg"))
            .attr('width', 500)
            .attr('height', 500);
        $('body').append(svg);
        var rect = $(createSvg("rect"))
            .attr("id","rect1")
            .attr("x","20")
            .attr("y","150")
            .attr("height","72")
            .attr("width","120")
            .attr("rx","20")
            .attr("stroke","black")
            .attr("fill","white");
        $("svg").append(rect);
        $("#rect1").on("click", sayHi);
        $("#rect1").attr("x",150);
    });
HalNoyes
  • 21
  • 1
-1

I have used SVG with jQuery and there is no need to change anything within jQuery core library. You simply need to generate svg tag like below

var svg = $('<svg></svg>').attr('xmlns','http://www.w3.org/2000/svg');

with jquery and add this to dom via $('body').html(svg); jQuery then treats it a dom object and you can call any dom related methods on this tag like you can add attributes etc. You can keep the var svg in global scope so you can use for further reference and also you can assign an id or class attribute so you can access it using jquery.

Imran Khan
  • 358
  • 3
  • 16
  • This does not work, as the SVG will not render if it is created using the XHTML namespace. – Wex Feb 18 '14 at 17:27