I want to enable both vertical scrolling and horizontal swiping at the same time. I detect the touch position in touchmove instead of touchend, because I need real-time coordinates. Unfortunatelly, Chrome for Android fires touchcancel right after touchstart, so no more touchmove is fired. This touchcancel event can be avoided by calling event.preventDefault() from either touchstart or touchmove. But scrolling becomes disabled this way, so my first approach is to go without event.preventDefault(), and use some alternative method instead to detect touch position after touchcancel. Is it possible?
Related
I have horizontally scrolling panel (via overflow-x:scroll) and user should be able to scroll it by dragging (not just scrollbar, but the content itself too).
Using some draggable carousel library (e.g. owlcarousel) isn't an option as all of them use transforms instead of native scroll.
So my plan is:
bind mousedown event
change horizontal scroll offset on mousemove
stop all actions at mouseup
All is good on desktop. But the problem is mobile, as mobile browsers trigger fake mousedown and mousemove events - the scrolling is corrupted. If I call preventDefault in touchstart/move - fake mouse events stop firing, but pane isn't scrolling either.
Is there any way to prevent fake mousedown/move/up events on mobile without calling e.preventDefault()?
Thanks for any input!
Quoting W3C:
To avoid processing the same interaction twice for touch (once for the touch event, and once for the compatibility mouse events), developers should make sure to cancel the touch event, suppressing the generation of any further mouse or click events. Alternatively, see the InputDeviceCapabilities API for a way to detect mouse events that were generated as a result of touch events.
Unfortunately this doesn't seem to be available in any browser (yet?).
A more viable possibility is to disable touch scrolling on your element, and letting your mouse handling code take care of the scrolling:
.my-panel {
touch-action: none;
}
If this makes scrolling too janky on mobile, a hacky but possibly effective solution might be to ignore any mousemove event that follows shortly (say, within 100 ms) after a touchmove event.
I am building a page that needs to work with touch and mouse interaction on PC, Mac, and mobile browsers.
In the event handler methods for touchStart, touchMove, touchEnd, and touchCancel I am calling event.preventDefault to prevent mobile browsers from firing both touch and mouse events.
This works great for mouseDown and mouseUp, which do not get fired when I touch the screen, but for some reason a short while (couple 100ms) after each touchStart is fired, the android browser still fires a mouseMove event (on the very first touchStart, this mouseMove is preceded by a mouseOver). If I touch quickly enough, the mouseMove gets fired after touchEnd (with the same delay relative to touchStart).
I'd really like to prevent any mouse events from being generated from touches and I'd also like to understand in detail what's going on here, so I have the following questions:
Is there some other touch event that I am not capturing which causes the mouseMove event?
Why is the mouseMove delayed a bit relative to the touch start?
Why isn't the mouseMove generated by any other touch events (touchMove, touchEnd)?
Do any other browsers have quirks that might generate mouse events from touches?
Is there a different cross-platform approach for preventing touch to cause mouse events? Maybe some CSS?
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.
I'm wondering if it's possible to detect when a user has finished scrolling.
When dragging a scrollbar the old fashioned way, a mouseup event fires when the user lets go
When swiping on a touchscreen a touchend or MSPointerUp fires.
But if the user is scrolling via a mousewheel or some other trackpad gesture then what event[s] can be used to establish that the scrolling intention has ended?
I could do this with timeout mechanism in the scroll event handler, but ideally a single event signalling the end of the scroll is what I want.
I have a larger problem with swipes not being registered. And I believe its because the SDK's assume you would want to click an drag the entire viewport of Safari instead of any of the divs that could be in it.
How can I prevent this default?
I believe you want to listen for the touchmove event and call event.preventDefault() therein on any elements you don't want to contribute to viewport movement.
jquery example:
$('.interestingElements').on('touchmove', function(event) {
event.preventDefault();
});
In mobile safari, the default behavior for a touchmove involving a single touch is to slide the viewport around.
If two touches are involved, the default behavior is to trigger a gesture event. Preventing default on touchmove prevents the gesture event from ever firing. You can use the changedTouches array to find out how many touches are involved in this touchmove event. Good luck!