d3.behavior.drag = function() { var x = 0, y = 0, listeners = [], dragit function drag() { var container = this .on("mousedown", mousedown) } function mousedown(d, i) { // Pick up on where we left before // NOTE: Are regexes necessary? var prevtrans = d3.select(this).attr('transform'); d3.select(window) .on("mousemove", mousemove) .on("mouseup", mouseup); if (prevtrans) { var reg = prevtrans.match(/translate\((\d+),(\d+)\)/i) x = reg[1]; y = reg[2]; } else { x = 0; y = 0; } // Replace x and y with new coordinates dragit = { x0: x - d3.event.clientX, y0: y - d3.event.clientY, target: this, data: d, index: i }; d3.event.preventDefault(); window.focus(); // TODO focusableParent } function mousemove() { if (dragit) { x = d3.event.clientX + dragit.x0; y = d3.event.clientY + dragit.y0; dispatch.call(dragit.target, dragit.data, dragit.index); } } function mouseup() { d3.select(window) .on("mousemove", null) .on("mouseup", null); if (dragit) { mousemove(); dragit = null; } } function dispatch(d, i) { var o = d3.event // Events can be reentrant (e.g., focus). d3.event = { translate: [x, y] }; try { for (var j = 0, m = listeners.length; j < m; j++) { listeners[j].call(this, d, i); } } finally { d3.event = o; } } drag.on = function(type, listener) { if (type == "drag") listeners.push(listener); return drag; }; return drag; };