Comments (57)
Hey, thanks for putting up the codesandbox!
Is that what you want to achieve? https://codesandbox.io/s/awesome-surf-414f1
I'm pretty sure this can be further simplified, but let me know if this works as is?
EDIT: not so sure it can be simplified after all 😅
from use-gesture.
Hey @codypersinger I have something working where drag only happens after a short delay or the mouse moving, but I just have one question: what's the difference between a drag and a click in your use case? The question is a bit silly, but is it the fact that the pointer should not move during a click, or is it that the click is supposed to be short?
from use-gesture.
For anyone looking to implement dragDelay
option from this thread, it has been renamed in release 7.0.0
from use-gesture.
Yes, that’s the main trick. Essentially, useGesture
keeps track of just one state, which is relative to pointer coordinates. What you usually want to do is move objects based on the mouse movement (ie the delta
value). But you need to know the origin position of each objects prior to the mouse movement so that you can add it to the delta
value.
In your case, you were only reading the origin position of the dragged item, and adding it to the delta value, so essentially that gave you the same value for all selected items.
Note that in a simple case where you only have one object without needing to enable / disable drag, this is exactly what the local
attribute is designed for.
from use-gesture.
Have left my computer at work :) will push the branch tomorrow morning CET time.
from use-gesture.
Hey, so I just pushed the code on the next
branch (tests are failing but that's expected).
Have a look at: https://codesandbox.io/s/dazzling-vaughan-4j8dd
I've set the time threshold to 1 second so that the lag is noticeable.
- If you just briefly click on the pink square, only the click counter should increment.
- If you mouse down for 1 second or more without moving your mouse, the drag status should show drag started.
- If you release your mouse while hovering the pink square, the the drag status should show drag ended and the click counter should increment
- If you mouse down and then move your mouse right after it should trigger a drag right away, without waiting for 1 second
All of this is expected in the way I've implemented the logic. Note that the click handler is untouched, so it behaves exactly like it should.
PS: after looking at Hammer JS code, they actually trigger a drag only after the pointer moves past a threshold (default is 10px
).
from use-gesture.
It is, but not natively in the lib. You can use the same trick from my sandbox above:
https://codesandbox.io/s/awesome-surf-414f1
from use-gesture.
EDIT: Much better solution can be seen here: https://codesandbox.io/s/hardcore-kowalevski-kepmr
That makes sense. Here's a simple example for anyone that sees this in the future: https://codesandbox.io/s/crazy-solomon-dtpts
If there is some way I can contribute to the documentation for these patterns I would be happy to do so!
EDIT: Much better solution can be seen here: https://codesandbox.io/s/hardcore-kowalevski-kepmr
from use-gesture.
thanks @codynova and @dbismut, I had not fully explored all of the attributes available in onDrag. For my purposes I used distance to filter/control the UI update and ignore drags:
onDrag:
if (distance < minDragDist) { //minDragDist = 10
return memo;
}
The quick replies are much appreciated... awesomely powerful library.
from use-gesture.
Just be careful with distance as dragging might start but then if you get back to your point of origin without releasing your drag, distance might pass under the threshold and your UI will not be updated.
from use-gesture.
Unless proven otherwise, I’ve found difficult to accurately predict whenever a drag should actually be triggered, this depends on the use case.
@dbismut For the record, using the click speed/delta time solution has been extremely accurate in my experience - although perhaps it depends on the use case, as you said. However this has been my go-to solution for complex UIs that strongly differentiate between clicking and dragging on the same element and it has always seemed perfectly accurate, I have never seen a false-positive.
EDIT: Sandbox here: https://codesandbox.io/s/hardcore-kowalevski-kepmr
from use-gesture.
@codynova one thing to point out, the {time: 1000}
param doesn't seem to do anything with any versions of react-use-gesture but 5.0.2_beta1
from use-gesture.
You’d just have to ask, I don’t have anything against it (but you’d have to provide me with a good name for it, time isn’t great and I suck at labeling things 🙃). Also it would be set to 0 by default.
from use-gesture.
Oh no don’t worry, I was joking! I’m not sure what other gestures would make sense to have that feature, so for now I think I’ll just make it work for drag (dragDelay
it should be).
It’s not that much of an edge case, being able to distinguish a click from a drag should be pretty common and if this avoids hacks or refs its a good thing to have!
from use-gesture.
There, v6.0.4
is out with dragDelay
as an option (set to false
by default, you can set it to true
and will take a default value of 180ms
but you can set any value you want).
from use-gesture.
Yeah in 6.0.4 I haven't made so that the drag is initiated as soon as the mouse moves (it really waits for the 1000ms). I can fix this in 6.0.5, I'll see what I can do now :)
from use-gesture.
Hey @codynova I've found a bug with dragDelay
this morning: in 6.0.6
if you moused down, moved and dragged longer than dragDelay, the square would go back to its origin position (I had forgotten to clear a timeout). This is now fixed in 6.0.7
.
I've copied your sandbox here and made a few tweaks, mainly moving to react-spring v9 which simplifies styling attributes: https://codesandbox.io/s/hardcore-kowalevski-kepmr
Also I think you can use performance.now()
without using window
, it should be better in case you ever move to SSR where window
is undefined.
from use-gesture.
Hey, thanks for reporting the issue. Do you mind creating a functional (simplified?) codesandbox reproducing the problem?
from use-gesture.
No problem, here is the codesandbox showing the issue. Try double-clicking to select two divs and move them both at the same time. Selecting the second div is difficult: https://codesandbox.io/s/xmqwz
I've noticed that setting a different top
value for each .content > div
in the CSS and zeroing out the initial xy
values will somewhat alleviate the issue, as you can see here: https://codesandbox.io/s/blazing-resonance-gw9pj
I suppose one solution is calculating the offset for each div based on the height (or size) - kind of like the draggable list example.
However, what I'd really like is some way to maintain the offsets of all the divs relative to each other. Imagine selecting multiple icons to drag/drop on the desktop, those icons keep their relative distance to one another while dragging. I think my issue is that the drag is trigger on click, so when clicking to select the second div, the first selected div is dragged towards the second one.
from use-gesture.
Yes, that's exactly what I wanted, and I don't think I would've figured that out on my own! It looks like the main trick is mapping the temp value? I'm sure I'll use this much more in the future, thanks very much for taking the time to help and teach.
from use-gesture.
@dbismut I've been playing around with the library more, and have come across a situation or two where it would still be useful to differentiate between a click and a drag event. Is there some way to do this, using the previous example in this thread? Thank you for your time!
from use-gesture.
That’s a bit trickier, as drag gesture is currently triggered by onMouseDown
, so at the moment a click event would inevitably trigger a drag gesture. One way to solve this would be to only trigger a drag event when the pointer actually moves or after a short delay. I’ll see if I can do this without generating regressions.
from use-gesture.
I thought that might be the case - and I had the same thought about triggering a click only if the pointer has moved, but I thought that might tend to trigger false clicks if someone was intending to drag but just hadn't decided where to move yet. Even with the delay, it doesn't sound like a concretely reliable solution, but it would likely be better than nothing.
I was wondering if it might be possible to initiate dragging on DragStart or Drag event, but I know from having implemented custom dnd solutions in the past that there are a lot of caveats and knock-on effects to consider. I need to take a closer look at the useGesture source and get a better understanding of what would be possible.
from use-gesture.
Just to clarify the idea would be to trigger a drag on the earliest condition:
- after a short delay following a mousedown event
- whenever the pointer moves after a mousedown
I think this is the logic adopted by hammerjs. Unfortunately I’m not sure there is a perfect alternative.
from use-gesture.
I agree, there is likely no perfect solution. I think what you've proposed is probably as good as it gets, and I think it would work well enough in the vast majority of situations.
I was looking at the DragRecognizer
, and can see it's using onMouseDown
and onTouchStart
, but I'm wondering what the implications of trying to use onDragStart
instead of onMouseDown
would be? Or perhaps a better question, what is the intention of using onMouseDown
in the DragRecognizer
compared to something like onDragStart
?
from use-gesture.
onDragStart would require to make the element draggable right (ie attribute draggable
set to true
)? That means conflicting with the native draggable api, we’ve tried that before and it’s a tough battle.
from use-gesture.
Yes, that's right. The native api absolutely leaves a lot to be desired. I've created one implementation in the past that goes this route, within React, and worked on the web as well as across all native devices that we tested with (at a big agency, so pretty extensive iOS/Android testing) - but it definitely involved fighting against the native api. I might play around with this idea in a fork. The implementation would be pretty extensive (maybe too extensive to be merged back), and there may be issues I'm overlooking. I think your initial suggestion is much more immediately useful and workable.
from use-gesture.
Awesome! I'm still playing around with the native API implementation, making slow progress. It's not a silly question at all. For pretty much all the use cases I can think of, the click being short is the more important and reliable factor.
from use-gesture.
Maybe there's no need for what I was mentioning above then:
https://codesandbox.io/s/awesome-surf-414f1
It's a bit silly, but I think this is more or less what you want isn't it?
from use-gesture.
It does more or less achieve the effect. It's fairly easy to both drag and click with quick gestures, which is not ideal behavior in the example codepen - but I think making sure the pointer hasn't moved would take care of that, so it looks like an easy adjustment on my end. It would be nice to have an onClick
binding abstraction which is configurable with props like duration
and allowMovement
, so that click-based logic doesn't have to live in "onDrag" - but I understand that those events are necessarily intertwined, and it may not jive with the goals of this library which seem drag-focused. What are your thoughts? I'd also be interested in the code changes to this library that you were originally mentioning with regards to drag only triggering after a delay/mouse movement.
from use-gesture.
I've just published it on npm with the next
tag. yarn add react-use-gesture@next
should do it.
from use-gesture.
I'm not noticing any difference in when react-use-gesture
's onDrag
is triggering in regards to either delay or cursor position after upgrading to 5.2.0-beta.1
, but perhaps I'm doing something wrong? I have to run to a meeting now but I'll knock together a codepen ASAP
from use-gesture.
I haven’t tested it myself except locally tbh so maybe there’s something wrong!
from use-gesture.
I'd be happy to take a look sometime tonight, if there's somewhere I can see the commits / history for that release? Thanks for all your time and effort on this so far, I truly appreciate it.
from use-gesture.
Smart choice! That sounds great, no rush. ✌️
from use-gesture.
👏 Very nice, this works extremely well. The only issue I've noticed is with this looks flawless from my admittedly limited testing.immeditate: true
when calling set
, the click
counter is incremented when the drag ends. Other than that,
https://codesandbox.io/s/boring-chandrasekhar-jfc3q
EDIT: My mistake, this is working as intended
from use-gesture.
Well yes... as I was saying, if you release your mouse over the dragged element it’s still considered as a click by the browser. immediate:true
pretty much guarantees that the dragged element follows your mouse so that’s why the click counter increments. Theres not much we can do about this.
from use-gesture.
I see what you mean, my mistake.
from use-gesture.
Is it possible to optionally prevent the click from being triggered if you are actively dragging and release the mouse over the pink square?
from use-gesture.
Looks like this never made it out of beta... anyone have a solution to this issue? Trying to use onDrag from react-use-gesture and onDblClick from konvajs and I always get a drag triggered for every double click
from use-gesture.
Hey @dmcmorris, indeed drag is triggered as soon as the user mouses down. Unless proven otherwise, I’ve found difficult to accurately predict whenever a drag should actually be triggered, this depends on the use case.
It shouldn’t be a big deal in your case though, nothing forces you to update your UI when the drag handler triggers. A double click generally happens with no mouse movement, so you could only update your UI in onDrag
when first
or last
are false
(ie mouse is moving). If you actually need something specific to happen when the user starts or ends dragging, you could use a ref. I can explain this in greater details if you provide me with a concrete use case.
from use-gesture.
EDIT: Much better solution can be seen here: https://codesandbox.io/s/hardcore-kowalevski-kepmr
@dmcmorris The solution can be seen here and here - you need to use first
and last
in useGesture
's onDrag
, and store the drag delta time in a ref. With this solution, you will need to decide on a click speed threshold for determining whether to trigger a click.
onDrag
:
if (first && time) {
// Drag started, no click triggered
dragDeltaTime.current = time;
}
else if (last && time) {
// Drag ended, no click triggered
dragDeltaTime.current = time - dragDeltaTime.current;
}
onClick
:
event.stopPropagation();
if (dragDeltaTime.current < 60) {
// Click started, no drag triggered
}
dragDeltaTime.current = 0;
EDIT: Much better solution can be seen here: https://codesandbox.io/s/hardcore-kowalevski-kepmr
from use-gesture.
I'm using a ref to track if the drag has passed the distance threshold or not, I need that to filter other events/logic anyways. I have some momentum scrolling using spring on this element and longpress events, so time based initiation of the drag was more problematic for me:
const dragInfo = React.useRef({ isDragging: false });
...
onDrag: ({
active,
movement,
velocity,
direction,
distance,
first,
last,
memo = position.getValue()
}) => {
...
if (!dragInfo.current.isDragging && distance < minDragDist) {
return memo;
}
dragInfo.current.isDragging = true;
if (last) {
dragInfo.current.isDragging = false;
}
...
return memo;
}
);
I'll try to throw a simple sandbox together and share later. Thanks again for the concise and helpful suggestions.
from use-gesture.
@codynova that’s good to know and I think I’ll add your sandbox to examples / FAQ. However native click events don’t depend on time or movement (I think they’re triggered as long as the target is still under the mouse when it’s released).
from use-gesture.
@dmcmorris that’s perfect indeed. No need for a sandbox ;)
from use-gesture.
@dbismut I made a second sandbox that's a bit clearer, and shows drag/click/double-click all working together. https://codesandbox.io/s/xenodochial-dubinsky-l9x7f
What do you mean exactly in regards to native events? Can you describe the effect that would have on the sandbox?
EDIT: Looks like there is a bit of an issue with triggering the click function when double-clicking, as can be seen by the counter increasing by 2 at times. This could potentially be solved with a click delta time, perhaps using the browser frame timing API or requestAnimationFrame.
EDIT2: Updated the sandbox with click time logic.
EDIT3: Much better sandbox here: https://codesandbox.io/s/hardcore-kowalevski-kepmr
from use-gesture.
@dmcmorris Good point. I'm not sure whether that will actually make it into the library at some point, but it is not necessary for the solution.
from use-gesture.
Sorry if that sounded rude! I realized my comment can be read two different ways - and I definitely didn't intend to throw shade 😅
Honestly I don't have an immediate use case for it, and I don't want to suggest adding a lot of clutter to the API - but I do feel like it could be useful, and I appreciate having access to parameters that allow edge-case solutions. react-spring
certainly seems to have a lot of those sorts of edge-case parameters, but I'm not sure if that's the direction you want to take this lib.
As far as a name, assuming it effects all gesture types, maybe something like gestureDelay
?
from use-gesture.
@dbismut Please disregard my last comment. My example sandbox breaks when updated to 6.0.4, and I initially thought it was due to the dragDelay
setting, but now I can see that's not the problem. Here's the original sandbox, and that same sandbox updated to 6.0.4. Can you help me understand the difference in the drag behavior between the two? I'm guessing this is just a need to reconfigure something from 5 -> 6.
from use-gesture.
@codynova yep that's an easy one, v6 labels things in a better / more conventional way.
Value | v5.x | v6.x |
---|---|---|
delta between current and previous event (xy - previous) | N/A | delta |
last gesture offset (xy - initial) | delta | movement |
offset since first gesture | local | offset |
So you just need to replace delta
with movement
and you should be good ;)
from use-gesture.
@dbismut Thanks very much for the speedy reply, I've made the change as suggested - but things still don't seem to be working as I'd expect.
5.2.0-beta.1 sandbox with time
configured to 1000ms (using delta
instead of movement
). With this setup, you can click, double-click, and click-and-drag without delay. You can also click-and-hold for 1000ms to initiate a drag.
6.0.4 sandbox with dragDelay
configured to 1000ms (using movement
instead of delta
). With this setup, you can click and double-click, but click-and-drag is not working properly. You can, however, still click-and-hold for 1000ms to initiate a drag, which works as I'd expect.
from use-gesture.
Awesome. Hopefully the update in 6.0.5 won't make dragDelay
confusing for consumers of the API. I suppose it might be possible to have a second parameter instantDragOnMove
or dragDelayOnMove
or something, which would allow utilizing dragDelay
in either the 6.0.4 or 6.0.5 fashion. Honestly without foreseeing exact use-cases, I think it's kind of hard to say whether it would be useful. Thank you very much for the great and speedy work on this lib! 😄
from use-gesture.
Yeah dragDelay
is optin and pretty sure people will stumble upon this thread if they have any questions ;) 6.0.5 is now out, let me know if it works better for you!
from use-gesture.
EDIT: Better sandbox here https://codesandbox.io/s/hardcore-kowalevski-kepmr
Love it. https://codesandbox.io/s/trusting-pine-jpqi5
I cleaned things up a bunch, and I think this is the best solution I can come up with - it supports click, double-click, immediate drag, and delayed drag. I'll be replacing the logic in my current projects with the logic from this sandbox. It requires three different refs, but it's working extremely well in my testing.
Rather than tracking drag delta time, we only use a timestamp ref for tracking the time of the last click, and we use boolean refs for tracking current drag and double-click status. And instead of using onClick
and onDoubleClick
both (and duplicating click delta time logic), we put the double click logic inside the onClick
handler.
I tried simply using the dragStatus
value to eliminate the need for the two boolean refs, but it was not nearly as accurate/performant as using the refs.
With this setup, it is (intentionally) not possible to trigger two double-clicks in a row. If the previous click was a double-click, the next non-drag click will be a regular click - even if you are clicking fast enough to be within the DOUBLE_CLICK_TIME_THRESHOLD
. If one would like to allow triggering simultaneous double-clicks, remove the isDoubleClicked
ref and relevant logic.
EDIT: Better sandbox here https://codesandbox.io/s/hardcore-kowalevski-kepmr
from use-gesture.
Excellent, that looks much better without the unnecessary manual interpolation cluttering up the example. 👏 Great job finding that bug - I have no idea how I missed it. And very smart to use requestAnimationFrame
instead of a setTimeout
in the sandbox.
from use-gesture.
Is there any example with v.10 regarding this?
Can't get @dbismut sandbox example above to work with latest versions of react-gesture and react-spring.
Even after changing dragDelay to delay 🤔
from use-gesture.
Ok I can answer this my self if someone else is as bad at reading the documentation as I am 😁:
https://use-gesture.netlify.app/docs/options/#filtertaps
from use-gesture.
Related Issues (20)
- Pinch bug: after opening/closing context menu, pinching gesture can be fired with 1 finger HOT 1
- Delegate drag to remaining finger after pinch or support multi-finger drag HOT 5
- Using modifierKey causes the mac pinch event to return HOT 2
- Using pointer.touch cannot be dragged under windows system HOT 6
- useDrag breaks onClick listener in React portal to shadow dom HOT 2
- using video element inside useDrag component doesn't allow the video to play/pause using single click over the video HOT 6
- DragBounds ignored when rerender target HOT 1
- dynamically updating useDrags axis option resets movement : [mx,my] HOT 2
- Using alt+left for navigation prevents all gestures on elements with axis: 'y'
- Drag gesture: Delay setting behavior does not adhere to documentation HOT 4
- Drag + Click + filtertaps option breaks onclick listener. Drag + Click + Treshold works. HOT 1
- touch-action: pan-y prevents L shaped gestures to scroll
- onPinch breaking on control + scroll HOT 5
- Where do I import a3f from? HOT 1
- Getting the error "a3f is not defined"
- Textarea doesn't work inside gesture container HOT 4
- Documentation website is broken (in firefox) HOT 8
- Type error with @types/react >=18.2.66
- (Firefox) Click event fired on drag end
- 100ms delay between pointermove events in Android webviews? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from use-gesture.