Mobile Safari - "touchend" event not firing when last touch is removed? - javascript

The "gesture" I'm trying to capture is a tap when but only when an element (other or same) already has a touch on it. So, touch (1) presses the button down while touch (2) taps to selected options, touch (1) releases and button is depressed.
The problem I'm having is with the last bit. The "touchend" event is not being fired when I release the last finger? So I have no way of depressing the button?
..also the "touchend" event always has touches.length = 0?
Here is some code so you can see what I mean. I think this may be a bug in mobile safari?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Multi-touch problem</title>
<style>
#touchpane{
width:900px;
height:500px;
background-color:#333;
}
</style>
</head>
<body>
<div id="touchpane" click="void();"></div>
<script>
var tp = document.getElementById("touchpane");
tp.addEventListener('touchstart', function(e){
e.preventDefault();// to stop copy and paste
console.log("touchstart " + e.touches.length );
}, false)
tp.addEventListener('touchend', function(e){
console.log("touchend " + e.touches.length );
// not called when last finger removed?
}, false)
tp.addEventListener('touchcancel', function(e){
console.log("touchcancel");
}, false)
</script>
</body>
</html>

I can help you with one problem, but I don't know why the "touchend" isn't firing when both fingers leave the screen, when I run your code above, the "touchend" fires when either finger leaves the screen (on an iPhone 4)
1) While the "touchend" javascript event for iPhone does have the "touches" property, it's always going to be empty when the last finger leaves the screen, because "touches" for the iPhone represents fingers currently touching the screen, and "touchend" only fires after a finger leaves the screen. So on "touchend" "e.touches.length" will always be 0 when the last finger is lifted.
2) You can access which touches have changed in the "touchend" event by using the "changedTouches" property. This is problematic because it's behaviour is not very consistent.
If you touch the screen with one finger, then another, and then you remove one finger, a number of things could happen.
If you when you have removed the second finger, nothing has changed about the first finger, your event object in "touchend" will have "touches.length = 1" (the finger still on the screen) and "changedTouches.length = 1" (the finger that left the screen).
However, if you are moving the first finger (even a bit) when you remove the second finger, then on "touchend" your event object will have "touches.length = 1" (the finger still on the screen) and "changedTouches.length = 2" (the finger that left the screen + the movement of the first finger).
I found this article very helpful:
http://m14i.wordpress.com/2009/10/25/javascript-touch-and-gesture-events-iphone-and-android/

TouchEvent of the type touchend always have e.touches.length of 0
The missing last touchend event could be dependent on the targets of the touches. If both fingers lift at the same time AND both have the same target then only one touchend will fire, but it will have both touches in the e.changedTouches object. If the targets are different then you will see two touchend events, each with the associated touch in the changedTouches object.
Furthermore, and most puzzling, is that when you lift one of two fingers you will get the same behavior as if you had lifted both. Then when the remaining finger moves it will fire another touchstart, with that finger's original identifier in the touches. The result is that there is no way to tell at the time of the touchend which touch has ended until after an arbitrary amount of time (when the remaining finger moves).
To verify this you need to document the touchLists in each event.
The only workaround I found is a cludge where I cache the touchstart events, setInterval for half a second, then hope that the remaining finger has fired a touchstart I can use to reconcile the state. Good Grief!

Related

Edge does not see button press on mouseleave / mouseenter

Left mouse button was pressed or not - Edge always shows .buttons and .button as 0. .which is always 1.
Other browsers work fine. Other events like click work fine in Edge too. Trouble is with mouseleave and mouseenter.
So how can I detect in Edge on mouseleave event if left mouse button was pressed or not?
P.S. I can solve it with ugly flag like "isClicked" and update it in all related events like mousedown, mouseup. But it is ugly and bug prone.
The #1 best answer: Tell your users that you do not support MS Edge.
If that is not an option, then you'll need to track the mouse button status yourself, like
var leftPressed;
function init() {
document.body.addEventListener("mousedown mouseup") {
//update leftPressed
}
}

How to differentiate between pinch or zoom in/out using touch pad and mouse wheel event

I had implemented zoom in/out an image using mousewheel event which is successfully working. But the behavior is different when I do that with touchpad(using two fingers to zoom in/out). How to differentiate beetween mousewheel event and touchpad events.
The same wheel event unfortunately fires for both pinch and mouse wheel, so it doesn't seem possible at this time to use a different event.
However, I found that the mouse wheel tends to trigger the e.deltaY number in a larger way than pinching.
Thus, I have a listener like so:
const handleZoom = (e) => {
e.preventDefault();
// ignore mouse wheel events that have bigger steps
if (Math.abs(e.deltaY) > 25) {
return;
}
// do what you want to do with pinching here
}
document.addEventListener("wheel", handleZoom);
You can play with the 25 variable to suit your own needs. But for the most part, I noticed that pinch movements are usually much more subtle and have a delta closer to 0, whereas mouse wheel events usually trigger a larger scroll.
First, you have to be careful when designing more advanced touch interactions: when the user uses a mouse it will respond via a click event, but when the user touches the screen both touch and click events will occur. For a single click the order of events is:
1) touchstart
2) touchmove
3) touchend
4) mouseover
5) mousemove
6) mousedown
7) mouseup
8) click
This, of course, means that if you are processing touch events like touchstart, you need to make sure that you don’t process the corresponding mousedown and/or click event as well. If you can cancel the touch events (call preventDefault() inside the event handler), then no mouse events will get generated for touch.
Update:
You can identify touch or click like this:
`
$('#element-id').on('click touchend',function(e){
if(e.type=='click')
console.log('Mouse Click');
else
console.log('Touch');
});
`

Android browsers long hold disable/ mouse up after 1second of mousedown

I am trying to build a one touch game on HTML5 canvas. It's a running game made with the help of this tutorial:
http://blog.sklambert.com/html5-game-tutorial-game-ui-canvas-vs-dom/
I changed the existing controls from space bar to a mouse click. It works perfectly across all the platforms except Android devices mobile browsers.
In Android devices, the touch makes the user jump. If there is a long hold in the touch, the user keeps jumping even when the touch is released. This problem does not happen in iPhones or iPads or desktops.
Can I make a Javascript function where a mouse down for a certain number of seconds is cut ? Something like:
if(mousedown for 1sec)
mouseup;
Let me know if you can think of another approach.
You can use touch events rather than mouse for touch enabled devices. Refer: https://developer.mozilla.org/en-US/docs/Web/API/Touch_events/Using_Touch_Events
function is_touch_device() {
/* Function code taken from http://stackoverflow.com/a/4819886/3946520 */
return 'ontouchstart' in window // works on most browsers
|| navigator.maxTouchPoints; // works on IE10/11 and Surface
};
if(is_touch_device()) {
canvas.addEventListener('touchstart', handleTouchStart, false);
canvas.addEventListener('touchend', handleTouchEnd, false);
}
else {
// Bind Mouse Events
}
function handleTouchStart(e) {
// This code runs when user touches the canvas i.e. on touch start
}
function handleTouchEnd(e) {
// This code runs when user removes finger from canvas i.e. on touch end
}
Also note that there can be scenario where the user puts two or more fingers on the canvas. Each of them will fire 'touchstart' event. So you'll have to handle that.
You can refer to http://www.javascriptkit.com/javatutors/touchevents.shtml for a good tutorial on touch events.

How to make work jquery "swipe" with scroll on iPad?

I have two divs, standing next to each other. In addition to click event I added a swiperight and swipeleft to do something. But when I add these swipe events, scroll doesn't work anymore on iPad. On PCs there's no problem!
Is there any other way to make them compatible with each other on iPad (touch screen devices)?
Merci!
Found a solution:
http://stephband.info/jquery.event.swipe/
Swipe events are a thin wrapper built on top of move events (stephband.info/jquery.event.move). Move events, by default, override native scrolling, as they assume that you want to move something rather than scroll the window. To re-enable scrolling, call e.preventDefault() inside a movestart handler.
In the example above, we want to be able to swipeleft and swiperight, but scroll up and down. Inside a movestart handler, the direction of the finger is moving is calculated and the event is prevented if it is found to be moving up or down::
jQuery('.mydiv')
.on('movestart', function(e) {
// If the movestart is heading off in an upwards or downwards
// direction, prevent it so that the browser scrolls normally.
if ((e.distX > e.distY && e.distX < -e.distY) ||
(e.distX < e.distY && e.distX > -e.distY)) {
e.preventDefault();
}
});

Does the touchmove event support multi-touch?

I have two squares on the screen. Each with a touchmove event. When I run this on my phone, I want it to return the correct X position of my finger. It works fine if I do it for one square at a time (ie just have one finger only on the screen). But if I have two fingers on each square and I move them simultaneously the X's get messed up. Is this the right way to handle multi-touch x's?
html:
<div id='container1'></div>
<div id='container2'></div>
javascript:
$('#container1').bind('touchmove', function() {
console.log("container1-" + event.pageX);
event.preventDefault();
});
$('#container2').bind('touchmove', function() {
console.log("container2-" + event.pageX);
event.preventDefault();
});
css:
#container1 {
margin:50px;
width:300px;
height:300px;
background:red;
}
#container2 {
margin:50px;
width:300px;
height:300px;
background:green;
}
My jsfiddle is here:
http://jsfiddle.net/foreyez/jghzqL9p/
You can run it in mobile if you press the mobile icon next to the 'Run' button.
When you are dealing with touch events, you should use the 'changedTouches' property of event object. It is a list of all current touches, with parameters such as identifier (identified the touch - your finger), pageX, pageY and more.
To get full understanding of multitouch handeling I would recoment you reading this MDN article.
Yes it does. As suggested by Maxim you should be using changedTouches to read the multiple touches. The points in "changedTouches" have different meaning for touchstart, touchend and touchmove events.
If you are trying to swap or move the objects then you should be using the combination of 'touchstart' and 'touchmove' to arrive at the final position of the object.

Categories