Detect change in scroll direction with jQuery - javascript

I am using a basic jQuery function to toggle some classes to a div when scrolling up or down.
Basically it works this way:
When the user scrolls down, add the class "is-header-hidden", remove the class "is-header-visible"
When the user scrolls up, add the class "is-header-visible", remove the class "is-header-hidden"
Here's my code:
function hidingHeader() {
var didScroll,
lastScrollTop = 0,
tolerance = 15,
header = $('header'),
headerHeight = header.outerHeight(true),
fixedClass = ('is-header-fixed'),
hiddenClass = ('is-header-hidden'),
visibleClass = ('is-header-visible'),
transitioningClass = ('is-header-transitioning');
win.scroll(function( event ) {
didScroll = true;
});
setInterval(function() {
if ( didScroll ) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// SCROLL DOWN
if( st > lastScrollTop ) {
header.removeClass( visibleClass );
if( st >= headerHeight ) {
header.addClass( fixedClass ).addClass( hiddenClass );
}
// SCROLL UP
} else {
// Make sure they scroll more than tolerance
if( Math.abs( lastScrollTop - st ) > tolerance ) {
header.removeClass( hiddenClass ).addClass( visibleClass );
}
}
// UPDATE SCROLL VAR
var lastScrollTop = st;
}
}
Now, I want to add an "is-transitioning" class containing CSS transform attributes, that I am going to remove with a CSS animation callback. The problem is that I need that class to be triggered once, in other words only when there's a change in scroll direction, not every time the user scrolls.
I thought to store a "second to last" scrollTop variable in order to detect when there is a change in scroll direction, but my attempts failed. Any advice?

Maybe something like this?
function hidingHeader() {
var didScroll,
lastScrollTop = 0,
tolerance = 15,
lastDir = null, // you can start with a non-null if you don't want to trigger the first down for example, make this lastDir = "down",
header = $('header'),
headerHeight = header.outerHeight(true),
fixedClass = ('is-header-fixed'),
hiddenClass = ('is-header-hidden'),
visibleClass = ('is-header-visible'),
transitioningClass = ('is-header-transitioning');
win.scroll(function( event ) {
didScroll = true;
});
setInterval(function() {
if ( didScroll ) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// SCROLL DOWN
if( st > lastScrollTop ) {
header.removeClass( visibleClass );
if( st >= headerHeight ) {
header.addClass( fixedClass ).addClass( hiddenClass );
}
if( lastDir !== "down" ) { // Should only get triggered once while scrolling down, the first time the direction change happens
lastDir = "down";
// do your transition stuff here
}
// SCROLL UP
} else {
// Make sure they scroll more than tolerance
if( Math.abs( lastScrollTop - st ) > tolerance ) {
header.removeClass( hiddenClass ).addClass( visibleClass );
}
if( lastDir !== "up" ) { // Should only get triggered once while scrolling up, the first time the direction change happens
lastDir = "up";
// do your transition stuff here
}
}
// UPDATE SCROLL VAR
var lastScrollTop = st;
}
}

Related

Detect if user scrolls more than 20px no matter where it's on the page

Is it possible to detect if the user scrolls more than 20px wherever it's on the page??
I mean, in a one page design, I need to remove a class when the user scrolls more than 20px but not only from the top of the document.
Each time he opens a popup, a class is added to the popup in question, once the user scrolls, I would like to remove this class.
Repeat this function no matter where it's on the page.
My current code :
$(window , 'body').on('scroll', function() {
$('.navbar-collapse').collapse('hide');
$("#wrapper").removeClass('newsletter-opened');
$("#newsletter").removeClass('opened');
});
Thank you!
You can use jQuery for that.
With my solution, if user has scroll 200px when he come on your page if he scroll to top or bottom with minumum 20px of scroll your changes was called.
var userScroll = $(document).scrollTop();
$(window).on('scroll', function() {
var newScroll = $(document).scrollTop();
if(userScroll - newScroll > 20 || newScroll - userScroll > 20){
$('.navbar-collapse').collapse('hide');
$("#wrapper").removeClass('newsletter-opened');
$("#newsletter").removeClass('opened');
}
}
EDIT:
After look your jsFiddle, i know what you want, just check that :
Just define the scroll at the moment when popin is enable and make your job only when the popin has class opened
$(document).ready(function(){
$("a.open-newsletter").on( "click", function() {
$("#newsletter").toggleClass('opened');
userScroll = $(document).scrollTop();
return false;
});
$(window , 'body').on('scroll', function() {
if ( $("#newsletter").hasClass('opened') ) {
var newScroll = $(document).scrollTop();
if (userScroll - newScroll > 100 || newScroll - userScroll > 100) {
$("#newsletter").removeClass('opened');
}
}
});
});
Actually, the Scroll function will take effect on every pixel the page is scrolled, which is too heavy in terms of performance.
As a result, if you just take the difference between newScroll & userScroll, the result may be wrong sometimes (because the new and old scroll positions will be updated shortly as the page is moving along)
Therefore, we can just set a time interval which checks the scroll position every 250 milliseconds (this will both increase performance and give time for users to scroll more than 20px as your requirement):
var didScroll;
var lastScrollTop = 0;
var delta = 20;
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// Return if they scroll less than 20px (delta)
if(Math.abs(lastScrollTop - st) <= delta)
return;
// Do what you want here
console.log("lastScrollTop: ",lastScrollTop, " - newScroll: ", st);
$('.navbar-collapse').collapse('hide');
$("#wrapper").removeClass('newsletter-opened');
$("#newsletter").removeClass('opened');
lastScrollTop = st;
}
EDITED VERSION BELOW:
(according to your fiddle, I deleted "use strict" and commented out the $('.navbar-collapse') & $('#wrapper'))
Would you mind trying this again (seems that some previous errors just prevented my code from executing)
$(document).ready(function(){
$("a.open-newsletter").on( "click", function() {
$("#newsletter").toggleClass('opened');
return false;
});
var didScroll;
var lastScrollTop = 0;
var delta = 20;
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// Return if they scroll less than 20px (delta)
if(Math.abs(lastScrollTop - st) <= delta)
return;
// Do what you want here
console.log("lastScrollTop: ",lastScrollTop, " - newScroll: ", st);
//$('.navbar-collapse').collapse('hide');
//$("#wrapper").removeClass('newsletter-opened');
$("#newsletter").removeClass('opened');
lastScrollTop = st;
}
});

Jquery image scroller slow and jerky

So I built this image scroller with little thumbnail images at the bottom, I wanted the thumbnails to scroll left and right when you hover over an indicated area and stop when the last one comes into view ( and the same with the first one for the other direction) The code that I came up with works for a little while on the page but after a while it starts to get slow and jerky so I was wondering if there was a cleaner way to accomplish the same thing.
The code is:
var licount = $('.hs_cos_flex-slides-thumb li').length; //counts rows in list
var thumbwidth = licount * 210; //gets width of all rows
var viewwidth = $(".hs-cos-flex-slider-control-panel").width(); //gets width of sarounding div
var scrollwidth = thumbwidth - viewwidth; //gets width where last row is visible
var intervalId = window.setInterval;
$( ".thumb-for" ).hover(
function() {
var scrollposition = $(".hs_cos_flex-slides-thumb").position().left; //calculates how far left it has moved
var absposition = Math.abs(scrollposition); //gets absolute value of left movement
var shover = true;
if ( scrollwidth > (absposition + 209) ){
$('.hs_cos_flex-slides-thumb').animate({
right: '+=210px'
}, 1500, 'linear');
absposition+=210;
}
intervalId = window.setInterval(moveticker, 1500)
function moveticker() {
if ( scrollwidth > (absposition + 209) ){
$('.hs_cos_flex-slides-thumb').animate({
right: '+=210px'
}, 1500, 'linear');
absposition+=210;
}
};
}, function() {
window.clearInterval(intervalId);
}
);
$( ".thumb-back" ).hover(
function() {
var scrollposition = $(".hs_cos_flex-slides-thumb").position().left; //calculates how far left it has moved
var absposition = Math.abs(scrollposition); //gets absolute value of left movement
var shover = true;
if ( scrollposition < 0 ){
$('.hs_cos_flex-slides-thumb').animate({
right: '-=210px'
}, 1500, 'linear');
scrollposition+=210;
}
intervalId = window.setInterval(moveticker, 1500)
function moveticker() {
if ( scrollposition < 0 ){
$('.hs_cos_flex-slides-thumb').animate({
right: '-=210px'
}, 1500, 'linear');
scrollposition+=210;
}
};
}, function() {
window.clearInterval(intervalId);
}
);

section snap to window (firefox issue)

I have written a simple custom section snapping script, works great in chrome and safari, but after nothing happens in firefox...
What it is does:
When scrolling stops it checks the direction and location of each secrion... if the top of a section is within a certain range either go to the top of the page or bottom. (scroll directions is also checked). Also, it accounts for the height of a fixed header. Like I said works in Chrome and Safari. Any ideas what's wrong?
$( document ).ready(function() {
var animating = false;
var mainHeader = $('#main-header');
var items = $("section");
var lastOffset = 0;
var scrollDir = 'none';
$(window).scroll(function() {
var windowHeight = $(this).height();
var currOffset = $(this).scrollTop();
var headerHeight = mainHeader.outerHeight();
if (currOffset > lastOffset) {
scrollDir = 'down';
} else {
scrollDir = 'up';
}
lastOffset = currOffset;
clearTimeout($.data(this, 'scrollTimer'));
if (!animating) {
$.data(this, 'scrollTimer', setTimeout(function() {
items.each(function(key, value) {
var currentItem = $(value);
var sectionOffset = currentItem.offset().top;
var sectionDist = sectionOffset - currOffset;
if ( scrollDir === 'up' && sectionDist > windowHeight*0.15 && sectionDist < windowHeight ) {
animating = true;
$('body').animate( { scrollTop: sectionOffset-windowHeight + 'px' }, 250);
setTimeout(function() { animating = false; }, 300);
return false;
}
else if ( scrollDir === 'down' && sectionDist < windowHeight*0.85 && sectionDist > 0 ) {
animating = true;
$('body').animate( { scrollTop: sectionOffset-headerHeight + 'px' }, 250);
setTimeout(function() { animating = false; }, 300);
return false;
}
});
}, 200));
}
});
});
Found the answer here...
Animate scrollTop not working in firefox
Firefox places the overflow at the html level, unless specifically styled to behave differently.
To get it to work in Firefox, use
$('body,html').animate( ... );

Stop a function when I click on a div

I am trying to stop a function when I click on a div "ego". The function displays or hides the header depending on the position of the scroll and should only work by default.
Here's my code:
$("#ego").click(function(e){
var $this = $(this);
if($this.data('clicked', false)){
hasScrolled();
}
e.stopPropagation();
});
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = $('header').outerHeight();
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// Make sure they scroll more than delta
if(Math.abs(lastScrollTop - st) <= delta)
return;
// If they scrolled down and are past the navbar, add class .nav-up.
// This is necessary so you never see what is "behind" the navbar.
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
$('header').animate({top:"-178px"}, 200, 'easeOutCubic');
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').animate({top:"0px"}, 200, 'easeOutCubic');
}
}
lastScrollTop = st;
}
Here's the fiddle:
https://jsfiddle.net/antoniobarcos/wL2vuv4h/2/
Any idea?
so if i get you right you want to stop hiding the navigation bar on top when you click a certain div:
you can achieve this by adding a class on click on the button to your #ego like stopNavigation. further you have to adjust your if clause where you set the top position of the header:
$("#ego").click(function(e){
var $this = $(this);
$this.toggleClass('stopNavigation');
});
and
if (st > lastScrollTop && st > navbarHeight && !$('#ego').hasClass('stopNavigation')){
// Scroll Down
$('header').animate({top:"-178px"}, 200);
}
i updated your fiddle for further information! i hope this is what you want to achieve: https://jsfiddle.net/wL2vuv4h/3/

How to stop javascript if scroll to the top and run if it not to the top

I use this jquery plugin: http://tympanus.net/codrops/2013/03/29/quotes-rotator/
Here is JSFiddle: http://jsfiddle.net/LmuR7/
This is my settings(also there are some options but don't know how to use it):
<script src="js/jquery.cbpQTRotator.min.js">
</script>
<script>
$( function () {
/*
- how to call the plugin:
$( selector ).cbpQTRotator( [options] );
- options:
{
// default transition speed (ms)
speed : 700,
// default transition easing
easing : 'ease',
// rotator interval (ms)
interval : 8000
}
- destroy:
$( selector ).cbpQTRotator( 'destroy' );
*/
$( '#cbp-qtrotator' ).cbpQTRotator();
}
);
</script>
How can I stop code if it scrolled to top and start if it scrolled down?
Use this:
$(window).scroll(function() {
var currentScroll = $(this).scrollTop();
if ( currentScroll <= 0 ) {
$( selector ).cbpQTRotator( 'destroy' );
} else {
$('#cbp-qtrotator').cbpQTRotator();
}
});
Try this ...
<script>
var lastScrollTop = 0;
$(window).scroll(function(event){
var scrollTop = $(this).scrollTop();
if (scrollTop > lastScrollTop){
$('#cbp-qtrotator').cbpQTRotator();
console.log("construct");
} else {
$('#cbp-qtrotator').cbpQTRotator('destroy');
console.log("destruct");
}
lastScrollTop = scrollTop;
});
</script>
Ref: How can I determine the direction of a jQuery scroll event?

Categories