Trying to turn off requestAnimation function when resizing browser - javascript

I have the following code and I am trying to turn off the function when window resize is run, currently it just keeps running on window.resize.
function headerParallax(x) {
if (x ==="true"){
$(window).scroll(function() {
// Store scrollTop in variable
var scrollPos = $(window).scrollTop();
// var viewportHeight = $(window).height();
console.log(scrollPos + 'bgbottle1');
var bouncePos = ((-1 * (scrollPos - 75) * 1.5) + scrollPos).toFixed(2);
var bouncePos1 = ((-1 * (scrollPos - 150) * 1.25) + scrollPos).toFixed(2);
$(".bottle1").css({ 'background-position': "right " + bouncePos + 'px'});
if (scrollPos > 150){
$(".bottle2").css({ 'background-position': "left " + bouncePos1 + 'px'});
}
});
}else if(x === "false"){
alert("no");
}
}
$(window).resize(function(){
if ($(window).width() < 1200){
window.requestAnimationFrame(headerParallax("false"));
}
});
if ($(window).width() > 1200){
window.requestAnimationFrame(headerParallax("true"));
}

You can try something like this:
var _preflag = -1;
var _unbindScroll = function(){};
// it will be fired only once (when flag is changed)
function headerParallax(flag){
if (flag === _preflag){
return;
}
_preflag = flag;
if (flag){
// TODO adjust the UI for true
window.requestAnimationFrame(theCalculatedValue);
_unbindScroll(); // It's duplicate work to unbind scroll here, but there's no harm calling it :)
$(window).on('scroll', _onscroll);
// update the ubind scroll so that anyone can ubind it safely
_unbindScroll = function(){
$(window).off('scroll', _onscroll);
_unbindScroll = function(){};
};
} else {
// TODO adjust the UI for false
window.requestAnimationFrame(theCalculatedValue);
_unbindScroll(); // unbind scrolling, this is what you want, right?
}
function _onscroll(){
// TODO
}
}
function resize(){
// this will be fired multipe times, need to check it in sub functions to take it once
headerParallax($(window).width() < 1200);
}
$(window).resize(resize);
resize();

Related

Function not starting when scroll point is over top of the div

I use a scrollTop function to start animations, delays, etc when the div is scrolled to. It works for other things on my page, but for some reason, this function is not working and it loads on page load.
Does anyone see anything wrong in my code? This can be seen live here:
<div class="blue-box-container">
</div>
$(function() {
var oTop = $('.blue-box-container').offset().top - window.innerHeight;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
console.log(pTop + ' - ' + oTop);
if (pTop > oTop) {
blueBoxDelays();
}
});
});
$('.fadeBlock').css('display', 'none');
blueBoxDelays();
function blueBoxDelays() {
var delay = 0;
$('.fadeBlock').each(function(i) {
$(this).delay(400 + delay).fadeIn(1000);
delay = 200 * (i + 1);
});
};
I extracted your code to a fiddle and it works correctly https://jsfiddle.net/26jw7Low/3/, you just need to remove the call to blueBoxDelays() which is outside of the initial function as seen below.
$(function() {
var oTop = $('.blue-box-container').offset().top - window.innerHeight;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
console.log(pTop + ' - ' + oTop);
if (pTop > oTop) {
blueBoxDelays();
}
});
});
$('.fadeBlock').css('display', 'none');
// REMOVE THIS blueBoxDelays();
function blueBoxDelays() {
var delay = 0;
$('.fadeBlock').each(function(i) {
$(this).delay(400 + delay).fadeIn(1000);
delay = 200 * (i + 1);
});
};
Function $('.fadeBlock').css('display', 'none'); maybe not yet execute
You can put it to $(function(){}) end try again:
$(function() {
$('.fadeBlock').css('display', 'none');
var oTop = $('.blue-box-container').offset().top - window.innerHeight;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
console.log(pTop + ' - ' + oTop);
if (pTop > oTop) {
blueBoxDelays();
}
});
});

Only execute JS if the screen size is more than 1024px?

I have a sidebar that becomes position:fixed when the bottom of the div is visible (followed this tutorial). My problem is I only need the JS to work if the screen size is more than or equal to 1025px.
I know I need something along the lines of if($(window).width() > 1025), but I can't figure out where that needs to be. I'm not great with JS so any help would be appreciated.
Demo
JS
$(function () {
if ($('.leftsidebar').offset()!=null) {
var top = $('.leftsidebar').offset().top - parseFloat($('.leftsidebar').css('margin-top').replace(/auto/, 0));
var height = $('.leftsidebar').height();
var winHeight = $(window).height();
var footerTop = $('#footer').offset().top - parseFloat($('#footer').css('margin-top').replace(/auto/, 0));
var gap = 100;
$(window).scroll(function (event) {
// what the y position of the scroll is
var y = $(this).scrollTop();
// whether that's below the form
if (y+winHeight >= top+ height+gap && y+winHeight<=footerTop) {
// if so, ad the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top',winHeight-height-gap +'px');
}
else if (y+winHeight>footerTop) {
// if so, add the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top',footerTop-height-y-gap+'px');
}
else
{
// otherwise remove it
$('.leftsidebar').removeClass('leftsidebarfixed').css('top','315px');
}
});
}
}
This should work:
var flag = false;
// This will keep on checking for window size while you are scrolling.
$(window).on("scroll", function() {
if (flag){
// Do whatever you want here
alert("hey");
}
});
$(window).on("resize", function() {
if ($(window).width() >= 1025){
flag = true;
} else {
flag = false;
}
})
From my comment: Just put that if($(window).width() > 1025) inside the function provided to the scroll event.
e.g.
$(window).scroll(function (event) {
if ($(window).width() > 1024) {
// what the y position of the scroll is
var y = $(this).scrollTop();
// whether that's below the form
if (y + winHeight >= top + height + gap && y + winHeight <= footerTop) {
// if so, ad the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top', winHeight - height - gap + 'px');
} else if (y + winHeight > footerTop) {
// if so, ad the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top', footerTop - height - y - gap + 'px');
JSFiddle: http://jsfiddle.net/TrueBlueAussie/3w5dt/31/
Notes:
not that 1 PX matters, but you did say > 1024px, hence changing 1025 to 1024 :)
First of all you should have a look at the jQuery documentation. The $.browser function was removed in jQuery 1.9. This can end up in serious problems in your code.
Just add something like the follwing code in the first if condition:
if (!msie6 && $('.leftsidebar').offset()!=null && $(window).width() > 1025 ) {
...
}
That should be all. If you want, that javascript should react on window resize just add something like the following
$(window).on('resize', function( event ) { /* code here */ }).trigger('resize');
if(screen.width >= 1024)
{
$(window).scroll(function (event) {
//Write your function code here
});
}
I hope it will help you.

Javascript animate on scroll position

I am trying to get a scrolling animation like here (notice the circle figure fading in when you scroll down):
http://demo.atticthemes.com/skoty/
This is what I have sofar, but it keeps hanging somehow:
http://jsfiddle.net/v4zjgwL6/
var timer;
var triggerHeight = $("#bar").offset().top;
var headerAvatar = $(".header-avatar-wrapper");
$(window).scroll(function() {
if(timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function() {
var y = $(window).scrollTop();
if(y > triggerHeight - 220) {
headerAvatar.css("visibility", "visible");
headerAvatar.animate({opacity: 1}, 200);
} else {
headerAvatar.animate({opacity: 0}, 200);
headerAvatar.css("visibility", "hidden");
}
}, 10);
});
You don't need to use a timer, the way you have implemented it causes performance drops.
I would suggest to use css classes instead:
var triggerHeight = $("#bar").offset().top;
var headerAvatar = $(".header-avatar-wrapper");
$(window).scroll(function() {
var y = $(window).scrollTop();
if (y > triggerHeight - 220 && !headerAvatar.hasClass("visible")) {
headerAvatar.addClass("visible");
} else if(y <= triggerHeight - 220 && headerAvatar.hasClass("visible")) {
headerAvatar.removeClass("visible");
}
});
I have also added this class in CSS:
.header-avatar-wrapper.visible{
opacity: 1;
visibility: visible;
}
JSFiddle demo
Or alternatively, use jQuery's .fadeIn() and fadeOut() functions:
var triggerHeight = $("#bar").offset().top;
var headerAvatar = $(".header-avatar-wrapper");
$(window).scroll(function() {
var y = $(window).scrollTop();
if (y > triggerHeight - 220 && headerAvatar.css("display") == "none") {
headerAvatar.fadeIn();
} else if(y <= triggerHeight - 220 && headerAvatar.css("display") == "block") {
headerAvatar.fadeOut();
}
});
In CSS I removed the opacity and visibility properties from .header-avatar-wrapper and added display: none; instead.
JSFiddle demo
Looks like you're only handling the cases where you need to change state (shown or hide the element) and not the cases where nothing should change. This causes you to continuously re-show (re-animate) the thing, which makes it flicker.
It's early and I have not yet had coffee, but something like this should fix you up. :)
var timer;
var triggerHeight = $("#bar").offset().top;
var headerAvatar = $(".header-avatar-wrapper");
var shown; // NEW
$(window).scroll(function() {
if(timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function() {
var y = $(window).scrollTop();
var shouldShow = y > triggerHeight - 220; // CHANGED
if(!shown && shouldShow) { // CHANGED
shown = true; // NEW
headerAvatar.css("visibility", "visible");
headerAvatar.animate({opacity: 1}, 200);
} else if (shown && !shouldShow) { // CHANGED
shown = false; // NEW
headerAvatar.animate({opacity: 0}, 200);
headerAvatar.css("visibility", "hidden");
}
}, 10); });
Proof: http://jsfiddle.net/bvaughn/oL85oj41/

How do I call a function only once during a specific scroll height?

I have a map on the bottom of my webpage and when a user scrolls down to the map, I want the google marker to drop and that specific time. I have this working already. The problem is that it keeps calling the function, how do I call it only once?
This is my JS code right now and I have tried to figure the bug out:
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 300 &&
$(window).scrollTop() <= $(document).height() - $(window).height() - 200
) {
var dropOnlyOnce = (function(){
dropped = false;
if (dropped == false) {
dropMarker(); // this is the function I'm calling
}
dropped = true;
})();
}
});
How can I get this to work or how can I just call the dropMarker function once?
You could remove the listener once the function has been called:
$(window).on('scroll', function(e) {
if( ...window at scrollTop ) {
$(window).off('scroll')
.... Drop your pin
}
})
Esteban Felix's Comment brings up a good point. This will remove all scroll handlers. If that's not something that works for you, you can move the function outside the handler, and only remove that:
var dropPinOnce = function() {
if( ... window at correct scrollTop ) {
... Drop pin here ...
$(window).off('scroll', dropPinOnce)
}
$(window).on('scroll', dropPinOnce)
Try
var callbacks = $.Callbacks("once")
, dropMarker = function() {
// do stuff
};
callbacks.add(dropMarker);
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 300 &&
$(window).scrollTop() <= $(document).height() - $(window).height() - 200
) {
var dropOnlyOnce = (function(){
dropped = false;
if (dropped == false) {
callbacks.fire() // call `dropMarker` "once"
}
dropped = true;
})();
}
});
See jQuery.Callbacks at "Possible Flags" -> "once"
var callbacks = $.Callbacks("once")
, dropMarker = function() {
console.log(123)
};
callbacks.add(dropMarker);
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 300 &&
$(window).scrollTop() <= $(document).height() - $(window).height() - 200
) {
var dropOnlyOnce = (function(){
dropped = false;
if (dropped == false) {
// dropMarker(); // this is the function I'm calling
callbacks.fire()
}
dropped = true;
})();
}
});
div {
height : 500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>abc</div>
If you just unbind after your condition is met then your function will effectively only be called once.
$(window).scroll(function callOnceOnScroll() {
var $window = $(window),
$document = $(document);
if ($window.scrollTop() >= $document.height() - $window.height() - 300 &&
$window.scrollTop() <= $document.height() - $window.height() - 200) {
$window.off('scroll', callOnceOnScroll);
dropMarker(); // this is the function I'm calling
}
});

Scroll if element is not visible

how to determine, using jquery, if the element is visible on the current page view. I'd like to add a comment functionality, which works like in facebook, where you only scroll to element if it's not currently visible. By visible, I mean that it is not in the current page view, but you can scroll to the element.
Live Demo
Basically you just check the position of the element to see if its within the windows viewport.
function checkIfInView(element){
var offset = element.offset().top - $(window).scrollTop();
if(offset > window.innerHeight){
// Not in view so scroll to it
$('html,body').animate({scrollTop: offset}, 1000);
return false;
}
return true;
}
Improving Loktar's answer, fixing the following:
Scroll up
Scroll to a display:none element (like hidden div's etc)
function scrollToView(element){
var offset = element.offset().top;
if(!element.is(":visible")) {
element.css({"visibility":"hidden"}).show();
var offset = element.offset().top;
element.css({"visibility":"", "display":""});
}
var visible_area_start = $(window).scrollTop();
var visible_area_end = visible_area_start + window.innerHeight;
if(offset < visible_area_start || offset > visible_area_end){
// Not in view so scroll to it
$('html,body').animate({scrollTop: offset - window.innerHeight/3}, 1000);
return false;
}
return true;
}
After trying all these solutions and many more besides, none of them satisfied my requirement for running old web portal software (10 years old) inside IE11 (in some compatibility mode). They all failed to correctly determine if the element was visible. However I found this solution. I hope it helps.
function scrollIntoViewIfOutOfView(el) {
var topOfPage = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
var heightOfPage = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
var elY = 0;
var elH = 0;
if (document.layers) { // NS4
elY = el.y;
elH = el.height;
}
else {
for(var p=el; p&&p.tagName!='BODY'; p=p.offsetParent){
elY += p.offsetTop;
}
elH = el.offsetHeight;
}
if ((topOfPage + heightOfPage) < (elY + elH)) {
el.scrollIntoView(false);
}
else if (elY < topOfPage) {
el.scrollIntoView(true);
}
}
I made a slightly more generic version of digitalPBK's answer that minimally scrolls an element contained within a div or some other container (including the body). You can pass DOM elements or selectors to the function, as long as the element is somehow contained within the parent.
function scrollToView(element, parent) {
element = $(element);
parent = $(parent);
var offset = element.offset().top + parent.scrollTop();
var height = element.innerHeight();
var offset_end = offset + height;
if (!element.is(":visible")) {
element.css({"visibility":"hidden"}).show();
var offset = element.offset().top;
element.css({"visibility":"", "display":""});
}
var visible_area_start = parent.scrollTop();
var visible_area_end = visible_area_start + parent.innerHeight();
if (offset-height < visible_area_start) {
parent.animate({scrollTop: offset-height}, 600);
return false;
} else if (offset_end > visible_area_end) {
parent.animate({scrollTop: parent.scrollTop()+ offset_end - visible_area_end }, 600);
return false;
}
return true;
}
You can take a look at his awesome link from the jQuery Cookbook:
Determining Whether an Element Is Within the Viewport
Test if Element is contained in the Viewport
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
if (
(elementOffset.top > minTop && elementOffset.top + elementHeight < maxTop) &&
(elementOffset.left > minLeft && elementOffset.left + elementWidth < maxLeft)
) {
alert('entire element is visible');
} else {
alert('entire element is not visible');
}
});
Test how much of the element is visible
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
verticalVisible, horizontalVisible,
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
function scrollToPosition(position) {
jQuery('html,body').animate({
scrollTop : position.top,
scrollLeft : position.left
}, 300);
}
if (
((elementOffset.top > minTop && elementOffset.top < maxTop) ||
(elementOffset.top + elementHeight > minTop && elementOffset.top +
elementHeight < maxTop))
&& ((elementOffset.left > minLeft && elementOffset.left < maxLeft) ||
(elementOffset.left + elementWidth > minLeft && elementOffset.left +
elementWidth < maxLeft)))
{
alert('some portion of the element is visible');
if (elementOffset.top >= minTop && elementOffset.top + elementHeight
<= maxTop) {
verticalVisible = elementHeight;
} else if (elementOffset.top < minTop) {
verticalVisible = elementHeight - (minTop - elementOffset.top);
} else {
verticalVisible = maxTop - elementOffset.top;
}
if (elementOffset.left >= minLeft && elementOffset.left + elementWidth
<= maxLeft) {
horizontalVisible = elementWidth;
} else if (elementOffset.left < minLeft) {
horizontalVisible = elementWidth - (minLeft - elementOffset.left);
} else {
horizontalVisible = maxLeft - elementOffset.left;
}
var percentVerticalVisible = (verticalVisible / elementHeight) * 100;
var percentHorizontalVisible = (horizontalVisible / elementWidth) * 100;
if (percentVerticalVisible < 50 || percentHorizontalVisible < 50) {
alert('less than 50% of element visible; scrolling');
scrollToPosition(elementOffset);
} else {
alert('enough of the element is visible that there is no need to scroll');
}
} else {
// element is not visible; scroll to it
alert('element is not visible; scrolling');
scrollToPosition(elementOffset);
}
The following code helped me achieve the result
function scroll_to_element_if_not_inside_view(element){
if($(window).scrollTop() > element.offset().top){
$('html, body').animate( { scrollTop: element.offset().top }, {duration: 400 } );
}
}
Here is the solution I came up with, working both up and down and using only Vanilla Javascript, no jQuery.
function scrollToIfNotVisible(element) {
const rect = element.getBoundingClientRect();
// Eventually an offset corresponding to the height of a fixed navbar for example.
const offset = 70;
let scroll = false;
if (rect.top < offset) {
scroll = true;
}
if (rect.top > window.innerHeight) {
scroll = true;
}
if (scroll) {
window.scrollTo({
top: (window.scrollY + rect.top) - offset,
behavior: 'smooth'
})
}
}
There is a jQuery plugin which allows us to quickly check if a whole element (or also only part of it) is within the browsers visual viewport regardless of the window scroll position. You need to download it from its GitHub repository:
Suppose to have the following HTML and you want to alert when footer is visible:
<section id="container">
<aside id="sidebar">
<p>
Scroll up and down to alert the footer visibility by color:
</p>
<ul>
<li><span class="blue">Blue</span> = footer <u>not visible</u>;</li>
<li><span class="yellow">Yellow</span> = footer <u>visible</u>;</li>
</ul>
<span id="alert"></span>
</aside>
<section id="main_content"></section>
</section>
<footer id="page_footer"></footer>
So, add the plugin before the close of body tag:
<script type="text/javascript" src="js/jquery-1.12.0.min.js"></script>
<script type="text/javascript" src="js/jquery_visible/examples/js/jq.visible.js"></script>
After that you can use it in a simple way like this:
<script type="text/javascript">
jQuery( document ).ready(function ( $ ) {
if ($("footer#page_footer").visible(true, false, "both")) {
$("#main_content").css({"background-color":"#ffeb3b"});
$("span#alert").html("Footer visible");
} else {
$("#main_content").css({"background-color":"#4aafba"});
$("span#alert").html("Footer not visible");
}
$(window).scroll(function() {
if ($("footer#page_footer").visible(true, false, "both")) {
$("#main_content").css({"background-color":"#ffeb3b"});
$("span#alert").html("Footer visible");
} else {
$("#main_content").css({"background-color":"#4aafba"});
$("span#alert").html("Footer not visible");
}
});
});
</script>
Here a demo
No-JQuery version.
The particular case here is where the scroll container is the body (TBODY, table.body) of a TABLE (scrolling independently of THEAD). But it could be adapted to any situation, some simpler.
const row = table.body.children[ ... ];
...
const bottomOfRow = row.offsetHeight + row.offsetTop ;
// if the bottom of the row is in the viewport...
if( bottomOfRow - table.body.scrollTop < table.body.clientHeight ){
// ... if the top of the row is in the viewport
if( row.offsetTop - table.body.scrollTop > 0 ){
console.log( 'row is entirely visible' );
}
else if( row.offsetTop - table.body.scrollTop + row.offsetHeight > 0 ){
console.log( 'row is partly visible at top')
row.scrollIntoView();
}
else {
console.log( 'top of row out of view above viewport')
row.scrollIntoView();
}
}
else if( row.offsetTop - table.body.scrollTop < table.body.clientHeight ){
console.log( 'row is partly visible at bottom')
row.scrollIntoView();
}
else {
console.log( 'row is out of view beneath viewport')
row.scrollIntoView();
}
I think this is the complete answer. An elevator must be able to go both up and down ;)
function ensureVisible(elementId, top = 0 /* set to "top-nav" Height (if you have)*/) {
let elem = $('#elementId');
if (elem) {
let offset = elem.offset().top - $(window).scrollTop();
if (offset > window.innerHeight) { // Not in view
$('html,body').animate({ scrollTop: offset + top }, 1000);
} else if (offset < top) { // Should go to top
$('html,body').animate({ scrollTop: $(window).scrollTop() - (top - offset) }, 1000);
}
}
}

Categories

Resources