Elements reverting back to original sizes after JQuery animation - javascript

So I am trying to get my header to change its size to become smaller after the user scrolls a certain distance down the page, the animations for the header to get bigger and smaller execute at the right time. Only issue is on the animation to make the header bigger, the animation happens as it should but as soon as it has finished animated the header reverts back to its original size for some reason. Not sure if this makes any difference but the header has its position set to fixed in the css. I have never come across an issue like this so have no idea what is going wrong, and googling it hasn't helped me either.
You can view the issue here: http://eventrem.com
Full Javascript:
function getScrollOffsets() {
var doc = document, w = window;
var x, y, docEl;
if ( typeof w.pageYOffset === 'number' ) {
x = w.pageXOffset;
y = w.pageYOffset;
} else {
docEl = (doc.compatMode && doc.compatMode === 'CSS1Compat')?
doc.documentElement: doc.body;
x = docEl.scrollLeft;
y = docEl.scrollTop;
}
return {x:x, y:y};
}
var IsHeaderBig;
window.onload = function() {
var offset = getScrollOffsets();
if (offset.y > 100) {
IsHeaderBig = false;
animateHeaderSmall(0);
} else {
IsHeaderBig = true;
animateHeaderBig(0);
}
}
window.addEventListener('scroll', function(){
var offset = getScrollOffsets();
if (offset.y > 100) {
//Make Small
if (IsHeaderBig) {
IsHeaderBig = false;
animateHeaderSmall(300);
}
} else {
//Make Big
if (!IsHeaderBig) {
IsHeaderBig = true;
animateHeaderBig(300);
}
}
});
function animateHeaderBig(speed) {
var header = $("#headerContainer");
var buffer = $("#homeBuffer");
header.animate({
height:'548px'
}, speed, function() {});
buffer.animate({
height:'470px'
}, speed, function() {});
}
function animateHeaderSmall(speed) {
var header = $("#headerContainer");
var buffer = $("#homeBuffer");
header.animate({
height:'100px'
}, speed, function() {});
buffer.animate({
height:'100px'
}, speed, function() {});
}

The easy solution is to handle the complete function and set the values there.
function animateHeaderBig(speed) {
var header = $("#headerContainer");
var buffer = $("#homeBuffer");
header.animate({
height:'548px'
}, {
duration: speed,
complete: function() {
$(this).css('height', '548px');
}
});
buffer.animate({
height:'470px'
}, {
duration: speed,
complete: function() {
$(this).css('height', '470px');
}
});

Related

jQuery curtain scroller app

I'm trying to build a curtain slider - much like what is used on the Apple site - http://www.apple.com/30-years/
http://jsfiddle.net/NYEaX/405/
I've created the following code - I need to add listeners to detect the mouse hovering over the far left/far right sides of the page - and then invoke an exponential slide.
var curtainSlider = {
invoke: function(el){
var that = this;
var list = $(el + " ul").find("li");
this.initialListWidth = list.outerWidth(true);
list
.mouseover(function() {
console.log("over");
that.expand(this);
})
.mouseout(function() {
console.log("out");
that.contract(this);
});
},
expand: function(el){
var that = this;
$(el).stop().animate({
width: that.initialListWidth*2
},400, function() {
// Animation complete.
});
},
contract: function(el){
var that = this;
$(el).stop().animate({
width: that.initialListWidth
},400, function() {
// Animation complete.
});
}
}
$(document).ready(function() {
console.log( "ready!" );
curtainSlider.invoke("#curtain");
});
**LATEST CODE - complete integration - http://jsfiddle.net/NYEaX/538/ **
I have stabilized this version of the scroller. - This curtains the images and spectrum fades them on start up. It repositions the a elements so the image is more centrally aligned.
http://jsfiddle.net/NYEaX/432/
I've separated out the code responsible for moving the slider unit, with an acceleration/deceleration. Its this part of the application I wish to focus on now.
http://jsfiddle.net/NYEaX/434/
I've tried to push the pagex variable into the animation part to help manipulate the duration of the animation. How can this be stabilized/improved on. I am finding it hard to reverse engineer the apple 30 year slider.
var curtainSlider = {
bindEvents: function(){
var that = this;
$("body").on("mousemove",function(event) {
if (event.pageX < 50) {
// animate curtain left
console.log("curtain left");
that.scroll("l", event.pageX);
}
if (event.pageX > (window.width - 50)) {
// animate curtain right
console.log("curtain right");
that.scroll("r", window.width - event.pageX);
}
});
},
scroll: function(direction, leveler){
var charge = "-";
if(direction == "r"){
charge = "+";
}
$('#curtainholder #slider').animate({
left: charge+"="+leveler
},400, function() {
// Animation complete.
});
},
invoke: function(el){
var that = this;
this.bindEvents();
}
}
$(document).ready(function() {
curtainSlider.invoke("#curtain");
});

jquery - Make number count up when in viewport [duplicate]

This question already has answers here:
Animate counter when in viewport
(4 answers)
Closed 6 years ago.
I'm trying to make a number count up when it's within the viewport, but currently, the script i'm using will interrupt the count on scroll.
How would I make it so that it will ignore the scroll and just count up when it's within the viewport? This needs to work on mobile, so even when a user is scrolling on touch. It cannot interrupt the count.
Please see here:
http://jsfiddle.net/Q37Q6/27/
(function ($) {
$.fn.visible = function (partial, hidden) {
var $t = $(this).eq(0),
t = $t.get(0),
$w = $(window),
viewTop = $w.scrollTop(),
viewBottom = viewTop + $w.height(),
_top = $t.offset().top,
_bottom = _top + $t.height(),
compareTop = partial === true ? _bottom : _top,
compareBottom = partial === true ? _top : _bottom,
clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true;
return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
};
})(jQuery);
// Scrolling Functions
$(window).scroll(function (event) {
function padNum(num) {
if (num < 10) {
return "" + num;
}
return num;
}
var first = 25; // Count up to 25x for first
var second = 4; // Count up to 4x for second
function countStuffUp(points, selector, duration) { //Animate count
$({
countNumber: $(selector).text()
}).animate({
countNumber: points
}, {
duration: duration,
easing: 'linear',
step: function () {
$(selector).text(padNum(parseInt(this.countNumber)));
},
complete: function () {
$(selector).text(points);
}
});
}
// Output to div
$(".first-count").each(function (i, el) {
var el = $(el);
if (el.visible(true)) {
countStuffUp(first, '.first-count', 1600);
}
});
// Output to div
$(".second-count").each(function (i, el) {
var el = $(el);
if (el.visible(true)) {
countStuffUp(second, '.second-count', 1000);
}
});
});
Your example is more complicated than you're aware, I think. You're doing things in a pretty unusual way, here, using a jQuery animate method on a custom property as your counter. It's kind of cool, but it also makes things a little more complicated. I've had to add a number of things to straighten up the situation.
I went ahead and rewrote your visible plugin, largely because I had no idea what yours was doing. This one's simple!
When your counters become visible, they get a "counting" class so that the counter isn't re-fired on them when they're already counting.
I save a reference to the object you have your custom counter animation on to the data attribute of the counter. This is vital: without that reference, you can't stop the animation when it goes offscreen.
I do some fanciness inside the step function to keep track of how much time is left so that you can keep your counter running at the same speed even if it stops and starts. If your counter runs for half a second and it's set to use one second for the whole animation, if it gets interrupted and restarted you only want to set it to half a second when you restart the counter.
http://jsfiddle.net/nate/p9wgx/1/
(function ($) {
$.fn.visible = function () {
var $element = $(this).eq(0),
$win = $(window),
elemTop = $element.position().top,
elemBottom = elemTop + $element.height(),
winTop = $win.scrollTop(),
winBottom = winTop + $win.height();
if (elemBottom < winTop) {
return false;
} else if (elemTop > winBottom) {
return false;
} else {
return true;
}
};
})(jQuery);
function padNum(num) {
if (num < 10) {
return " " + num;
}
return num;
}
var $count1 = $('.first-count');
var $count2 = $('.second-count');
// Scrolling Functions
$(window).scroll(function (event) {
var first = 25; // Count up to 25x for first
var second = 4; // Count up to 4x for second
function countStuffUp(points, selector, duration) {
//Animate count
var $selector = $(selector);
$selector.addClass('counting');
var $counter = $({
countNumber: $selector.text()
}).animate({
countNumber: points
}, {
duration: duration,
easing: 'linear',
step: function (now) {
$selector.data('remaining', (points - now) * (duration / points));
$selector.text(padNum(parseInt(this.countNumber)));
},
complete: function () {
$selector.removeClass('counting');
$selector.text(points);
}
});
$selector.data('counter', $counter);
}
// Output to div
$(".first-count").each(function (i, el) {
var el = $(el);
if (el.visible() && !el.hasClass('counting')) {
var duration = el.data('remaining') || 1600;
countStuffUp(first, '.first-count', duration);
} else if (!el.visible() && el.hasClass('counting')) {
el.data('counter').stop();
el.removeClass('counting');
}
});
// Output to div
$(".second-count").each(function (i, el) {
var el = $(el);
if (el.visible() && !el.hasClass('counting')) {
var duration = el.data('remaining') || 1000;
countStuffUp(second, '.second-count', duration);
} else if (!el.visible() && el.hasClass('counting')) {
el.data('counter').stop();
el.removeClass('counting');
}
});
});
There's a lot here. Feel free to ask me questions if anything's not clear.

Jquery = setInterval code works in Firefox but not in Chrome

The code (from an old plugin that I am trying to make responsive) slides a set of images across every n seconds. It uses setInterval code as below, and works well on Firefox. On Chrome it runs once only, and debugging indicates that the second setInteral function is just not called. Please help as its diving me mad. Running example at http://lelal.com/test/site10/index.html (sorry about the load time)
play = setInterval(function() {
if (!busy) {
busy = true;
updateCurrent(settings.direction);
slide();
}
}, settings.speed);
The complete plugin code is below (sorry its long)
/*
* jQuery Queue Slider v1.0
* http://danielkorte.com
*
* Free to use and abuse under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*/
(function($){
var QueueSlider = function(element, options) {
var play = false,
busy = false,
current = 2,
previous = 2,
widths = [],
slider = $(element),
queue = $('ul.queue', slider),
numImages = $('img', queue).size(),
viewportWidth = slider.width(),
settings = $.extend({}, $.fn.queueSlider.defaults, options);
$(window).resize(function(){
if(busy !== false)
clearTimeout(busy);
busy = setTimeout(resizewindow, 200); //200 is time in miliseconds
});
function resizewindow() {
viewportWidth = slider.width();
if (settings.scale > 0) {
slider.css('height',viewportWidth * settings.scale);
computeQueueWidth();
}
queue.css('left', -getQueuePosition());
busy = false;
}
function requeue() {
$('li', queue).each(function(key, value) {
$(this).attr('class', 'slide-' + (key+1));
});
}
function updateCurrent(dir) {
current += dir;
if (current < 1) {
current = numImages;
} else if (current > numImages) {
current = 1;
}
}
function getQueuePosition() {
var i = 0, index = current-1,
queuePosition = (viewportWidth - widths[index]) / -2;
for (i = 0; i < index; i++) { queuePosition += widths[i]; }
return queuePosition;
}
function computeQueueWidth() {
var queueWidth = 0;
// factor = slider.height() / settings.imageheight;
// settings.imageheight = settings.imageheight * factor;
// Get the image widths and set the queue width to their combined value.
$('li', queue).each(function(key, value) {
var slideimg = $("img", this),
slide = $(this),
// width = slide.width() * factor,
width = slideimg.width();
slide.css('width', width+'px');
queueWidth += widths[key] = width;
});
queue.css('width', queueWidth + 500);
}
function slide() {
var animationSettings = {
duration: settings.transitionSpeed,
queue: false
};
// Emulate an infinte loop:
// Bring the first image to the end.
if (current === numImages) {
var firstImage = $('li.slide-1', queue);
widths.push(widths.shift());
queue.css('left', queue.position().left + firstImage.width()).append(firstImage);
requeue();
current--; previous--;
}
// Bring the last image to the beginning.
else if (current === 1) {
var lastImage = $('li:last-child', queue);
widths.unshift(widths.pop());
queue.css('left', queue.position().left + -lastImage.width()).prepend(lastImage);
requeue();
current = 2; previous = 3;
}
// Fade in the current and out the previous images.
if (settings.fade !== -1) {
$('li.slide-'+current, queue).animate({opacity: 1}, animationSettings);
$('li.slide-'+previous, queue).animate({opacity: settings.fade}, animationSettings);
}
// Animate the queue.
animationSettings.complete = function() { busy = false; };
queue.animate({ left: -getQueuePosition() }, animationSettings);
previous = current;
}
//
// Setup the QueueSlider!
//
if (numImages > 2) {
// Move the last slide to the beginning of the queue so there is an image
// on both sides of the current image.
if (settings.scale > 0) {
slider.css('height',viewportWidth * settings.scale);
}
computeQueueWidth();
widths.unshift(widths.pop());
queue.css('left', -getQueuePosition()).prepend($('li:last-child', queue));
requeue();
// Fade out the images we aren't viewing.
if (settings.fade !== -1) { $('li', queue).not('.slide-2').css('opacity', settings.fade); }
// Include the buttons if enabled and assign a click event to them.
if (settings.buttons) {
slider.append('<button class="previous" rel="-1">' + settings.previous + '</button><button class="next" rel="1">' + settings.next + '</button>');
$('button', slider).click(function() {
if (!busy) {
busy = true;
updateCurrent(parseInt($(this).attr('rel'), 10));
clearInterval(play);
slide();
}
return false;
});
}
// Start the slideshow if it is enabled.
if (settings.speed !== 0) {
play = setInterval(function() {
if (!busy) {
busy = true;
updateCurrent(settings.direction);
slide();
}
}, settings.speed);
}
}
else {
// There isn't enough images for the QueueSlider!
// Let's disable the required CSS and show all one or two images ;)
slider.removeClass('queueslider');
}
};
$.fn.queueSlider = function(options) {
return this.each(function(key, value) {
var element = $(this);
// Return early if this element already has a plugin instance.
if (element.data('queueslider')) { return element.data('queueslider'); }
// Pass options to plugin constructor.
var queueslider = new QueueSlider(this, options);
// Store plugin object in this element's data.
element.data('queueslider', queueslider);
});
};
$.fn.queueSlider.defaults = {
scale: 0,
imageheight: 500,
fade: 0.3, // Opacity of images not being viewed, use -1 to disable
transitionSpeed: 700, // in milliseconds, speed for fade and slide motion
speed: 7000, // in milliseconds, use 0 to disable slideshow
direction: 1, // 1 for images to slide to the left, -1 to silde to the right during slideshow
buttons: true, // Display Previous/Next buttons
previous: 'Previous', // Previous button text
next: 'Next' // Next button text
};
}(jQuery));
Have a look here:
http://www.w3schools.com/jsref/met_win_setinterval.asp
The setInterval() method will continue calling the function until clearInterval() is called, or the window is closed.
Looks like you're calling clearInterval after the first usage of play, which makes it stop working.

jQuery rearrange DOM elements

I'm a little confused why this is not working how it's supposed to.
I have a list of <div>s that wrap around based on the size of the page. But clicking the div it .animate() the width of the clicked div and animates the divs after it closer together and stacks them.
This all works except the last stacked div, despite having plenty of room still gets knocked down to the next row.
please see my code on jsfiddle:
http://jsfiddle.net/ZHYRq/2/
$.each($('.employee-box'), function(i, el) {
$(el).addClass("top-" + (Math.round($(el).offset().top)));
return $(el).css('position', 'relative').attr('data-left', Math.round($(el).offset().left));
});
$('.employee-image').hover(function(e) {
var $employee;
$employee = $(e.target).parents('.employee-box');
if (e.type === 'mouseenter') {
return $($employee.find('a.bio')).addClass('highlight');
} else {
return $($employee.find('a.bio')).removeClass('highlight');
}
});
$('.employee-image, a.bio').click(function(e) {
var $employee, is_expanded, speed;
speed = 150;
$employee = $(e.target).parents('.employee-box');
is_expanded = $employee.hasClass('bio-expanded');
if ($('.bio-expanded').length > 0) {
$.when(collapse_previous_bio(speed)).then(function() {
if (!is_expanded) {
return expand_bio_box($employee, speed);
}
});
} else {
expand_bio_box($employee, speed);
}
return false;
});
var collapse_previous_bio = function(speed) {
var klass;
klass = "." + $('.bio-expanded').attr('class').match(/top-\d{1,5}/)[0];
$('.bio-expanded .bio-block').fadeOut(speed, function() {
$('.bio-expanded').animate({
width: "185px"
}, speed);
$(klass).animate({
left: '0px'
}, speed);
$('.bio-expanded').removeClass('bio-expanded');
});
};
var expand_bio_box = function($employee, speed) {
var curr_left, klass;
klass = "." + $employee.attr('class').match(/top-\d{1,5}/)[0];
curr_left = parseInt($employee.data('left'));
// comment out the $.when block and un-comment out the collapse_others() to see the other elements collapse as they should
$.when(collapse_others(klass, curr_left)).then(function() {
$employee.animate({
width: "392px"
}, speed, function() {
$employee.find('.bio-block').fadeIn(speed);
$employee.addClass('bio-expanded');
});
});
// collapse_others(klass, curr_left)
};
var collapse_others = function(klass, curr_left) {
var left_pos;
left_pos = 0;
$.each($(klass), function(i, el) {
var el_left;
el_left = parseInt($(el).data('left'));
$(el).css({
zIndex: 100 - i
});
if (el_left > curr_left) {
$(el).animate({
left: "-" + left_pos + "px"
}, 100);
left_pos += 100;
}
});
};
I'm not sure what is wrong here. Any thoughts?

javascript 'over-clicking' bug

I have a bug in Javascript where I am animating the margin left property of a parent container to show its child divs in a sort of next/previous fashion. Problem is if clicking 'next' at a high frequency the if statement seems to be ignored (i.e. only works if click, wait for animation, then click again) :
if (marLeft === (-combinedWidth + (regWidth) + "px")) {
//roll margin back to 0
}
An example can be seen on jsFiddle - http://jsfiddle.net/ZQg5V/
Any help would be appreciated.
Try the below code which will basically check if the container is being animated just return from the function.
Working demo
$next.click(function (e) {
e.preventDefault();
if($contain.is(":animated")){
return;
}
var marLeft = $contain.css('margin-left'),
$this = $(this);
if (marLeft === (-combinedWidth + (regWidth) + "px")) {
$contain.animate({
marginLeft: 0
}, function () {
$back.fadeOut('fast');
});
} else {
$back.fadeIn(function () {
$contain.animate({
marginLeft: "-=" + regWidth + "px"
});
});
}
if (marLeft > -combinedWidth) {
$contain.animate({
marginLeft: 0
});
}
});
Sometimes is better if you create a function to take care of the animation, instead of writting animation code on every event handler (next, back). Also, users won't have to wait for the animation to finish in order to go the nth page/box.
Maybe this will help you:
if (jQuery) {
var $next = $(".next"),
$back = $(".back"),
$box = $(".box"),
regWidth = $box.width(),
$contain = $(".wrap")
len = $box.length;
var combinedWidth = regWidth*len;
$contain.width(combinedWidth);
var currentBox = 0; // Keeps track of current box
var goTo = function(n) {
$contain.animate({
marginLeft: -n*regWidth
}, {
queue: false, // We don't want animations to queue
duration: 600
});
if (n == 0) $back.fadeOut('fast');
else $back.fadeIn('fast');
currentBox = n;
};
$next.click(function(e) {
e.preventDefault();
var go = currentBox + 1;
if (go >= len) go = 0; // Index based, instead of margin based...
goTo(go);
});
$back.click(function(e) {
e.preventDefault();
var go = currentBox - 1;
if (go <= 0) go = 0; //In case back is pressed while fading...
goTo(go);
});
}
Here's an updated version of your jsFiddle: http://jsfiddle.net/victmo/ZQg5V/5/
Cheers!
Use a variable to track if the animation is taking place. Pseudocode:
var animating = false;
function myAnimation() {
if (animating) return;
animating = true;
$(this).animate({what:'ever'}, function() {
animating = false;
});
}
Crude, but it should give you the idea.
Edit: Your current code works fine for me as well, even if I jam out on the button. On firefox.

Categories

Resources