@@ -38,24 +38,44 @@ dragElement.unhoverRaw = unhover.raw;
3838 * - Freezes the cursor: whatever mouse cursor the drag element had when the
3939 * interaction started gets copied to the coverSlip for use until mouseup
4040 *
41+ * If the user executes a drag bigger than MINDRAG, callbacks will fire as:
42+ * prepFn, moveFn (1 or more times), doneFn
43+ * If the user does not drag enough, prepFn and clickFn will fire.
44+ *
45+ * Note: If you cancel contextmenu, clickFn will fire even with a right click
46+ * (unlike native events) so you'll get a `plotly_click` event. Cancel context eg:
47+ * gd.addEventListener('contextmenu', function(e) { e.preventDefault(); });
48+ * TODO: we should probably turn this into a `config` parameter, so we can fix it
49+ * such that if you *don't* cancel contextmenu, we can prevent partial drags, which
50+ * put you in a weird state.
51+ *
52+ * If the user clicks multiple times quickly, clickFn will fire each time
53+ * but numClicks will increase to help you recognize doubleclicks.
54+ *
4155 * @param {object } options with keys:
4256 * element (required) the DOM element to drag
4357 * prepFn (optional) function(event, startX, startY)
4458 * executed on mousedown
4559 * startX and startY are the clientX and clientY pixel position
4660 * of the mousedown event
47- * moveFn (optional) function(dx, dy, dragged)
48- * executed on move
61+ * moveFn (optional) function(dx, dy)
62+ * executed on move, ONLY after we've exceeded MINDRAG
63+ * (we keep executing moveFn if you move back to where you started)
4964 * dx and dy are the net pixel offset of the drag,
5065 * dragged is true/false, has the mouse moved enough to
5166 * constitute a drag
52- * doneFn (optional) function(dragged, numClicks, e)
53- * executed on mouseup, or mouseout of window since
54- * we don't get events after that
55- * dragged is as in moveFn
67+ * doneFn (optional) function(e)
68+ * executed on mouseup, ONLY if we exceeded MINDRAG (so you can be
69+ * sure that moveFn has been called at least once)
70+ * numClicks is how many clicks we've registered within
71+ * a doubleclick time
72+ * e is the original mouseup event
73+ * clickFn (optional) function(numClicks, e)
74+ * executed on mouseup if we have NOT exceeded MINDRAG (ie moveFn
75+ * has not been called at all)
5676 * numClicks is how many clicks we've registered within
5777 * a doubleclick time
58- * e is the original event
78+ * e is the original mousedown event
5979 */
6080dragElement . init = function init ( options ) {
6181 var gd = options . gd ;
@@ -68,7 +88,9 @@ dragElement.init = function init(options) {
6888 newMouseDownTime ,
6989 cursor ,
7090 dragCover ,
71- initialTarget ;
91+ initialEvent ,
92+ initialTarget ,
93+ rightClick ;
7294
7395 if ( ! gd . _mouseDownTime ) gd . _mouseDownTime = 0 ;
7496
@@ -78,10 +100,6 @@ dragElement.init = function init(options) {
78100 element . ontouchstart = onStart ;
79101
80102 function onStart ( e ) {
81- if ( e . buttons && e . buttons === 2 ) { // right click
82- return ;
83- }
84-
85103 // make dragging and dragged into properties of gd
86104 // so that others can look at and modify them
87105 gd . _dragged = false ;
@@ -90,6 +108,8 @@ dragElement.init = function init(options) {
90108 startX = offset [ 0 ] ;
91109 startY = offset [ 1 ] ;
92110 initialTarget = e . target ;
111+ initialEvent = e ;
112+ rightClick = ( e . buttons && e . buttons === 2 ) || e . ctrlKey ;
93113
94114 newMouseDownTime = ( new Date ( ) ) . getTime ( ) ;
95115 if ( newMouseDownTime - gd . _mouseDownTime < DBLCLICKDELAY ) {
@@ -104,11 +124,11 @@ dragElement.init = function init(options) {
104124
105125 if ( options . prepFn ) options . prepFn ( e , startX , startY ) ;
106126
107- if ( hasHover ) {
127+ if ( hasHover && ! rightClick ) {
108128 dragCover = coverSlip ( ) ;
109129 dragCover . style . cursor = window . getComputedStyle ( element ) . cursor ;
110130 }
111- else {
131+ else if ( ! hasHover ) {
112132 // document acts as a dragcover for mobile, bc we can't create dragcover dynamically
113133 dragCover = document ;
114134 cursor = window . getComputedStyle ( document . documentElement ) . cursor ;
@@ -136,7 +156,7 @@ dragElement.init = function init(options) {
136156 dragElement . unhover ( gd ) ;
137157 }
138158
139- if ( options . moveFn ) options . moveFn ( dx , dy , gd . _dragged ) ;
159+ if ( gd . _dragged && options . moveFn && ! rightClick ) options . moveFn ( dx , dy ) ;
140160
141161 return Lib . pauseEvent ( e ) ;
142162 }
@@ -167,27 +187,36 @@ dragElement.init = function init(options) {
167187 numClicks = Math . max ( numClicks - 1 , 1 ) ;
168188 }
169189
170- if ( options . doneFn ) options . doneFn ( gd . _dragged , numClicks , e ) ;
171-
172- if ( ! gd . _dragged ) {
173- var e2 ;
174-
175- try {
176- e2 = new MouseEvent ( 'click' , e ) ;
177- }
178- catch ( err ) {
179- var offset = pointerOffset ( e ) ;
180- e2 = document . createEvent ( 'MouseEvents' ) ;
181- e2 . initMouseEvent ( 'click' ,
182- e . bubbles , e . cancelable ,
183- e . view , e . detail ,
184- e . screenX , e . screenY ,
185- offset [ 0 ] , offset [ 1 ] ,
186- e . ctrlKey , e . altKey , e . shiftKey , e . metaKey ,
187- e . button , e . relatedTarget ) ;
190+ if ( gd . _dragged ) {
191+ if ( options . doneFn ) options . doneFn ( e ) ;
192+ }
193+ else {
194+ if ( options . clickFn ) options . clickFn ( numClicks , initialEvent ) ;
195+
196+ // If we haven't dragged, this should be a click. But because of the
197+ // coverSlip changing the element, the natural system might not generate one,
198+ // so we need to make our own. But right clicks don't normally generate
199+ // click events, only contextmenu events, which happen on mousedown.
200+ if ( ! rightClick ) {
201+ var e2 ;
202+
203+ try {
204+ e2 = new MouseEvent ( 'click' , e ) ;
205+ }
206+ catch ( err ) {
207+ var offset = pointerOffset ( e ) ;
208+ e2 = document . createEvent ( 'MouseEvents' ) ;
209+ e2 . initMouseEvent ( 'click' ,
210+ e . bubbles , e . cancelable ,
211+ e . view , e . detail ,
212+ e . screenX , e . screenY ,
213+ offset [ 0 ] , offset [ 1 ] ,
214+ e . ctrlKey , e . altKey , e . shiftKey , e . metaKey ,
215+ e . button , e . relatedTarget ) ;
216+ }
217+
218+ initialTarget . dispatchEvent ( e2 ) ;
188219 }
189-
190- initialTarget . dispatchEvent ( e2 ) ;
191220 }
192221
193222 finishDrag ( gd ) ;
0 commit comments