Bi-Directional Infinite Scroll Loop Javascript - javascript

I'm working on a website with 5 slides (background pics + text). I want them to be looped when scrolling down and also when scrolling up. I made it work down, but not up. Please help!
document.addEventListener( "DOMContentLoaded", function() {
var div = document.getElementById( "container" );
div.addEventListener( "scroll", function() {
var max_scroll = this.scrollHeight - this.clientHeight;
var current_scroll = this.scrollTop;
var bottom = 100;
if ( current_scroll + bottom >= max_scroll ) {
var content = document.getElementsByTagName( "content" )[ 0 ];
var current = parseInt( content.dataset.current, 10 );
var section = document.getElementsByTagName( "section" )[ current ];
var new_section = section.cloneNode( true );
content.appendChild( new_section );
content.dataset.current = current + 1;
} } );
} );

Related

Detect if element is visible when scrolling up

I am using JavaScript to detect when an element is visible on scroll like this..
function isOnScreen(elem) {
// if the element doesn't exist, abort
if( elem.length == 0 ) {
return;
}
var $window = jQuery(window)
var viewport_top = $window.scrollTop()
var viewport_height = $window.height()
var viewport_bottom = viewport_top + viewport_height
var $elem = jQuery(elem)
var top = $elem.offset().top
var height = $elem.height()
var bottom = top + height
return (top >= viewport_top && top < viewport_bottom) ||
(bottom > viewport_top && bottom <= viewport_bottom) ||
(height > viewport_height && top <= viewport_top && bottom >= viewport_bottom)
}
jQuery( document ).ready( function() {
window.addEventListener('scroll', function(e) {
if( isOnScreen( jQuery( '.shipping-logos' ) ) ) { /* Pass element id/class you want to check */
alert( 'The specified container is in view.' );
}
});
});
This is working well, but I am trying to change things so that the detection only happens if the screen is scrolling up? When a user is scrolling down I want the function to ignore the element.
Anyone have an example of how to achieve this?

Detect change in scroll direction with jQuery

I am using a basic jQuery function to toggle some classes to a div when scrolling up or down.
Basically it works this way:
When the user scrolls down, add the class "is-header-hidden", remove the class "is-header-visible"
When the user scrolls up, add the class "is-header-visible", remove the class "is-header-hidden"
Here's my code:
function hidingHeader() {
var didScroll,
lastScrollTop = 0,
tolerance = 15,
header = $('header'),
headerHeight = header.outerHeight(true),
fixedClass = ('is-header-fixed'),
hiddenClass = ('is-header-hidden'),
visibleClass = ('is-header-visible'),
transitioningClass = ('is-header-transitioning');
win.scroll(function( event ) {
didScroll = true;
});
setInterval(function() {
if ( didScroll ) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// SCROLL DOWN
if( st > lastScrollTop ) {
header.removeClass( visibleClass );
if( st >= headerHeight ) {
header.addClass( fixedClass ).addClass( hiddenClass );
}
// SCROLL UP
} else {
// Make sure they scroll more than tolerance
if( Math.abs( lastScrollTop - st ) > tolerance ) {
header.removeClass( hiddenClass ).addClass( visibleClass );
}
}
// UPDATE SCROLL VAR
var lastScrollTop = st;
}
}
Now, I want to add an "is-transitioning" class containing CSS transform attributes, that I am going to remove with a CSS animation callback. The problem is that I need that class to be triggered once, in other words only when there's a change in scroll direction, not every time the user scrolls.
I thought to store a "second to last" scrollTop variable in order to detect when there is a change in scroll direction, but my attempts failed. Any advice?
Maybe something like this?
function hidingHeader() {
var didScroll,
lastScrollTop = 0,
tolerance = 15,
lastDir = null, // you can start with a non-null if you don't want to trigger the first down for example, make this lastDir = "down",
header = $('header'),
headerHeight = header.outerHeight(true),
fixedClass = ('is-header-fixed'),
hiddenClass = ('is-header-hidden'),
visibleClass = ('is-header-visible'),
transitioningClass = ('is-header-transitioning');
win.scroll(function( event ) {
didScroll = true;
});
setInterval(function() {
if ( didScroll ) {
hasScrolled();
didScroll = false;
}
}, 250);
function hasScrolled() {
var st = $(this).scrollTop();
// SCROLL DOWN
if( st > lastScrollTop ) {
header.removeClass( visibleClass );
if( st >= headerHeight ) {
header.addClass( fixedClass ).addClass( hiddenClass );
}
if( lastDir !== "down" ) { // Should only get triggered once while scrolling down, the first time the direction change happens
lastDir = "down";
// do your transition stuff here
}
// SCROLL UP
} else {
// Make sure they scroll more than tolerance
if( Math.abs( lastScrollTop - st ) > tolerance ) {
header.removeClass( hiddenClass ).addClass( visibleClass );
}
if( lastDir !== "up" ) { // Should only get triggered once while scrolling up, the first time the direction change happens
lastDir = "up";
// do your transition stuff here
}
}
// UPDATE SCROLL VAR
var lastScrollTop = st;
}
}

Angularizing: Vertically Centering Text in Textarea

I'm trying to replicate the functionality found in this codepen example.
Primarily, I'd like to include this code:
$( function() {
var $wrap = $('#wrap');
var $textarea = $('textarea');
var $dummy = $('.dummy');
function positionTextarea() {
var h = $wrap.height();
var top = Math.max( 0, ( h - $dummy.height() ) * 0.5 );
$textarea.css({
paddingTop: top,
height: h - top
});
}
$textarea.on( 'keyup change', function( event ) {
var html = formatDummyText( $textarea.val() );
$dummy.html( html );
positionTextarea();
}).trigger('change');
// should debounce this
$( window ).on( 'resize', positionTextarea );
});
in a directive. I'll have a textarea with a dummy div nearby with 0 opacity. What's the best way to include this functionality in a directive?

how to change the background of a div smoothly?

I have created on script for changing the background of a div continuously after some time intervals as following
jQuery( function( $ ) {
var images = [ "images/bg-a.jpg","images/bg-b.jpg" , "images/bg-c.jpg" ];
var bg_spans = [ "#bg-a","#bg-b","#bg-c" ];
var currentImage = 0;
function changeBackground() {
$( '#bdy' ).css( { backgroundImage: 'url(' + images[ ++currentImage ] + ')'} );
for(i=0; i<bg_spans.length; i++ ) {
if(i==currentImage) {
$( bg_spans[currentImage]).css ( { background: "#eb5405"} );
$( bg_spans[currentImage]).css ("border-color","#fff" );
}
else {
$( bg_spans[i]).css ( { background: "#000098"} );
$( bg_spans[i]).css ("border-color","#000098" );
}
}
if ( currentImage >= images.length - 1 ) {
currentImage -= images.length;
}
}
setInterval( changeBackground, 6000 ); `});
here the images are changing after some time intervals. I want some animation effects with this transition. for example images should fade smoothly. How can i do this?
I would lay all images on top of eachother. All with opacity 0 except the first. Than jquery animate the opacity from the second to 1 and the first to 0. And so on...

Animation flickers with Firefox 18.0.1 (due to RequestAnimationFrame?)

i used this http://www.netmagazine.com/tutorials/create-interactive-street-view-jquery tutorial to create an intro for one of our customers:
http://f-bilandia.de/kunstmann/bronski/
It used to work really good on all browsers. When I updated to the newest stable version of Firefox (FF 18.0.1) however, there is heavy flickering while changing the images.
When reading the release notes of the newest version, i saw that ff has a new Javascript engine and has improved image quality with a new HTML scaling algorithm. Maybe it's because of that? Other possible solutions?
Below you can see the code i've used:
$(document).ready(function(){
var $doc = $(document);
var $win = $(window);
// dimensions - we want to cache them on window resize
var windowHeight, windowWidth;
var fullHeight, scrollHeight;
var streetImgWidth = 1024, streetImgHeight = 640;
calculateDimensions();
var currentPosition = -1, targetPosition = 0;
var $videoContainer = $('.street-view');
var video = $('.street-view > img')[0];
var $hotspotElements = $('[data-position]');
// handling resize and scroll events
function calculateDimensions() {
windowWidth = $win.width();
windowHeight = $win.height();
fullHeight = $('#main').height();
scrollHeight = fullHeight - windowHeight;
}
function handleResize() {
calculateDimensions();
resizeBackgroundImage();
handleScroll();
}
function handleScroll() {
targetPosition = $win.scrollTop() / scrollHeight;
}
// main render loop
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
function animloop(){
if ( Math.floor(currentPosition*5000) != Math.floor(targetPosition*5000) ) {
currentPosition += (targetPosition - currentPosition) / 5;
render(currentPosition);
}
requestAnimFrame(animloop);
}
// rendering
function render( position ) {
// position the elements
var minY = -windowHeight, maxY = windowHeight;
$.each($hotspotElements,function(index,element){
var $hotspot = $(element);
var elemPosition = Number( $hotspot.attr('data-position') );
var elemSpeed = Number( $hotspot.attr('data-speed') );
var elemY = windowHeight/2 + elemSpeed * (elemPosition-position) * scrollHeight;
if ( elemY < minY || elemY > maxY ) {
$hotspot.css({'visiblity':'none', top: '-1000px','webkitTransform':'none'});
} else {
$hotspot.css({'visiblity':'visible', top: elemY, position: 'fixed'});
}
});
renderVideo( position );
}
function resizeBackgroundImage(){
// get image container size
var scale = Math.max( windowHeight/streetImgHeight , windowWidth/streetImgWidth );
var width = scale * streetImgWidth , height = scale * streetImgHeight;
var left = (windowWidth-width)/2, top = (windowHeight-height)/2;
$videoContainer
.width(width).height(height)
.css('position','fixed')
.css('left',left+'px')
.css('top',top+'px');
}
// video handling
var imageSeqLoader = new ProgressiveImageSequence( "street/vid-{index}.jpg" , 387 , {
indexSize: 4,
initialStep: 16,
onProgress: handleLoadProgress,
onComplete: handleLoadComplete,
stopAt: 1
} );
// there seems to be a problem with ie
// calling the callback several times
var loadCounterForIE = 0;
imageSeqLoader.loadPosition(currentPosition,function(){
loadCounterForIE++;
if ( loadCounterForIE == 1 ) {
renderVideo(currentPosition);
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
imageSeqLoader.load();
}
});
var currentSrc, currentIndex;
function renderVideo(position) {
var index = Math.round( currentPosition * (imageSeqLoader.length-1) );
var img = imageSeqLoader.getNearest( index );
var nearestIndex = imageSeqLoader.nearestIndex;
if ( nearestIndex < 0 ) nearestIndex = 0;
var $img = $(img);
var src;
if ( !!img ) {
src = img.src;
if ( src != currentSrc ) {
video.src = src;
currentSrc = src;
}
}
}
$('body').append('<div id="loading-bar" style="">Loading...</div>');
function handleLoadProgress() {
var progress = imageSeqLoader.getLoadProgress() * 100;
$('#loading-bar').css({width:progress+'%',opacity:1});
}
function handleLoadComplete() {
$('#loading-bar').css({width:'100%',opacity:0,display: "none"});
$("html, body").css("overflow", "auto");
$("html, body").css("overflow-x", "hidden");
$("nav").css("display", "block");
$("#preloader").fadeOut("slow");
$("#scroll-hint").css("display", "block");
}
$win.resize( handleResize );
$win.scroll( handleScroll );
handleResize();
animloop();
});
Inside your "render( position )" function the following lines seem like they should be refactored.
if ( elemY < minY || elemY > maxY ) {
$hotspot.css({'visiblity':'none', top: '-1000px','webkitTransform':'none'});
} else {
$hotspot.css({'visiblity':'visible', top: elemY, position: 'fixed'});
}
For one visibility is spelled wrong and there is no "none" value for it (it would be "hidden"). Just use "display" with "none" and "" values.
The "top", "webkitTransform", and "position" keys seem unnecessary. If the element is not visible there's no need to set the top, and why wouldn't the element always be fixed position?

Categories