toolkit/javascript/d3/src/behavior/drag.js
changeset 47 c0b4a8b5a012
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolkit/javascript/d3/src/behavior/drag.js	Thu Apr 10 14:20:23 2014 +0200
@@ -0,0 +1,104 @@
+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;
+  }
+}