0

I'm relatively new to javascript, and am learning about drag and drop using snap.svg. My problem is in the drop. I can't tell if the dragged element is over the drop target. In this code, I want to drag the circle over the square, and thought I could use mouseover. My (distilled) example may also be a simpler version of this post.

var paper = Snap(300, 300);
var square = paper.rect(100, 100, 40, 40).attr({fill:"blue"});
var circle = paper.circle(50, 50, 20).attr({fill:"red"});

circle.drag();
square.mouseover(
        function() {
            console.log("Over the square");
        }
);

As written, the mouseover will fire when you move the pointer over the blue square, but not when you drag the red circle over the blue square. If you reverse the creation of the square and circle, the mouseover fires either way, but of course the circle is behind the square.

Evidently the event gets caught in the view hierarchy (or something) and doesn't propagate. There must be an easy way around this. Any help?

(And if the best answer is, "use jQuery," fine, but I'd love to learn how to make this work directly, since snap.svg makes dragging so easy.)

Addition: The direction I'm hoping for: the snap.svg documentation for Element.drag() says, in part, "When Element is dragged over another element, drag.over.<id> fires as well." A fine, event-based direction, which would let me (for example) highlight the drop target without a lot of fuss.

But I haven't figured out how to listen for that event! Any help or advice?

Community
  • 1
  • 1
Tim Erickson
  • 582
  • 5
  • 15
  • I think this is a bit fiddly unless I'm missing something, as to stop the event of the circle and allow the mouseover means that it would prevent the drag from working. So I think this isn't going to work in some 'simple' drag way. Options that spring to mind that 'may' work, are to add some box collision type detection within the drag handler, or maybe attaching the handler to the paper, but then you have none intuitive dragging going on, that will probably get fiddly and may not work anyway. – Ian Jan 06 '16 at 20:48
  • And yet, when the circle is behind the square/target, the square gets the event AND the drag continues. – Tim Erickson Jan 07 '16 at 03:54

1 Answers1

1

Only quick way without collision or element detection from points that I can think of, is to place an almost invisible clone in front of the object, later in the DOM that you can't really see, eg ...

paper.append( square.clone().attr({ opacity: 0.000001 }) )

jsfiddle

Depends how complex your svgs are going to be as to whether this would work I guess, you also have a slight issue if you drop the element over it, your redrag start won't get picked up, so you would need to code around that as well. I think some testing is probably going to be the most bug free solution (there are a few solutions on S.O for getElementFromPoint or hit detection type solutions).

jsfiddle workaround for point above

Ian
  • 13,724
  • 4
  • 52
  • 75
  • Cool! Sneaky! I may go this way, or just compute the circle's position when I drop it. But I'd love to do this in some more elegant, object-oriented, event-driven way. I've added a little to my original post based on further digging; if you have a clue how to use `drag.over.` I'd be grateful :) – Tim Erickson Jan 19 '16 at 18:00
  • I think it depends what one is after. Ie its quite different to detect mouse is over an element as opposed to one element is slightly over another etc, especially if greater accuracy than bounding box detection is needed. – Ian Jan 19 '16 at 19:48
  • Looking at Snap code, I think this was commented out. I suspect because it relies on el.getIntersectionList which I think has had buggy or non-existing support in some browsers (think it was an issue in firefox). You may need to roll your own comparing bounding boxes of required elements vs mouse events. – Ian Jan 19 '16 at 20:36
  • Thanks; I'll keep poking at it... :) – Tim Erickson Jan 20 '16 at 21:06