I abused JQuery UI's "draggable" on the HTML elements, which gave me:
* "start," "stop," and "drag" events
* an API for creating helpers
"droppable" doesn't work on SVG, though, so…
* I created my own drag-drop model object.
* I attached "mouseover" and "mouseout" events to the candidate SVG elements
SVG:
MouseOver on the SVG element updated the drag-drop model with information on what element the cursor was over
MouseOut would clear that information
Draggable:
Start registered the dragged item with the drag-drop model
Stop used logic in the drop manager to determine if the dragged item and the dropped item were compatible.
If so, I executed my application logic for what should happen for a successful drop
If not, I just cleared both the dragged item and the over item from the model.
There were a couple of tricky things:
* The helper has to be moved out from under the cursor. If your helper is directly under the cursor, mouseOver / mouseOut events won't trigger on the underlying SVG elements (they appear to be intercepted by the helper instead)
* From the draggable's standpoint, the element always "reverts" ("revert: true"). So on Drag I pre-tested whether or not a drop would be successful, and set the revertDuration to 0 if it was. If it wasn't, I used a revert duration of 300.
At no point in this process did I use D3 -- I only used D3 for the drawing, not the drag-drop implementation.
I'll try to write up some sample code if I can claw some time away from other things -- what I have written now is pretty deeply infected with AngularJS.