Question

Second update: if I include the path and the circle from the beginning (hard code it) everything works why does jquery append not update the dom?

update: I realized I should have checked my example as it did not have everything I had made in my actual code.

I am trying to draw a svg line with a circle at the end and record its locations in a JavaScript object. However I’m running into some trouble getting the image to show up and I’m baffled as to why, no relevant firebug or chrome messages show up. Here is my code:

Here is updated code

<!doctype html>
<html lang="en">
    <head>
    <meta charset="utf-8">
    <title>demo</title>
    <style>
        input{
        border: none;
        background: inherit;
        }
        body{
        font-family: Courier New;
        }
        .point{
        width: 10px;
        height: 10px;
        border:0px solid;
        border-radius:5px;
        background: #000099;
        z-index: 9999;
        }
        #drawnLine{
        }
        .identification{
        position: absolute;
        background: #ddd;
        width: 200px;
        z-index: 9888;
        top:0;
        left:0;
        }
        #subjectImage{
        margin: auto;
        height: 100%;
        display: block;
        z-index: 1;
        }
    </style>
    </head>
    <body>
    <svg id="drawing" xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:100%; height:100%; position:absolute; top:0; left:0; z-index:2">

    </svg>
    <button class="identification" onmousedown="drawLine(this)" id="tests" >test</button>
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
    <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
    <script>
        var zindexParts = 100;
        var mouseDX = 0;
        var mouseDY = 0;
        var part = {
        id: 'Ganglion',
        name: {
            location: {
            x: 0, y: 0, z: 0
            }
        },
        line: {
            stroke: "blue",
            strokewidth: "3",
            beginning: {
            x: 0, y: 0, z: 0,
            circle: {
                cx: 0,
                cy: 0,
                r: 5
            }
            },
            end: {
            x: 0, y: 0, z: 0,
            circle: {
                cx: 0,
                cy: 0,
                r: 5
            }
            }
        }
        };
        function drawLine(line) {
        $(line).mousedown(function(e) {
            part.line.beginning.x = $(this).position().left + ($(this).width() / 2);
            part.line.beginning.y = $(this).position().top + ($(this).height() / 2);
            $('body').mousemove(function(ee) {
                part.line.end.circle.cx = ee.pageX;
                part.line.end.circle.cy = ee.pageY;
                part.line.end.x = ee.pageX;
                part.line.end.y = ee.pageY;
                $('#' + part.id + 'Circle').attr({cx: part.line.end.circle.cx, cy: part.line.end.circle.cy});
                $('#' + part.id + 'Line').attr('d', 'M ' + part.line.beginning.x + ' ' + part.line.beginning.y + ' L ' + part.line.end.x + ' ' + part.line.end.y);
            });
        });
        }
        $(function() {
        $(".draggable").draggable();
        $('body').mouseup(function(e) {
            $('body').off('mousemove');
        });
        $('#drawing').append('<path id="' + part.id + 'Line" class="drawnLine" style="z-index:' + zindexParts++ + '" d="M 0 0 L 0 0" stroke="blue" stroke-width="3"/><circle id="' + part.id + 'Circle" class="point draggable ui-widget-content"style="z-index:' + zindexParts++ + '" cx="-999" cy="-999" r="' + part.line.end.circle.r + '" />');
        });
    </script>
    </body>
 </html>

and here is the dom results of clicking the test button:

<svg id="drawing" xmlns="http://www.w3.org/2000/svg" version="1.1" style="width:100%; height:100%;  top:0; left:0; z-index:2">
    <path id="GanglionLine" class="drawnLine" style="z-index:100" d="M 0 0 L 0 0" stroke="blue" stroke-width="3"></path>
    <circle id="GanglionCircle" class="point draggable ui-widget-content" style="z-index:101" cx="9" cy="9" r="5"></circle>
</svg>
Was it helpful?

Solution

jQuery puts the dynamically generated elements in the HTML namespace, but they have to be in the SVG namespace. You see that if you add the following code after the section $('#drawing').append(...):

alert((new XMLSerializer()).serializeToString(document.getElementById("drawing")));

This will give you something like:

<svg style="width:100%; height:100%; position:absolute; top:0; left:0; z-index:2" version="1.1"
  xmlns="http://www.w3.org/2000/svg" id="drawing">
  <path xmlns="http://www.w3.org/1999/xhtml" stroke-width="3" stroke="blue" d="M 0 0 L 0 0"
    style="z-index:100" class="drawnLine" id="GanglionLine"/>
  <circle xmlns="http://www.w3.org/1999/xhtml" r="5" cy="-999" cx="-999" style="z-index:101"
    class="point draggable ui-widget-content" id="GanglionCircle"/>
</svg>

Note the <path xmlns="http://www.w3.org/1999/xhtml" ...> part.

To work around this, you might resort to plain DOM manipulation methods, or you could use DOMParser:

$('#drawing').append((new DOMParser()).parseFromString(
  '<g xmlns="http://www.w3.org/2000/svg"><path id="' + part.id + 'Line" class="drawnLine" style="z-index:' + zindexParts++ + '" d="M 0 0 L 0 0" stroke="blue" stroke-width="3"/><circle id="' + part.id + 'Circle" class="point draggable ui-widget-content" style="z-index:' + zindexParts++ + '" cx="-999" cy="-999" r="' + part.line.end.circle.r + '" /></g>', 
  "image/svg+xml"
).documentElement);

Note that you have to wrap everything into a <g> element for two reasons:

  • .parseFromString() needs well formed XML syntax with exactly one root element
  • You need to declare the SVG namespace somewhere (but you could also do this on the <circle> and <path> elements as well)

This gets you halfway there. Your code still produces a zero length line and an offscreen circle.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top