How to add scroll background effect to multiple elements with different settings? - javascript

In this demo http://www.htmldrive.net/items/demo/527/Animated-background-image-with-jQuery
This code is for one background only. I want to add multiple background with different direction and speed.
var scrollSpeed = 70;
var step = 1;
var current = 0;
var imageWidth = 2247;
var headerWidth = 800;
var restartPosition = -(imageWidth - headerWidth);
function scrollBg(){
current -= step;
if (current == restartPosition){
current = 0;
}
$('#header').css("background-position",current+"px 0");
}
var init = setInterval("scrollBg()", scrollSpeed);
Currently it has settings for
$('#header').css("background-position",current+"px 0");
In a website I want to use this effect on #footer or #content background also. but with different speed and direction.
And is there any better and more optimized jquery method to achieve same effect?
And can we get same effect using CSS 3, without javascript?

Just saw the OP's answer, but decided to post anyway:
I've created a jQuery plugin to do this:
(function($) {
$.fn.scrollingBackground = function(options) {
// settings and defaults.
var settings = options || {};
var speed = settings.speed || 1;
var step = settings.step || 1;
var direction = settings.direction || 'rtl';
var animStep;
// build up a string to pass to animate:
if (direction === 'rtl') {
animStep = "-=" + step + "px";
}
else if (direction === 'ltr') {
animStep = '+=' + step + "px";
}
var element = this;
// perform the animation forever:
var animate = function() {
element.animate({
backgroundPosition: animStep + " 0px"
}, speed, animate);
};
animate();
};
})(jQuery);
Usage:
$("#header").scrollingBackground({
speed: 50,
step: 50,
direction: 'ltr'
});
This is pretty basic, and assumes that you're background-repeat is 'repeat-x' on the element you call it on. This way, there's no need to reset the background position every so often.
Working example: http://jsfiddle.net/andrewwhitaker/xmtpr/

I could work out the following solution. Am not sure if it is efficient. Will wait for anyone to comment or provide a better option.
Till then...:
var scrollSpeed = 70;
var step = 1;
var current = 0;
var images =
[
{
imageWidth:2247,
imagePath:"images/image1"
},
{
imageWidth:1200,
imagePath:"images/image2"
}
]
var headerWidth = 800;
var imageRotateCount = 0;
var imagesLength = images.length;
$('#header').css("background-image", images[0].imagePath);
function scrollBg(){
var curIndex = imageRotateCount%imagesLength;
var curImage = images[curIndex];
current -= step;
var restartPosition = -(curImage.imageWidth - headerWidth);
if (current == restartPosition){
current = 0;
imageRotateCount++;
curIndex = imageRotateCount%imagesLength;
curImage = images[curIndex];
$('#header').css("background-image", curImage.imagePath);
}
$('#header').css("background-position",current+"px 0");
}
var init = setInterval("scrollBg()", scrollSpeed);

Related

javascript, offsetTop, offsetBottom

I have a paragraph tag in my html id is move, I am trying to move the p tag to slowing fall down while on page load. but my code is not working.......
var speed = 12;
var direction = 1;
var getParagraph = document.getElementById("move");
getParagraph.onmouseover = moving;
function moving() {
var bo = getParagraph.offsetHeight;
var boTop = getParagraph.offsetTop;
var boBottom = boTop + bo;
// When right side of the box goes too far - change direction:
if (boBottom > document.body.offsetHeight) {
direction = -1;
}
// When left side of the box goes too far - change direction:
if (boTop < 0) {
direction = 1;
}
// Recalculate position:
getParagraph.style.Top = (boTop + speed * direction)
}
This is your code with minor changes, and it "works":
JS:
var speed = 12;
var direction = 1;
var getParagraph = document.getElementById("move");
document.getElementById("move").addEventListener("mouseover", moving);
//getParagraph.onmouseover = moving;
function moving() {
console.log("Moving??");
var bo = document.getElementById("move").offsetHeight;
var boTop = document.getElementById("move").offsetTop;
var boBottom = boTop + bo;
// When right side of the box goes too far - change direction:
if (boBottom > document.body.offsetHeight) {
direction = -1;
}
// When left side of the box goes too far - change direction:
if (boTop < 0) {
direction = 1;
}
// Recalculate position:
document.getElementById("move").style.marginTop = (boTop + speed * direction) + "px";
speed++;
}
CSS:
#move {
display : block ;
position : absolute ;
}
Hope it helps.

Parallax scroll choppy performance on Safari & Firefox

I'm building a onepager with a parallax intro. For the parallax effect I'm using the following piece of JS:
// Parallax
var layerBg = document.querySelector('.js-layer-bg');
var layerText = document.querySelector('.js-layer-text');
var sectionIntro = document.getElementById('section-intro');
var scrollPos = window.pageYOffset;
var layers = document.querySelectorAll('[data-type=\'parallax\']');
var parallax = function() {
for (var i = 0, len = layers.length; i < len; i++) {
var layer = layers[i];
var depth = layer.getAttribute('data-depth');
var movement = (scrollPos * depth) * -1;
var translate3d = 'translate3d(0, ' + movement + 'px, 0)';
layer.style['-webkit-transform'] = translate3d;
layer.style.transform = translate3d;
}
};
window.requestAnimationFrame(parallax);
window.addEventListener('scroll', function() {
// Parallax layers
scrollPos = window.pageYOffset;
window.requestAnimationFrame(parallax);
// Animate text layers
var vhScrolled = Math.round(window.pageYOffset / window.innerHeight * 100);
if (vhScrolled > 100 && layerText.classList.contains('is-hidden')) {
layerText.classList.remove('is-hidden');
} else if (vhScrolled <= 100 && !layerText.classList.contains('is-hidden')) {
layerText.classList.add('is-hidden');
}
});
Apart from this I'm animating a few other things on scroll using 2 libraries: ScrollMonitor and ScrollReveal. Nothing too special.
I've been developing this on Chrome and everything seems to be working smoothly enough. However, when I tested on Safari and especially Firefox, things got so laggy to the point of actually crashing my browser.
I really can't figure out what I am doing wrong and why performance is so different between browsers.
Hopefully you can help me out, thanks!
I'm not altogether certain about what's specifically causing the lag/choppiness issues, I seem to remember something similar in past projects. I'd look into any further image optimization to lower the weight of what's being rendered, that can make a huge difference. Otherwise, I've made a few suggestions for efficiency tweaks that might help it run a bit faster:
// Parallax
var layerBg = document.querySelector('.js-layer-bg');
var layerText = document.querySelector('.js-layer-text');
var sectionIntro = document.getElementById('section-intro');
var layers = document.querySelectorAll('[data-type=\'parallax\']');
var len = layers.length; // cache length
var layerarray = []; //create cache for depth attributes
var i = -1;
while(++i < len){
layerarray.push([layers[i], parseInt(layers[i].getAttribute('data-depth'))]); //create an array that stores each element alongside its depth attribute instead of requesting that attribute every time
}
var parallax = function() {
var scrollPos = window.pageYOffset; //define inside function instead of globally
var i = -1;
while(++i < len) { //while loop with cached length for minor speed gains
var layer = layerarray[i][0];
var depth = layerarray[i][1];
var movement = (scrollPos * depth) * -1;
var translate3d = ['translate3d(0, ', movement, 'px, 0)'].join(""); //join statement is much faster than string concatenation
layer.style['-webkit-transform'] = translate3d;
layer.style.transform = translate3d;
}
// Animate text layers
var vhScrolled = Math.round(scrollPos / window.innerHeight * 100);
if (vhScrolled > 100 && layerText.classList.contains('is-hidden')) {
layerText.classList.remove('is-hidden');
} else if (vhScrolled <= 100 && !layerText.classList.contains('is-hidden')) {
layerText.classList.add('is-hidden');
}
};
window.requestAnimationFrame(parallax);
window.addEventListener('scroll', function() {
// Parallax layers
window.requestAnimationFrame(parallax);
//moved text animation into the animationframe request
});

Javascript Resize to reset variables

I'm trying to have a bunch of variables reset themselves on a resize (I'm just a little crazy like that. Yes, I know virtually no one will do it as their using the page). I want to be able to have the plugin that I created (hScroll) reset it's variables when the user resizes the page. I only want to declare them and set them within one line, so I tried using the window.variableName = ... but that didn't seem to work. Once again, all I want to be able to do is have to declare and set the variable within one line, and on resize, have the variables reestablish themselves, since a few are size dependent. As you can see, I have also tried the triggerHandler method as well, but it does not seem to be working.
(function($) {
$.fn.extend({
hScroll: function(options) {
var defaults = {
container: "nav",
sliderName: ".sliderName",
partContainer: ".beep"
};
var o = $.extend(defaults, options);
return this.each(function() {
// I want to set global variables and have them reset... START
var slider = $(o.container + " " + o.sliderName),
sliderWidth = slider.outerWidth(),
container = $(o.container),
containerWidth = container.outerWidth(),
containerInnerWidth = containerWidth - (2 * parseInt(container.css("padding-left"))),
sliderPieces = slider.children(o.partContainer),
numberOfPieces = sliderPieces.length,
containerWidth = $(o.container).width(),
piecesWidth = 0;
// set slide widths
if (containerInnerWidth > sliderWidth / numberOfPieces) {
piecesWidth = sliderWidth / numberOfPieces
} else {
piecesWidth = containerInnerWidth;
}
sliderPieces.width(piecesWidth);
// set gutter and how many pieces can be seen at once.
var wholePiecesSeen = Math.floor(containerInnerWidth / piecesWidth),
gutter = parseInt((containerInnerWidth - (wholePiecesSeen * piecesWidth)) / 2);
// END - I want this block to be reset when the window is resized.
var isContainerBigEnough = function() {
if (containerInnerWidth > sliderWidth) {
$(o.container).removeClass("tooBig");
} else {
$(o.container).addClass("tooBig");
}
}
isContainerBigEnough();
// arrow variables
$(o.container + " .previous").click(function() {
var addOn = 0,
newPosition = 0,
thisFarGone = parseInt(slider.css("left")),
moveThisFar = piecesWidth,
allTheWay = containerInnerWidth - sliderWidth;
// always make sure to center your tiles
if (thisFarGone == allTheWay) {
moveThisFar = moveThisFar - gutter;
console.log(moveThisFar);
console.log("in");
};
newPosition = -thisFarGone - moveThisFar;
//make sure it doesn't go too far
if (newPosition < 0) {
newPosition = 0;
}
newPosition = parseInt(newPosition); // - addOn);
slider.css({
"left": (-newPosition) + "px"
});
});
$(o.container + " .next").click(function() {
var addOn = 0,
newPosition = 0,
thisFarGone = parseInt(slider.css("left")),
moveThisFar = piecesWidth;
// always make sure to center your tiles
if (thisFarGone == 0 ||
thisFarGone == -0 ||
thisFarGone == undefined) {
moveThisFar = moveThisFar - gutter;
};
newPosition = moveThisFar - thisFarGone;
//make sure it doesn't go too far
if (newPosition > sliderWidth - containerInnerWidth) {
newPosition = sliderWidth - containerInnerWidth;
}
newPosition = parseInt(newPosition); // - addOn);
slider.css({
"left": (-newPosition) + "px"
});
});
$(window).resize(function() {
console.log("working");
$(o.container).triggerHandler("hScroll");
});
});
}
});
})(jQuery);
$(document).ready(function() {
$(".posts-timeline").hScroll({
container: ".posts-timeline",
sliderName: "#slider",
partContainer: ".post"
});
});
Something like this?
console.log("working");
$(o.container).hScroll("hScroll");
Maybe not exactly that, but if you want those variables to be reassigned, I'm guessing that would wind up being done somewhere in $(window).resize(function() {

jQuery: change class after conditional is met

I created this site where you have multiple sliders moving vertically using this example on stackoverflow > here < along with this fiddle.
The site when loaded has an overflow: hidden on the body and position fixed on my main content div(div class="content-fs row"). The idea is that when you first arrive on the page, you scroll through each slide and once you hit the last one, the position changes on the main content div(div class="content-fs row") from fixed to static and the overflow: hidden is removed from the body. I'm having trouble writing the conditional statement that says "if its the last slider, change the position." The jquery below is the code i'm using for the site along with the conditional statement that doesn't work.
Any pointers/advice would be greatly appreciated!
jquery:
function scrollLax(){
/*
initialize
*/
var scrollDown = false;
var scrollUp = false;
var scroll = 0;
var $view = $('#portfolio');
var t = 0;
var h = $view.height() - 250;
$view.find('.portfolio-sliders').each(function() {
var $moving = $(this);
// position the next moving correctly
if($moving.hasClass('from-bottom')) {
$moving.css('top', h); // subtract t so that a portion of the other slider is showing
}
// make sure moving is visible
$moving.css('z-index', 10);
});
var $moving = $view.find('.portfolio-sliders:first-child');
$moving.css('z-index', 10);
/*
event handlers
*/
var mousew = function(e) {
var d = 0;
if(!e) e = event;
if (e.wheelDelta) {
d = -e.wheelDelta/3;
} else if (e.detail) {
d = e.detail/120;
}
parallaxScroll(d);
}
if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', mousew, false);
}
window.onmousewheel = document.onmousewheel = mousew;
/*
parallax loop display loop
*/
window.setInterval(function() {
if(scrollDown)
parallaxScroll(4);
else if(scrollUp)
parallaxScroll(-4);
}, 50);
function parallaxScroll(scroll) {
// current moving object
var ml = $moving.position().left;
var mt = $moving.position().top;
var mw = $moving.width();
var mh = $moving.height();
// calc velocity
var fromBottom = false;
var vLeft = 0;
var vTop = 0;
if($moving.hasClass('from-bottom')) {
vTop = -scroll;
fromBottom = true;
}
// calc new position
var newLeft = ml + vLeft;
var newTop = mt + vTop;
// check bounds
var finished = false;
if(fromBottom && (newTop < t || newTop > h)) {
finished = true;
newTop = (scroll > 0 ? t : t + h);
}
// set new position
$moving.css('left', newLeft);
$moving.css('top', newTop);
// if finished change moving object
if(finished) {
// get the next moving
if(scroll > 0) {
$moving = $moving.next('.portfolio-sliders');
if($moving.length == 0)
$moving = $view.find('.portfolio-sliders:last');
//this is where I am trying to add the if conditional statement.
if ('.portfolio-sliders:last')
$('.content-fs.row').css({'position': 'static'});
if('.portfolio-sliders:last' && (mt == 0))
$('html, body').removeClass('overflow');
} else {
$moving = $moving.prev('.portfolio-sliders');
if($moving.length == 0)
$moving = $view.find('.portfolio-sliders:first-child');
//reverse the logic and if last slide change position
if('.portfolio-sliders:first-child')
$('.content-fs.row').css({'position': 'fixed'});
}
}
// for debug
//$('#direction').text(scroll + "/" + t + " " + ml + "/" + mt + " " + finished + " " + $moving.text());
}
}
Your code as it is simply asks whether .portfolio-sliders:last exists. Seems you should be doing:
if ($moving == $('.portfolio-sliders:last') )
or something along those lines, instead checking whether the active slide is the last.

Event on margin change

I have an element with animated top margin. I need to detect if it isn't too close from the border, and if it is, scroll parent div to lower position, to prevent animated element from hiding. Here is an example:
http://jsfiddle.net/zYYBR/5/
This green box shouldn't be below the red line after clicking the "down" button.
Do you mean this?
var new_margin;
var step = 75;
var limit = $("#max")[0].offsetTop;
$('#down').click(function() {
var goStep = step;
var elHeight = $("#animated")[0].offsetTop + $("#animated")[0].offsetHeight;
if((elHeight + step) > limit)
{
goStep = limit - elHeight;
}
new_margin = goStep + parseInt($('#animated').css('margin-top'));
$("#animated").animate({marginTop: new_margin}, 1000);
});
http://jsfiddle.net/zYYBR/8/
EDIT: Or maybe something like that (of course you can improve the calculation, because currently it's very buggy with scroll):
var new_margin;
var step = 75;
$('#down').click(function () {
scroll(1000);
});
var scrollTimer = null;
$("#container").bind("scroll", function () {
clearTimeout(scrollTimer);
scrollTimer = setTimeout(function () { scroll(1); }, 10);
});
function scroll(speed) {
var scrollStep, animationStep = step;
var currentBoxBottom = $("#animated")[0].offsetTop + $("#animated")[0].offsetHeight;
var nextCurrentBoxBottom = currentBoxBottom + step;
var limit = $("#max")[0].offsetTop + $("#container")[0].scrollTop;
if (nextCurrentBoxBottom > limit) {
if (limit >= $("#container")[0].scrollTop) {
scrollStep = $("#container")[0].scrollTop + nextCurrentBoxBottom - limit;
}
else {
scrollStep = $("#container")[0].scrollTop - nextCurrentBoxBottom - limit;
animationStep = nextCurrentBoxBottom - limit;
}
$("#container")[0].scrollTop = scrollStep;
}
new_margin = animationStep + parseInt($('#animated').css('margin-top'));
$("#animated").animate({ marginTop: new_margin }, speed);
}
http://jsfiddle.net/zYYBR/13/
Do you mean something like this?
I have the same visual result as Alex Dn did, but I added a little extra direction to what I think you're talking about. If it's what you're looking for I'll make updates:
var new_margin;
var step = 75;
var limit = $("#max")[0].offsetTop;
$('#down2').click(function() {
var anim = $("#animated");
var hrOff = $("#max").offset();
var thOff = anim.offset();
new_margin = Math.min(hrOff.top - thOff.top - anim.height(), 75);
console.log(new_margin, hrOff.top, thOff.top);
var st = 0;
if (new_margin < 75) {
st = 75 - new_margin;
//have container scroll by this much?
}
anim.animate({
marginTop: "+=" + new_margin
}, 1000);
});​
​
http://jsfiddle.net/zYYBR/10/

Categories

Resources