I am porting a piece of code for an HTML5 app from iOS/Android to Windows Phone 8. In this App there is a vertical scroll view with a number of elements.
In the original App I use "touchstart" and "touchend" events. This means every time the user touches the List I get a touchstart event, and even after scrolling around, when the user lifts the finger I get a touchend.
The MSPointer model works different. There is MSPointerDown which is the exact equivalent of touchstart, so no problem on this end.
I can't get my head around how to model the touchend behaviour though. MSPointerUp is not enough because it is only thrown if the user lifts its finger inside the same container where the MSPointerDown occurred. So if a user touches the list, then swipes it up and then lifts the finger, the event will not be fired. There is also MSPointerOut, which triggers when a user leaves the container where MSPointerUp was fired, the problem here is, it fires as soon as the container is left (so during the scrolling of the list) and doesn't fire after the user lifts its finger.
I'm a bit on a loss here how to model a "touchend" with MSPointer that will trigger in exact the same way as the Webkit one.
Cheers
Tom
This is the way I handle this issue.
Even though the Down/Move listeners are attached to some element, I attach the Up listener to the window.
This means that no matter where on the screen the user lifts the finger/pen/mouse (even outside the browser window in IE on a PC), the Up event is triggered.
This also means that you must handle all Up events in your app in one function. But you can set a flag (some global variable) on an element's Down event, and check for that flag in the UP event.
I've been doing this for a long time for mouse events on PC web pages, to handle when the user let's go of the mouse button outside the browser window.
It's annoying when they don't do this, like in Google Maps Street View where you're trying to pan around far and have to move the mouse a lot, and you let go of the button outside the window but it still thinks you're dragging.
Related
is there a touch equivalent of the mouseenter.
I would like to detect if user slide on my DIV.
I prefer a solution depending directly on the target element not on a parent element with recounting positions etc.
The site: http://dizzyn.github.io/piano-game/ - works fine with mouse (mouse down and slide; not working with touch slide)
Thank you
2019: Yes-ish: Using pointerenter.
BUT, by default, a touch (or mouse down) causes the element to 'capture' the pointer, preventing further pointerleave/enter events unless you explicitly release the capture.
Moreover, you'll want to set touch-action:none on relevant elements to avoid the browser intercepting touches for default pan/zoom etc.
Example:
CSS:
*{ touch-action: none; }
JS:
let div = document.querySelector("div")
div.addEventListener("pointerdown",(e)=>{
console.log("down")
console.log("attempt release implicit capture")
div.releasePointerCapture(e.pointerId) // <- Important!
})
div.addEventListener("pointerenter",(e)=>{
console.log("enter")
})
div.addEventListener("pointerleave",(e)=>{
console.log("leave")
})
Works in Chrome at least. Not so much in Mobile Safari 13 beta though... According to the w3c specs, I'm fairly certain it should work this way. Maybe when iOS 13 is officially released we'll be in the clear. [I've filed a bug and looks like it's being attended to.]
[Update: iOS 13 issue fixed. Should work in Chrome/FF/Safari]
Look into these events:
touchstart Triggers when the user makes contact with the touch surface and creates a touch point inside the element the event is bound to.
touchmove Triggers when the user moves the touch point across the touch surface.
touchend Triggers when the user removes a touch point from the surface. It fires regardless of whether the touch point is removed while inside the bound-to element, or outside, such as if the user's finger slides out of the element first or even off the edge of the screen.
touchenter Triggers when the touch point enters the bound-to element. This event does not bubble.
touchleave Triggers when the touch point leaves the bound-to element. This event does not bubble.
touchcancel Triggers when the touch point no longer registers on the touch surface. This can occur if the user has moved the touch point outside the browser UI or into a plugin, for example, or if an alert modal pops up.
Specifically touchenter and touchleave.
Source: http://www.javascriptkit.com/javatutors/touchevents.shtml
For anyone who is trying to handle touch events in a web app here is helpful documentation W3C - Touch Events which explains the events in detail and how they are handled.
WC3 states:
If a Web application can process touch events, it can intercept them, and no corresponding mouse events would need to be dispatched by the user agent. If the Web application is not specifically written for touch input devices, it can react to the subsequent mouse events instead.
In short:
You can merely handle mouse events relative to touch events instead of handling both touch and mouse events.
I just wanted to say thank you to the previous poster. His suggestion worked perfectly. And I've been struggling to find a solution to this for weeks. If you're using Svelte within your pointerdown handler function I would suggest using:
const pointerDownHandler = (event) => {
// whatever logic you need
event.target.releasePointerCapture(event.pointerId);
}
He's accurate in saying this part is key. It will not work without it.
Answered this at Touchenter/Touchleave question.
Check please.
https://stackoverflow.com/a/61179966/835753
I will make a shot clarifying for Ian's answer:
Equivalent for mouseenter event is pointerenter event. But it will not work out of the box. To make it work you should:
Add to parent element pointerdown event listener with releasePointerCapture method
div.addEventListener("pointerdown",(e) => e.target.releasePointerCapture(e.pointerId))
Add to parent and to your element touch-action: none CSS property.
Enjoy :)
I am using dojox/gesture/swipe to trigger a carousel card change whenever a user performs a swipe gesture on my carousel widget. However, it seems that the user input is effectively "trapped" within whatever element is capturing the gesture which means that the user can't scroll the page by swiping up up or down on the screen if the scrolling starts by the user tapping and swiping from within the carousel.
It seems that this is almost the intended behaviour as well since this happens even with the most bare custom gesture that simply inherits from dojox/gesture/swipe without overriding any methods. Is there any way to let the scrolling of the page happen even while the gesture is being "interpreted" or am I misunderstanding the usage of the gesture system? I guess the intended use may actually be a means of more robust user like interpreting letter gestures akin to a Palm Pilot.
The objective is to have a component, in this case a carousel, that responds to the touchmove event when the user is moving his finger from left to right, but does not prevent the default scrolling up and down, even if the touch originates on the component in question, provided the user moves his finger on the y axis beyond a certain threshold.
Or, more plainly, I need to disable the browser scroll on touch devices, until the touchmove even says its OK, and re-enables it.
Despite several hours of tinkering, I've only been able to disable browser scroll completely or not disable it all. Conditionally disabling does not seem to want to work.
The basic logic is:
Record the coordinates on finger down (touch start).
On touchmove, check to see if the Y difference is greater than 200px.
If so, allow the default of browser scrolling, disable the touchmove listener.
If not, prevent the default of scrolling, scroll left/right.
I've been testing this on a late edition iPad mini. I have discovered the following:
Calling preventDefault() in the touchstart handler stops all browser scrolling for that touch, it cannot be re-enabled during drag.
Trying to conditionally prevent default in the dragmove handler behaves the same as preventDefault in the touchstart handler. That is, it blocks the drag, and ignores the condition!
A condition like this in dragmove:
if(Math.abs(MouseMoveDistanceY) < 200){
if(ev.preventDefault){ev.preventDefault();}
}
...blocks vertical scrolling permanently, even if the threshold gets exceeded!
In any case, how can I, on touch devices and in the dragmove handler, surrender control to the browser scroll when a condition is met? Something like "unPreventDefault()" would be great. Barring that, any ideas?
Just an idea, as I can't give you a direct answer so this is more of just looking at a different approach.. but have you looked at changing the page so that there is nothing to actually scroll when on the touch event? ie/ fix the height and add in overflow hidden.
I've been developing a mobile site for my homepage and I have run into an issue when hooking into mobile touchevents. Basically I would like to accomplish the following:
User scrolls down
on touchend event is fired --> a function is called to figure out the amount of the document that is hidden above after the scroll (like jQuery scrollTop)
program takes action based on the amount of the document that is hidden up top
My issues are the following. So touchend works like expected in iOS, when the user lifts her finger the function makes a call to jQuery.scrollTop() which gives me a pixel value for how much the user has scrolled down. However on Android Browser devices it seems that the jQuery.scrollTop() value is calculated on touchstart. That is to say the event doesn't fire off properly, I get the correct pageX & Y coordinates from the touchend event, however scrolltop() returns the value from when the user started scrolling. I've checked around on the inet and this seems to be a known android browser bug, what I want to know is if there a decent workaround for this issue i.e. one that doesn't involve preventing the default scroll behaviour!? Thanks in advance!
Are you taking into account smooth scrolling? or just basic scrolling?
With basic scrolling you should be able to get the correct value simply by using document.body.scrollTop
Let me know if there is an issue
I have an element that is moved (via altering it's leftmargin) relative to a user touch on a mobile device (i.e. dragging it around the screen with your finger).
I have noticed that during a touchmove event (which i believe fires repeatedly for the entire time between touchstart and touchend), the browser does not repaint the window, meaning that the display is not updated until after the user takes their finger off the screen.
I haven't had the opportunity to test this across various devices, so it could only relate to Android devices, or to webkit, or a wider group.
Has anybody come accross this and might there be a workaround to force the browser to redraw during the events duration?
Call event.preventDefault() on the touchstart event.
http://uihacker.blogspot.tw/2011/01/android-touchmove-event-bug.html