Limit 'mousewheel' delta to fire once per scroll - javascript

I'm using the following code below, to scroll two divs in different directions () but I'm curious to know if you can limit the scroll so it only fires once per scroll (rather than it continually scrolling and sending my functions into an endless loop.
$('.page-left, .page-right').bind('mousewheel', function(event, delta) {
var windowHeight = $(window).height();
if (delta < 0) {
prevProject();
}
if (delta > 0) {
nextProject();
}
});
You can see where I'm up up to here: http://dev.rdck.co/lyonandlyon/
Thanks in advance,
R
Animation functions for reference:
var prevProject = function() { // up arrow/scroll up
var windowHeight = $(window).height();
$('.page-left .page-left-wrapper').css({bottom:'auto'});
$('.page-left .page-left-wrapper').animate({top:0},800, function() {
$('.page-left .page-left-wrapper').prepend($('.page-left .project-left:last-of-type'));
$('.page-left .page-left-wrapper').css({top:-windowHeight});
});
$('.page-right .page-right-wrapper').css({top:'auto'});
$('.page-right .page-right-wrapper').animate({bottom:+windowHeight*2},800, function() {
$('.page-right .page-right-wrapper').append($('.page-right .project-right:first-of-type'));
$('.page-right .page-right-wrapper').css({bottom:+windowHeight});
});
};
var nextProject = function() { // down arrow/scroll down
var windowHeight = $(window).height();
$('.page-left .page-left-wrapper').animate({top:0},800, function() {
$('.page-left .page-left-wrapper').prepend($('.page-left .project-left:last-of-type'));
$('.page-left .page-left-wrapper').css({top:-windowHeight});
});
$('.page-right .page-right-wrapper').animate({bottom:+windowHeight*2},800, function() {
$('.page-right .page-right-wrapper').append($('.page-right .project-right:first-of-type'));
$('.page-right .page-right-wrapper').css({bottom:+windowHeight});
});
};

You can just check for animation within the mousewheel function (demo)
$('.page-left, .page-right').on('mousewheel', function(event, delta) {
if ($('.page-left-wrapper, .page-right-wrapper').is(':animated') ) {
return false;
}
var windowHeight = $(window).height();
if (delta < 0) {
prevProject();
}
if (delta > 0) {
nextProject();
}
});
Update: we resolved to use debounce as the long scroll (sliding a finger down a touchpad) needed to be stopped (updated demo).
$(document).keydown( $.debounce( 250, function(e) {
switch (e.which) {
case 38: // up arrow
prevProject();
break;
case 40: // down arrow
nextProject();
break;
}
}) );
$('.page-left, .page-right').on('mousewheel', $.debounce( 250, function(event, delta) {
var windowHeight = $(window).height();
if (delta < 0) {
prevProject();
}
if (delta > 0) {
nextProject();
}
}) );

You can get around this problem with a flag. You can use a global flag isAnimating and set it to true, if you are currently animating the position of the divs of your website.
So the code can look something like this:
var isAnimating = false;
$('.page-left, .page-right').bind('mousewheel', function(event, delta) {
// if the div will be animated at this moment return
if(isAnimating) {
return;
}
var windowHeight = $(window).height();
if (delta < 0) {
prevProject();
}
if (delta > 0) {
nextProject();
}
});
var prevProject = function() {
isAnimating = true;
var oneIsDone = false,
finish = function() {
// if both animations are done, set the flag to false
if(oneIsDone) {
isAnimating = false;
}
// at least one is done...
oneIsDone = true;
};
// animate the previous project and set the flag to false (in the callback)
$('.page-left .page-left-wrapper').css({bottom:'auto'});
$('.page-left .page-left-wrapper').animate({top:0},800, function() {
$('.page-left .page-left-wrapper').prepend($('.page-left .project-left:last-of-type'));
$('.page-left .page-left-wrapper').css({top:-windowHeight});
finish();
});
$('.page-right .page-right-wrapper').css({top:'auto'});
$('.page-right .page-right-wrapper').animate({bottom:+windowHeight*2},800, function() {
$('.page-right .page-right-wrapper').append($('.page-right .project-right:first-of-type'));
$('.page-right .page-right-wrapper').css({bottom:+windowHeight});
finish();
});
};
var nextProject = function() {
// the same as in the prevProject function, but only in the other direction
};

I suggest to detect extremums to fire the function:
var mw1 = 0;
var mw2 = 0;
var lock;
$(document).bind('mousewheel', function(evt) {
var delta = evt.originalEvent.deltaY
if(((delta > 0 && delta < mw2 && mw2 > mw1) || (delta < 0 && delta > mw2 && mw2 < mw1)) && !lock){
console.log(mw1 + " " + mw2 + " " + delta)
// call some function here
lock = true;
window.setTimeout(function(){
lock = false;
},200)
}
mw1 = mw2;
mw2 = delta;
})
lock is actually should not be necessary but extremums sometimes are found more than once per scroll for some reason.

Related

Complex jquery scroll

I need to trigger a function specifically after an user scroll almost at the bottom of the page then up until certain point. How do I do it properly?
advertisement.refreshAd = function() {
$(window).scroll(function(event) {
if('almost at the end then scroll up to certain point')
{console.log('trigger refresh!');}
});
}
What you are looking for is the jQuery function scrollTop(). The code would look something like this:
var atEnd = false;
advertisement.refreshAd = function() {
$(window).scroll(function(event) {
if($(document).scrollTop() > $(document).height()-500) { //point1
atEnd = true;
} if (($(document).scrollTop() < point2) && atEnd){
console.log('trigger refresh!');
}
});
}
Try below code
<script>
var touchedBottom = 0;
jQuery(window).scroll(function(event) {
if(jQuery(window).scrollTop() + jQuery(window).height() == jQuery(document).height()) {
touchedBottom = 1;
console.log("touched Bottom");
}
if(touchedBottom){
if(jQuery(window).scrollTop() < jQuery("#point_2").offset().top){
touchedBottom = 0;
console.log("touched point 1");
}
}
});
</script>
advertisements.refreshAd = function() {
var furthestPoint = false;
var point2 = 1700 //will be dynamic;
var lastScrollTop = 0;
var scrolledToPosition = false;
$(window).scroll(function() {
var st = $(this).scrollTop();
if($(window).scrollTop() + $(window).height() > $(document).height() - 100) {
furthestPoint = true;
}
if (st < lastScrollTop && st < point2 && furthestPoint){
if (!scrolledToPosition) {
console.log('TRIGGER! - once only!');
scrolledToPosition = true;
}
}
lastScrollTop = st;
});
};
advertisements.refreshAd();

Adding additional case to script for onClick event

I have a pop-up for a website that asks the user to sign up if they aren't already signed in. I'm using a script called "subscribe-better.js" (https://github.com/peachananr/subscribe-better) and this works great for loading the popup when the user first enters the site.
However, I want this pop-up to show when a user clicks a button. This is my button:
<div id="popClick" class="button btn">Sign Up to Proceed</div>
and here is how I am calling the pop-up:
<script>
$(document).ready(function() {
$(".subscribe-me2").subscribeBetter({
trigger: "onclick",
animation: "fade",
delay: 0,
showOnce: true,
autoClose: false,
scrollableModal: false
});
});
</script>
<div class="subscribe-me2">
Sample Pop Up Content Here
</div>
And the code to make it pop-up. You'll see I've added the case for onclick but nothing is happening when I click my button. I also tried instead of document.ready() to call the pop-up within a $('#popClick').click() but that didn't make the pop-up appear either. How can I fix the switch statement to make the pop-up appear when the #popClick button is clicked?
!function($){
var defaults = {
trigger: "atendpage", // atendpage | onload | onidle
animation: "fade", // fade | flyInRight | flyInLeft | flyInUp | flyInDown
delay: 0,
showOnce: true,
autoClose: false,
scrollableModal: false
};
$.fn.subscribeBetter = function(options){
var settings = $.extend({}, defaults, options),
el = $(this),
shown = false,
animating = false;
el.addClass("sb");
$.fn.openWindow = function() {
var el = $(this);
if(el.is(":hidden") && shown == false && animating == false) {
animating = true;
setTimeout(function() {
if (settings.scrollableModal == true) {
if($(".sb-overlay").length < 1) {
$("body").append("<div class='sb-overlay'><div class='sb-close-backdrop'></div><div class='sb sb-withoverlay'>" + $(".sb").html() + "</div></div>");
$(".sb-close-backdrop, .sb-close-btn").one("click", function() {
$(".sb.sb-withoverlay").closeWindow();
return false;
});
$(".sb.sb-withoverlay").removeClass("sb-animation-" + settings.animation.replace('In', 'Out')).addClass("sb-animation-" + settings.animation);
setTimeout(function(){
$(".sb.sb-withoverlay").show();
$("body").addClass("sb-open sb-open-with-overlay");
}, 300);
}
} else {
if ($(".sb-overlay").length < 1) {
$("body").append("<div class='sb-overlay'><div class='sb-close-backdrop'></div></div>");
$(".sb").removeClass("sb-animation-" + settings.animation.replace('In', 'Out')).addClass("sb-animation-" + settings.animation);
$(".sb-close-backdrop, .sb-close-btn").one("click", function() {
$(".sb").closeWindow();
return false;
});
setTimeout(function(){
$(".sb").show();
$("body").addClass("sb-open");
}, 300);
}
}
if (settings.showOnce == true) shown = true;
animating = false;
}, settings.delay);
}
}
$.fn.closeWindow = function() {
var el = $(this);
if(el.is(":visible") && animating == false) {
animating = true;
if (settings.scrollableModal == true) {
$(".sb.sb-withoverlay").removeClass("sb-animation-" + settings.animation).addClass("sb-animation-" + settings.animation.replace('In', 'Out'));
setTimeout(function(){
$(".sb.sb-withoverlay").hide();
$("body").removeClass("sb-open sb-open-with-overlay");
setTimeout(function() {
$(".sb-overlay").remove();
}, 300);
}, 300);
} else {
$(".sb").removeClass("sb-animation-" + settings.animation).addClass("sb-animation-" + settings.animation.replace('In', 'Out'));
setTimeout(function(){
$(".sb").hide();
$("body").removeClass("sb-open");
setTimeout(function() {
$(".sb-overlay").remove();
}, 300);
}, 300);
}
animating = false;
}
}
$.fn.scrollDetection = function (trigger, onDone) {
var t, l = (new Date()).getTime();
$(window).scroll(function(){
var now = (new Date()).getTime();
if(now - l > 400){
$(this).trigger('scrollStart');
l = now;
}
clearTimeout(t);
t = setTimeout(function(){
$(window).trigger('scrollEnd');
}, 300);
});
if (trigger == "scrollStart") {
$(window).bind('scrollStart', function(){
$(window).unbind('scrollEnd');
onDone();
});
}
if (trigger == "scrollEnd") {
$(window).bind('scrollEnd', function(){
$(window).unbind('scrollStart');
onDone();
});
}
}
switch(settings.trigger) {
case "atendpage":
$(window).scroll(function(){
var yPos = $(window).scrollTop();
if (yPos >= ($(document).height() - $(window).height()) ) {
el.openWindow();
} else {
if (yPos + 300 < ($(document).height() - $(window).height()) ) {
if(settings.autoClose == true) {
el.closeWindow();
}
}
}
});
break;
case "onload":
$(window).load(function(){
el.openWindow();
if(settings.autoClose == true) {
el.scrollDetection("scrollStart", function() {
el.closeWindow();
});
}
});
break;
case "onidle":
$(window).load(function(){
el.scrollDetection("scrollEnd", function() {
el.openWindow();
});
if(settings.autoClose == true) {
el.scrollDetection("scrollStart", function() {
el.closeWindow();
});
}
});
break;
case "onclick":
$('#popClick').click(function(){
el.openWindow();
});
break;
}
}
}(window.jQuery);
I believe the problem is that you're using 'showOnce' which globally limits the popup from showing more than once. So, your onclick probably is firing (I'd suggest adding a console.log in to be sure) but then if(el.is(":hidden") && shown == false && animating == false) { in the openWindow function is no longer true.

My JQuery Scroll Down works but scroll up doesn't work at all

I've put in a html several divs with IDs in a row prepended with the letter d, e.g: #d1, #d2, #d3... Then i created the javascript code below:
var pos = 0;
$("#button-up").on('click', function(e) {
e.preventDefault();
if(pos > 1){
pos -= 1;
$("html, body").stop().animate({
'scrollTop': $("#d"+pos).offset().top-300},200,"swing");
};
});
$("#button-down").on('click', function(e) {
e.preventDefault();
if(pos < 10){
pos += 1;
$("html, body").stop().animate({
'scrollTop': $("#d"+pos).offset().top-300},200,"swing");
};
});
window.addEventListener("scroll", function(event) {
var posi = this.pageYOffset;
if(posi-(pos-1)*1070+50 >= 1070){pos += 1} else if((pos-1)*1070+50-posi <= -1070){pos -= 1};
});
Finally my site scrolls down when i click the button-down, but i need to click twice the button-up for it scrolls up. Why? Is there a better way than this that gets the expected result?
I made it work changing this part:
window.addEventListener("scroll", function(event) {
var posi = this.pageYOffset;
if(posi-(pos-1)*1070+50 >= 1070){pos += 1} else if((pos-1)*1070+50-posi <= -1070){pos -= 1};
});
with this one:
window.addEventListener("mousewheel", function(e) {
e.preventDefault();
console.log('passou por 6');
var evt = window.event || e //equalize event object
evt = evt.originalEvent ? evt.originalEvent : evt; //convert to originalEvent if possible
var delta = evt.detail ? evt.detail*(-40) : evt.wheelDelta //check for detail first, because it is used by Opera and FF
if(delta > 0) {
if(pos > 1){
console.log('passou por 3');
pos -= 1;
$("html, body").stop().animate({
'scrollTop': $("#d"+pos).offset().top-300},200,"swing");
};
//scroll up
console.log('cima');
}
else{
if(pos < 10){
pos += 1;
$("html, body").stop().animate({
'scrollTop': $("#d"+pos).offset().top-300},200,"swing");
};
console.log('baixo');
//scroll down
};
});
Use jquery scoll function
$(window).scroll(function(event){
// your code
});

Slider overflow responsive

I'm working with this slider, all works great but why on small screen
(less than 480) or on responsive view it don't run?!
how can i fix this problem?!
More details in the fiddle below
http://jsfiddle.net/roXon/tMxp5/1/
$(function() {
var c = 1,
timeOut,
fit,
isStopped = false,
boxw = $('.box').outerWidth(true),
boxh = $('.box').outerHeight(true),
boxn = $('.box').length;
$('#slider').width(boxw*boxn);
$('#gal, #slider').height(boxh);
//////////////////////////////////
function measure() {
var winw = $(window).width();
fit = Math.ceil(winw/boxw)-1; // math ceil -1 to get the number of COMPLETELY visible boxes
$('#gal').width(winw);
$('#t').html('Boxw='+boxw+' Boxh='+boxh+' Winw='+winw+' VisibleBoxes='+ fit);
}
measure();
$(window).resize(function() {
measure();
});
//////////////////////////////////
function b(){
cc = (c === 1) ? $('.prev').hide() : $('.prev').show();
ccc =(c >= boxn/fit) ? $('.next').hide() : $('.next').show();
}
$('.btn').hide();
/////////////////////////////////
function a(cb){
$('#slider').animate({left: '-'+ (boxw*fit)*(c-1) },800, cb);
}
////////////////////////////////
function auto() {
if(isStopped){ return };
clearTimeout(timeOut);
timeOut = setTimeout(function() {
$('.btn').hide();
c++;
if (c >= (boxn/fit)+1) {
c = 1;
}
a(function(){
auto();
});
}, 2000);
}
auto();
/////////////////////////////////////////////////////////////////
$('.next').click(function() {
c++;
b();
a();
});
$('.prev').click(function() {
c--;
b();
a();
});
/////////////////////////////////////////////////////////////////
$('#gal').bind('mouseenter mouseleave', function(e) {
( e.type === 'mouseenter' ) ?
( isStopped=true, b(), clearTimeout(timeOut) ) :
( isStopped=false, auto() );
});
});
thank you
It's because your measure function set the number of visible boxes to 0
try changing the measure function to:
function measure() {
var winw = $(window).width();
fit = Math.ceil(winw/boxw)-1; // math ceil -1 to get the number of COMPLETELY visible boxes
$('#gal').width(winw);
if (fit == 0) fit = 1;
$('#t').html('Boxw='+boxw+' Boxh='+boxh+' Winw='+winw+' VisibleBoxes='+ fit);
}
And it should fix your problem: http://jsfiddle.net/tMxp5/270/

jQuery plugin: Do stuff to matched elements

Here's the plugin in case anyone finds it useful. http://silvestreh.github.io/onScreen/
Thanks again!
So, I'm trying to write my very first jQuery plugin and I already found my first road block. The plugin is supposed to do something to an element when it's visible (as in the view port area, not CSS visibility)
This is what the plugin looks like:
(function($) {
$.fn.onScreen = function(options) {
var self = $(this);
params = $.extend({
doIn: function(){
console.log('on screen');
},
doOut: function(){
console.log('off screen');
},
offset: 0
}, options);
return this.each(function() {
var $el = $(this);
var elTop = $el.offset().top;
$(window).scroll(function() {
var pos = $(window).scrollTop();
if (pos + params.offset >= (elTop - $el.height()) && pos + params.offset < (elTop + $el.height())) {
params.doIn.call($el[0]);
} else if (pos + params.offset > (elTop + $el.height()) || pos + params.offset < elTop) {
if (typeof(params.doOut) == 'function') {
params.doOut.call($el[0]);
}
}
});
});
};
})(jQuery);
And this is how I'm trying to use it:
$(function(){
$('div').onScreen({
doIn: function() {
$(this).stop().animate({
left: 20
},500)
},
doOut: function() {
$(this).stop().animate({
left: 0
},500)
}
});
});
The problem is that $(this) refers to the window object (because of the $(window).scroll() in the plugin) and not the matched elements. What am I doing wrong? How do I tell my plugin that I want to do stuff to the matched elements instead?
Thanks in advance :-)
EDIT: I just created a JSFiddle so you can check it out. http://jsfiddle.net/FBEFJ/3/
EDIT 2: bfavaretto fixed the code. I updated the question with the working code. Thank you!
The problem is how you're calling doIn and doOut in the plugin. Perhaps the simplest solution is to enforce a this value with Function.prototype.call:
if (pos + params.offset >= (elTop - $el.height()) && pos + params.offset < (elTop + $el.height())) {
params.doIn.call($el[0]);
} else if (pos + params.offset > (elTop + $el.height()) || pos + params.offset < elTop) {
if (typeof(params.doOut) == 'function') {
params.doOut.call($el[0]);
}
}

Categories