clauderic / dnd-kit

The modern, lightweight, performant, accessible and extensible drag & drop toolkit for React.
http://dndkit.com
MIT License
13.04k stars 646 forks source link

Drag Collision Hysteresis #1456

Open kamyarkaviani opened 3 months ago

kamyarkaviani commented 3 months ago

In all of the collision detection algorithms in dnd kit, there is a specific point in the page that after the mouse crosses, the items would swap. The problem is when the mouse is right at that point, the two items being swapped in the sortable container will glitch and move up and down randomly many times:

https://github.com/user-attachments/assets/fbfcb76c-ba86-4d8c-8cb5-2e1737333466

Compare this to react beautiful dnd:

https://github.com/user-attachments/assets/c49ea7bf-7f34-4b5d-812b-7161321237cb

There is a small amount of hysteresis for activation of the swap. In simple terms, when the swap happens, the threshold is reset to be slightly higher than right in the middle, so that the glitch right at the switching position is removed. This is common in electronics, for example, when comparing a signal with an opamp, there is always some hysteresis to prevent transitioning between switch states hundreds of times randomly. It's called a Schmitt trigger, but same concept.

ChasKane commented 2 months ago

Welp, I learned something new today. dm me if you wanna pair code on fixing this.

puopg commented 1 month ago

You may wanna just use a different collision algorithm. Default it compares the closest center point of the potential candidate rects.

But you can use for example, the pointerWithin collision detection to instead require your pointer to be within an item's bounds. So since you have a gap between your row items, you wouldn't retrigger until you crossed that gap and back again.

You can combine this with other state tracking to implement your own collision hysteresis that you desire. Whether that be time based or distance based.