I'd assume this question has been asked to death, but I'm not finding anything good.
What I'd like is a unified set of events that span devices. I know the mapping isn't always 1 to 1, but just something that covers the basics like:
ignores/disables hover events/styles on a touch device
maps a touchstart to a mousedown
similarly, touchend to mouseup
tap to click
etc...
maybe even touch, hold 1s, touchmove to dragstart...
I haven't thought through all the specifics. And of course device specific events like hover on a desktop, or swipe on a tablet, can't be translated and should just be ignored if not supported.
Anybody know of a library that will do this. Preferably an invisible jQuery patch.
Thanks.
jQuery Mobile does exactly this, amongst many other things.
See their documentation on virtual mouse events, which:
... provide a set of "virtual" mouse events that attempt to abstract away mouse and touch events
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 want to listen to pointermove event on IE11, but it seems that pointermove only fires for mouse (and possibly pen), but not when you are using your finger.
http://jsfiddle.net/qq2hjL2g/
Actually, the specification says that it fires for pens/mice, so this may not be really a bug.
But, is there any way to listen to pointermove on IE for touch? There must be, but I was very surprised to see pointermove not firing at all.
EDIT: I found that if I put CSS touch-action: none on the div, pointermove events fire. But why? I'm trying to find documents related to this, but I couldn't find any so far.
EDIT: I learend that the touch-action CSS specifies which touch actions are handled by the browser. This means setting touch-action to none tells the browser to not handle any touch events, and the developer is responsible for controlling the behaviour throutgh JavaScript events. This is why I was getting the events fired properly only when I had the CSS. (See more at MDN.)
I'm also trying to interface with IE11 touch.
I believe MSGesture is used for touch events because in their documentation they refer to "fingers"
http://msdn.microsoft.com/en-us/library/windows/apps/hh465856.aspx
http://msdn.microsoft.com/en-US/library/ie/hh968249.aspx
I believe the gestures you are interested in are:
MSGestureStart - "Triggered when the screen is touched on a location over this element."
MSGestureChange - "Triggered when the finger positions associated with the interaction moves on the screen."
MSGestureEnd - "This event fires when all associated contacts are removed from the surface"
Making a nice quick-responding website is relatively difficult because of the conflicts between touchstart, tap and the 300ms delayed click.
Ofcourse vclick should fix these issues, but also they seem to have problems fixing it completely. From the documentation:
Warning: Use vclick with caution
Use vclick with caution on touch devices. Webkit based browsers
synthesize mousedown, mouseup, and click events roughly 300ms after
the touchend event is dispatched. The target of the synthesized mouse
events are calculated at the time they are dispatched and are based on
the location of the touch events and, in some cases, the
implementation specific heuristics which leads to different target
calculations on different devices and even different OS versions for
the same device. This means the target element within the original
touch events could be different from the target element within the
synthesized mouse events.
We recommend using click instead of vclick anytime the action being
triggered has the possibility of changing the content underneath the
point that was touched on screen. This includes page transitions and
other behaviors such as collapse/expand that could result in the
screen shifting or content being completely replaced.
Now I'm thinking about doing something simpler. Whenever a touchstart event is being triggered I know this is a touch device for sure. I just disable all click events, and start listening to touchstart (or tap) events only. Ignoring the 300ms delayed click events.
Of course there are devices with a mouse and touch, but people using these at the same time seem like a minority to me.
Is this a good idea, or am I missing something in my thinking?
First of… what makes you say that people that use both touch and mouse input are a minority?
The 300ms click delay has been gone a while now on Android when using <meta name="viewport" content="width=device-width">. Unfortunately it can't be removed on iOS because it's a scroll gesture on unzoomable pages that almost nobody seems to be aware of.
I'd say that the best approach is still to support both mouse as well as touch input, despite the 300ms delay on iOS devices. It's dangerous to assume a user will exclusively use touch input when they use it once.
Imagine a user happily using a mouse to navigate. They see something interesting that they want to look at a bit closer so they use a touch gesture to zoom in and all of a sudden mouse clicks don't work anymore. That sounds broken to me.
I just remembered an interesting discussion about detecting a mouse user. Maybe it'll help you see things a bit differently.
Yes, in my honest opinion it is smart way to go. This has proven to be quite a hard problem and when you still combine it to the compatibility problems caused by some really crappy mobile devices which don't follow standards even that bit, it quickly becomes a battle that you can't win. We have adopted a solution close to this, with realization of fact that there might arise problems with poor devices. But after all, you can't satisfy the needs of everybody and the distribution of usage tends to favor those devices (nowadays) that follow the standards.
Also note that you don't need to wait for first touchstart to happen. Instead you can do this trick after DOM is ready and bind the events accordingly.
var isTouchDevice = 'ontouchstart' in document.documentElement;
which is copied from KevBurnsJr's answer.
Also as you most probably already know, you can bind to all kind of events and then check when entering the callback of which type the event actually is with
event.type
Good luck!
It would be a bad idea to disable all click events on the basis of a single touchstart as you suggest. While using both pointers or touch at the same time isn't a common use case. Preventing dual use of mouse/pens and touch isn't a forward compatible approach.
And when you say: "Ignoring the 300ms delayed click events."
I think you make a false assumption on click. You'd still have to synthesize clicks one way or another. touchstart alone isn't a click action. An assumed click happens on touchend, not touchstart. Here is the principle behind detecting clicks early on mobile: https://developers.google.com/mobile/articles/fast_buttons
If you are looking for fastclicks you may want to look into the fastclick script or other fastclick ones on github instead of vclicks.
To avoid issues with people using both touchscreen and mouse with pleasant reactivity I suggest this in JQuery, it works good enough for me:
$elem.on('click touchstart', function(e){
var $self = $(this);
if(e.type == 'touchstart'){
$self.mouseenter(); //fire events you still need
e.preventDefault();
}
/* your code */
});
From my experience it's better than keep the delay on click event and some hazardous comportment through devices, but there's inconvenient too.
On the iPad I tested, it avoids the situation where hover event is triggered on first tap then click event on second tap, but also it seems that the click event fire when you tap near the border of your element and not the touchstart, have to keep it in mind.
Also, it seems not working well with 'tap' event, certainly because it's not well treated yet by JQuery.
Setting pointer-events:none seems to also turn off touch events. This obviously doesn't make sense, because "touch" events aren't "pointer" events. My finger is not a pointer. :)
Is there some way to turn off only pointer/mouse events, but leave touch events alone? A property like touch-events would be nice.
Actually, a touch event is a specific type of pointer event based on the definition.
From W3.org, Pointer Events, Section 1
A pointer can be any point of contact on the screen made by a mouse
cursor, pen, touch (including multi-touch), or other pointing input
device.
Also:
The events for handling generic pointer input look a lot like those
for mouse: pointerdown, pointermove, pointerup, pointerover,
pointerout, etc. This facilitates easier content migration from Mouse
Events to Pointer Events. Pointer Events provide all the usual
properties present in Mouse Events (client coordinates, target
element, button states, etc.) in addition to new properties for other
forms of input: pressure, contact geometry, tilt, etc. So authors can
easily code to Pointer Events to share logic between different input
types where it makes sense, and customize for a particular type of
input only where necessary to get the best experience.
So, setting pointer-events:none; will affect both touch and mouse events.
So to answer your question; you can't distinguish between mouse events (I assume by pointer events in your question you basically meant mouse events) and touch events with css only and the pointer-events property. But since mouse events and touch events are different, you can revert to javascript for your needs in this case.
There is no way to disable only mouse events through CSS. But you can easily do it with javascript:
Check touch support by using Modernizr or simply see a discussion about touch detection How can I detect device touch support in JavaScript?
If touch events are not supported, apply a CSS class (you previously created) or directly add the CSS rule on all the elements you want to ignore pointer events.
A script I'm working on samples x/y mouse coordinates to determine a set of user gestures. It's currently attaching a mousemove event listener to document.body.
New requirements include adding listeners for mousedowns and keypress frequency. Those are simple enough. The other new requirement is replicating the interaction listening on mobiles/tablets.
My tentative plan is to avoid device-specific code like the touches object by using the legacy mouse and keypress support.
What challenges should I be aware of? For example, gotchas where a gesture with a mouse and a gesture with one finger will produce vastly different sets of x/y coordinates on mousemove... or a widely used mobile browser with super-odd event handling.
http://www.quirksmode.org/mobile/tableTouch.html is a wonderful reference.
Thanks!
Have you given jQuery Mobile a try? It comes loaded with all the touch gestures you'll ever need. I have used it and can confirm that it works across iOS and Android. Didn't quite test on other platforms though.
There is also this great jQuery plugin called jGestures which gives you access to many events such as touch, tap, pinch and even has a orientation change event.
jGestures: http://jgestures.codeplex.com/
Also I found this interesting page about touch events in Android and iOS and has a list of supported events on each platform: http://backtothecode.blogspot.com/2009/10/javascript-touch-and-gesture-events.html
Forgive me if I've misunderstood your question and posted something unrelated. Hope this helps.