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

Pan event doesn't work correctly with touch-action pan-y in Chrome 55 #1050

Open
zuibunan opened this issue Nov 28, 2016 · 49 comments
Open

Pan event doesn't work correctly with touch-action pan-y in Chrome 55 #1050

zuibunan opened this issue Nov 28, 2016 · 49 comments

Comments

@zuibunan
Copy link

Before upgrade to Chrome 55.0.2883.59 beta (64-bit), it works fine
but now, when I pulldown in chrome emulator , the panmove event just triggered once or twice, and the event data is not correct

image

this is the right event data when i set touchAction none, but if touchAction is none , the page will not scroll

image

coarse demo
http://jsbin.com/tevitozuku/edit?output

@BossLevel
Copy link

I have a similar problem - panmove has been working for nearly 2 years, no change to the code and it's stopped. This is Chromium Version 55.0.2883.75 (64-bit). The event appears to trigger correctly at first but the event data I am capturing (var x = event.changedPointers[0].movementX * -1;var y = event.changedPointers[0].movementY * -1;) appears as 0 values. The event will then trigger with any mouse move (not pan) over the bound area.

It appears to work fine in Firefox 50.0.2 but there my bound Tap events are now passing incorrect x/y info.

@glomotion
Copy link

I think i too am having this issue after updating to Chrome to Version 55.0.2883.75.

All pan directions are a problem for me right now. PanStart fires as expected, but the onPan event fires once only, for that entire gesture.

*Note, it only seems to be a problem while touch emulation is running. If you disable "touch emulation" then everything works as expected.

My guess is the chrome team changed something in the way that chrome emulates device touch events...

@vnavarrete17
Copy link

+1 , I have the same problem on pandown/panup and my panend is never triggered .
:(

@IgorKharkiv
Copy link

IgorKharkiv commented Dec 14, 2016

+1 , I have the same problem on pandown/panup and my panend is never triggered .
:(

+1 This is a very big problem =((

@BossLevel
Copy link

Agreed - I'm going to have to pull hammer out of my project if it remains this way.

@sitexw
Copy link

sitexw commented Dec 15, 2016

Ok, I'm not crazy ^^ I have exactly the same problem.
(Except that in my case, I am on the eve of a release in production !)

@arjunkathuria
Copy link
Contributor

arjunkathuria commented Dec 15, 2016

looks like chrome team indeed update touch-action options.

they added 'pan-up pan-down pan-left pan-right' with earlier pan-x and pan-y.
link here

they might be interfering with the TOUCH_ACTION constants in hammer.
link here

These properties force the user to start gestures in one direction before the element will respond. This is similar to the "pull-to-refresh" gesture which only responds when the user gestures downwards on the screen.

This line could be the troubling bit.

cc:- @arschmitz

@glomotion
Copy link

So we're also in the unfortunate predicament of being very, very close to a launch. The app concerned is pretty heavily affected by this bug.

Is there any chance at all, we could get some kind of eta on a potential patch? Or even just an indication of how severe this problem really is (and how complicated the fix will need to be) - would be awesome.

I really don't want to have to rip hammer out of the project (hammer rox!) - but may be forced to if this issue remains for much longer. :(

@zuibunan
Copy link
Author

@glomotion Chrome Dev for Android have the problem too , not only emulator

@glomotion
Copy link

@zuibunan Yup. I'm now finding that too. :( I think it was because the Android devices I was testing on were yet to upgrade to Chrome 55. 55 appears to have since rolled out to all our test devices now - and now they all show this problem.

@raghavendra-polanki
Copy link

Any one able to find a solution for this problem?

@gargsahil25
Copy link

Make sure you set the proper touch-action css attribute for your canvas element.
Ref: https://developers.google.com/web/updates/2016/10/touch-action
My issue got resolved by adding below code in my css
.main-canvas { touch-action: none !important; }

@rejhgadellaa
Copy link

I've done some digging and testing and it looks like the Chrome's new Pointer Events api has some issues:

  • On desktop it fires pointermove after pointerup
  • On mobile (android, at least) the touch-action css property does not get inherited by child elements

That last thing might be the problem if you, like me, attached hammer to an element that has children because the event gets cancelled if you start the touch on a child element (it fires pointerdown, pointermove and then pointercancel).

I've created tickets for the issues above on the chromium tracker so you can star those:
https://goo.gl/esp1S5 and https://goo.gl/LesGXI

@rejhgadellaa
Copy link

rejhgadellaa commented Dec 16, 2016

As an addition to @gargsahil25 solution: make sure the touch-action property is set to all child elements as well:
.main-canvas, .main-canvas * { touch-action: none; }

I recommend not using the !important because you may want to override that property for one or more child elements, like..
.main-canvas .cant-touch-this { touch-action: auto; }

Also, using !important is not a good idea in general and should only be used when needed. Or maybe unless gargsahil25 has a very good reason for using that, of course :)

(PS: the above solution is a complete hack/workaround for a bug. the bug needs fixing, this solution needs to go :P)

@antipod
Copy link

antipod commented Dec 16, 2016

Thanks @gargsahil25, it worked semi-ok. I have a couple of carousels on the mobile website and this at least made it pan i y-direction as it did before. The only problem is that before Chrome 55 rolled out, I could put my finger on the carousel and scroll up and down on the page, whereas now nothing happens.

Maybe that can be solved with hammer.js itself. If anyone have a clue about how to fix that, I'm listening.

@rejhgadellaa
Copy link

@antipod You want horizontal carousel but have vertical scroll work?
`touch-action: pan-y;

See hammerjs docs:
http://hammerjs.github.io/touch-action/

And:
https://github.com/hammerjs/hammer.js/wiki/How-to-fix-Chrome-35--and-IE10--scrolling-(touch-action)`

@antipod
Copy link

antipod commented Dec 16, 2016

@rejhgadellaa I did try that but it doesn't work completely. I can pan in the x direction, and it will allow me to scroll on the page. BUT, hammer.js registers that vertical scroll as a panleft / panright on the carousel and it bugs like it did before, after Chrome updated to 55. Though it only registers it once. Still, this offsets the carousel. Might be a solution there somewhere... I'll find it.

@rejhgadellaa
Copy link

@antipod did you also attach touch-action to all the child elements? see my comment above. I have an implementation like that (with pan-y) and it works for me.

@BossLevel
Copy link

I'm afraid that touch-action on my affected elements didn't solve any of them so sadly it appears to be an incomplete hack.

@runspired
Copy link
Contributor

cc @arschmitz I think this is a little out of my knowledge domain at the moment, if there's a new spec to read I'll read it and a link to new APIs is appreciated but sounds like this may also require some spelunking on how the new stuff works?

@hanwiz
Copy link

hanwiz commented Dec 20, 2016

When I use v2.04 or the latest version v2.08 Nov, this doesn't allow me to pan or swipe in Chrome 55. However, with v2.08 Apr, distributed version irons out all the bugs I got. So someone like me should use the distributed version first before trying anything else.

Oops, actually without "touch-action: none", it doesn't work in the Chrome debugging mode (touch emulation).

So, you should use both the distributed version v2.08 Apr and touch-action: none.

@BossLevel
Copy link

Again, using the Apr distributed version (I'm assuming by that you mean the .min.js file) === no dice (I was using that version all along).

Noting that the Hammer home page works fine and demos the functionality that I previously had working with panmove, I had a look at the code. I see there that you use the event.deltaX/Y values where I had been using the event.changedPointers[0].movementX/Y values. However adapting my code to use these did not result in a fix as e.g. changing direction mid-pan is not reflected by these values (as they are deltas).

@runspired & @arschmitz I really apologise for telling you guys what to do, but it strikes me that if the developers of the world's most popular browser decide to alter their internal API and that impinges directly on your maintained project's functionality, then you're going to have to bite the bullet and re-factor. Or be maintainers of an increasingly out-of-date project.

@BossLevel
Copy link

And if it's any consolation (and I know it isn't) I've had Google do this to me on multiple occasions also :(

@hanwiz
Copy link

hanwiz commented Dec 21, 2016

@BossLevel Can you adapt your code something like this? In firefox, two values are the same most of the time except outside the boundaries. Here is my pen http://codepen.io/hanwiz/pen/ObqGEo.

var pY=0;
// listen to events...
mc.on("panleft panright panup pandown tap press", function(ev) {
    myElement.textContent = ev.type +" gesture detected." + ev.changedPointers[0].movementY + " " + (ev.deltaY - pY);
   pY = ev.deltaY;
});

@BossLevel
Copy link

@hanwiz - thanks for your time and effort - the good news is that with some slight modifications, your code works :)

2 points to make before documenting said modifications:

  1. I had wanted to avoid the use of some "globals" (pY - I know it's not a proper global) as it seemed redundant to have to manage these when Hammer was meant to be doing it for me. However given the ease and speed of implementation utilising these, needs must.
  2. FYI, as per my original post, the ev.changedPointers[0].movementX/movementY values are always zero for me, no matter where and how fast I pan.

With that in mind, line 14 of your pen can be reduced to myElement.textContent = ev.type +" gesture detected." + (ev.deltaY - pY);

In addition, after ending a panmove, the next pan jerks initially. To remove this add the additional following binding:

mc.on('panend', function(event) {
			pX = 0;
			pY = 0;
		});

I still think something needs to be done about this issue (or at least have an example/documentation on the site) but that's your business and I once again thank you for your efforts, particularly @hanwiz

@hrvojekindl
Copy link

hrvojekindl commented Dec 28, 2016

Adding the "touch-action: pan-y" to the affected scrollable element (and it's descendants) solved the issue for me. Here's the SASS class that I used:

.scroll-and-swipe {
  overflow-y: scroll;
  touch-action: pan-y !important;
  -webkit-overflow-scrolling: touch;

  & * {
    touch-action: pan-y !important;
  }
}

@glomotion
Copy link

So I'm still having quite a few problems with Hammer.
Even the simplest examples of hammer seem to be broken in Chrome (with touch emulation enabled) atm.
Also, having padding applied to the hammer bound element also seems to cause issues with offset calcs.

http://codepen.io/creative-lab-sydney/pen/ygyMMO

@miksh7
Copy link

miksh7 commented Jan 30, 2017

One of the Chromium tickets mentioned above has been fixed
https://bugs.chromium.org/p/chromium/issues/detail?id=161464

Would it fix this issue or the Hammer team should still make a fix?

@wmertens
Copy link

@Mathews2115 has your workaround been behaving well? Would it be hard to do this in hammerjs itself?

I don't understand how the bogus event comes to be, for me it only happens when I pan across a certain area of my screen…

@Mathews2115
Copy link

@wmertens So far so good on my end.

@blackswanny
Copy link

fixed with the same
if(ev.srcEvent.type !== 'pointercancel'){
however, 50% of my pans are marked as canceled, which are rejected

@Zenfeder
Copy link

@glomotion Thank you very much, it works correctly when i do it as you said.

@MattKunze
Copy link

@blackswanny - I think I'm seeing similar behavior where many of the pans aren't being recognized right on Android, I made a project to reproduce the issue and #1118 as a simple fix that improves the case I'm running into at least

@web-jenezis
Copy link

Got the same issue yesterday during the work with Hammer.js. Here is the solution:

// by default, it only adds horizontal recognizers
var mc = new Hammer(myElement);

// let the pan gesture support all directions.
// this will block the vertical scrolling on a touch-device while on the element
mc.get('pan').set({ direction: Hammer.DIRECTION_ALL });```

@paranoidjk
Copy link

same problem here.

@malina-kirn
Copy link

@web-jenezis : your solution worked for me. I saw that the pointercancel event type pointed out by @alexanderwiebe was indeed causing the bad deltaX and deltaY values, but as @blackswanny commented, some interactions were nearly all pointercancel events, so discarding them would occasionally cause the pan to be almost completely unresponsive. Setting the pan direction caused the pointercancel events to stop firing altogether.

@blackswanny
Copy link

@web-jenezis @malina-kirn I used Hammer for React and not sure that directions prop is passed to hammer, cause i still see issues with it


 <Hammer
            direction={Hammer.DIRECTION_ALL}
            onPan={this.onPan}
            onPanEnd={this.onPanEnd}
            onPanStart={this.onPanStart}
            onDoubleTap={this.onDoubleTap}
            options={{
                recognizers: {
                    swipe: {
                        enable: false
                    },
                    pinch: {
                        enable: false
                    },
                    press: {
                        enable: false
                    },
                    pan: {
                        enable: true
                    },
                    tap: {
                        enable: true
                    }
                }
            }}>

@malina-kirn
Copy link

malina-kirn commented Oct 26, 2017

@blackswanny : as @web-jenezis pointed out, setting the direction attribute blocks vertical scroll on the element. Perhaps you can block native vertical scroll instead of setting direction? This also seems to work for me:

CSS:

.no-scroll {
  overflow: hidden;
}

Add the no-scroll class to the element you're panning. I'd previously tried this on outer elements (blocking scroll on the entire page), but it seems it must be applied directly to the element being panned. I suspect it would have worked if I'd applied the rule to all child elements.

@grumpygary
Copy link

add:
delete window.PointerEvent;
in your index.html PRIOR to loading hammer.js, and it will ignore those events.
You can also set SUPPORT_POINTER_EVENTS = false; (line 384 of v2.0.8) to do the same thing.
Ideally the devs would add the ability to turn this off, but so goes the open source dilemma...

@ghost
Copy link

ghost commented Dec 7, 2017

@garyskiba

easier solution if you add the

var SUPPORT_POINTER_EVENTS = false; line at the beginning of your file.

It's dirty but at least don't touch the hammer.js itself

@blackswanny
Copy link

@fssrepository , according to what i see it's not global var and we can't override it so hammer will pick up another value. But I would rather change this var than override native PointerEvent, cause not like to affect other parts of app

@SelfishLucho
Copy link

@garyskiba @fssrepository Both solutions brakes 'press' if u are unfornate as me if u want to use both 'pan' and 'press' with hammerJS globally available

pirxpilot added a commit to pirxpilot/liftie that referenced this issue Dec 24, 2017
Chrome > 55 implements pointer events but in order for them to work
properly we need to make sure that all children of swipe element have
touch-action property (it is not inherited in chrome)

see:
hammerjs/hammer.js#1050
@simeyla
Copy link

simeyla commented Aug 29, 2018

The actual issue described still persists today - not surprising since hammerjs hasn't been updated.

That is the issue of getting wildly odd numbers like

deltaX: -120
deltaY: -118

As others have mentioned, the solution is to use touchAction: 'none' on the thing you're panning. Unfortunately if you want this 'thing' to be scrollable vertically (as part of normal vertical scrolling behavior) you must remove this touchAction - because the browser locks the scrollability when you have it.

I had cases where I wanted to be informed about the attempt of the user to scroll - i didn't really need a delta. I just needed to know which direction it was.

Turns out you can filter out these bizarre numbers with:

filter(e=> e.center.x != 0 && e.center.y != 0)

That leaves you with a few events like e.deltaX = 2, e.deltaY = -11 but that will let you scroll the page and still get an indication of the users intent.

Remember that when you scroll the whole page what do you really expect delta to be? You're moving the whole viewport after all! This at least filters out that awful janky large seemingly random numbers.

Me 36 hours ago: "I'm so excited to finally have time to play with hammerjs, the leading gestures library - and never have to worry about compatibility ever again"
Me now: REDACTED

@marcus13371337
Copy link

On the parent wrapper:
touch-event: none

The element inside the wrapper I wanted to be able to scroll vertically:
touch-event: pan-y

Solved it for me!

@divisey
Copy link

divisey commented Sep 18, 2019

I have tried

if (ev.eventType !== Hammer.INPUT_MOVE) return;

in my handler. this saves me from the trouble.

@melnikovau
Copy link

melnikovau commented Nov 29, 2019

Thanks @divisey

That combo works fine to me:

var mc = new Hammer(kek, {
    recognizers: [
        [Hammer.Pan, { direction: Hammer.DIRECTION_HORIZONTAL, pointers: 1, threshold: 10 }]
    ]
});

mc.on('panright panleft', function(ev) {
    ev.preventDefault();
    if (ev.eventType !== Hammer.INPUT_MOVE) return;
    if (ev.pointerType == 'touch' && (Math.abs(ev.deltaX) <= Math.abs(ev.deltaY)+5)) return;
    if (ev.srcEvent.type !== 'pointercancel') {
        ...
        your code
        ...
    }
});

@elena-cz
Copy link

I was also getting a lot of premature pointercancel events while panning on Chrome. This ended up working for me:

Adding the touch-event: pan-y property to the child div inside the parent Hammer container. So for the hammer container, I left the default settings (which applies "touch-event: pan-y"), and didn't have to add "touch-events: none" anywhere.

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

No branches or pull requests