Prevent touchmove default (browser scrolling) until condition is met? - javascript

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.

Related

Draggable scroll and potential issues on mobile

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.

Differentiate touch events from mouse events in Firefox in fixed DIV

I got this custom scrollbar that works fine everywhere, except in that fixed DIV. I'm testing with an Asus laptop with a touch screen (dunno if it matters).
So, on "regular" DIV, when I try to scroll by touching the screen, it triggers a wheel event and it works wonderful. On the fixed DIV, it triggers a mousemove event and I have no idea how to handle it.
I'm guessing that if I can detect if the event is trigger by touch or the mouse, I would be able to do some specific behavior, but the events look exactly the same. I obviously can't do custom behavior for all mousemove events because the user needs to be able to move his mouse without scrolling stuff.
NB: I think the issue came from the fact that the DIV I want to scroll is fixed, but I am not 100% sure (still pretty confident though).

How can one prevent the ability to click and drag the viewport for safari on iPad or iPhone?

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!

Android browser touchend event bug workaround

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

How do I prevent the default behavior of the touchmove event in iOS 5?

I have a web-based application that includes a component that the user can scroll up and down with their finger. I use the event's preventDefault method to prevent the default behavior where the touch move shifts the whole screen around on iOS devices.
Unfortunately this does not seem to work anymore in iOS 5 which I just upgraded to this morning. I have to assume that this is just done differently in iOS 5, but I have yet to be able to find a resource that provides instructions.
Update #1: I haven't been able to find an answer to my specific question, but I was able adjust my code a bit to use the -webkit-overflow-scrolling style (set to a value of "touch") and implement the snazzy inertial scrolling capability (where the content scrolls faster depending on the velocity of your swipe and will "rubber band bounce" back if it hits the boundaries. Pretty cool looking...
Update #2: I have another strange problem now. For some odd reason that overflow scrolling behavior gets mixed up sometimes whereby you have to drag your finger left and right across the containing element in order to make its contents move up and down. I have yet to be able to figure out why this happens - does anyone have any ideas?
I found a very simple solution. When the event hits your element that is allowed to scroll, just flag the event. On the event listener on the document just check if the flag is set and only stop the event if the flag isn't set:
this.$scrollableEl.on('touchmove', function(event){
event.comesFromScrollable = true;
// when you have containers that are srollable but
// doesn't have enough content to scroll sometimes:
// event.comesFromScrollable = el.offsetHeight < el.scrollHeight;
});
$(document).on('touchmove', function(event){
if (!event.comesFromScrollable){
event.preventDefault();
}
});
You could also use event.stopImmediatePropagation instead, so you dont need the eventListener on the document element, but this breaks zepto.js tap in my case:
this.$scrollableEl.on('touchmove', function(event){
event.stopImmediatePropagation();
});
First, I can verify that e.preventDefault() disables all scrolling in iOS 5 using the following code:
document.ontouchmove = function(e){ e.preventDefault(); }
Unfortunately, however, this disables the scrolling on overflow:scroll divs. (If anyone has a solution that leaves the inner element scrolling enabled, please share.)
Regarding update#2, I have noticed strange behavior when there is a scrollable element nested in another scrollable element (including the page itself). Sometimes the device hesitates on which element the user intends to scroll. In particular I've noticed this problem using position:fixed. My solution was to make sure the body has 100% height and that the scrollable elements use position:absolute where possible.

Categories

Resources