import “../core/document”; import “../core/rebind”; import “../event/drag”; import “../event/event”; import “../event/mouse”; import “../event/touches”; import “behavior”;

d3.behavior.drag = function() {

var event = d3_eventDispatch(drag, "drag", "dragstart", "dragend"),
    origin = null,
    mousedown = dragstart(d3_noop, d3.mouse, "mousemove", "mouseup"),
    touchstart = dragstart(touchid, touchposition, "touchmove", "touchend");

function drag() {
  this.on("mousedown.drag", mousedown)
      .on("touchstart.drag", touchstart);
}

function touchid() {
  return d3.event.changedTouches[0].identifier;
}

function touchposition(parent, id) {
  return d3.touches(parent).filter(function(p) { return p.identifier === id; })[0];
}

function dragstart(id, position, move, end) {
  return function() {
    var target = this,
        parent = target.parentNode,
        event_ = event.of(target, arguments),
        eventTarget = d3.event.target,
        eventId = id(),
        drag = eventId == null ? "drag" : "drag-" + eventId,
        origin_ = position(parent, eventId),
        dragged = 0,
        offset,
        w = d3.select(d3_window).on(move + "." + drag, moved).on(end + "." + drag, ended),
        dragRestore = d3_event_dragSuppress();

    if (origin) {
      offset = origin.apply(target, arguments);
      offset = [offset.x - origin_[0], offset.y - origin_[1]];
    } else {
      offset = [0, 0];
    }

    event_({type: "dragstart"});

    function moved() {
      if (!parent) return ended(); // target removed from DOM

      var p = position(parent, eventId),
          dx = p[0] - origin_[0],
          dy = p[1] - origin_[1];

      dragged |= dx | dy;
      origin_ = p;

      event_({type: "drag", x: p[0] + offset[0], y: p[1] + offset[1], dx: dx, dy: dy});
    }

    function ended() {
      w.on(move + "." + drag, null).on(end + "." + drag, null);
      dragRestore(dragged && d3.event.target === eventTarget);
      event_({type: "dragend"});
    }
  };
}

drag.origin = function(x) {
  if (!arguments.length) return origin;
  origin = x;
  return drag;
};

return d3.rebind(drag, event, "on");

};