-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance: Drag items via transform property to avoid layout and re-paints #33395
Conversation
45c332f
to
f42ff4b
Compare
Size Change: +28 B (0%) Total Size: 1.07 MB
ℹ️ View Unchanged
|
Playing around with the draggable + dropzone code, it feels like we have a few opportunities.
|
I did some testing and the results seem good so far. The blue drop zone indicators are noticeably quite delayed at updating position, so that might be something to improve. I think that's one of those things that needs to feel quite responsive, or the user will perceive it as slow, even if the code is well optimized. Definitely a good idea to work on this iteratively, so if we can get some noticeable improvements with the Draggable first, we can ship that straight away. |
Sounds good, I can tidy up changes to pull out the draggable changes first (will set this to ready for review when I'm done). General dragging performance is still going to be pretty slow from the existing dropzone handlers, but the difference in removing those layout shifts should be visible from browser profiling. I'll spin up a follow up draft to continue experimenting with drag intents. |
y = event.clientY - 100; | ||
// Can also be written as the affine transform: matrix( 0.5, 0, 0, 0.5, x, y ). | ||
// Note that order matters, translate should be done before scale. | ||
cloneWrapper.style.transform = `translate( ${ x }px, ${ y }px ) scale(0.5)`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any examples where we drag an item that's more than 700px? I was wondering if we still needed to handle this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think just about every interaction uses a draggable chip now rather than a clone of an element, so this is just here for consumers of the package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm quite tempted to rip out this case. Here's what it looks like in trunk with a draggable with a 701x701px square. Scaling to 50% of the original draggable isn't going to work with larger items, so folks will likely need to come up with a similar solution to what we went with.
The positioning also looks off, cursor at top left vs center (which I can fix, but would modify current behavior).
trunk_701px.mp4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried removing this case in 9667539
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, yeah. It feels like it'd be better if it had a max size instead of reducing by 50%, but maybe that's to stop the drag image from being blurry.
Removing it seems ok, we can monitor to see if there's any negative feedback.
I imagine this was for large blocks, so the use case is more than likely no longer present.
This one is ready for review 👍 I moved over other exploratory dropzone performance handling to #33435 |
dragState.cursorLeft = e.clientX; | ||
dragState.cursorTop = e.clientY; | ||
dragState.x = nextX; | ||
dragState.y = nextY; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it might be confusing updating the object properties in this way through an object reference. 🤔
Maybe here it could call an updateDragState
function that makes the change to a ref
defined by useRef
or something. Not sure. I recall the previous version of this code being a bit hard to follow anyhow.
Any other ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried removing the dragState object in 9667539 removing the extra function.
Closures are pretty common in animation/drawing handlers (since we need to keep track of what happened in the last step vs the current step), but we could try to tidy up function signatures in a larger refactor. I'd maybe move that to a seperate PR though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good so far. The removeEventListener issue was the only thing I spotted that seems like it needs to be fixed.
634c518
to
998ff0d
Compare
998ff0d
to
9667539
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this, lets get this in.
Background
Our draggable component updates a drag chip by modifying
top
andleft
properties. This unfortunately forces the browser to go through layout > paint> and compositing steps which is expensive. As we can see in the profiler on trunk, we're both dropping frames and seeing layout shifts.Changes in this PR update this to use
transform
instead which can skip layout and paint, to go straight to composite. We also add a throttle to reduce the number of fired drag events, and early escape if the mouse has not moved.Our drop zone handlers are also causing major performance issues when dragging quickly. This will be handled in #33435
Videos below are taken with the Armando theme, using the "alternating rows with images and headings" pattern.
Testing Instructions
Profiling In Trunk
trunk.mp4
Profiling in Branch
branch.mp4