Set to drag a minimum distance before drop actions occur - too sensitive if move one pixel while trying to click element in drop card initiates drop actions

I have a card with items that are selectable, I set the card as dynamic panel with drag and drop interactions. The problem is when users just want to select an interaction like an icon dropdown that’s in the card, if they move the mouse at all in the selection, it thinks it’s a drag and then the card changes based on the replace function that’s being simulated where on drop a new page is loaded with the cards swapped.
Is there a way to set sensitivity so it’s a clear drag and not just a user selecting something with the inadvertant slightest mouse movement, like move x pixels before its considered a drag and drop?

image

You could try playing around with the [[DragTime]] variable. Don’t move the widget until the mouse moves for at least 200ms or something to that effect.

You could try moving the buttons outside of the dynamic panel and set the interaction that when the panel moves it moves the buttons with it.

Long ago (I think Axure RP 6?) I came up with a solution that I still use (I don’t have an RP 10 license, but it should still work.) Essentially, in the Dragged event I include a conditional case like so:

Dragged
Case 1, real drag not a click
If “[[ math.abs(TotalDragY) ]]” is greater than “5”)
// insert your drag actions

In this way, your Drag code only fires after the cursor moves 6 vertical pixels. Otherwise, it will be ignored, or you can handle it as a click. You can also use TotalDragX to track only horizontal movement, or combine both with a second condition in the same case, and setting it to “Match Any” …something like this:

If you want to test out this “drag sensitivity” factor, you can create a global variable, e.g., “dragSlop” and set that to a custom value, replacing “5” with that global variable in the code example above. You could even include a text field to change this on the fly when testing your prototype to dial it in.

Note that if you are also using the Drag Started event in your code, it will fire upon that initial cursor movement regardless of any slop factor, so this method pretty much renders Drag Started useless. Most times I can use the Mouse Button Down event instead, but if you really need to trigger actions when a “real drag” starts–and not repeatedly during the drag, you can build in some more conditions or fire the event of another widget, using it like a kind of sub-routine.

Once I added all these caveats I figured I better include a file. Here is a quick demo showing click versus drag, and how to handle or ignore “sloppy clicks”
Drag Sensitivity and Sloppy Clicks.rp (62.8 KB)


Details…

This is something I’ve had to deal with since the dawn of Axure. It is particularly an issue for touchscreen interactions with fingers and usability tests where “real people” use a prototype. I’ve referred to this issue as “sloppy clicks” but it’s really just “human clicks” where a tiny bit of movement between mouseDown and mouseUp is just natural when you click on something. Normally this is not an issue as you are typically only concerned with a basic click–like a button, or a basic drag–like moving a dynamic panel from point A to point B. But, when you need to handle both–like your “changeable card” or you use drag events to scroll through a long list of buttons, it can be difficult to discern the difference between a click and a drag–which comes down to your interaction code trying to determine if the user intended to click a widget or drag that widget.

So, a pointer or mouse event starts when it is first detected–the instant a mouse button is pressed down–but not released, or in a touchscreen the pen/finger touches the screen (in Axure, the Mouse Button Down event is triggered.) If the mouse or finger is moved prior to releasing it, a drag event starts (in Axure, the Drag Started and Dragged events are triggered.) In native-OS touchscreen systems and most app code, a kind of “slop factor” or “wiggle factor” is built in, allowing for a few pixels of cursor movement to occur without triggering a drag. Axure does not have this built in, which is good and bad, as you can control things more precisely and responsively (and potentially more consistently across platforms,) but you have to manually add in a method to provide a slop factor for more natural and more sophisticated drag-and-click interactions.

In my demo file above, I use a dynamic panel with 3 states:

  • State1: Normal
  • State2: Dragged
  • State3: Clicked

…which makes an easy way to show when a drag versus a click is registered. You can look at the interaction code to see how I use the current state of the dynamic panel in the conditional case logic, as well as the “dragSlop” global variable. In the Drag Dropped event (which fires regardless of the slop factor–any time three cursor events occur: down, move, up) I added a “Wait 10ms” before resetting the dynamic panel to State1, just to ensure that happens after the Mouse Button Up event action–potentially causing a “click” to happen. In retrospect, since I also included a fade of 250ms it shouldn’t be necessary as the state change is not registered until that fade transition is complete–but it also doesn’t hurt to include it and 10ms won’t be human-recognizable.

The math.abs()_ statement is a javascript-based function that is built in to Axure, and the TotalDragX is a variable also built in to Axure. The “abs” refers to “absolute value” so that function simply makes all values positive. When Axure tracks the drag amount in pixels, a left-wise or up-wise movement is a negative value. So the math.abs() is just a way to track movement in either direction.

Something else to note… Once a drag has started, the Dragged event gets fired every time it detects a change in the cursor location. So, if you click down and move the box 100 px then Dragged would get fired up to 100 times (maybe less if you move real fast or the computer is real slow.) So, all three actions would get repeatedly triggered. In my demo I use Move, Bring to Front, and Set Panel State. The latter two get ignored if not needed, so effectively they should only happen once the first time Dragged is fired during a cursor move. If your code is more complex it could slow down the Dragged event and/or make the drag motion jumpy or glitchy. If this is the case, you can move all initial actions–typically anything other than Move–to a different widget (like a hidden one) and then indirectly call it with something like Click or Tap MyDragStartWidget or Fire Event MyDragStartWidget Click or Tap. Then, on that MyDragStartWidget widget include a conditional case that tests if an active drag is in effect. I’ve done this in the past by assigning a global variable to “true” in the Dragged event then setting it to “false” in the Drag Dropped event.

You could use this same approach using the DragTime variable, as @huban suggests, instead of TotalDragX and/or TotalDragY, if the amount of time is important. Say, you want to add in a time delay no matter what. In my experience the drag distance is usually more important though. You could try combining them by adding a third condition to the one I demonstrate–tracking the amount of DragTime as well as drag distance.

1 Like