@@ -24,6 +24,9 @@ export default class Resizable extends React.Component<Props, void> {
24
24
handleRefs : { [ key : ResizeHandleAxis ] : ReactRef < HTMLElement > } = { } ;
25
25
lastHandleRect : ?ClientRect = null ;
26
26
slack : ?[ number , number ] = null ;
27
+ // We add these two fields to remember the state at start of resizing
28
+ dragStart = null ;
29
+ sizeStart = null ;
27
30
28
31
componentWillUnmount ( ) {
29
32
this . resetData ( ) ;
@@ -87,48 +90,30 @@ export default class Resizable extends React.Component<Props, void> {
87
90
* @return {Function } Handler function.
88
91
*/
89
92
resizeHandler ( handlerName : 'onResize' | 'onResizeStart' | 'onResizeStop' , axis : ResizeHandleAxis ) : Function {
90
- return ( e : SyntheticEvent < > , { node, deltaX, deltaY} : DragCallbackData ) => {
93
+ // Using `lastX` and `lastY` rather than `deltaX` and `deltaY` (see longer comment below)
94
+ return ( e : SyntheticEvent < > , { node, lastX, lastY} : DragCallbackData ) => {
91
95
// Reset data in case it was left over somehow (should not be possible)
92
- if ( handlerName === 'onResizeStart' ) this . resetData ( ) ;
96
+ if ( handlerName === 'onResizeStart' ) {
97
+ this . resetData ( ) ;
98
+ // Remembering state at start of resizing
99
+ this . dragStart = { x : lastX , y : lastY } ;
100
+ this . sizeStart = { x : this . props . width , y : this . props . height } ;
101
+ }
93
102
94
103
// Axis restrictions
95
104
const canDragX = ( this . props . axis === 'both' || this . props . axis === 'x' ) && axis !== 'n' && axis !== 's' ;
96
105
const canDragY = ( this . props . axis === 'both' || this . props . axis === 'y' ) && axis !== 'e' && axis !== 'w' ;
97
106
// No dragging possible.
98
107
if ( ! canDragX && ! canDragY ) return ;
99
108
100
- // Decompose axis for later use
101
- const axisV = axis [ 0 ] ;
102
- const axisH = axis [ axis . length - 1 ] ; // intentionally not axis[1], so that this catches axis === 'w' for example
103
-
104
- // Track the element being dragged to account for changes in position.
105
- // If a handle's position is changed between callbacks, we need to factor this in to the next callback.
106
- // Failure to do so will cause the element to "skip" when resized upwards or leftwards.
107
- const handleRect = node . getBoundingClientRect ( ) ;
108
- if ( this . lastHandleRect != null ) {
109
- // If the handle has repositioned on either axis since last render,
110
- // we need to increase our callback values by this much.
111
- // Only checking 'n', 'w' since resizing by 's', 'w' won't affect the overall position on page,
112
- if ( axisH === 'w' ) {
113
- const deltaLeftSinceLast = handleRect . left - this . lastHandleRect . left ;
114
- deltaX += deltaLeftSinceLast ;
115
- }
116
- if ( axisV === 'n' ) {
117
- const deltaTopSinceLast = handleRect . top - this . lastHandleRect . top ;
118
- deltaY += deltaTopSinceLast ;
119
- }
120
- }
121
- // Storage of last rect so we know how much it has really moved.
122
- this . lastHandleRect = handleRect ;
123
-
124
- // Reverse delta if using top or left drag handles.
125
- if ( axisH === 'w' ) deltaX = - deltaX ;
126
- if ( axisV === 'n' ) deltaY = - deltaY ;
127
-
128
- // Update w/h by the deltas. Also factor in transformScale.
129
- let width = this . props . width + ( canDragX ? deltaX / this . props . transformScale : 0 ) ;
130
- let height = this . props . height + ( canDragY ? deltaY / this . props . transformScale : 0 ) ;
131
-
109
+ // In order to fix an issue where resizing does not correctly follow the mouse cursor, we use the `lastX` and
110
+ // `lastY` properties of the mouse event rather than the `deltaX` and `deltaY` properties.
111
+ //
112
+ // This approach is more robust because `lastX` and `lastY` are absolute values and will remain true even if some
113
+ // events get dropped, whereas calculating the resulting width with `deltaX` and `deltaY` in a cumulative way will
114
+ // accumulate errors if some events are skipped.
115
+ let width = this . sizeStart . x + ( canDragX ? lastX - ( this . dragStart . x ?? 0 ) : 0 ) ;
116
+ let height = this . sizeStart . y + ( canDragY ? lastY - ( this . dragStart . y ?? 0 ) : 0 ) ;
132
117
// Run user-provided constraints.
133
118
[ width , height ] = this . runConstraints ( width , height ) ;
134
119
0 commit comments