GithubHelp home page GithubHelp logo

Comments (57)

dbismut avatar dbismut commented on July 20, 2024 3

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.

dbismut avatar dbismut commented on July 20, 2024 3

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.

SidKH avatar SidKH commented on July 20, 2024 2

For anyone looking to implement dragDelay option from this thread, it has been renamed in release 7.0.0

https://github.com/react-spring/react-use-gesture/blob/fa6dd05957c34450533445224a42fdc89852be68/CHANGELOG.md#breaking-changes

from use-gesture.

dbismut avatar dbismut commented on July 20, 2024 1

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.

dbismut avatar dbismut commented on July 20, 2024 1

Have left my computer at work :) will push the branch tomorrow morning CET time.

from use-gesture.

dbismut avatar dbismut commented on July 20, 2024 1

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.

  1. If you just briefly click on the pink square, only the click counter should increment.
  2. If you mouse down for 1 second or more without moving your mouse, the drag status should show drag started.
  3. If you release your mouse while hovering the pink square, the the drag status should show drag ended and the click counter should increment
  4. 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.

dbismut avatar dbismut commented on July 20, 2024 1

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.

codynova avatar codynova commented on July 20, 2024 1

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.

dmcmorris avatar dmcmorris commented on July 20, 2024 1

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.

dbismut avatar dbismut commented on July 20, 2024 1

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.

codynova avatar codynova commented on July 20, 2024 1

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.

dmcmorris avatar dmcmorris commented on July 20, 2024 1

@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.

dbismut avatar dbismut commented on July 20, 2024 1

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.

dbismut avatar dbismut commented on July 20, 2024 1

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.

dbismut avatar dbismut commented on July 20, 2024 1

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.

dbismut avatar dbismut commented on July 20, 2024 1

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.

dbismut avatar dbismut commented on July 20, 2024 1

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.

dbismut avatar dbismut commented on July 20, 2024

Hey, thanks for reporting the issue. Do you mind creating a functional (simplified?) codesandbox reproducing the problem?

from use-gesture.

codynova avatar codynova commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

@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.

dbismut avatar dbismut commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

I've just published it on npm with the next tag. yarn add react-use-gesture@next should do it.

from use-gesture.

codynova avatar codynova commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

I haven’t tested it myself except locally tbh so maybe there’s something wrong!

from use-gesture.

codynova avatar codynova commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

Smart choice! That sounds great, no rush. ✌️

from use-gesture.

codynova avatar codynova commented on July 20, 2024

👏 Very nice, this works extremely well. The only issue I've noticed is with immeditate: true when calling set, the click counter is incremented when the drag ends. Other than that, this looks flawless from my admittedly limited testing.

https://codesandbox.io/s/boring-chandrasekhar-jfc3q

EDIT: My mistake, this is working as intended

from use-gesture.

dbismut avatar dbismut commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

I see what you mean, my mistake.

from use-gesture.

codynova avatar codynova commented on July 20, 2024

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.

dmcmorris avatar dmcmorris commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

dmcmorris avatar dmcmorris commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

@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.

dbismut avatar dbismut commented on July 20, 2024

@dmcmorris that’s perfect indeed. No need for a sandbox ;)

from use-gesture.

codynova avatar codynova commented on July 20, 2024

@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.

codynova avatar codynova commented on July 20, 2024

@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.

codynova avatar codynova commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

@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.

dbismut avatar dbismut commented on July 20, 2024

@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.

codynova avatar codynova commented on July 20, 2024

@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.

codynova avatar codynova commented on July 20, 2024

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.

dbismut avatar dbismut commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

codynova avatar codynova commented on July 20, 2024

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.

J4v4Scr1pt avatar J4v4Scr1pt commented on July 20, 2024

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.

J4v4Scr1pt avatar J4v4Scr1pt commented on July 20, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.