Detect when scrollIntoView stopped scrolling [duplicate] - javascript

I am using Javascript method Element.scrollIntoView()
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Is there any way I can get to know when the scroll is over. Say there was an animation, or I have set {behavior: smooth}.
I am assuming scrolling is async and want to know if there is any callback like mechanism to it.

There is no scrollEnd event, but you can listen for the scroll event and check if it is still scrolling the window:
var scrollTimeout;
addEventListener('scroll', function(e) {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function() {
console.log('Scroll ended');
}, 100);
});

2022 Update:
The CSS specs recently included the overscroll and scrollend proposal, this proposal adds a few CSS overscroll attributes, and more importantly to us, a scrollend event.
Browsers are still working on implementing it. (It's already available in Chromium under the Web Platforms Experiments flag.)
We can feature-detect it by simply looking for
if (window.onscrollend !== undefined) {
// we have a scrollend event
}
While waiting for implementations everywhere, the remaining of this answer is still useful if you want to build a polyfill:
For this "smooth" behavior, all the specs say[said] is
When a user agent is to perform a smooth scroll of a scrolling box box to position, it must update the scroll position of box in a user-agent-defined fashion over a user-agent-defined amount of time.
(emphasis mine)
So not only is there no single event that will fire once it's completed, but we can't even assume any stabilized behavior between different browsers.
And indeed, current Firefox and Chrome already differ in their behavior:
Firefox seems to have a fixed duration set, and whatever the distance to scroll is, it will do it in this fixed duration ( ~500ms )
Chrome on the other hand will use a speed, that is, the duration of the operation will vary based on the distance to scroll, with an hard-limit of 3s.
So this already disqualifies all the timeout based solutions for this problem.
Now, one of the answers here has proposed to use an IntersectionObserver, which is not a too bad solution, but which is not too portable, and doesn't take the inline and block options into account.
So the best might actually be to check regularly if we did stop scrolling. To do this in a non-invasive way, we can start an requestAnimationFrame powered loop, so that our checks are performed only once per frame.
Here one such implementation, which will return a Promise that will get resolved once the scroll operation has finished.
Note: This code misses a way to check if the operation succeeded, since if an other scroll operation happens on the page, all current ones are cancelled, but I'll leave this as an exercise for the reader.
const buttons = [ ...document.querySelectorAll( 'button' ) ];
document.addEventListener( 'click', ({ target }) => {
// handle delegated event
target = target.closest('button');
if( !target ) { return; }
// find where to go next
const next_index = (buttons.indexOf(target) + 1) % buttons.length;
const next_btn = buttons[next_index];
const block_type = target.dataset.block;
// make it red
document.body.classList.add( 'scrolling' );
smoothScroll( next_btn, { block: block_type })
.then( () => {
// remove the red
document.body.classList.remove( 'scrolling' );
} )
});
/*
*
* Promised based scrollIntoView( { behavior: 'smooth' } )
* #param { Element } elem
** ::An Element on which we'll call scrollIntoView
* #param { object } [options]
** ::An optional scrollIntoViewOptions dictionary
* #return { Promise } (void)
** ::Resolves when the scrolling ends
*
*/
function smoothScroll( elem, options ) {
return new Promise( (resolve) => {
if( !( elem instanceof Element ) ) {
throw new TypeError( 'Argument 1 must be an Element' );
}
let same = 0; // a counter
let lastPos = null; // last known Y position
// pass the user defined options along with our default
const scrollOptions = Object.assign( { behavior: 'smooth' }, options );
// let's begin
elem.scrollIntoView( scrollOptions );
requestAnimationFrame( check );
// this function will be called every painting frame
// for the duration of the smooth scroll operation
function check() {
// check our current position
const newPos = elem.getBoundingClientRect().top;
if( newPos === lastPos ) { // same as previous
if(same ++ > 2) { // if it's more than two frames
/* #todo: verify it succeeded
* if(isAtCorrectPosition(elem, options) {
* resolve();
* } else {
* reject();
* }
* return;
*/
return resolve(); // we've come to an halt
}
}
else {
same = 0; // reset our counter
lastPos = newPos; // remember our current position
}
// check again next painting frame
requestAnimationFrame(check);
}
});
}
p {
height: 400vh;
width: 5px;
background: repeat 0 0 / 5px 10px
linear-gradient(to bottom, black 50%, white 50%);
}
body.scrolling {
background: red;
}
<button data-block="center">scroll to next button <code>block:center</code></button>
<p></p>
<button data-block="start">scroll to next button <code>block:start</code></button>
<p></p>
<button data-block="nearest">scroll to next button <code>block:nearest</code></button>
<p></p>
<button>scroll to top</button>

You can use IntersectionObserver, check if element .isIntersecting at IntersectionObserver callback function
const element = document.getElementById("box");
const intersectionObserver = new IntersectionObserver((entries) => {
let [entry] = entries;
if (entry.isIntersecting) {
setTimeout(() => alert(`${entry.target.id} is visible`), 100)
}
});
// start observing
intersectionObserver.observe(element);
element.scrollIntoView({behavior: "smooth"});
body {
height: calc(100vh * 2);
}
#box {
position: relative;
top:500px;
}
<div id="box">
box
</div>

I stumbled across this question as I wanted to focus a particular input after the scrolling is done (so that I keep the smooth scrolling).
If you have the same usecase as me, you don't actually need to wait for the scroll to be finished to focus your input, you can simply disable the scrolling of focus.
Here is how it's done:
window.scrollTo({ top: 0, behavior: "smooth" });
myInput.focus({ preventScroll: true });
cf: https://github.com/w3c/csswg-drafts/issues/3744#issuecomment-685683932
Btw this particular issue (of waiting for scroll to finish before executing an action) is discussed in CSSWG GitHub here: https://github.com/w3c/csswg-drafts/issues/3744

Solution that work for me with rxjs
lang: Typescript
scrollToElementRef(
element: HTMLElement,
options?: ScrollIntoViewOptions,
emitFinish = false,
): void | Promise<boolean> {
element.scrollIntoView(options);
if (emitFinish) {
return fromEvent(window, 'scroll')
.pipe(debounceTime(100), first(), mapTo(true)).toPromise();
}
}
Usage:
const element = document.getElementById('ELEM_ID');
scrollToElementRef(elment, {behavior: 'smooth'}, true).then(() => {
// scroll finished do something
})

These answers above leave the event handler in place even after the scrolling is done (so that if the user scrolls, their method keeps getting called). They also don't notify you if there's no scrolling required. Here's a slightly better answer:
$("#mybtn").click(function() {
$('html, body').animate({
scrollTop: $("div").offset().top
}, 2000);
$("div").html("Scrolling...");
callWhenScrollCompleted(() => {
$("div").html("Scrolling is completed!");
});
});
// Wait for scrolling to stop.
function callWhenScrollCompleted(callback, checkTimeout = 200, parentElement = $(window)) {
const scrollTimeoutFunction = () => {
// Scrolling is complete
parentElement.off("scroll");
callback();
};
let scrollTimeout = setTimeout(scrollTimeoutFunction, checkTimeout);
parentElement.on("scroll", () => {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(scrollTimeoutFunction, checkTimeout);
});
}
body { height: 2000px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="mybtn">Scroll to Text</button>
<br><br><br><br><br><br><br><br>
<div>example text</div>

i'm not an expert in javascript but i made this with jQuery. i hope it helps
$("#mybtn").click(function() {
$('html, body').animate({
scrollTop: $("div").offset().top
}, 2000);
});
$( window ).scroll(function() {
$("div").html("scrolling");
if($(window).scrollTop() == $("div").offset().top) {
$("div").html("Ended");
}
})
body { height: 2000px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="mybtn">Scroll to Text</button>
<br><br><br><br><br><br><br><br>
<div>example text</div>

I recently needed callback method of element.scrollIntoView(). So tried to use the Krzysztof Podlaski's answer.
But I could not use it as is. I modified a little.
import { fromEvent, lastValueFrom } from 'rxjs';
import { debounceTime, first, mapTo } from 'rxjs/operators';
/**
* This function allows to get a callback for the scrolling end
*/
const scrollToElementRef = (parentEle, childEle, options) => {
// If parentEle.scrollTop is 0, the parentEle element does not emit 'scroll' event. So below is needed.
if (parentEle.scrollTop === 0) return Promise.resolve(1);
childEle.scrollIntoView(options);
return lastValueFrom(
fromEvent(parentEle, 'scroll').pipe(
debounceTime(100),
first(),
mapTo(true)
)
);
};
How to use
scrollToElementRef(
scrollableContainerEle,
childrenEle,
{
behavior: 'smooth',
block: 'end',
inline: 'nearest',
}
).then(() => {
// Do whatever you want ;)
});

Related

How to freeze Javascript timeouts and BS4/jQuery animations?

I have an HTML page that has timeouts. I want to freeze them when you press a button (#pauseButton) and then resume when you press it again, preferably freezing all BS4 and jQuery animations also.
<button id="pauseButton"></button>
<script>
$(document).ready(function(){
setTimeout(function() {
alert("This is an alert")
},10000);
$("#pauseButton").click(function(){
// Pause timeouts and page
});
});
</script>
EDIT
I have been notified that there is a possible duplicate answer, so I am now focusing on pausing animations and other page elements.
That answer shows how to pause timeouts only.
There are many ways to solve this issue. Many of them are mentioned in this question as mentioned by #EmadZamout in the comments.
But, if you are looking for an easy and maybe an alternate way to solve this. Try this. Here I am using requestAnimationFrame to solve the issue
let ran = Date.now(); // contains the last updated time
let time = 0; // time in seconds
let paused = false; // store the state
const func = () => {
if (!paused && Date.now() - ran > 1000) {
time++;
ran = Date.now();
console.log('now')
}
if (time === 8)
return alert('This works!');
requestAnimationFrame(func);
}
func();
document.querySelector('button').addEventListener('click', () => paused = !paused);
<button>Change state</button>
For stopping all the animations of the website, you need to manually stop each animation.
For stopping a jQuery animation, you can use .stop() helper. An example:
let paused = false; // state of the animation
let dir = 'down'; // to store the direction of animation so that the next time continues in the correct direction
let timeDown = 2000; // to animate properly after resuming
let timeUp = 2000; // to animate properly after resuming
// the initial calling of the animation
(function() {
slideDown();
})();
// function which resumes the animation
function animate() {
switch (dir) {
case 'up':
slideUp();
break;
case 'down':
slideDown();
break;
}
}
// a function to animate in the uppward direction
function slideUp() {
dir = 'up'; // setting direction to up
timeDown = 2000; // resetting the duration for slideDown function
$('div').stop().animate({
left: 0
}, {
duration: timeUp,
complete: slideDown, // calling slideDown function on complete
progress: function (animation, progress, ms) {
timeUp = ms; // changing the duration so that it looks smooth when the animation is resumed
}
}); // actual animation
}
// a function to animate in the downward direction
function slideDown() {
dir = 'down'; // setting direction to down
timeUp = 2000; // resetting the duration for slideDown function
$('div').stop().animate({
left: 200
}, {
duration: timeDown,
complete: slideUp, // calling slideUp function on complete
progress: function (animation, progress, ms) {
timeDown = ms; // changing the duration so that it looks smooth when the animation is resumed
}
}); // actual animation
}
// button click event listener
$('button').click(function() {
if (paused)
animate(); // to resume the animation
else
$('div').stop(); // to stop all the animations on the object
paused = !paused; // toggling state
});
div {
position: relative;
width: 100px;
height: 100px;
background: dodgerblue;
}
<button>Pause</button>
<div></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
For bootstrap, I don't think you have any bootstrap animations which needed to be paused in this scenario which you have mentioned since bootstrap animations depend on user interactions. If you want to prevent user interaction, you can put an overlay over the website says "Paused". Or, if you don't want to do that you can use CSS property pointer-events: none to disable all the pointer events.
Now for CSS animations, you can set a property called animation-play-state to paused.
If you want to change the state of the animations to paused when the user is not on the page (As I understood for your updated questions) you can use the new visibilityState API for that. There is an event visibilitychange which is fired when there a change in visibility.
document.addEventListener("visibilitychange", function() {
console.log( document.visibilityState );
document.querySelector('div').innerHTML = document.visibilityState;
});
<div>
Try opening a different tab or change the focus to another app
</div>

mousewheel event is too fast. How to disable it

I am trying to bring in an effect like hugeinc.com in my website udowalzfinal.umatechcorner.com
I did the following
$(window).on({
'DOMMouseScroll mousewheel': ScrollBegin
});
var delta = 0;
var scrollThreshold = 10;
function ScrollBegin(e) {
// --- Scrolling up ---
if (e.originalEvent.detail < 0 || e.originalEvent.wheelDelta > 0) {
delta--;
console.log(delta);
if ( Math.abs(delta) >= scrollThreshold) {
timer = setTimeout(function () {
MoveScreen('up');
}, 800);
clearTimeout(timer);
}
}
// --- Scrolling down ---
else {
delta++;
console.log(delta);
if (delta >= scrollThreshold) {
timer = setTimeout(function () {
MoveScreen('down');
clearTimeout(timer);
}, 800);
}
}
// Prevent page from scrolling
return false;
}
I don't know what value to set for scrollThreshold.
mousewheel event is raised & ScrollBegin is executed. But this is too slow in IE & too fast in Safari with Apple Mouse.
Mousewheel event is raised for each mouse wheel move. In my case, it raises the event 10 times when I scroll the mouse wheel once. How can I disable those 9 events and only handle it once.
How to get a MouseWheel Event to fire only once in jQuery? article does not fix my problem. This only gives support for moving up once & then down once. But I have 5 slides in my page.
Can someone please help?
You should probably use a debouncer.
//Debouncer functions add a delay between an event and a reaction, so scaling and scrolling don't evoke a function dozens of times.
function debouncer(func, timeout) {
var timeoutID , timeout = timeout || 200;
return function () {
var scope = this , args = arguments;
clearTimeout( timeoutID );
timeoutID = setTimeout( function () {
func.apply( scope , Array.prototype.slice.call( args ) );
} , timeout );
};
}
This is a general purpose function. Use it like this:
jQuery(window).scroll(debouncer(function(){
//Call your scroll handler here.
}));
To really fine tune the delay, add a cecond parameter, like:
jQuery(window).scroll(debouncer(function(){
//Call your scroll handler here.
}), 600);
You want to look at something like Underscore.js's Debounce function. You can either use debounce directly by bringing underscore onto your page (not a bad idea), or implement it yourself. There's also throttle, which works slightly differently; here's an example with both:
http://goo.gl/jEl9lA

A Function to Check if the Mouse is Still Hovering an Element Every 10 Milliseconds (and run a function if it is)

I was wondering if there is a function to be run after an element (e.g. div class="myiv") is hovered and check every X milliseconds if it's still hovered, and if it is, run another function.
EDIT: This did the trick for me:
http://jsfiddle.net/z8yaB/
For most purposes in simple interfaces, you may use jquery's hover function and simply store in a boolean somewhere if the mouse is hover. And then you may use a simple setInterval loop to check every ms this state. You yet could see in the first comment this answer in the linked duplicate (edit : and now in the other answers here).
But there are cases, especially when you have objects moving "between" the mouse and your object when hover generate false alarms.
For those cases, I made this function that checks if an event is really hover an element when jquery calls my handler :
var bubbling = {};
bubbling.eventIsOver = function(event, o) {
if ((!o) || o==null) return false;
var pos = o.offset();
var ex = event.pageX;
var ey = event.pageY;
if (
ex>=pos.left
&& ex<=pos.left+o.width()
&& ey>=pos.top
&& ey<=pos.top+o.height()
) {
return true;
}
return false;
};
I use this function to check that the mouse really leaved when I received the mouseout event :
$('body').delegate(' myselector ', 'mouseenter', function(event) {
bubbling.bubbleTarget = $(this);
// store somewhere that the mouse is in the object
}).live('mouseout', function(event) {
if (bubbling.eventIsOver(event, bubbling.bubbleTarget)) return;
// store somewhere that the mouse leaved the object
});
You can use variablename = setInterval(...) to initiate a function repeatedly on mouseover, and clearInterval(variablename) to stop it on mouseout.
http://jsfiddle.net/XE8sK/
var marker;
$('#test').on('mouseover', function() {
marker = setInterval(function() {
$('#siren').show().fadeOut('slow');
}, 500);
}).on('mouseout', function() {
clearInterval(marker);
});​
jQuery has the hover() method which gives you this functionality out of the box:
$('.myiv').hover(
function () {
// the element is hovered over... do stuff
},
function () {
// the element is no longer hovered... do stuff
}
);
To check every x milliseconds if the element is still hovered and respond adjust to the following:
var x = 10; // number of milliseconds
var intervalId;
$('.myiv').hover(
function () {
// the element is hovered over... do stuff
intervalId = window.setInterval(someFunction, x);
},
function () {
// the element is no longer hovered... do stuff
window.clearInterval(intervalId);
}
);
DEMO - http://jsfiddle.net/z8yaB/
var interval = 0;
$('.myiv').hover(
function () {
interval = setInterval(function(){
console.log('still hovering');
},1000);
},
function () {
clearInterval(interval);
}
);

jQuery scroll() detect when user stops scrolling

Ok with this..
$(window).scroll(function()
{
$('.slides_layover').removeClass('showing_layover');
$('#slides_effect').show();
});
I can tell when someone is scrolling from what I understand. So with that I am trying to figure out how to catch when someone has stopped. From the above example you can see I am removing a class from a set of elements while the scrolling is occurring. However, I want to put that class back on when the user stops scrolling.
The reason for this is I am intent on having a layover show while the page is scrolling to give the page a special effect I am attempting to work on. But the one class I am trying to remove while scrolling conflicts with that effect as its a transparency effect to some nature.
$(window).scroll(function() {
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
// do something
console.log("Haven't scrolled in 250ms!");
}, 250));
});
Update
I wrote an extension to enhance jQuery's default on-event-handler. It attaches an event handler function for one or more events to the selected elements and calls the handler function if the event was not triggered for a given interval. This is useful if you want to fire a callback only after a delay, like the resize event, or such.
It is important to check the github-repo for updates!
https://github.com/yckart/jquery.unevent.js
;(function ($) {
var on = $.fn.on, timer;
$.fn.on = function () {
var args = Array.apply(null, arguments);
var last = args[args.length - 1];
if (isNaN(last) || (last === 1 && args.pop())) return on.apply(this, args);
var delay = args.pop();
var fn = args.pop();
args.push(function () {
var self = this, params = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(self, params);
}, delay);
});
return on.apply(this, args);
};
}(this.jQuery || this.Zepto));
Use it like any other on or bind-event handler, except that you can pass an extra parameter as a last:
$(window).on('scroll', function(e) {
console.log(e.type + '-event was 250ms not triggered');
}, 250);
http://yckart.github.com/jquery.unevent.js/
(this demo uses resize instead of scroll, but who cares?!)
Using jQuery throttle / debounce
jQuery debounce is a nice one for problems like this. jsFidlle
$(window).scroll($.debounce( 250, true, function(){
$('#scrollMsg').html('SCROLLING!');
}));
$(window).scroll($.debounce( 250, function(){
$('#scrollMsg').html('DONE!');
}));
The second parameter is the "at_begin" flag. Here I've shown how to execute code both at "scroll start" and "scroll finish".
Using Lodash
As suggested by Barry P, jsFiddle, underscore or lodash also have a debounce, each with slightly different apis.
$(window).scroll(_.debounce(function(){
$('#scrollMsg').html('SCROLLING!');
}, 150, { 'leading': true, 'trailing': false }));
$(window).scroll(_.debounce(function(){
$('#scrollMsg').html('STOPPED!');
}, 150));
Rob W suggected I check out another post here on stack that was essentially a similar post to my original one. Which reading through that I found a link to a site:
http://james.padolsey.com/javascript/special-scroll-events-for-jquery/
This actually ended up helping solve my problem very nicely after a little tweaking for my own needs, but over all helped get a lot of the guff out of the way and saved me about 4 hours of figuring it out on my own.
Seeing as this post seems to have some merit, I figured I would come back and provide the code found originally on the link mentioned, just in case the author ever decided to go a different direction with the site and ended up taking down the link.
(function(){
var special = jQuery.event.special,
uid1 = 'D' + (+new Date()),
uid2 = 'D' + (+new Date() + 1);
special.scrollstart = {
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
} else {
evt.type = 'scrollstart';
jQuery.event.handle.apply(_self, _args);
}
timer = setTimeout( function(){
timer = null;
}, special.scrollstop.latency);
};
jQuery(this).bind('scroll', handler).data(uid1, handler);
},
teardown: function(){
jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
}
};
special.scrollstop = {
latency: 300,
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout( function(){
timer = null;
evt.type = 'scrollstop';
jQuery.event.handle.apply(_self, _args);
}, special.scrollstop.latency);
};
jQuery(this).bind('scroll', handler).data(uid2, handler);
},
teardown: function() {
jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
}
};
})();
I agreed with some of the comments above that listening for a timeout wasn't accurate enough as that will trigger when you stop moving the scroll bar for long enough instead of when you stop scrolling. I think a better solution is to listen for the user letting go of the mouse (mouseup) as soon as they start scrolling:
$(window).scroll(function(){
$('#scrollMsg').html('SCROLLING!');
var stopListener = $(window).mouseup(function(){ // listen to mouse up
$('#scrollMsg').html('STOPPED SCROLLING!');
stopListner(); // Stop listening to mouse up after heard for the first time
});
});
and an example of it working can be seen in this JSFiddle
ES6 style with checking scrolling start also.
function onScrollHandler(params: {
onStart: () => void,
onStop: () => void,
timeout: number
}) {
const {onStart, onStop, timeout = 200} = params
let timer = null
return (event) => {
if (timer) {
clearTimeout(timer)
} else {
onStart && onStart(event)
}
timer = setTimeout(() => {
timer = null
onStop && onStop(event)
}, timeout)
}
}
Usage:
yourScrollableElement.addEventListener('scroll', onScrollHandler({
onStart: (event) => {
console.log('Scrolling has started')
},
onStop: (event) => {
console.log('Scrolling has stopped')
},
timeout: 123 // Remove to use default value
}))
You could set an interval that runs every 500 ms or so, along the lines of the following:
var curOffset, oldOffset;
oldOffset = $(window).scrollTop();
var $el = $('.slides_layover'); // cache jquery ref
setInterval(function() {
curOffset = $(window).scrollTop();
if(curOffset != oldOffset) {
// they're scrolling, remove your class here if it exists
if($el.hasClass('showing_layover')) $el.removeClass('showing_layover');
} else {
// they've stopped, add the class if it doesn't exist
if(!$el.hasClass('showing_layover')) $el.addClass('showing_layover');
}
oldOffset = curOffset;
}, 500);
I haven't tested this code, but the principle should work.
function scrolled() {
//do by scroll start
$(this).off('scroll')[0].setTimeout(function(){
//do by scroll end
$(this).on('scroll',scrolled);
}, 500)
}
$(window).on('scroll',scrolled);
very small Version with start and end ability
This detects the scroll stop after 1 milisecond (or change it) using a global timer:
var scrollTimer;
$(window).on("scroll",function(){
clearTimeout(scrollTimer);
//Do what you want whilst scrolling
scrollTimer=setTimeout(function(){afterScroll()},1);
})
function afterScroll(){
//I catched scroll stop.
}
Ok this is something that I've used before.
Basically you look a hold a ref to the last scrollTop().
Once your timeout clears, you check the current scrollTop() and if they are the same, you are done scrolling.
$(window).scroll((e) ->
clearTimeout(scrollTimer)
$('header').addClass('hidden')
scrollTimer = setTimeout((() ->
if $(this).scrollTop() is currentScrollTop
$('header').removeClass('hidden')
), animationDuration)
currentScrollTop = $(this).scrollTop()
)
please check the jquery mobile scrollstop event
$(document).on("scrollstop",function(){
alert("Stopped scrolling!");
});
For those Who Still Need This Here Is The Solution
$(function(){
var t;
document.addEventListener('scroll',function(e){
clearTimeout(t);
checkScroll();
});
function checkScroll(){
t = setTimeout(function(){
alert('Done Scrolling');
},500); /* You can increase or reduse timer */
}
});
This should work:
var Timer;
$('.Scroll_Table_Div').on("scroll",function()
{
// do somethings
clearTimeout(Timer);
Timer = setTimeout(function()
{
console.log('scrolling is stop');
},50);
});
Here is how you can handle this:
var scrollStop = function (callback) {
if (!callback || typeof callback !== 'function') return;
var isScrolling;
window.addEventListener('scroll', function (event) {
window.clearTimeout(isScrolling);
isScrolling = setTimeout(function() {
callback();
}, 66);
}, false);
};
scrollStop(function () {
console.log('Scrolling has stopped.');
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
</body>
</html>

Trigger function when the page stops scrolling

How can I trigger a function when the browser window stops scrolling? Either by mouse wheel, click, space bar or arrow key? Is there any event for such action? I have tried to search online but couldn't get any solution. I'm fine with a jQuery solution.
There's no "event" but you could make your own, like this:
$(function() {
var timer;
$(window).scroll(function() {
clearTimeout(timer);
timer = setTimeout(function() {
$(window).trigger("scrollStop");
}, 250);
});
});
Then you could bind to it, like this:
$(window).bind("scrollStop", function() {
alert("No one has scrolled me in 250ms, where's the love?");
});
This creates an event, there's no "stop" for this, but you can define your own... in this case "stop" is defined as "hasn't scrolled in 250ms", you can adjust the timer to your liking, but that's the idea.
Also, if you're just doing one thing there's no need for an event, just put your code where I'm calling $(window).trigger("scrollStop") and it'll run n milliseconds after the scroll stops.
The Non-jQuery Javascript version of the chosen answer:
var elem = document.getElementById('test');
(() => {
var onScrollStop = (evt) => {
// you have scroll event as evt (for any additional info)
var scrollStopEvt = new CustomEvent('scrolling-stopped', {detail: 'foobar stopped :)'});
elem.dispatchEvent(scrollStopEvt);
}
var scrollStopLag = 300 // the duration to wait before onScrollStop is triggerred.
var timerID = 0;
const handleScroll = (evt) => {
clearInterval(timerID);
timerID = setTimeout(
() => onScrollStop(evt),
scrollStopLag
)
}
elem.addEventListener('scroll', handleScroll);
})()
elem.addEventListener(
'scrolling-stopped',
(evt) => console.log(evt.detail)
)
#test {
height: 300px;
width: 300px;
overflow: auto;
}
#test #test-inner {
height: 3000px;
background: linear-gradient(lightseagreen 0%, lightyellow 40%, lightcoral 100%);
}
<h4>Scroll inside the green box below:</h4>
<div id="test">
<div id="test-inner"></div>
</div>
Good Luck...
P.S. I am a BIG fan of jQuery :)

Categories