Double tap recognition takes too long? (Hammer.js 2.0) - hammer.js

I am programming a highly responsive web application and came across the issue that most time is used to recognize double taps.
I am using this code from the website:
var singleTap = new Hammer.Tap({ event: 'singletap' });
var doubleTap = new Hammer.Tap({event: 'doubletap', taps: 2 });
hammer.add([doubleTap, singleTap]);
doubleTap.recognizeWith(singleTap);
singleTap.requireFailure(doubleTap);
This basically works quite fine. However, due to the timeouts/intervals the recognition of a double tap takes quite "long". I guess its about 2 times the interval - one for each tap.
The waiting for the last interval (waiting for a third tap) is senseless in my scenario.
Is there any "ok tapCount == 2, we fire now and don't wait any longer"-TapRecognizer option?
Update, I have done some logging:
First column: passed ms since first event
0 input: mousedown
74ms input: mouseup
145ms input: mousedown
218ms input: mouseup
520ms double tap
-
0 input: mousedown
64ms input: mouseup
366ms single tap
This confirms my theory that double tap is waiting for a third click but I don't think there's an option to disable this.

I share my solution to the problem:
I copied the TapRecognizer and named it DblTapRecognizer. The interesting source code lines are:
if (tapCount === 0) {
// no failing requirements, immediately trigger the tap event
// or wait as long as the multitap interval to trigger
if (!this.hasRequireFailures()) {
return STATE_RECOGNIZED;
} else {
this._timer = setTimeoutContext(function() {
this.state = STATE_RECOGNIZED;
this.tryEmit();
}, options.interval, this);
return STATE_BEGAN;
}
}
"if (!this.hasRequireFailures())" seems to misbehave in my situation, since the comment hints at immediate firing... So just "return STATE_RECOGNIZED;" and delete the rest for the DblTapRecognizer.

We ran into similar slowness issues. Apparently there is an inherent lag on tap action on touch devices.
We ended up using FastClick
All you need to do is FastClick.attach(document.body);
This improved the "tap performance" for us.

Related

Chaining animations in SwiftUI

I'm working on a relatively complex animation in SwiftUI and am wondering what's the best / most elegant way to chain the various animation phases.
Let's say I have a view that first needs to scale, then wait a few seconds and then fade (and then wait a couple of seconds and start over - indefinitely).
If I try to use several withAnimation() blocks on the same view/stack, they end up interfering with each other and messing up the animation.
The best I could come up with so far, is call a custom function on the initial views .onAppear() modifier and in that function, have withAnimation() blocks for each stage of the animation with delays between them. So, it basically looks something like this:
func doAnimations() {
withAnimation(...)
DispatchQueue.main.asyncAfter(...)
withAnimation(...)
DispatchQueue.main.asyncAfter(...)
withAnimation(...)
...
}
It ends up being pretty long and not very "pretty". I'm sure there has to be a better/nicer way to do this, but everything I tried so far didn't give me the exact flow I want.
Any ideas/recommendations/tips would be highly appreciated. Thanks!
As mentioned in the other responses, there is currently no mechanism for chaining animations in SwiftUI, but you don't necessarily need to use a manual timer. Instead, you can use the delay function on the chained animation:
withAnimation(Animation.easeIn(duration: 1.23)) {
self.doSomethingFirst()
}
withAnimation(Animation.easeOut(duration: 4.56).delay(1.23)) {
self.thenDoSomethingElse()
}
withAnimation(Animation.default.delay(1.23 + 4.56)) {
self.andThenDoAThirdThing()
}
I've found this to result in more consistently smoother chained animations than using a DispatchQueue or Timer, possibly because it is using the same scheduler for all the animations.
Juggling all the delays and durations can be a hassle, so an ambitious developer might abstract out the calculations into some global withChainedAnimation function than handles it for you.
Using a timer works. This from my own project:
#State private var isShowing = true
#State private var timer: Timer?
...
func askQuestion() {
withAnimation(Animation.easeInOut(duration: 1).delay(0.5)) {
isShowing.toggle()
}
timer = Timer.scheduledTimer(withTimeInterval: 1.6, repeats: false) { _ in
withAnimation(.easeInOut(duration: 1)) {
self.isShowing.toggle()
}
self.timer?.invalidate()
}
// code here executes before the timer is triggered.
}
I'm afraid, for the time being, there is no support for something like keyframes. At least they could have added a onAnimationEnd()... but there is no such thing.
Where I did manage to have some luck, is animating shape paths. Although there aren't keyframes, you have more control, as you can define your "AnimatableData". For an example, check my answer to a different question: https://stackoverflow.com/a/56885066/7786555
In that case, it is basically an arc that spins, but grows from zero to some length and at the end of the turn it progressively goes back to zero length. The animation has 3 phases: At first, one end of the arc moves, but the other does not. Then they both move together at the same speed and finally the second end reaches the first. My first approach was to use the DispatchQueue idea, and it worked, but I agree: it is terribly ugly. I then figure how to properly use AnimatableData. So... if you are animating paths, you're in luck. Otherwise, it seems we'll have to wait for the possibility of more elegant code.

AJAX Submitted in order, starts in order, received out of order

I have a web application that submits an ajax request (to start an IR LED sending data) onmousedown, and stops it onmouseup. Generally works.
However if one is clicking fast I get the stop command going to the LED control before the start command. I added code to track order and the actual event submission (open on XMLHttpRequest) is in the proper order (and they are async). Then I instrumented the onstatechange to log each state and a time stamp when that state change occurs, and what I see is occasionally while the started (0) and server connection initialized (1) states occur in the proper order, the "received" (2) and subsequent states occur out of order.
My first question is whether these events are SUPPOSED to occur in the order submitted?
And if so, any idea what could cause them not to?
And if processing order is not assured, is there any way to force it (short of building my own queue and allowing only one ajax call to be outstanding, which is a paint)?
To demonstrate the issue (with client on Windows 8.1 and Chrome 39.0.2171.71m as well as IE 11.0.14, server on a raspberry pi running php 5.4.4-14+deb7u11 and Apache/2.2.22), here's a log captured from a series of events. It's small and a bit obscure, so I tried to color code each click (green, blue, orange in sequence), and the state code is in the 3rd column. Notice up (highlighted in yellow) precedes the down in the 3rd click once it gets to state 2.
Next is the code that submits it. I believe a lot of it to be irrelevant to the problem but am including it just in case. Note "RemoteFunc" is called both on mouseup and mousedown as well as (for separate objects) plain click, but each with a different func, then a POST is done. Each object either uses mouseup/mousedown or onclick, never both.
The processing time for the post can easily be greater then the duration of a mouse click, so it is not unexpected for a new "down" to come before the first "down" or "up" completes, but the issue is that I want them to process in order. And indeed they seem to be submitting in order and starting (going to state 1) in order, but are received out of order, so I assume ajax is creating multiple connections, and the response to those connections is getting out of order.
Which makes me suspect that order is not guaranteed. But I haven't found anything to confirm that (other than absence of a guarantee to be in order).
Any easy solution other than to manually build a queue and single stream the requests?
function RemoteFunc(str,func)
{
var xmlhttp=new XMLHttpRequest();
if(event.button!=0)
{
AddMessageEntry(str + " dismissed - not left click",true);
return true; //Only respond to left mouse down so context menus do not fire click and cause a competing event
}
if(taskrunning!="")
{
AddMessageEntry(str + " ignored, " + taskrunning + " already running",false);
return true;
}
if(func=="remoteup.cgi") { updown=" mouse-up"; }
else if (func=="remotedown.cgi") { updown=" mouse-down"; }
else { updown=""; }
AddMessageEntry(str + updown + " Started",true);
xmlhttp.onreadystatechange=function()
{
// if (xmlhttp.readyState==4)
// {
if(func=="remoteup.cgi") { updown=" mouse-up"; } // because this can run in overlapping functions we need to recalculate this here
else if (func="remotedown.cgi") { updown=" mouse-down"; }
else { updown=""; }
AddMessageEntry(str + updown + " " + states[xmlhttp.readyState] + " " + xmlhttp.responseText,false);
if(xmlhttp.readyState==4) {taskrunning="";}
// }
}
if(event.type.toString()=="click") // We only need to track running tasks invoked with a click -- mousedown/up are async since they run continually (from down) until stopped (from up)
{
taskrunning=str;
}
xmlhttp.open("POST","cgi-bin/" + func + "?Button="+str,true);
xmlhttp.send();
}

Listen on event during other event only

How do I listen to MouseMove event, only after I have pressed my mouse button (MouseDown event)
Im basicly looking for Click->Drag->Release functionality in a F# forms application
This behavior can be nicely captured using the F# async workflows mechanism. I wrote an article about this (implementing exactly drag & drop kind of functionality) where you can find the details - See Programming user interfaces with F# async workflows.
The sample application implements drawing where you push a button, then move the mouse (to define a rectangle) and then eventually release the button:
let rec drawingLoop(clr, from) = async {
// Wait for the first MouseMove occurrence
let! move = Async.AwaitObservable(form.MouseMove)
if (move.Button &&& MouseButtons.Left) = MouseButtons.Left then
// Refresh the window & continue looping
drawRectangle(clr, from, (move.X, move.Y))
return! drawingLoop(clr, from)
else
// Return the end position of rectangle
return (move.X, move.Y) }
let waitingLoop() = async {
while true do
let! down = Async.AwaitObservable(form.MouseDown)
let downPos = (down.X, down.Y)
if (down.Button &&& MouseButtons.Left) = MouseButtons.Left then
let! upPos = drawingLoop(Color.IndianRed, downPos)
do printfn "Drawn rectangle (%A, %A)" downPos upPos }
The nice thing here is that you can pretty nicely express the logic - wait for MouseDown (inside waitingLoop), then call the drawingLoop function which waits for MouseMove until the button is released (and then transfers the control back to waitingLoop which starts waiting for another mouse down event).
Another version of a similar piece of code is in Phil Trelford's fractal zoom, which uses the same gesture for zooming.
The complete source code is a part of the Chapter 16 source code of Real-World Functional Programming.
Attach the event listeners for move and up in the mouse down event, remove it in the up. This does mean the handler method needs to be a method (or you need to keep hold of the delegate used) to pass to the event's remove method.
(If this were for C# I would point you towards Rx—the Reactive Extensions—as this is perhaps the defining example, but I'm unsure how well Rx works with F#.)
You can also use something like this:
let setupDrag(target, fn) =
let isDown = ref false
target.MouseDown |> Event.add(fun _ -> isDown := true)
target.MouseMove |> Event.filter(fun _ -> !isDown) |> Event.add(fn)
target.MouseUp |> Event.add(fun( _ -> isDown := false)
In a real implementation, you may want to actually do other stuff when the transition starts, stops, and all those things. You may for example want to capture the pointer on target.

d3.js - transition interruption event?

I was wondering how to handle the fact that an interrupted transition within d3.js does not trigger an end event. As the API doc says
Note that if the transition is superseded by a later-scheduled
transition on a given element, no end event will be dispatched for
that element; interrupted transitions do not trigger end events.
from: https://github.com/mbostock/d3/wiki/Transitions#control
In my case transitions are triggered by user interaction. These transitions might be interrupted when the user triggers a new transition through mouse click. Let's say in the first transition an element was meant to fade out and be removed at the end of the transition. If this transition is interrupted the element will never be removed. I could disallow further user interaction during the time a transition happens yet that is not really what I want (particular as i have back and forward buttons which allow the user to click through previous states of my svg graph quickly ... ) Basically I would need an "Interruption Event"
Thanks
martin
I think there is no really satisfactory way to do this. A little bit painful workaround would be counting the number of transitions currently taking place and reasoning from that.
So, initialize:
var transitionCount = 0;
And whenever you schedule new transitions:
if ( transitionCount != 0 ) {
// handle interrupted transitions here somehow
transitionCount = 0;
}
var myTransition = selection.transition().... ;
transitionCount += myTransition.size();
myTransition.each('end', function() { transitionCount --; });
If you can handle manually cleaning up interrupted transitions like this, this would be fine. Notice, that you can't use 'start' events to increment the counter as there is a delay between scheduling a transition and it being started so you'd get a race condition there.

JavaFX: pause transition, not equal times

I have written a small application that performs some long-running tasks. Instead of having the user to wait and seeing just a progress bar, I would like to display some (changing) information about the application.
For that purpose, I wrote the following code within the constructor of an extended Pane:
FadeTransition fadeOutTransition = new FadeTransition(Duration.millis(1000), this);
fadeOutTransition.setFromValue(0.8);
fadeOutTransition.setToValue(0.0);
Similarly the fadeInTransition. And further...
SequentialTransition seqTransition = new SequentialTransition (
new Transition() {
{ setInterpolator(Interpolator.DISCRETE);
setCycleDuration(Duration.seconds(1)); }
protected void interpolate(double frac) {
int nextElement = (int) ((explenations.size() - 1) * Math.random());
Explenation explenation = explenations.get(nextElement);
questionLabel.setText(explenation.getQuestion());
answerLabel.setText(explenation.getAnswer());
}
},
fadeInTransition,
new PauseTransition(Duration.seconds(15)),
fadeOutTransition
);
What I woud like is the text to fade in, stay there for ~15 seconds and then fade out again. Unfortunately, the animation flickers, moves faster and slower - and the PauseTransition never takes 15 seconds! What is wrong about the code? I'm using Java 7, and JavaFX 2.2 on Mac OS X.
The problem seems to be that I called the function
seqTransition.play();
multiple times. From there comes probably the flickering and the unequal waiting time.

Resources