d3.behavior.drag = function() {
var event = d3.dispatch("drag", "dragstart", "dragend");
function drag() {
this
.on("mousedown.drag", mousedown)
.on("touchstart.drag", mousedown);
d3.select(window)
.on("mousemove.drag", d3_behavior_dragMove)
.on("touchmove.drag", d3_behavior_dragMove)
.on("mouseup.drag", d3_behavior_dragUp, true)
.on("touchend.drag", d3_behavior_dragUp, true)
.on("click.drag", d3_behavior_dragClick, true);
}
// snapshot the local context for subsequent dispatch
function start() {
d3_behavior_dragEvent = event;
d3_behavior_dragEventTarget = d3.event.target;
d3_behavior_dragOffset = d3_behavior_dragPoint((d3_behavior_dragTarget = this).parentNode);
d3_behavior_dragMoved = 0;
d3_behavior_dragArguments = arguments;
}
function mousedown() {
start.apply(this, arguments);
d3_behavior_dragDispatch("dragstart");
}
drag.on = function(type, listener) {
event.on(type, listener);
return drag;
};
return drag;
};
var d3_behavior_dragEvent,
d3_behavior_dragEventTarget,
d3_behavior_dragTarget,
d3_behavior_dragArguments,
d3_behavior_dragOffset,
d3_behavior_dragMoved,
d3_behavior_dragStopClick;
function d3_behavior_dragDispatch(type) {
var o = d3.event, p = d3_behavior_dragTarget.parentNode, dx = 0, dy = 0;
if (p) {
p = d3_behavior_dragPoint(p);
dx = p[0] - d3_behavior_dragOffset[0];
dy = p[1] - d3_behavior_dragOffset[1];
d3_behavior_dragOffset = p;
d3_behavior_dragMoved |= dx | dy;
}
try {
d3.event = {dx: dx, dy: dy};
d3_behavior_dragEvent[type].apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
} finally {
d3.event = o;
}
o.preventDefault();
}
function d3_behavior_dragPoint(container, type) {
// TODO Track touch points by identifier.
var t = d3.event.changedTouches;
return t ? d3.svg.touches(container, t)[0] : d3.svg.mouse(container);
}
function d3_behavior_dragMove() {
if (!d3_behavior_dragTarget) return;
var parent = d3_behavior_dragTarget.parentNode;
// O NOES! The drag element was removed from the DOM.
if (!parent) return d3_behavior_dragUp();
d3_behavior_dragDispatch("drag");
d3_eventCancel();
}
function d3_behavior_dragUp() {
if (!d3_behavior_dragTarget) return;
d3_behavior_dragDispatch("dragend");
d3_behavior_dragTarget = null;
// If the node was moved, prevent the mouseup from propagating.
// Also prevent the subsequent click from propagating (e.g., for anchors).
if (d3_behavior_dragMoved && d3_behavior_dragEventTarget === d3.event.target) {
d3_behavior_dragStopClick = true;
d3_eventCancel();
}
}
function d3_behavior_dragClick() {
if (d3_behavior_dragStopClick && d3_behavior_dragEventTarget === d3.event.target) {
d3_eventCancel();
d3_behavior_dragStopClick = false;
d3_behavior_dragEventTarget = null;
}
}