1

I have the following code (jsfiddled). I want to use red SVG rectangle as a handle for draggable div element, but because the SVG element is not a child of div, it is not possible. The idea is to let the handle (red rect) fire drag event of div and when div is being dragged, the code updates position of red SVG rectangle. How can I get SVG rectangle to act as drag handle for the div (so that SVG element is not a child of div element)?

I have tested to make SVG a child of div and used SVG rect as handle, and this worked normally. When I dragged SVG rect, the div and SVG rect were moved while dragging. But the problem is that also SVG element itself is dragged. But I don't want that SVG element itself is moved while dragging, only rect and div.

EDIT: Some sort of triggering drag event of div when pressing mouse on svg rect comes to my mind as a possible solution, but not tested yet.

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>jQuery UI Draggable - Handles</title>
        <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.0/themes/base/jquery-ui.css" />
        <script src="http://code.jquery.com/jquery-1.8.2.js"></script>
        <script src="http://code.jquery.com/ui/1.9.0/jquery-ui.js"></script>
        <style>
            #draggable { position:absolute; opacity:0.5;
    width: 100px; height: 100px; padding: 0.5em; float: left; margin: 0 10px 10px 0; }
           #draggable p { cursor: move; }
           #draggable {left:30px;top:0px;z-index:1}
        </style>
        <script>
            $(function() {
                $( "#draggable" ).draggable({ handle: "p" });
                $( "div, p" ).disableSelection();
            });
        </script>
    </head>
    <body>
        <div id="draggable" class="ui-widget-content">
            <p class="ui-widget-header">I can be dragged only by this handle</p>
        </div>
        <svg width="500" height="500" style="position:absolute;z-index:-1">
            <rect x="0" y="0" width="100" height="100" fill="#FF8888"/>
        </svg>
    </body>
</html>
Timo Kähkönen
  • 11,962
  • 9
  • 71
  • 112
  • I don't understand your question. If the svg is not supposed to be dragged, how do you want to use it as a handle? If the handle does not move, why should the target? – StrubT Oct 12 '12 at 18:29
  • SVG element is the "top" element, like is BODY element. They should not be moved, only the red rectangle which is a child of SVG element and the div which is a child of BODY element. – Timo Kähkönen Oct 12 '12 at 18:32
  • OK, now I understand. You might want to have a look at the following question: http://stackoverflow.com/questions/5744068/drag-div-by-handle-that-is-not-nested. – StrubT Oct 12 '12 at 18:43
  • The accepted answer there is "One possible solution could be to have the handle inside, but use css to position it outside." Which seems to mean that handle should be child of div. But I don't understand how to fit the principle in my problem. How to append SVG rect to child of div, but so that SVG root element is not being dragged? – Timo Kähkönen Oct 12 '12 at 18:52
  • Do you need any of the extra functionality that jQuery UI draggable provides? In this case it's more straightforward implementing in puer javascript. – methodofaction Oct 13 '12 at 08:33
  • Yes I need. And it seems to be possible to trigger drag event on mousedown of SVG rect: http://stackoverflow.com/a/6091655/1691517. – Timo Kähkönen Oct 13 '12 at 10:07
  • Some sort of workaround would be to use combination of the div.trigger(e) and in draggable div's drag-function update SVG rect's transform attribute like this: http://jsfiddle.net/dYw9v/ . It relies on pointer-events:none in div, so not works in Opera, but in other browsers yes. – Timo Kähkönen Oct 13 '12 at 10:18

1 Answers1

2

After some testing I ended up to use combination of div.trigger(e) and updating SVG rect's transform attribute in draggable div's drag-function this jsfiddled way.

The key point is the following code, which triggers div's drag event when pressing mouse on SVG path element:

$("#path_1").mousedown(function(e) {
    $( "#div_1" ).trigger(e);
});

And the other key point is the following, which updates SVG path element's transform attribute to achieve movement:

drag: function(e, ui)
{
    var x=$( "#div_1" )[0].style.left;
    var y=$( "#div_1" )[0].style.top;
    x = parseInt(x);
    y = parseInt(y);
    $( "#path_1" ).attr("transform", "translate("+x+","+y+")");
}

It relies on pointer-events:none in div, so not works in Opera, but in other new browsers yes. There is a hack to allow pointer-events:none, but better to wait that all newest browsers allow it natively. And pointer-events is not problem in the question's example because red rectangle is not fully below div.

Jsfiddle example can be extended to eg. make a selection rectangle functionality for SVG elements, if you want to use jQuery Draggable plugin for dragging SVG's graphical objects and want to use divs as selection rectangles. (Other possible solution to selection rectangles is to use two SVG root elements, one for selection rectangles and one for actual shapes.)

And using setTimeout() we can force that always when div is moved, also SVG path is moved.

Timo Kähkönen
  • 11,962
  • 9
  • 71
  • 112