section scrolling using mousewheel - javascript

I'm using the mousewheel plugin to scroll sections of my page.
What I should look into for disabling the function I wrote until the animation has fully completed?
I am running stop() but that only cancels out the animation.
$('section').mousewheel(function(event, delta, deltaX, deltaY) {
$('section' ).waypoint(function(direction){
thisID = $(this);
},{ offset: '25%' });
if (delta > 0) {
console.log('up');
if ($(this).not(":first-child")) {
//$(this).animate(function(){
$('html, body').stop().animate({
scrollTop: thisID.prev().offset().top
}, 1000);
//});
}else {
$('html, body').stop().animate({
scrollTop: thisID.offset().top
}, 1000);
}
}
else if (delta < 0) {
if ($(this).not(":first-child")) {
$('html, body').stop().animate({
scrollTop: thisID.next().offset().top
}, 1000);
}
else {
$('html, body').stop().animate({
scrollTop: thisID.offset().top
}, 1000);
}
console.log('down');
}
return false; // prevent default
});

One way to do this would be to create a "stoplight" variable. Set it to False at the beginning of your function, and then re-set it to True at the end of the animation using the complete argument of the animate() function. Then make the main function only run if this variable is True.

Instead of reinventing the wheel you might want to take a look at things such as fullPage.js.
It will save you from many headaches when you start dealing with touch devices, touch screens, old browsers, kinetic scrolling present in trackpads or Apple laptops...

Related

How to throttle function using the mousewheel plugin?

I'm using this plugin:
https://github.com/jquery/jquery-mousewheel
It's a horizontally scrolling one-page site, and the function is intended as a "scrollsnap"-- a scroll on the current section will force snap it to the next section. However, after the first "snap", it only happens after ~5 seconds, which I believe is due to the function firing too many times in a row.
function scrollSnap() {
$('.page:not(:last-child)').each(function(){
var nextTarget = $(this).next().position().left;
$(this).mousewheel(function(){
if(event.deltaY >= 50) {
$('main').animate({
scrollLeft: nextTarget
}, 700);
console.log("scrolled to: ", nextTarget);
}
});
});
$('.page:not(:first-child)').each(function(){
var prevTarget = $(this).prev().position().left;
$(this).mousewheel(function(){
if(event.deltaY <= -50) {
$('main').animate({
scrollLeft: prevTarget
}, 700);
console.log("scrolled to: ", prevTarget);
}
});
});
}
$(document).ready(function() {
scrollSnap();
});
You can throttle events like these with something called a debounce function. You can create your own or use a utility library like lodash which has it built in.

JQuery .resize function running code x times resized

I now use CSS Media queries for my carousels and the buttons. But for the scroll animation to work properly I need Jquery. The problem I'm having is that if I resize to a device resolution and back to desktop, doing that 3 times means the code will run 3 times. so doing that 6 times, it will run the code 6 times.
Jquery:
function setupButtons() {
if ($(window).width() > 1198) {
if ($('#carousel-a').is(':visible')) { // desktop
$("#OnzeDiensten").click(function(a) {
a.preventDefault();
$('html, body').animate({
scrollTop: $("#OnzeDienstenHeading").offset().top - 80
}, 2000);
alert(" MAIN!");
});
}
}
if ($(window).width() < 992) { // device
if ($('#carousel-d').is(':visible')) {
$("#OnzeDienstenDevices").click(function(b) {
b.preventDefault();
$('html, body').animate({
scrollTop: $("#OnzeDienstenHeadingDevice").offset().top - 80
}, 2000);
alert("DEVICE!");
});
}
}
if ($(window).width() < 1198 && $(window).width() > 992) { // tablet
if ($('#carousel-e').is(':visible')) {
$("#OnzeDienstenResponsive").click(function(c) {
c.preventDefault();
$('html, body').animate({
scrollTop: $("#OnzeDienstenHeadingResponsive").offset().top - 80
}, 2000);
alert("RESPONSIVE!");
});
}
}
}
function resizeAnimatedScreenButton() {
var resizeTimeout;
$(window).resize(function() {
clearTimeout(resizeTimeout);
if ($(window).width() > 1198) {
resizeTimeout = setTimeout(function() {
if ($('#carousel-a').is(':visible')) { // desktop
$("#OnzeDiensten").click(function(a) {
a.preventDefault();
$('html, body').animate({
scrollTop: $("#OnzeDienstenHeading").offset().top - 80
}, 2000);
alert(" MAIN!");
$('#carousel-a').unbind();
});
}
}, 500);
}
if ($(window).width() < 992) { // device
resizeTimeout = setTimeout(function() {
if ($('#carousel-d').is(':visible')) {
$("#OnzeDienstenDevices").click(function(b) {
b.preventDefault();
$('html, body').animate({
scrollTop: $("#OnzeDienstenHeadingDevice").offset().top - 80
}, 2000);
alert("DEVICE!");
$('#carousel-d').unbind();
});
}
}, 500);
}
if ($(window).width() < 1198 && $(window).width() > 992) { // tablet
resizeTimeout = setTimeout(function() {
if ($('#carousel-e').is(':visible')) {
$("#OnzeDienstenResponsive").click(function(c) {
c.preventDefault();
$('html, body').animate({
scrollTop: $("#OnzeDienstenHeadingResponsive").offset().top - 80
}, 2000);
alert("RESPONSIVE!");
$('#carousel-e').unbind();
});
}
}, 500);
}
});
} // end resizeanimation
$(document).ready(function() {
setupButtons();
resizeAnimatedScreenButton();
});
CSS Media Queries:
#media (min-width:1198px)
.carousele, .carouseld, .DienstResponsive, .DienstDevice {
display:none!important;
}
#media (max-width:1197px) and (min-width: 993px)
.carousela, .carouseld, .DienstDesktop, .DienstDevice {
display:none;
}
#media (max-width:992px)
.carousele, .carousela, .DienstDesktop, .DienstDevice {
display:none;
}
The problem is that you attach a .click listener inside the scroll callback :
$(window).resize(function() {
$("#OnzeDiensten").click(function(a) { ... }
})
This means that you are attaching one click listener every time the window is resized by 1 pixel. So if you resize the window by 100 pixels, you attach 100 listeners (!) And when the button is clicked, the code runs 100 times.
Even worse, as I already said in the comments, you are not caching your jQuery objects. So jQuery must traverse the whole DOM and look for each of $('#carousel-a'), $('html, body'), $("#OnzeDienstenDevices"), $("#OnzeDienstenHeadingDevice") and $('#carousel-d') a HUNDRED times, and build this many jQuery objects a HUNDRED times, every time! This is just horrendous, performance-wise.
So 1. CACHE your objects
var $OnzeDiensten = $("#OnzeDiensten");
// and then RE-USE them at will
$OnzeDiensten.click(...)
$OnzeDiensten.animate(...)
$OnzeDiensten.css(...)
and 2. cancel previous click listeners before re-attaching them :
$OnzeDiensten
.off("click") // Remove any previous click listeners
.on("click", function(){ // attaches ONE click listener
// do stuff once
})

JavaScript / JQuery - How to temporarily disable function after use?

I have a simple JS that would smoothly autoscroll to another div whenever mousewheel is moved up or down.
Here's the script:
$(document).bind('mousewheel', function(evt) {
var delta = evt.originalEvent.wheelDelta
if(delta < 0){
$('html, body').animate({
scrollTop: $("#content-wrapper").offset().top
}, 3000);
}
else {
$('html, body').animate({
scrollTop: $("#bgheader").offset().top
}, 3000);
}
});
My problem is that if i play for a few seconds with the mousewheel it would start scrolling here and there forever, since every move recorded is queued as additional script launch.
Is there any way to put some sort of 'cooldown' to the script? So that after using once it would become avaiable to use again in, let's say' 3 seconds? Or once the animation is finished?
You can unbind the wheel event listener, and then use jQuery's .animate() callback function to re attach the event listener after it is done, like so:
function scrollHandler (event) {
$(document).off("mousewheel.custom");
var delta = event.originalEvent.wheelDelta
if(delta < 0){
$('html, body').animate({
scrollTop: $("#content-wrapper").offset().top
}, 3000, function () {
// animation callback function
$(document).on("mousewheel.custom", scrollHandler);
}));
}
else {
$('html, body').animate({
scrollTop: $("#bgheader").offset().top
}, 3000, function () {
// animation callback function
$(document).on("mousewheel.custom", scrollHandler);
});
}
}
// namespace the event so we can easily .off() it
$(document).on('mousewheel.custom', scrollHandler);
I've used timeouts.
var maxPoll = 3000,
eventActive = false;
$(document).bind('mousewheel', function(evt) {
if(eventActive) {
return
} else {
setTimeout(maxPoll, function() { eventActive = True })
}
var delta = evt.originalEvent.wheelDelta
if(delta < 0){
$('html, body').animate({
scrollTop: $("#content-wrapper").offset().top
}, maxPoll);
}
else {
$('html, body').animate({
scrollTop: $("#bgheader").offset().top
}, maxPoll);
}
});
It's rough and it uses globals, but it basically turns off your event while the animation is running.

Cancel scrolling after user interaction

My webpage animates scrolling when users click on links to the same page. I want to cancel this animation as soon as the user tries to scroll (otherwise the user and the browser are fighting for control) – no matter whether with the mouse wheel, the keyboard or the scrollbar (or any other way – are there other ways of scrolling?). I managed to cancel the animation after the mouse wheel or keyboard are used, how do I get this working with the scrollbar?
Here is how my code looks for the keyboard:
$(document.documentElement).keydown( function (event) {
if(event.keyCode == 38 || 40) stopScroll();
});
function stopScroll() {
$("html, body").stop(true, false);
}
I also tried a more elegant way of doing this by using scroll(), the problem is that scroll() catches everything including the animated and automated scrolling. I could not think of any way to let it catch all scrolling except the animated scrolling.
you need animation marker, something like this
$("html, body").stop(true, false).prop('animatedMark',0.0).animate({scrollTop : top, animatedMark: '+=1.0'})
Here is the code, the code was mix of GWT and javascript so moved it to js, not fully tested, please try it
var lastAnimatedMark=0.0;
function scrollToThis(top){
// Select/ stop any previous animation / reset the mark to 0
// and finally animate the scroll and the mark
$("html, body").stop(true, false).prop('animatedMark',0.0).
animate({scrollTop : top, animatedMark: '+=1.0'}
,10000,function(){
//We finished , nothing just clear the data
lastAnimatedMark=0.0;
$("html, body").prop('animatedMark',0.0);
});
}
//Gets the animatedMark value
function animatedMark() {
var x=$("html, body").prop('animatedMark');
if (x==undefined){
$("html, body").prop('animatedMark', 0.0);
}
x=$("html, body").prop('animatedMark');
return x;
};
//Kills the animation
function stopBodyAnimation() {
lastAnimatedMark=0;
$("html, body").stop(true, false);
}
//This should be hooked to window scroll event
function scrolled(){
//get current mark
var currentAnimatedMark=animatedMark();
//mark must be more than zero (jQuery animation is on) & but
//because last=current , this is user interaction.
if (currentAnimatedMark>0 && (lastAnimatedMark==currentAnimatedMark)) {
//During Animation but the marks are the same !
stopBodyAnimation();
return;
}
lastAnimatedMark=currentAnimatedMark;
}
Here is the blog about it
http://alaamurad.com/blog/#!canceling-jquery-animation-after-user-interaction
Enjoy!
Here's a jquery function that should do the trick:
function polite_scroll_to(val, duration, callback) {
/* scrolls body to a value, without fighting the user if they
try to scroll in the middle of the animation. */
var auto_scroll = false;
function stop_scroll() {
if (!auto_scroll) {
$("html, body").stop(true, false);
}
};
$(window).on('scroll', stop_scroll);
$("html, body").animate({
scrollTop: val
}, {
duration: duration,
step: function() {
auto_scroll = true;
$(window).one('scroll', function() {
auto_scroll = false;
});
},
complete: function() {
callback && callback();
},
always: function() {
$(window).off('scroll', stop_scroll);
}
});
};
It's not very elegant, but you could use a flag of some kind to detect what type of scrolling you're dealing with (animated or 'manual') and always kill it when it's animated. Here's an untested example:
var animatedScroll = false;
// you probably have a method looking something like this:
function animatedScrollTo(top) {
// set flag to true
animatedScroll = true;
$('html').animate({
scrollTop : top
}, 'slow', function() {
// reset flag after animation is completed
animatedScroll = false;
});
}
function stopScroll() {
if (animatedScroll) {
$("html, body").stop(true, false);
}
}

javascript - how to scroll page smothly until user relese mouse button

Shor question - page opened on pc with not-so-good touch-screen display. I created 2 big arrows and dont know how to program it using JS/jQuery.
First try: onClick->scroll - it works but user must tap many times to scroll article.
Second:
var scrolling = false;
$("#scUp").mouseup(function(){
$(this).css("opacity", 0.3);
scrolling = false;
}).mousedown(function(){
$(this).css("opacity", 1);
scrolling = true;
while(scrolling) {
$('html, body').stop().animate({ scrollTop: 50 }, 500);
}
event.preventDefault();
});
Doesnt work ;)
I`m trying to simulate real browser scroll arrows - until you keep preesed mouse button page scrolls down (or up).
I answered this question some time back... basically it sets a flag when the mouse is down and clears when the mouse is up. Then a setTimeout loops until the flag clears. Also, it has mousewheel and drag-and-drop functionality.
Check out the demo
Your code above doesn't work because JavaScript is not multi-threaded. That is, your while loop is eating CPU and probably preventing other code from running (i.e. the mouseup event).
I did something like this not too long back. Please feel free to check out my blog post.
Also, not sure if you're doing this or not, but make sure that you place all of your JavaScript code in jQuery's ready() function; otherwise, jQuery may not find the #scUp element.
Here's the relevant code from my old blog post:
var scrollTimer;
function scrollContent(amt)
{
$("#content").scrollTop($("#content").scrollTop()+amt);
scrollTimer = window.setTimeout("scrollContent(" + amt + ")", 25);
}
$(document).ready(function ()
{
$("#content").css("overflow", "hidden");
$("#scrollUp").mousedown(function() {
window.clearTimeout(scrollTimer); //Not necessary, but just to be sure...
$("#scrollUp").animate({"opacity": 100}, 'fast');
scrollContent(-10);
});
$("#scrollUp").mouseup(function() {
window.clearTimeout(scrollTimer);
$("#scrollUp").animate({"opacity": 0}, 'fast');
});
$("#scrollDown").mousedown(function() {
window.clearTimeout(scrollTimer); //Not necessary, but just to be sure...
$("#scrollDown").animate({"opacity": 100}, 'fast');
scrollContent(10);
});
$("#scrollDown").mouseup(function() {
window.clearTimeout(scrollTimer);
$("#scrollDown").animate({"opacity": 0}, 'fast');
});
//$("#scrollUp").css("opacity", 0); //Alternative
$("#scrollUp").animate({"opacity": 0}, 'slow');
$("#scrollDown").animate({"opacity": 0}, 'slow');
});
...and the link:
http://blake-miner.blogspot.com/2010/08/javascript-sticky-footer-and-scroll.html
Hope this helps!
In meantime I wrote this code:
var scrollId = 0;
$("#scUp").mouseup(function(){
$(this).css("opacity", 0.3);
clearInterval(scrollId);
}).mousedown(function(){
$(this).css("opacity", 1);
var scroll = function() { $("html, body").stop().animate({ scrollTop: "-=10px" }, 15); }
scroll();
scrollId = setInterval(scroll, 15);
});
$("#scDw").mouseup(function(){
$(this).css("opacity", 0.3);
clearInterval(scrollId);
}).mousedown(function(){
$(this).css("opacity", 1);
var scroll = function() { $("html, body").stop().animate({ scrollTop: "+=10px" }, 15); }
scroll();
scrollId = setInterval(scroll, 15);
});
It works BUT not on Opera ... funny thing - kiosk is based on Opera browser, so, any solution?
btw. Is there any materials about building kiosk (not outdated for 1.x version of FF) on Linux with FF (linux is no problem for me but I searching for security-plugin for FF).
<div style="position:fixed">
Up
Down
</div>
<script>
var scrollValue = 2;
function scrollAs(value) {
if(value) scrollValue = value;
document.body.scrollTop += (scrollValue - 2)*10;
if(scrollValue != 2) setTimeout(scrollAs, 100);
}
<script>

Categories

Resources