Fix top-left resizing - account for new position when calling back onResize#136
Fix top-left resizing - account for new position when calling back onResize#136STRML merged 22 commits intoreact-grid-layout:masterfrom
Conversation
|
Hi @conor-kelleher. Thanks a lot for this contribution! I'd like for this to make it into 2.0. #133 contributed a test suite into the application, it would be really great if you could rebase on |
STRML
left a comment
There was a problem hiding this comment.
Implementation works, just some minor bits on the code & comments. Thanks!
| const canDragY = (this.props.axis === 'both' || this.props.axis === 'y') && ['e', 'w'].indexOf(axis) === -1; | ||
|
|
||
| // Check if handle's position has moved since last resizeHandler call - adjust deltas accordingly | ||
| if (this.draggingNode == null && e.target instanceof HTMLElement) { |
There was a problem hiding this comment.
Is saving this ref necessary (rather than simply using e.target)?
There was a problem hiding this comment.
I originally had it just using e.target on each callback but because the listener is calling back to any movement in the document body, e.target will not always be the same value during a drag. It will be whatever element the mouse is currently over. As you can see, using this value directly causes jumpy behaviour when the mouse enters different elements:

Hence the need to persist a reference to the same element through multiple callbacks
lib/Resizable.js
Outdated
| deltaY += deltaTopSinceLast / this.props.transformScale; | ||
| } | ||
| } | ||
| this.lastTop = handleRect.top; |
There was a problem hiding this comment.
Can this be a single property (this.lastHandleRect = handleRect)?
There was a problem hiding this comment.
Yep, it can. I've rolled that in now
lib/Resizable.js
Outdated
| const deltaLeftSinceLast = handleRect.left - this.lastLeft; | ||
| const deltaTopSinceLast = handleRect.top - this.lastTop; | ||
|
|
||
| if (canDragX && axis.indexOf('w') > -1) { |
There was a problem hiding this comment.
The allowable values for axis are:
['s', 'w', 'e', 'n', 'sw', 'nw', 'se', 'ne']So this could be more clear as axis[axis.length - 1] === 'w', similar to https://github.com/STRML/react-resizable/blob/a1fff416339df13b15b23044b026ebbe376a2b9d/lib/Resizable.js#L97.
This of course would be a great use case for String#endsWith() but we are trying to avoid prototype methods that aren't supported in IE.
There was a problem hiding this comment.
Good point, I've made this change now
lib/Resizable.js
Outdated
| if (canDragX && axis.indexOf('w') > -1) { | ||
| deltaX += deltaLeftSinceLast / this.props.transformScale; | ||
| } | ||
| if(canDragY && axis.indexOf('n') > -1) { |
There was a problem hiding this comment.
See above comment, axis[0] === 'n' will work here.
There was a problem hiding this comment.
Very true, much cleaner this way 👌
lib/Resizable.js
Outdated
| const canDragX = (this.props.axis === 'both' || this.props.axis === 'x') && ['n', 's'].indexOf(axis) === -1; | ||
| const canDragY = (this.props.axis === 'both' || this.props.axis === 'y') && ['e', 'w'].indexOf(axis) === -1; | ||
|
|
||
| // Check if handle's position has moved since last resizeHandler call - adjust deltas accordingly |
There was a problem hiding this comment.
It'd be great if you could expand upon this comment with some of the detail in this PR: that is, what happens, why it only affects n and w directions, and how this fixes it.
There was a problem hiding this comment.
Fleshed these comments out a good bit. Hopefully they're clear enough now 🤞
|
I've made the requested changes to the code. Need to add some tests before re-requesting a review |
|
Hey @conor-kelleher Great PR 🎉 . Really looking forward to its release. |
|
Hey @STRML, sorry for the delay getting this fixed up. I've made the suggested changes, added a suite of tests for the new functionality and added a new set of examples to the demo, keeping the absolutely positioned ones away from the inline ones: Just note: after pulling the changes you pushed to master preparing for v2, I couldn't get the example to run since the webpack config was referencing a non-existent file |
lib/Resizable.js
Outdated
| deltaY += deltaTopSinceLast / this.props.transformScale; | ||
| } | ||
| } | ||
| this.lastHandleRect = handleRect; |
There was a problem hiding this comment.
Not that it matters much, but why not just save the whole rect?
There was a problem hiding this comment.
I hit an issue with flow upon trying to cast an exact object to an inexact type. I'm new to flow so couldnt find a proper way around this, just got it working by taking the exact data I needed. I'm open to changes though
|
Any updates on this fix? Ran into this same issue! |
|
I have the same issue. @STRML would this fix available soon? |
|
This works great. Thanks for the contribution! |
|
Is there some code sandbox for the final solution ? |
|
Any plans on updating the official demo to demonstrate this. Anyone have any codesandbox for this, I tried the |
|
Can someone help me? Why when positioning my resize handles on top/left/top-left the behavior is so weird like i show at the GIF? Is something im doing wrong or i need to implement the right behavior by my self? I expected that the grid would follow my mouse but it expand to the other side... Thanks for the attention |





What's wrong?
Hey, love the library. Works really well for the most part but, as a few different issues have mentioned, it has some serious issues when resizing from the left or the top, using anything other than top-left positioning. The following open issues are just some that have documented the issue:
I've put together a minimal codesandbox to demonstrate the issue as well:
https://codesandbox.io/s/react-playground-vwlpk?file=/index.js
Samples from the above codesandbox:
Dragging to the right: smooth

Dragging to the left: jumpy/flickering

The Cause?
The problem is that on subsequent calls of the
resizeHandlerfunction, it's reporting a resize based on thedeltaXanddeltaYof the movement. However, if calling back through theonResizeprop results in a position change (for instance, if you are using right-based absolute positioning as in my example above, or if you are manually updating the top/left positions based on the resize), then the drag handle itself might be moved by the re-render, so the next call toresizeHandlerwill report that the handle has moved, even though this is a prop-driven movement rather than a mouse-event driven one.The solution
I've added a few lines to track a reference to the drag handle element in the document and in every call of
resizeHandler, I'm comparing the new top and left of the element on the page with the previous values. A difference in these values will be a result of a positioning change, and so we want to account for this in ourdeltaX/deltaYvalues.If dragging any handle with an
'n'in it and its position has changed, then our event's reporteddeltaYvalue will either be larger or smaller than we expect it to be (because this value will include the position change). Adding this y-position differential to the delta value accounts for this and keeps the callback only reporting on movement that was caused by the mouse event. The same goes for the x-axis and any handle with a'w'in it.Demo
I've added a new example to the examples demo page which features a new box with omni-directional movement. This can be used to demonstrate a before and after and also shows much more power behind this library.
e.g.
Old - omni-directional box stuttering dragging top and left

New - omni-directional box smoothly resizing in all directions

Let me know of any issues you come across with it and have a good day!