Disable scrolling but capture scrolling data with JavaScript? - javascript

I'm trying to prevent default scrolling behavior while still determining the number of pixels a user has attempted to scroll.
My objective is (at some vertical position on my page) to fix a navigation element to the top of the screen and hijack the scroll/swipe event to pull down a mobile menu when the user scrolls back up (so moving said element up and down by n pixels depending on how many pixels the user tries to scroll).
I am aware of the UX/accessibility concerns insofar as blocking native behavior, but the suits want what the suits want.
So far I have:
$('body').on({
'mousewheel' : function(e) {
e.preventDefault();
e.stopPropagation();
}
});
but am stumped as to how to access the number of pixels scrolled (since element/scroll offsets are no longer a guide).
Edit: Please note that this question is specifically asking for information regarding mouse/scroll actions while scrolling is blocked. Don't think this has been appropriately marked as duplicate.

This is browser-depended because of the mousewheel event you are using. This is because it is non-standard. Don't use it!
In Chrome (43.0) you get different properties with different values:
e.originalEvent.wheelDelta: -120
e.originalEvent.wheelDeltaY: -120
e.originalEvent.deltaY: 100
In IE (11.0), you can get only one property:
e.originalEvent.wheelDelta: -120
In Firefox (38.0.5), the capturing of the mousewheel event doesn't work at all.
Solution:
Use the wheel event (MDN reference). This event has the e.originalEvent.deltaY property in all browsers.

Before cancelling event propagation take the deltaY out of the original event like this
$('body').on({
'wheel' : function(e) {
console.log(e.originalEvent.deltaY);
e.preventDefault();
e.stopPropagation();
}
});

Related

How to identify REAL mouse movement when entering fullscreen mode

I have the problem, that I need to know if the user actually moved his mouse for real when entering fullscreen, or if it just is a programatically side effect of entering the fullscreen.
Because, when entering fullscreen, the mouse Y coordinates change automatically because the mouse moves upwards on the absolute screen position (since the top navigation of the browser disappears). And since every browser brings a notification in fullscreen mode, this very notification triggers a mousemove event.
So, this makes it very painful to find out, whether the user acually move the mouse, or not.
Is there a solution to identify REAL mouse movement?
$(document).on('mousemove', function(event){
/* gets also triggered when just entering fullscreen,
but without actual movement of the physical mouse..
how can this be identified/ignored?
*/
});
JS Fiddle
What I've tried so far
I tried already relativating the mouse position by using something like window.screen.top - but this seems not to be implemented yet by any browser so far.
I don't think there's anything formally implemented as yet to detect full screen. There's a fullscreenchange as part of the Fullscreen API but it's still experimental and requires vendor-specific prefixes.
So, basically you'll have to get around that limitation with some tricks, like intersecting the resize event and skipping whatever logic you are running on mousemove. Here's an example...
var resizing = false;
$(document).on('mousemove', function(event){
if(resizing == false){
$('p').text(event.pageX + ':' + event.pageY);
console.log("moving");
}
});
$(window).resize(function(){
resizing = true;
setTimeout(function(){
resizing = false;
}, 4000);
});
This example simply defines a flag that determines whether the window is resizing or not, if resizing the onmousemove logic is skipped. Particularly I hate to use setTimeout with an arbitrary time to switch off the resizing flag, but if your requirements are not so strict it can get the job done beautifully
Why don't you incorporate a delay (for example 0.5 seconds) where you ignore all mouse inputs. After the delay, any mouse movements are likely to be from the user...
I solved it now by saving the mouse coordinates, and check if they change - while I force one mousemove event after fullscreen in order to update the coordinates once.
$(document).on('mousemove', function(event){
if(event.pageX == $(this).data('mouseX') && event.pageY == $(this).data('mouseY'))
return;
$(this)
.data('mouseX', event.pageX)
.data('mouseY', event.pageY)
;
});
$(document).mousemove();

With javascript / query, is there a way to just "nudge" or "flick" the scroll so it's interruptible by the user (better description within)

I want some js to automatically scroll just a slight bit down the page, however I also want this scroll to be interruptible by the user.
When using jquery to auto scroll, when you animate the scroll with .animate and then the user starts scrolling while the animation scroll is still going they interact with each other and create a strange jumping effect.
Is there a way to make so when the user scroll during a javascript scroll it just stop the javascript scroll?
It can't be done since you can't know if the end-user scrolled or you scrolled the page via javascript.
A scroll event is sent whenever the element's scroll position changes, regardless of the cause. A mouse click or drag on the scroll bar, dragging inside the element, pressing the arrow keys, or using the mouse's scroll wheel could cause this event.
Docs
What I tried to do but failed because the above:
// callback for the scroll event
$(document.body).scroll(function(){
// Stop the scrolling!
$('html, body').stop();
});
A not working demo...
The other users answer is actually incorrect, it is possible and has been answered before:
How can I differentiate a manual scroll (via mousewheel/scrollbar) from a Javascript/jQuery scroll?
Check the answer
"$('body,html').bind('scroll mousedown wheel DOMMouseScroll mousewheel keyup', function(e){
if ( e.which > 0 || e.type == "mousedown" || e.type == "mousewheel"){
$("html,body").stop();
}
})"
I've updated the previous users JS Fiddle to work with the proposed solution and it works perfectly.
http://jsfiddle.net/Lwvba/7/

Disable scrolling when touch moving certain element

I have a page with a section to sketch a drawing in. But the touchmove events, at least the vertical ones, are also scrolling the page (which degrades the sketching experience) when using it on a mobile browser. Is there a way to either a) disable & re-enable the scrolling of the page (so I can turn it off when each line is started, but turn it back on after each is done), or b) disable the default handling of touchmove events (and presumably the scrolling) that go to the canvas the sketch is drawn in (I can't just disable them completely, as the sketching uses them)?
I've used jquery-mobile vmouse handlers for the sketch, if that makes a difference.
Update: On an iPhone, if I select the canvas to be sketched in, or just hold my finger for a bit before drawing, the page doesn't scroll, and not because of anything I coded in the page.
Set the touch-action CSS property to none, which works even with passive event listeners:
touch-action: none;
Applying this property to an element will not trigger the default (scroll) behavior when the event is originating from that element.
Note: As pointed out in the comments by #nevf, this solution may no longer work (at least in Chrome) due to performance changes. The recommendation is to use touch-action which is also suggested by #JohnWeisz's answer.
Similar to the answer given by #Llepwryd, I used a combination of ontouchstart and ontouchmove to prevent scrolling when it is on a certain element.
Taken as-is from a project of mine:
window.blockMenuHeaderScroll = false;
$(window).on('touchstart', function(e)
{
if ($(e.target).closest('#mobileMenuHeader').length == 1)
{
blockMenuHeaderScroll = true;
}
});
$(window).on('touchend', function()
{
blockMenuHeaderScroll = false;
});
$(window).on('touchmove', function(e)
{
if (blockMenuHeaderScroll)
{
e.preventDefault();
}
});
Essentially, what I am doing is listening on the touch start to see whether it begins on an element that is a child of another using jQuery .closest and allowing that to turn on/off the touch movement doing scrolling. The e.target refers to the element that the touch start begins with.
You want to prevent the default on the touch move event however you also need to clear your flag for this at the end of the touch event otherwise no touch scroll events will work.
This can be accomplished without jQuery however for my usage, I already had jQuery and didn't need to code something up to find whether the element has a particular parent.
Tested in Chrome on Android and an iPod Touch as of 2013-06-18
There is a little "hack" on CSS that also allows you to disable scrolling:
.lock-screen {
height: 100%;
overflow: hidden;
width: 100%;
position: fixed;
}
Adding that class to the body will prevent scrolling.
document.addEventListener('touchstart', function(e) {e.preventDefault()}, false);
document.addEventListener('touchmove', function(e) {e.preventDefault()}, false);
This should prevent scrolling, but it will also break other touch events unless you define a custom way to handle them.
The ultimate solution would be setting overflow: hidden; on document.documentElement like so:
/* element is an HTML element You want catch the touch */
element.addEventListener('touchstart', function(e) {
document.documentElement.style.overflow = 'hidden';
});
document.addEventListener('touchend', function(e) {
document.documentElement.style.overflow = 'auto';
});
By setting overflow: hidden on start of touch it makes everything exceeding window hidden thus removing availability to scroll anything (no content to scroll).
After touchend the lock can be freed by setting overflow to auto (the default value).
It is better to append this to <html> because <body> may be used to do some styling, plus it can make children behave unexpectedly.
EDIT:
About touch-action: none; - Safari doesn't support it according to MDN.
try overflow hidden on the thing you don't want to scroll while touch event is happening. e.g set overflow hidden on Start and set it back to auto on end.
Did you try it ? I'd be interested to know if this would work.
document.addEventListener('ontouchstart', function(e) {
document.body.style.overflow = "hidden";
}, false);
document.addEventListener('ontouchmove', function(e) {
document.body.style.overflow = "auto";
}, false);
I found that ev.stopPropagation(); worked for me.
To my surprise, the "preventDefault()" method is working for me on latest Google Chrome (version 85) on iOS 13.7. It also works on Safari on the same device and also working on my Android 8.0 tablet.
I am currently implemented it for 2D view on my site here:
https://papercraft-maker.com
this worked for me on iphone
$(".owl-carousel").on('touchstart', function (e) {
e.preventDefault();
});
the modern way (2022) of doing this is using pointer events as outlined here in the mozilla docs: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
Pointer events build on touchstart and other touch events and actually stop scroll events by default along with other improvements.

Is there a way to set the window's scroll position without using scroll() or scrollTo()?

...the reason I ask is that Safari has a bug in its implementation of scroll() that is breaking my UI.
Imagine a page:
<body>
<div id="huge" style="width: 4000px; height: 4000px;"></div>
</body>
...so that you get both horizontal and vertical scrollbars. Now, normally when you press the scrollbar, the page scrolls (vertically). For the purposes of our fancy UI we don't want that to happen, so we squash the keyDown event:
window.onkeydown = function(e) {
if(e.keyCode == 32)
{
return false;
}
};
This works great...unless we decide that instead of preventing scrolling altogether, we want our own, custom scrolling behavior:
window.onkeydown = function(e) {
if(e.keyCode == 32)
{
window.scroll(foo, bar); // Causes odd behavior in Safari
return false;
}
};
In other browsers (Chrome, Firefox), this will instantaneously move the window's scroll position to the desired coordinates. But in Safari this causes the window to animate to the desired scroll position, similar to the scrolling animation that takes place if you press the space bar.
Note that if you trigger this scroll off of any key OTHER than the space bar, the animation does not take place; the window scrolls instantly as in other browsers.
If you happen to be scrolling, say, 1000 pixels or more, then the animated scroll can induce some serious discomfort.
I'm scratching my head trying to find a way around this. I suspect that there isn't one, but I'm hoping some God of Javascript here can suggest something. I'd really like to be able to use the space bar for this command.
If you know where in the document you want to scroll to then you can simply use named anchors. Setting document.location to the anchor (e.g. #top, #div50 or whatever) should be very reliable.
Use document.documentElement.scrollTop = ... (and document.body in some browsers).

How to control the scroll increment in Firefox when clicking the scrollbar buttons?

I thought it was related to line-height CSS property, but it doesn't work. How to adjust the scroll amount when clicking the scroll up/down buttons?
As far as I know, this isn't something you have control over. However, you could listen for the Javascript onScroll event and then use the Javascript scrollBy method to scroll the page more or less depending on what you wanted. I'm not sure how this would look though, things could be a bit jerky and confusing to the user. You'd also have to take into account whether or not the user has zoomed the page in or out.
Assuming you want to scroll an arbitrary area (rather than an object, such as a tree, that already supports scrolling), then you could set overflow: hidden and use explicit scrollbar elements. Unfortunately there's no easy way for script to detect user interaction with scrollbar elements, other than watching the curpos attribute.
You can't control, directly, the scroll increment in Firefox when clicking the scrollbar buttons but you can use this code:
//element may be window or a HTML element
//amount of incrementation should be an integer representing the number of pixels to be scrolled
//works in all last versions of major browsers
element.addEventListener(/firefox/i.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel', function (event) {
element.scrollTop -= (event.detail ? (event.detail % 2 ? event.detail / -3 : event.detail / -2) : event.wheelDelta / 120) * amount;
event.preventDefault();
}

Categories

Resources