@@ -10,10 +10,10 @@ var classNames = require('classnames');
10
10
//
11
11
12
12
function createUIEvent ( draggable ) {
13
- // State changes are often (but not always!) async. We want the latest value.
14
- var state = draggable . _pendingState || draggable . state ;
13
+ // State changes are often (but not always!) async. We want the latest value.
14
+ var state = draggable . _pendingState || draggable . state ;
15
15
return {
16
- node : draggable . getDOMNode ( ) ,
16
+ node : draggable . getDOMNode ( ) ,
17
17
position : {
18
18
top : state . clientY ,
19
19
left : state . clientX
@@ -126,18 +126,20 @@ function removeEvent(el, event, handler) {
126
126
}
127
127
128
128
function snapToGrid ( draggable , clientX , clientY ) {
129
- var directionX = clientX < parseInt ( draggable . state . clientX , 10 ) ? - 1 : 1 ;
130
- var directionY = clientY < parseInt ( draggable . state . clientY , 10 ) ? - 1 : 1 ;
129
+ var stateX = parseInt ( draggable . state . clientX , 10 ) ;
130
+ var stateY = parseInt ( draggable . state . clientY , 10 ) ;
131
+ var directionX = clientX < stateX ? - 1 : 1 ;
132
+ var directionY = clientY < stateY ? - 1 : 1 ;
131
133
132
- clientX = Math . abs ( clientX - parseInt ( draggable . state . clientX , 10 ) ) >= draggable . props . grid [ 0 ] ?
133
- ( parseInt ( draggable . state . clientX , 10 ) + ( draggable . props . grid [ 0 ] * directionX ) ) :
134
- draggable . state . clientX ;
134
+ clientX = Math . abs ( clientX - stateX ) >= draggable . props . grid [ 0 ] ?
135
+ ( stateX + ( draggable . props . grid [ 0 ] * directionX ) ) :
136
+ stateX ;
135
137
136
- clientY = Math . abs ( clientY - parseInt ( draggable . state . clientY , 10 ) ) >= draggable . props . grid [ 1 ] ?
137
- ( parseInt ( draggable . state . clientY , 10 ) + ( draggable . props . grid [ 1 ] * directionY ) ) :
138
- draggable . state . clientY ;
138
+ clientY = Math . abs ( clientY - stateY ) >= draggable . props . grid [ 1 ] ?
139
+ ( stateY + ( draggable . props . grid [ 1 ] * directionY ) ) :
140
+ stateY ;
139
141
140
- return [ clientX , clientY ] ;
142
+ return [ clientX , clientY ] ;
141
143
}
142
144
143
145
// Useful for preventing blue highlights all over everything when dragging.
@@ -149,6 +151,21 @@ var userSelectStyle = {
149
151
userSelect : 'none' ,
150
152
} ;
151
153
154
+ function createCSSTransform ( style ) {
155
+ if ( ! style . x && ! style . y ) return { } ;
156
+ // Replace unitless items with px
157
+ var x = style . x + 'px' ;
158
+ var y = style . y + 'px' ;
159
+ return {
160
+ transform : 'translate(' + x + ',' + y + ')' ,
161
+ WebkitTransform : 'translate(' + x + ',' + y + ')' ,
162
+ OTransform : 'translate(' + x + ',' + y + ')' ,
163
+ msTransform : 'translate(' + x + ',' + y + ')' ,
164
+ MozTransform : 'translate(' + x + ',' + y + ')'
165
+ } ;
166
+ }
167
+
168
+
152
169
//
153
170
// End Helpers.
154
171
//
@@ -315,23 +332,12 @@ module.exports = React.createClass({
315
332
onStop : React . PropTypes . func ,
316
333
317
334
/**
318
- * A workaround option which can be passed if onMouseDown needs to be accessed, since it'll always be blocked (due to that there's internal use of onMouseDown)
319
- *
335
+ * A workaround option which can be passed if onMouseDown needs to be accessed,
336
+ * since it'll always be blocked (due to that there's internal use of onMouseDown)
320
337
*/
321
338
onMouseDown : React . PropTypes . func ,
322
339
} ,
323
340
324
- componentDidMount : function ( ) {
325
- var node = this . getDOMNode ( ) ;
326
- this . setState ( {
327
- mounted : true ,
328
- startX : node . offsetLeft ,
329
- startY : node . offsetTop ,
330
- clientX : node . offsetLeft ,
331
- clientY : node . offsetTop
332
- } ) ;
333
- } ,
334
-
335
341
componentWillUnmount : function ( ) {
336
342
// Remove any leftover event handlers
337
343
removeEvent ( window , dragEventFor [ 'move' ] , this . handleDrag ) ;
@@ -354,19 +360,13 @@ module.exports = React.createClass({
354
360
355
361
getInitialState : function ( ) {
356
362
return {
357
- // Whether or not this has been mounted
358
- mounted : false ,
359
-
360
- // Whether or not currently dragging
363
+ // Whether or not we are currently dragging.
361
364
dragging : false ,
362
365
363
- // Start top/left of this.getDOMNode()
364
- startX : 0 , startY : 0 ,
365
-
366
- // Offset between start top/left and mouse top/left
366
+ // Offset between start top/left and mouse top/left while dragging.
367
367
offsetX : 0 , offsetY : 0 ,
368
368
369
- // Current top/left of this.getDOMNode()
369
+ // Current transform x and y.
370
370
clientX : 0 , clientY : 0
371
371
} ;
372
372
} ,
@@ -379,8 +379,6 @@ module.exports = React.createClass({
379
379
// return
380
380
// }
381
381
382
- var node = this . getDOMNode ( ) ;
383
-
384
382
// Make it possible to attach event handlers on top of this one
385
383
this . props . onMouseDown ( e ) ;
386
384
@@ -392,15 +390,13 @@ module.exports = React.createClass({
392
390
393
391
var dragPoint = getControlPosition ( e ) ;
394
392
395
- // Initiate dragging
393
+ // Initiate dragging. Set the current x and y as offsets
394
+ // so we know how much we've moved during the drag. This allows us
395
+ // to drag elements around even if they have been moved, without issue.
396
396
this . setState ( {
397
397
dragging : true ,
398
- offsetX : parseInt ( dragPoint . clientX , 10 ) ,
399
- offsetY : parseInt ( dragPoint . clientY , 10 ) ,
400
- // Reset starting offsets. It's possible this item might have been
401
- // moved by external forces, class changes, whatever.
402
- startX : node . offsetLeft ,
403
- startY : node . offsetTop
398
+ offsetX : dragPoint . clientX - this . state . clientX ,
399
+ offsetY : dragPoint . clientY - this . state . clientY
404
400
} ) ;
405
401
406
402
// Call event handler
@@ -433,20 +429,20 @@ module.exports = React.createClass({
433
429
handleDrag : function ( e ) {
434
430
var dragPoint = getControlPosition ( e ) ;
435
431
436
- // Calculate top and left
437
- var clientX = ( this . state . startX + ( dragPoint . clientX - this . state . offsetX ) ) ;
438
- var clientY = ( this . state . startY + ( dragPoint . clientY - this . state . offsetY ) ) ;
432
+ // Calculate X and Y
433
+ var clientX = dragPoint . clientX - this . state . offsetX ;
434
+ var clientY = dragPoint . clientY - this . state . offsetY ;
439
435
440
436
// Snap to grid if prop has been provided
441
437
if ( Array . isArray ( this . props . grid ) ) {
442
438
var coords = snapToGrid ( this , clientX , clientY ) ;
443
439
clientX = coords [ 0 ] , clientY = coords [ 1 ] ;
444
440
}
445
441
446
- // Update top and left
442
+ // Update transform
447
443
this . setState ( {
448
- clientX : clientX ,
449
- clientY : clientY
444
+ clientX : clientX ,
445
+ clientY : clientY
450
446
} ) ;
451
447
452
448
// Call event handler
@@ -456,28 +452,24 @@ module.exports = React.createClass({
456
452
render : function ( ) {
457
453
// Create style object. We extend from existing styles so we don't
458
454
// remove anything already set (like background, color, etc).
459
- // We do completely overwrite the position.
460
- var style = this . props . children . props . style || { } ;
461
- if ( this . state . mounted ) {
462
- style = assign ( { } , userSelectStyle , style , {
463
- // Set top if vertical drag is enabled
464
- top : canDragY ( this ) ?
465
- this . state . clientY :
466
- this . state . startY ,
467
-
468
- // Set left if horizontal drag is enabled
469
- left : canDragX ( this ) ?
470
- this . state . clientX :
471
- this . state . startX ,
472
-
473
- position : 'absolute'
474
- } ) ;
475
-
476
- // We only position with top/left. Delete bottom/right as they
477
- // will screw us up.
478
- delete style . bottom ;
479
- delete style . right ;
480
- }
455
+ var childStyle = this . props . children . props . style || { } ;
456
+
457
+ // Add a CSS transform to move the element around. This allows us to move the element around
458
+ // without worrying about whether or not it is relatively or absolutely positioned.
459
+ // If the item you are dragging already has a transform set, wrap it in a <span> so <Draggable>
460
+ // has a clean slate.
461
+ var transform = createCSSTransform ( {
462
+ // Set left if horizontal drag is enabled
463
+ x : canDragX ( this ) ?
464
+ this . state . clientX :
465
+ 0 ,
466
+
467
+ // Set top if vertical drag is enabled
468
+ y : canDragY ( this ) ?
469
+ this . state . clientY :
470
+ 0
471
+ } ) ;
472
+ var style = assign ( { } , userSelectStyle , childStyle , transform ) ;
481
473
482
474
// Set zIndex if currently dragging and prop has been provided
483
475
if ( this . state . dragging && ! isNaN ( this . props . zIndex ) ) {
0 commit comments