Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pressup does not fire if finger is moved before touch ends #751

Closed
gregtzar opened this issue Jan 22, 2015 · 11 comments
Closed

pressup does not fire if finger is moved before touch ends #751

gregtzar opened this issue Jan 22, 2015 · 11 comments

Comments

@gregtzar
Copy link

In hammer v1.x touchrelease worked fine. Since touchrelease no longer exists in hammer v2.x I am using pressup instead. However, pressup is not fired if the finger is moved before releasing. Is this a bug, or by design? Is there a way to replicate the touchrelease functionality in hammer v2.x?

@jaredLunde
Copy link

I was able to get around this by adding additional listeners for touchend and mouseup on the element. You'll want to track whether or not press was fired in your onRelease callback, too.

e.g.

pressed = false;
function onHold(e){
  pressed = true;
}
function onRelease(e){
  if(pressed){ 
    do_stuff 
    pressed = false;
  }
}
hammer.on('press', onHold);
hammer.on('pressup', onRelease);
goog.events.listen(element, 'mouseup', onRelease);
goog.events.listen(element, 'touchend', onRelease);

@runspired
Copy link
Contributor

@arschmitz I've encountered this a few times. Basically the TL;DR is that instead of pressup firing pan begins to be recognized.

The first interactive example here demos this behavior: http://runspired.github.io/ember-mobiletouch/#/action-area-example

I've often debated whether this is a bug (pan shouldn't recognize after press has been recognized) or a feature (pan should still be recognized if a press turns into a pan). I lean towards feature, but this should probably be warned about.

@arschmitz
Copy link
Contributor

@runspired Yeah things like this come up all the time with custom events like this what events should prevent other events. Should double tap prevent a single tap or a press prevent a tap a tap prevent ( or cause ) a click etc...

I tend to lean towards the non preventing route there are valid use cases for wanting both. If you only want one you should ( and i know this does not currently work here YET ) but call preventDefault and then the later events should check if default has been prevented.

@runspired
Copy link
Contributor

Custom gestures using recognizeFailure and recognizeWith are also ideal for situations in which explicit control over the behavior is needed.

@superlin
Copy link

I meet the same bug

@runspired
Copy link
Contributor

Closing as I believe this is by design, see my previous comment for a way to make this behave the way you want.

@transfluxus
Copy link

the example link is not working anymore and I don't find a clear answer to this problem.
I miss the press_up even tho I don't register pan activities or registered with enable: false

cduivis added a commit to cduivis/hammer.js that referenced this issue Oct 12, 2017
The `Press` gesture recognizer in HammerJS has problems consistently firing a `pressup` event following a `press` event in the context of small `time` values. This is well-known. See e.g. hammerjs#1011, hammerjs#836, hammerjs#751.

We've found that given a pair of `Press` and `Pan` gestures configured as below, the `pressup` event will fairly consistently break ( especially when using touch input ).
This particular scenario is used for detecting a `Press` for instant setting of a position and `Pan` gradually controlling a set position ( we specifically use this for creating a "dual-ended between" variant of the `input type="range"` ):

```js
{
  recognizers : [
    [ Hammer.Pan, {
      direction : Hammer.DIRECTION_HORIZONTAL,
      threshold : 0
    }],
    [ Hammer.Press, {
      threshold : 1,
      time      : 0
    }]
   ]
}```

The root cause is with a granularity problem with browser timeouts as used in the `setTimeoutContext`, which causes part of the gesture logic to fire too late (or not at all). This issue and probably others like it, such as hammerjs#1011, hammerjs#836 or hammerjs#751 can be fixed by not using a timeout at all if the gesture's `time` property is 0.
@codeabilly
Copy link

Ok, I've had the same issue and fast googling didn't give any solution.
So here's how I tackled the problem.

I added another hammer listener.

function onHold(e){
  // do some hold stuff here
}
function onRelease(e){
  // release stuff here
}
function onPanEnd(e){
  if (e.target !== e.srcEvent.target) {
    onRelease();
  }
}
hammer.on('press', onHold);
hammer.on('pressup', onRelease);
hammer.on('panend', onPanEnd);

You can replace panend with panmove if you want to trigger release event as soon as you move pointer away from your target element.

@kmlprtsng
Copy link

I had the issue when using hammerjs with Ionic 2 (Angular 2+) and I manged to get it working by removing recognizers that I didn't need.

public ngAfterViewInit() {
    if(this.blurOverlayElement) {
      const mc = Hammer(this.blurOverlayElement.nativeElement, {});
      mc.remove(Constants.hammer.pan);
      mc.remove(Constants.hammer.rotate);
      mc.remove(Constants.hammer.pinch);
      mc.remove(Constants.hammer.swipe);
      mc.remove(Constants.hammer.tap);
      mc.remove(Constants.hammer.doubletap);
    }
}

However, on Google Pixel, if I tapped my blurred overlay , even then the press up and press events were getting fired and in the wrong order 😞.

@kmlprtsng
Copy link

I ended up using timeout to simulate press event.

<div class="blur-overlay"
      (touchstart)="onPhotoTouchStart($event)"
      (touchend)="onPhotoTouchEnd($event)"
      (mousedown)="onPhotoTouchStart($event)"
      (mouseup)="onPhotoTouchEnd($event)"
      (mouseout)="onPhotoTouchEnd($event)">

onPhotoTouchStart(event: Event) {
   event.preventDefault();
   clearTimeout(this.touchStartTimer);
   
   this.touchStartTimer = setTimeout(() => {
     this.isClear = true;
   }, 250);
 }

 onPhotoTouchEnd(event: Event) {
   event.preventDefault();
   clearTimeout(this.touchStartTimer);
   this.isClear = false;
 }

@jackie-d
Copy link

Hi,
reading all the solution I found the one that works for me.

Basically, the "pan-end" event fires every time you move your pointer away from the press start point and then release the press anywhere. So just by catching it, it works as same as the "press-up" event.

    const hammerTime = new Hammer.Manager(this.thePressableButton.nativeElement);

    hammerTime.add(new Hammer.Press({}));
    hammerTime.add(new Hammer.Pan({}));

    hammerTime.on('press', (event: MSGestureEvent) => {
      this.onPress();
    });

    hammerTime.on('pressup', (event: MSGestureEvent) => {
      this.onPressUp();
    });

    hammerTime.on('panend', (e) => {
        this.onPressUp();
    });

with onPress() and onPressUp() being your functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants