Skip to content

Commit 785e6ca

Browse files
Applying patch from react-grid-layout#237
1 parent 070d0ad commit 785e6ca

File tree

1 file changed

+19
-34
lines changed

1 file changed

+19
-34
lines changed

lib/Resizable.js

+19-34
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export default class Resizable extends React.Component<Props, void> {
2424
handleRefs: {[key: ResizeHandleAxis]: ReactRef<HTMLElement>} = {};
2525
lastHandleRect: ?ClientRect = null;
2626
slack: ?[number, number] = null;
27+
// We add these two fields to remember the state at start of resizing
28+
dragStart = null;
29+
sizeStart = null;
2730

2831
componentWillUnmount() {
2932
this.resetData();
@@ -87,48 +90,30 @@ export default class Resizable extends React.Component<Props, void> {
8790
* @return {Function} Handler function.
8891
*/
8992
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) => {
9195
// 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+
}
93102

94103
// Axis restrictions
95104
const canDragX = (this.props.axis === 'both' || this.props.axis === 'x') && axis !== 'n' && axis !== 's';
96105
const canDragY = (this.props.axis === 'both' || this.props.axis === 'y') && axis !== 'e' && axis !== 'w';
97106
// No dragging possible.
98107
if (!canDragX && !canDragY) return;
99108

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);
132117
// Run user-provided constraints.
133118
[width, height] = this.runConstraints(width, height);
134119

0 commit comments

Comments
 (0)