Number of touchmove events severely reduced on Android 2.3.3 - javascript

I am currently working on the redesign of a website following the responsive design + mobile first approach.
I am trying to detect swipe events using JS on touch-enabled devices. For this purpose, I am using the following code:
document.addEventListener ('touchstart', function(event) {
//Get initial finger coords
}, false);
document.addEventListener ('touchmove', function(event) {
//Update final finger coords
}, false);
document.addEventListener ('touchend', function(event) {
//Compare initial and final coords, trigger swipe events if necessary
}, false);
I have tested this code on an iPad 1, an iPhone 4 and several devices running Android 2.2.1, and the result when I drag my finger on the screen is what I am expecting: the touchmove event fires several times (it can easily rise up to a hundred when doing a long gesture).
The problem comes when I test it on an Android 2.3.3 device (I'm using a Samsung Galaxy S2). Using its native broswer, the amount of touchmove events is reduced to only 1 (or rarely 2).
Am I doing something wrong or is it supposed to behave like that? Has anybody found the same problem? I was unable to find documentation about the behaviour of touchmove events in this version of Andriod.
You can test it here (using a touch-enabled device): http://jsfiddle.net/xs5BG/embedded/result/

It seems that galaxy S2 doesn't fire the touchmove after the scrolling starts to work. If you do a preventDefault it fires the events as expected.

Testing your jsFiddle example with my HTC Desire Z (running 2.3.3) i get many more than just one touchmove event - as desired. So i am unable to reproduce your actual problem with this device, although on the same API Level :( Interestingly enough your code also shows the problem that i am experiencing on my current project: The first touchmove event seems to have some kind of a threshold:
Putting the finger down and only moving a tiny bit will give 0 touchmove events... once over the threshold it will trigger touchmove events in intervals of milliseconds as it then recognises each and every pixel distance of a move (like it should do). Maybe this could be related to your phenomenon, respectively do you see this on your 2.3.3 device as well?

On many android versions if you don't preventDefault on touchstart the Android device will go into default scrolling mode and stops sending touch events to webview. So you would need to
document.addEventListener ('touchstart', function(event) {
event.preventDefault();
}, false);
Now all the touch events will fire, but default scrolling will be disabled.
There is a shim to overcome this issue that emulates a swipe gesture https://github.com/TNT-RoX/android-swipe-shim

Related

Surface Pro 3 with Firefox - Have single touch trigger touch/mouse events instead of wheel events

On the Surface Pro 3 with Firefox only:
When making a swiping gesture with a single finger over an element, the browser will fire wheel events instead of touchmove or mousemove events. How do you stop the wheel behavior, and allow a single finger to always be treated as touch/mouse movement instead?
So I want to treat a single finger swipe as a series of mousemove or touchmove instead of as wheel events. I do not want a single finger swipe to scroll the page at all if swiping over this element. This is easy to do in Chrome and IE11. This seems not-possible right now in Firefox. Current I think this is a bug, but there may be something I'm missing.
Here is a simplistic example:
http://codepen.io/simonsarris/pen/PwbdRZ
var can = document.getElementById('can');
can.addEventListener('mousemove', function(e) {
// Will never happen on the Surface Pro 3 in Firefox
// Will happen in IE11 though
console.log('mouseMove')
});
can.addEventListener('touchmove', function(e) {
// Will never happen on the Surface Pro 3 in Firefox
// Will happen in Chrome though
console.log('touchMove')
});
// Stops the window from scrolling in firefox when you swipe on the element
// But stopping this does not allow the single touch gesture to register as mousemove or touchmove events
can.addEventListener('wheel', function(e) {
console.log('wheel')
e.preventDefault();
});
// consider also the 'DOMMouseScroll' event, though preventing this event will not stop firefox from panning the page.
Because I am preventing default in wheel, scrolling the page is stopped when one-finger swiping up or down
The window scrolling is stopped in firefox if you swipe in the red box, but no mousemove or touchmove events will fire. (yet mousemove will fire if you swipe horizontally instead of vertically)
Touch events are currently disabled in the desktop version of Firefox (36.0.4), though they will work while running Firefox in Metro mode or by explicitly enabling them via the dom.w3c_touch_events.enabled setting. See the MDN article on Touch events for more information.

How do I get touch events without big library

I am using jquery, but I don't want to use jquery mobile, because it is so large, and I don't think I need it. All I am trying to do is get a touch event. This is what I've got.
$('#menuButton').on('click touchstart', function(){
$('#menu').toggleClass('block')
});
It only kind-of works, but seems to be firing twice a lot on my phone. I think I should check for both touchstart and touchend somehow. This needs to work on all types of devices, hopefully. Thanks!
Behold! The lifecycle of a touch:
your finger hits the glass -> touchstart!
your finger leaves the glass -> touchend!
your finger it lingers -> click!
Now the lifecycle of a mouse click:
your finger depresses the button -> mousedown!
your finger it removes pressure from the button -> mouseup!
your finger it lingers -> click!
If you are listening for both touchstart and click, the event will fire once on mouse or trackpad computers, and twice on touch devices as you are listening for 2 events in the lifecycle.
If you really want to use click for desktops and touchstart of touch devices (a good idea in many cases), you can do something like this:
var clickEvent = (isMobile)?'touchstart':'click';
$('#menuButton').on(clickEvent, function(){
$('#menu').toggleClass('block')
});
How you go about finding isMobile is another story.
update : I've written a handy script for detecting mobile, if your interested its npm isMobile

Understanding touch events

I'm trying to make some of my libraries work with touch devices, but I'm having a hard time trying to figure out how they're supported and how they work.
Basically, there are 5 touch events, but it seems there's consensus among mobile browsers only on the touchstart event (duh). I've created a fiddle as a test case.
I've tested this on my Galaxy Note with Android 4 on board, but you can check the link with a desktop browser too.
The goal is to try to figure out how to handle taps, double taps and long taps. Nothing fancy.
Basically, this is what happens:
The Android stock browser doesn't fire touch events. It just tries to emulate mouse clicks with taps, firing mousedown, mouseup and click events consecutively, but double taps just zoom in and out tha page.
Chrome for Android fires the touchstart event when the finger touches the screen. If it's released soon enough, it fires then mousedown, mouseup, touchend and finally click events.
In case of long tap, after about half a second it fires mousedown and mouseup, and touchend when the finger is lifted, with no click event at the end.
If you move your finger, it fires a touchmove event a couple of times, then it fires a touchcancel event, and nothing happens afterwards, not even a touchend event when lifting the finger.
A double tap triggers the zoom in/out features, but event-wise it fires the combo touchstart-touchevent twice, with no mouse events fired.
Firefox for Android correctly fires the touchstart event, and in case of short tap fires mousedown, mouseup, touchend and click afterwards.
In case of long tap, it fires mousedown, mouseup and finally touchend events. It's the same of Chrome for these things.
But if you move your finger, if fires touchmove continously (as one may expect) but it doesn not fire the touchleave event when the finger leaves the element with the event listener, and doesn't fire the touchcancel event when the finger gets out of the browser viewport.
For double taps, it behaves just like Chrome.
Opera Mobile does the same thing of Chrome and Firefox for a short tap, but in case of long press activates some sort of sharing feature that I really want to disable. If you move your finger, or double tap, it behaves just like Firefox.
Chrome beta does the usual for short taps, but in case of long taps it doesn't fire the mouseup event anymore, just touchstart, then mousedown after half a second, then touchend when the finger is lifted. When the finger is moved, now it behaves like Firefox and Opera Mobile.
In case of double taps, it doesn't fire touch events when zooming out, but only when zooming in.
Chrome beta shows the oddest behaviour, but I can't really complain since it's a beta.
The question is: is there a simple and way to try to detect short taps, long taps and double taps in the most common browsers of touch devices?
Too bad I can't test it on iOS devices with Safari, or IE for Windows Phone 7/Phone 8/RT, but if some of you can, your feedback would be very appreciated.
If you haven't already, I would suggest reading the source code for Hammer.js
https://github.com/hammerjs/hammer.js/blob/master/hammer.js
Between comments and code it's about 1400 lines, there is great documentation and the code is easy to understand.
You can see how the author has chosen to solve a lot of the common touch events:
hold, tap, doubletap, drag, dragstart, dragend, dragup, dragdown,
dragleft, dragright, swipe, swipeup, swipedown, swipeleft, swiperight,
transform, transformstart, transformend, rotate, pinch, pinchin,
pinchout, touch (gesture detection starts), release (gesture detection
ends)
I think after reading the source code you will have much better understanding of how touch events work and how to identify which events the browser is capable of handling.
http://eightmedia.github.io/hammer.js/
There's a really excellent resource https://patrickhlauke.github.io/touch/tests/results/ that details the order of events across a staggering number of browsers. It also appears to be updated regularly (in September 2016, it was last updated August 2016).
The gist is, essentially everything triggers mouseover and related events; most also trigger touch events, which usually complete (reach touchend) before mouseover and then continue to click (unless a change to page content cancels this). Those awkward exceptions are thankfully relatively rare (3rd party android browsers and blackberry playbook).
That linked resource goes into an impressive level of detail, here's a sample of the first three of many, many operating system, device and browser tests:
To summarise some of the key points:
Mobile browsers
All listed browsers trigger mouseover on the first tap. Only some Windows Phone browsers trigger it on a second tap.
All trigger click. It doesn't specify which cancel click if mouseover changes the page (I believe most do)
Most browsers trigger mouseover after touchstart and touchend. This includes iOS7.1 Safari, stock Android, Chrome, Opera and Firefox for Android, and some (not all Windows phone browsers)
Several Windows Phone browsers (all Windows 8 / 8.1 and one version for 10) and several 3rd-party Android browsers (Dolphin, Maxathon, UC) trigger mouseover after touchstart and touchend.
Only Blackberry Playbook triggers mouseover between touchstart and touchend
Only Opera Mini and Puffin (3rd party Android browser) lack touchstart or touchend.
Desktop browsers
Reasonably up to date versions of desktop Chrome and Opera behave like their mobile counterparts, touchstart and touchend followed by mouseover.
Firefox and Microsoft browsers (IE <=11 and many versions of Edge) don't trigger any touchstart and touchend events.
No data on Macs, but presumably no Ma browsers support touchstart and touchend given the scarcity of Mac touchscreen interfaces.
There's also an incredible amount of data on browsers combined with assistive technologies.
Yes you can start a timer attouchstart and end it on touchend and make your choices from there.
Also you can make... let's say swipe, my triggering touchmove you can get the coordonates of the "finger" and see how much i traveled before touchend gets triggered.
I don't know if there's any simpler way rather than using a touch events library, but i suppose you could write one for simple 'tap', 'double tap', 'swipe' events pretty easily.
Here is my latest observation on touch and mouse events on Android 4.3
Opera, Firefox, and Chrome seem to have a standard behavior
On Swipe (touchstart-touchmove-touchend):
No mouse event(exluding mouseover) fires.
Mouseover fires only if touchstart and touchend occurs on the same element. (touchstart-touchmove-touchend-mouseover)
If default is prevented on touchstart: the default swipe behavior does not work. no changes occur regarding mouse event firing.
On Tap(touchstart-touchend):
All mouse events mouseover-mousemove-mousedown-mouseup-click fire after a delay
If default is prevented on touchstart: only mouseover fires.
Android default browser has some non-standard behaviors:
Mouseover fires before touchstart which means mouseover always fires.
All mouse events fire on Tap, even if the default is prevented on touchstart.

iOS Delay between touchstart and touchmove?

I'm attempting to convert my web app into a form usable by mobile devices. I'm attempting to build in support for touch gestures like horizontal scrolling. I'm finding some strange behavior in my app.
I start a gesture with a touchstart event, and then scroll on touchmove. However, my application sees a 500-700 ms delay between receiving these two events. As far as I can tell, my app is doing no other work between these two events.
Other aspects:
The code is written in jquery, using
$(element).bind(touchmove, function(ev) {return myobject.DoTouch(ev) }
were the DoTouch command simply checks the ev.type, records the touch position, and returns false.
Any ideas what I should look for to try to solve this? The lag between touching and getting a response from the app is very annoying.
Yes. It turns out, this is how iOS works. I was pulling my own hair out for some time. Read more here: http://developer.apple.com/library/ios/#DOCUMENTATION/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html. Essentially, if iOS thinks it can handle this as an internal PAN gesture, it does and doesn't even bother sending a touchmove event at all.
In my project, I found that if the viewer makes the touchmove gesture very deliberately and pauses a bit longer before lifting the finger at the end of the move, then the touchmove event is, in fact, sent as one might expect. So, the documented behaviour may be a little iffy versus reality, which only added to confusion and my debugging efforts.
Anyway, if iOS handles the event internally as a PAN gesture, it will send a scroll event before the touchend. In my project I was able to use this to set the flag I was using to distinguish dragging gestures (which was normally sent in my touchmove handler) and ignore any behaviour in stand-alone touchend handlers that were not related to the handling of my own scroll-handling.
I hope this helps you (and others) as well!

Documentation for touchscreen events in Javascript

Where can I find documentation or a reference for touchscreen events in Javascript, ex. "touchstart".
I found this useful link http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ (EDIT: page no longer exists) where the events "touchstart", "touchmove" and "touchend" are mentioned for IPhone.
Are there more? What about Blackberry and Android? I did not find much on SO and Google.
Edit
Here is a good documentation by Apple: https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html
I used this site when developing a mobile web app http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/
But with research I have gotten a decent list.
touchstart
Action: fires when the screen is touched (will fire for multi-point touches as well)
Equivalent: mousedown
touchend
Action: fires when a finger is lifted from a screen (is really finiky with single point touch
Equivalent: mouseup
touchmove
Action: fires when one or more fingers move on the screen
Equivalent: mousemove
touchcancel
Action: when a touch event is canceled by the system
Equivalent: none that I'm aware
Other touch devices map the touch events to mouse events. Others ignore touch events.
To a Google API discussion - "Apart from mobile safari, there isn't a way to access touch events on
desktops that have a touch screen."

Categories

Resources