|
1 d3.behavior.drag = function() { |
|
2 var event = d3.dispatch("drag", "dragstart", "dragend"); |
|
3 |
|
4 function drag() { |
|
5 this |
|
6 .on("mousedown.drag", mousedown) |
|
7 .on("touchstart.drag", mousedown); |
|
8 |
|
9 d3.select(window) |
|
10 .on("mousemove.drag", d3_behavior_dragMove) |
|
11 .on("touchmove.drag", d3_behavior_dragMove) |
|
12 .on("mouseup.drag", d3_behavior_dragUp, true) |
|
13 .on("touchend.drag", d3_behavior_dragUp, true) |
|
14 .on("click.drag", d3_behavior_dragClick, true); |
|
15 } |
|
16 |
|
17 // snapshot the local context for subsequent dispatch |
|
18 function start() { |
|
19 d3_behavior_dragEvent = event; |
|
20 d3_behavior_dragEventTarget = d3.event.target; |
|
21 d3_behavior_dragOffset = d3_behavior_dragPoint((d3_behavior_dragTarget = this).parentNode); |
|
22 d3_behavior_dragMoved = 0; |
|
23 d3_behavior_dragArguments = arguments; |
|
24 } |
|
25 |
|
26 function mousedown() { |
|
27 start.apply(this, arguments); |
|
28 d3_behavior_dragDispatch("dragstart"); |
|
29 } |
|
30 |
|
31 drag.on = function(type, listener) { |
|
32 event.on(type, listener); |
|
33 return drag; |
|
34 }; |
|
35 |
|
36 return drag; |
|
37 }; |
|
38 |
|
39 var d3_behavior_dragEvent, |
|
40 d3_behavior_dragEventTarget, |
|
41 d3_behavior_dragTarget, |
|
42 d3_behavior_dragArguments, |
|
43 d3_behavior_dragOffset, |
|
44 d3_behavior_dragMoved, |
|
45 d3_behavior_dragStopClick; |
|
46 |
|
47 function d3_behavior_dragDispatch(type) { |
|
48 var o = d3.event, p = d3_behavior_dragTarget.parentNode, dx = 0, dy = 0; |
|
49 |
|
50 if (p) { |
|
51 p = d3_behavior_dragPoint(p); |
|
52 dx = p[0] - d3_behavior_dragOffset[0]; |
|
53 dy = p[1] - d3_behavior_dragOffset[1]; |
|
54 d3_behavior_dragOffset = p; |
|
55 d3_behavior_dragMoved |= dx | dy; |
|
56 } |
|
57 |
|
58 try { |
|
59 d3.event = {dx: dx, dy: dy}; |
|
60 d3_behavior_dragEvent[type].apply(d3_behavior_dragTarget, d3_behavior_dragArguments); |
|
61 } finally { |
|
62 d3.event = o; |
|
63 } |
|
64 |
|
65 o.preventDefault(); |
|
66 } |
|
67 |
|
68 function d3_behavior_dragPoint(container, type) { |
|
69 // TODO Track touch points by identifier. |
|
70 var t = d3.event.changedTouches; |
|
71 return t ? d3.svg.touches(container, t)[0] : d3.svg.mouse(container); |
|
72 } |
|
73 |
|
74 function d3_behavior_dragMove() { |
|
75 if (!d3_behavior_dragTarget) return; |
|
76 var parent = d3_behavior_dragTarget.parentNode; |
|
77 |
|
78 // O NOES! The drag element was removed from the DOM. |
|
79 if (!parent) return d3_behavior_dragUp(); |
|
80 |
|
81 d3_behavior_dragDispatch("drag"); |
|
82 d3_eventCancel(); |
|
83 } |
|
84 |
|
85 function d3_behavior_dragUp() { |
|
86 if (!d3_behavior_dragTarget) return; |
|
87 d3_behavior_dragDispatch("dragend"); |
|
88 d3_behavior_dragTarget = null; |
|
89 |
|
90 // If the node was moved, prevent the mouseup from propagating. |
|
91 // Also prevent the subsequent click from propagating (e.g., for anchors). |
|
92 if (d3_behavior_dragMoved && d3_behavior_dragEventTarget === d3.event.target) { |
|
93 d3_behavior_dragStopClick = true; |
|
94 d3_eventCancel(); |
|
95 } |
|
96 } |
|
97 |
|
98 function d3_behavior_dragClick() { |
|
99 if (d3_behavior_dragStopClick && d3_behavior_dragEventTarget === d3.event.target) { |
|
100 d3_eventCancel(); |
|
101 d3_behavior_dragStopClick = false; |
|
102 d3_behavior_dragEventTarget = null; |
|
103 } |
|
104 } |