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
})
Related
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.
Here's my code :
if ($('document').scrollTop() < 0) {
//Automatic Scroll
setTimeout(function () {
$('html, body').animate({
scrollTop: $('.main-header').offset().top - 0
}, 1800, 'easeInOutQuad');
},8000);
}
If a user does not scroll, the page scrolls automatically to a certain div.
But I don't know how to trigger when a user do not scroll.
Thanks for your help !
To detect if a user hasn't scrolled, what I would do is set up a hasScrolled variable.
var hasScrolled = false;
Then change that variable to 'true' if the user scrolls:
document.addEventListener("scroll", function(){ hasScrolled = true; });
Then do your setTimeout to see if, in 8 seconds, the user has scrolled, and if not, do your thing:
setTimeout(triggerScroll,8000);
And in your triggerScroll function, the first line could be if (hasScrolled) return so that it doesn't run if they've scrolled
https://jsfiddle.net/eergdw3v/
try this
document.body.scrollTop === 0
You need to create a timer at the scroll event using setTimeout
function setUnscrollEvent( scrollTimeout, callback )
{
$( window).scroll(function() {
if ( window.scrollTimer )
{
clearTimeout( window.scrollTimer ); //if the scroll has already started then clear the timeout
}
window.scrollTimer = setTimeout( function(){
callback(); //invoke the callback in case scroll has been idle for srollTimeout ms
}, scrollTimeout );
});
}
You need to invoke it this way
setUnscrollEvent( 100, function(){
console.log( "no scrolling for 100ms" );
});
DEMO
function setUnscrollEvent( scrollTimeout, callback )
{
$( window).scroll(function() {
if ( window.scrollTimer )
{
clearTimeout( window.scrollTimer ); //if the scroll has already started then clear the timeout
}
window.scrollTimer = setTimeout( function(){
callback(); //invoke the callback in case scroll has been idle for srollTimeout ms
}, scrollTimeout );
});
}
setUnscrollEvent( 100, function(){
console.log( "no scrolling for 100ms" );
});
.container
{
width: 1000px;
height: 1000px;
background-color: #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
</div>
let scrollHandler = function(e) {
//do your stuff
}
$(window).on("scroll",scrollHandler);
That will detect scrolling for you, to answer the question in your title. I don't follow what you're trying to say under your code though
Export your function, so that you can call it when you want :
if ($('document').scrollTop() < 0) {
//Automatic Scroll
setTimeout(triggerScroll,8000);
}
function triggerScroll() {
$('html, body').animate({
scrollTop: $('.main-header').offset().top - 0
}, 1800, 'easeInOutQuad');
}
// Manual trigger :
triggerScroll();
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.
Click on the second div and see how it stutters.
Demo: http://jsfiddle.net/mirohristov/76xtt3hm/
$("body").on('click', '.mysection', function(){
var el = $(this);
if($(this).hasClass('active')){
url = $('.active .nectar-button').attr('href');
window.open(url, '_self')
}else{
$("html, body").animate({ scrollTop: el.offset().top+'px' }, 500,function(){
el.addClass('active');
var scroller = setInterval(function(){
$("html, body").scrollTop(el.offset().top);
}, 50); //if i change this to 14 or 1 it works here but in my real case there is more content and images in the divs and it's like 150 here - it's sluggish or flickers
$('.mysection').not(el).removeClass('active');
setTimeout(function(){window.clearInterval(scroller)}, 1000);
});
}
});
In the real project, I'm using divs as pages to display content. The selected div should aligned with top of page while the div above is being 'closed'.
I used a loop to re-set the scrollTop to that of the element position but in my real example it, even though the setTitmeout delay is 14 or 1, it acts like in the demo (at 50 delay).
I belive it's because there's more content and full-width, HD background images that go fullscreen in my actual project. It's as if the setTimeout is updated slower than the CSS animation.
How can I make it smooth? Is it even possible?
Try this (demo)
$('body').on('click', '.mysection', function () {
var scroller,
el = $(this),
html = $('html')[0],
body = $('body')[0];
if ($(this).hasClass('active')) {
url = $('.active .nectar-button').attr('href');
window.open(url, '_self')
} else {
el.one('transitionend', function (e) {
clearInterval(scroller);
});
$('html, body').animate({
scrollTop: el.offset().top + 'px'
}, 500, function () {
el.addClass('active');
scroller = setInterval(function () {
var top = el.offset().top;
html.scrollTop = top;
body.scrollTop = top;
}, 10);
$('.mysection').not(el).removeClass('active');
});
}
});
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...