Height check on resize causing lag - javascript

I'm using the below jquery to check and reset the height of my div on resize. However, there is a terrible freeze/lag when using the below code. The structure is just three absolutely positioned divs. One at the top, one at the bottom, and one in the middle. Any idea why this might be happening?
$(window).resize(function () {
if ($("#master_bodywrapper_div").height() < 500) {
$("#master_bodywrapper_div").height(500);
}
else {
$("#master_bodywrapper_div").height("auto");
}
});

This is because, on some browsers, the resize event can fire dozens of times per second. You should have a resizing function that is called only after the window is done being resized, like so:
(function($) {
var resizeTimer = false;
function doResize() {
if ($("#master_bodywrapper_div").height() < 500) {
$("#master_bodywrapper_div").height(500);
}
else {
$("#master_bodywrapper_div").height("auto");
}
resizeTimer = false;
}
$(window).on("resize", function() {
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(doResize, 300);
});
})(jQuery);
Hope this helps!

Well, it is querying the DOM twice every time resize is triggered and this function called, which might be the source (DOM querying can be expensive). Note that resize is triggered a lot even if you simply grab the edge and move your mouse (with a moderate speed) 200px to one side. Try moving the $("#master_bodywrapper_div") query to above the resize callback, cached in a var, and then use that var reference in your callback function.
var div = $("#master_bodywrapper_div");
$(window).resize(function () {
if (div.height() < 500) {
div.height(500);
}
else {
div.height("auto");
}
});

Related

auto scroll stopped working when I added an an hover

I have a page that auto scrolls - the function scroll() below worked just fine.
I needed to add an on-hover function - which should pause the scrolling, giving the user control over the scroll.
I added some code to stop scrolling on-hover.
<script>
var theInterval;
function startScroll() {
theInterval = setInterval(scroll, 50);
}
function stopScroll() {
clearInterval(theInterval);
}
$(function () {
scroll();
$('#scrollDiv').hover(function () {
stopScroll();
}, function () {
startScroll();
})
});
function scroll() {
if (document.getElementById('scrollDiv').scrollTop < (document.getElementById('scrollDiv').scrollHeight - document.getElementById('scrollDiv').offsetHeight)) {
-1
document.getElementById('scrollDiv').scrollTop = document.getElementById('scrollDiv').scrollTop + 1
}
else { document.getElementById('scrollDiv').scrollTop = 0; }
}
setInterval(scroll, 50);
</script>
I expected that the extra functions would stop the scrolling when the user hovers over the content.
What happened was that the scrolling simply stopped
You are dropping the interval pointer from your initial call to scroll. setInterval returns an ID to the timer that is running the function at the specified cadence.
Your code is kicking off the scrolling on the last line, but not capturing this timer ID to clear -- so on 1st hover you clear a null pointer in theInterval, then on blur you're starting another timer calling scroll.
You probably notice that it gets faster because 2 logic paths are now adding 1px every 50 ms.
On the last line, you need to also set theInterval to keep track of that call, like:
theInterval = setInterval(scroll, 50)
That should fix it.

jQuery "Snap To" Effect

I have a specific effect I want for a website I'm building. As you can see in this website, I want the screen to "snap to" the next section after the user scrolls, but only after (not the instant) the scroll event has fired. The reason I don't want to use a plugin like panelSnap is because I
1: Want smaller code and
2. Want the website, when viewed on mobile, to have more of the "instant snap" effect (try reducing the browser size in the website mentioned above). I know I theoretically could try combining two plugins, like panelsnap and scrollify, and activate them appropriately when the browser is a certain width, but I don't know if I want to do that... :(
So all of that said, here's the code:
var scrollTimeout = null;
var currentElem = 0;
var options = {
scrollSpeed: 1100,
selector: 'div.panels',
scrollDelay: 500,
};
$(document).ready(function() {
var $snapElems = $(options.selector);
console.log($($snapElems[currentElem]).offset().top);
function snap() {
if ($('html, body').scrollTop() >= $($snapElems[currentElem]).offset().top) {
if (currentElem < $snapElems.length-1) {
currentElem++;
}
}else{
if (currentElem > 0) {
currentElem = currentElem - 1;
}
}
$('html, body').animate({
scrollTop: $($snapElems[currentElem]).offset().top
}, options.scrollSpeed);
}
$(window).scroll(function() {
if ($(window).innerWidth() > 766) {
if (scrollTimeout) {clearTimeout(scrollTimeout);}
scrollTimeout = setTimeout(function(){snap()}, options.scrollDelay);
}else{
//I'll deal with this later
}
});
});
My problem is that every time the snap function is called, it triggers the scroll event, which throws it into a loop where the window won't stop scrolling between the first and second elements. Here's the poor, dysfunctional site: https://tcfchurch.herokuapp.com/index.html Thank for the help.
You can use a boolean to record when the scroll animation in snap is in progress and prevent your $(window).scroll() event handler from taking any action.
Here's a working example:
var scrollTimeout = null;
var currentElem = 0;
var options = {
scrollSpeed: 1100,
selector: 'div.panels',
scrollDelay: 500,
};
$(document).ready(function() {
var scrollInProgress = false;
var $snapElems = $(options.selector);
console.log($($snapElems[currentElem]).offset().top);
function snap() {
if ($('html, body').scrollTop() >= $($snapElems[currentElem]).offset().top) {
if (currentElem < $snapElems.length-1) {
currentElem++;
}
}else{
if (currentElem > 0) {
currentElem = currentElem - 1;
}
}
scrollInProgress = true;
$('html, body').animate({
scrollTop: $($snapElems[currentElem]).offset().top
}, options.scrollSpeed, 'swing', function() {
// this function is invoked when the scroll animate is complete
scrollInProgress = false;
});
}
$(window).scroll(function() {
if (scrollInProgress == false) {
if ($(window).innerWidth() > 766) {
if (scrollTimeout) {clearTimeout(scrollTimeout);}
scrollTimeout = setTimeout(function(){snap()}, options.scrollDelay);
}else{
//I'll deal with this later
}
}
});
});
The variable scrollInProgress is set to false by default. It is then set to true when the scroll animate starts. When the animate finishes, scrollInProgress is set back to false. A simple if statement at the top of your $(window).scroll() event handler prevents the handler from taking any action while the animate scroll is in progress.
Have you considered using the well known fullPage.js library for that? Check out this normal scroll example. The snap timeout is configurable through the option fitToSectionDelay.
And nothing to worry about the size... it is 7Kb Gzipped!
I know I theoretically could try combining two plugins, like panelsnap and scrollify, and activate them appropriately when the browser is a certain width, but I don't know if I want to do that
fullPage.js also provides responsiveWidth and responsiveHeight options to turn it off under certain dimensions.

How to launch functions depending on screen size and stop others after resize?

I'm trying to launch different functions depending on screen size after load, resize and scroll. To prevent effect of calculations in other functions I need to stop them.
Here if example with dummy functions from Jsfiddle
Here is example with real functions from Jsfiddle (it doesn't show html or css, just functions for your understanding)
If you look at console you will see that after first rezise first function runs, but when you get another window size breakpoint another function will run together with first one. the same with third function if you get third breakpoint. I want to stop function after window changed size to another breakpoint
here is my jquery:
function sticker1220() {
$(window).on("load resize scroll",function(){
console.log('sticker1220');
});
};
function sticker950() {
$(window).on("load resize scroll",function(){
console.log('sticker950');
});
};
function sticker320() {
$(window).on("load resize scroll",function(){
console.log('sticker320');
});
};
function checksize() {
if ( $(window).width() > 1220 ) {
sticker1220();
} else if ( $(window).width() > 640 & $(window).width() < 1219 ) {
sticker950();
} else if ( $(window).width() < 639 ) {
sticker320();
}
};
checksize();
$(window).resize(function() {
checksize();
$('p').text($(window).width());
});
You could do something like this.
I have abstracted the media queries into an object that can be iterated to find the applicable callback if one is available.
There is also now only on resize callback which is easier to manage as you don't need to run separate resize events which could lock up your ui thread. And the events will work properly if you change the screen resolution, whereas previously were binding a new resize event each time the screen resized.
If you need to make it faster you could change the resize event to a recursive timer using setTimeout.
function checksize(mediaQueries) {
return function(e) {
const width = window.innerWidth
$('p').text(width)
const query = mediaQueries.find(x => {
switch (true) {
case !!x.min && !!x.max:
return width >= x.min && width < x.max
case !!x.min:
return width >= x.min
case !!x.max:
return width <= x.max
default:
return false
}
})
if (typeof query.cb === 'function') {
return query.cb(e)
}
}
}
var atMedia = [
{
max: 639,
cb: function(e) {
console.log('sticker320')
}
},
{
min: 640,
max: 1219,
cb: function(e) {
console.log('sticker950')
}
},
{
min: 1220,
cb: function(e) {
console.log('sticker1220')
}
}
]
$(window).resize(checksize(atMedia)).trigger('resize')
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p></p>

Slide div on and off the page on scroll without interrupting the animation when the user continues to scroll

I am trying to smoothly slide a div on and off the page (left to right) using jQuery only. I have accomplished the task, however if you continue to scroll up or down while the animation is still going, it will interrupt it in the middle of the action causing it to hesitate. I've run into this issue before and could never figure it out without using a plugin of some sort.
I know how to accomplish this with CSS transitions, jQuery UI, greensock, etc., but I am curious if there is a way to prevent that interruption with jQuery only. I am open to a pure JavaScript solution (no jQuery) as well if there is one.
My code:
var amountScrolled = 50;
$(window).scroll(function() {
if ($(window).scrollTop() > amountScrolled) {
$('#slide').stop().animate({marginLeft:"0px"}, 500);
} else {
$('#slide').stop().animate({marginLeft: "-400px"}, 500);
}
});
Example: https://jsfiddle.net/Hysteresis/hg9cvxop/6/
This works: JSFIDDLE link
It's all about the Callback Functions!
var amountScrolled = 50;
var loopRunning = 0;
$(window).scroll(function() {
if ($(window).scrollTop() > amountScrolled){
if(loopRunning === 0){
animateSlide("0px",500);
}
} else {
if(loopRunning === 0){
animateSlide("-400px",500);
}
}
});
function animateSlide(px, time){
loopRunning = 1;
$('#slide').stop().animate({marginLeft:px}, time, function(){
loopRunning = 0;
});
}
Well, to answer your question rather than provide advice on better ways to do it, I usually handle tasks like this by assigning a temporary class to denote that something is in the process of being animated. As somebody else said, the reason for the stuttering is because the scroll function is getting called multiple times, so you keep stopping and restarting the animation.
So you can try something like this (Fiddle):
var amountScrolled = 50;
$(window).scroll(function() {
if ($('#slide').hasClass('sliding')) {
return;
}
if ($(window).scrollTop() > amountScrolled) {
$('#slide').stop().addClass('sliding').animate({marginLeft:"0px"}, 500, function() {
$(this).removeClass('sliding');
});
} else {
$('#slide').stop().addClass('sliding').animate({marginLeft: "-400px"}, 500, function() {
$(this).removeClass('sliding');
});
}
});

query two events for on

I have a page with links on top. When a link is clicked it scrolls down to a particular section. For styling purposes, I had to write a small jQuery to have to land 100px above the actual section that it scrolls to. Now I need the pixel number to change depending on the media query. Is there something wrong about how this is written? The responsive part isn't working..
function offsetAnchor() {
if(jQuery(location.hash).length !== 0) {
if (jQuery(window).width() <= 350) {
window.scrollTo(window.scrollX, window.scrollY - 180);
}
else {
window.scrollTo(window.scrollX, window.scrollY - 100);
}
}
}
// This will capture hash changes while you are on the same page
jQuery(window).on("hashchange", function () {
offsetAnchor();
});
window.setTimeout(function() {
offsetAnchor();
}, 1);
the syntax should be :
jQuery(window).on("hashchange resize", function () {}
you can read more about .on() function at jQuery API

Categories

Resources