I have been reading several similar questions about this, but I can't get it to work. I have a scroll detection function in jQuery, which I want to have 3 parameters:
function scroll_detection(box_selector, trigger_offset, the_animation){
//something here
the_animation();
}
Where the_animation is a function that will be called like this:
scroll_detection("section", .8, function(){
//stuff here
});
The problem is, when I add the function, the animation do not run anymore.
This code works perfectly:
function scroll_detection(duration, box_selector, element_selector, ease, trigger_offset ){
var effect_offset = Math.floor($(window).height() * trigger_offset);
$(window).bind('scroll', function() {
$(box_selector).each(function() {
var post = $(this);
var position = post.position().top - ($(window).scrollTop() + effect_offset);
if (position <= 0) {
$(this).find(element_selector).animate( { marginLeft: "0" }, duration, ease );
}
});
});
}
scroll_detection(2000, "section", ".section-title", "easeOutBack", .8);
scroll_detection(3000, ".article-wrap", ".article-title", "easeOutBounce", .7);
But this does not:
function scroll_detection(the_animation, box_selector, trigger_offset ){
var effect_offset = Math.floor($(window).height() * trigger_offset);
$(window).bind('scroll', function() {
$(box_selector).each(function() {
var post = $(this);
var position = post.position().top - ($(window).scrollTop() + effect_offset);
if (position <= 0) {
the_animation();
}
});
});
}
scroll_detection( function(){
$(this).find(".section-title").animate( { marginLeft: "0" }, 2000, "easeOutBounce");
}, "section", .8);
I want to be able to change easily what kind of effect I want. Any help will be appreciated.
Edit 11/09/2015:
As #Aguardientico and #LuiGui pointed out, the problem was the scope of the $(this) inside the callback function, and I went with the #Aguardientico solution.
jQuery(document).ready(function($){
function scroll_detection(the_animation, box_selector, trigger_offset ){
var effect_offset = Math.floor($(window).height() * trigger_offset);
$(window).bind('scroll', function() {
$(box_selector).each(function() {
var post = $(this);
var position = post.position().top - ($(window).scrollTop() + effect_offset);
if (position <= 0) {
the_animation.call(post); //Add call to give the function the right scope
}
});
});
}
scroll_detection( function(){
$(this).find(".section-title").animate( { marginLeft: "0" }, 2000, "easeOutBounce");
}, "section", .8);
It looks like an issue related with scope, you are calling $(this) inside your anonymous function aka the_animation, what if you do the following? the_animation.call(post)
function scroll_detection(the_animation, box_selector, trigger_offset ){
var effect_offset = Math.floor($(window).height() * trigger_offset);
$(window).bind('scroll', function() {
$(box_selector).each(function() {
var post = $(this);
var position = post.position().top - ($(window).scrollTop() + effect_offset);
if (position <= 0) {
the_animation.call(post);
}
});
});
}
scroll_detection( function(){
$(this).find(".section-title").animate( { marginLeft: "0" }, 2000, "easeOutBounce");
}, "section", .8);
You are function calls DO NOT match the function definitions.
Your parameters are OUT OF ORDER.
Try this NEW CODE:
var scroll_detection = function scroll_detection_func(
the_animation, box_selector, trigger_offset
){
var effect_offset = Math.floor($(window).height() * trigger_offset);
$(window).bind('scroll', function() {
$(box_selector).each(function() {
var post = $(this);
var position = post.position().top
- ($(window).scrollTop()
+ effect_offset)
;
if (position <= 0) {
the_animation();
}
});
});
}
scroll_detection(
function(){
$(this).find(".section-title").animate({
marginLeft: "0" },
2000, "easeOutBounce"
);
}, //the_animation
"section", //box_selector
.8 //trigger_offset
);
From the code you give,the_animation means
$(this).find(element_selector).animate( { marginLeft: "0" }, duration, ease );
so you can there is a this in your function. When you pass a function with this as a parameter, you need to specify what this mean, just try to specify the scope of this use apply(),bind() or 'call()' function, here are some explanations:
http://javascriptissexy.com/javascript-apply-call-and-bind-methods-are-essential-for-javascript-professionals/
Related
I have created a few animations and each of them should be a separate slide on the main site slider.
Thats why, I've got from my boss an object structure (code below) and he said I should use it to those animations.
var RDAnimation = function(o){
var f = $.extend({
start: function() {
return true;
},
pause: function() {
return true;
},
reset: function() {
return true;
},
stop: function() {
if (this.pause()) {
return this.reset();
}
},
vars: {}
},o);
this.start = f.start;
this.pause = f.pause;
this.reset = f.reset;
this.stop = f.stop;
this.vars=f.vars;
};
But because I don't have a much of experience with working on objects, I just paste all of the animating function into 'start', just to see what will happen (code below).
var anim3=new RDAnimation({
start: function() {
var $this = this;
function bars() {
var barHeight = 0;
$('.chart-bar').each(function () {
barHeight = Math.floor(Math.random() * 100);
$(this).delay(1000).animate({
'height': barHeight + '%',
'min-height': '20px'},
700, function(){
bars();
});
});
}
var count = 0;
function badgeClone() {
var badge1 = $('.badge');
var badge2 = $('.badge').clone();
var badgeWidth = badge1.width();
var badgeHeight = badge1.height();
//badge1.text(count);
badge1.after(badge2);
badge2.css({
'line-height': '180px',
'text-align': 'center',
'font-size': '70px',
'font-weight': 'bold',
'color': '#fff',
'opacity':'0'
});
badge2.animate({
'width': badgeWidth * 2 + 'px',
'height': badgeHeight *2 + 'px',
'line-height': '360px',
'font-size': '140px',
'top': '-150px',
'right': '-100px'
},
100, "linear", function() {
if(count >= 9) {
count = 1
} else {
count++
}
badge2.text(count);
badge2.delay(300).animate({
'width': badgeWidth + 'px',
'height': badgeHeight + 'px',
'line-height': '180px',
'font-size': '70px',
'top': '-60px',
'right': '-40px',
'opacity': '1'},
100, "linear", function(){
badge1.fadeOut(600, function(){
$(this).remove();
});
});
});
}
bars();
var chartbars = $('.chart-bar');
$(chartbars).each(function(i) {
chartbar = chartbars[i];
var leftPos = i * 24 + 4;
$(chartbar).css({'left': leftPos + 'px'});
});
// ppl animations
var height = $('.person').height();
$('.person').css({'top': -height + 'px'});
var female = function(){
$('.female').fadeIn(300).animate({'top': '0px'}, 2500, function(){
male();
badgeClone();
$(this).delay(1000).fadeOut(500, function() {
$(this).css({'top': -height + 'px'});
});
});
};
var male = function(){
$('.male').fadeIn(300).animate({'top': '0px'},2500,function(){
badgeClone();
female();
$(this).delay(1000).fadeOut(500, function() {
$(this).css({'top': -height + 'px'});
});
});
};
male();
},
pause: function() {
var $this = this;
$('.chart-bar').stop();
},
reset: function() {
var $this = this;
$this.count = 0;
},
vars: {
}
});
And it's working! Animation will start when I run anim3.start. But now.. How can I stop it? Because I have to stop it when user chose another animated slide, and start it from beginning when user again chose this slide.
I've wrote a simple code, just for test.. But it doesnt work.
In code above I've wrote $('.chart-bar').stop(); in pause, to check if this will stop at least one chart-bar animation but it doesnt.
In reset I've wrote $this.count = 0; to reset number on the .badge element - but it doesnt work as well..
Obviously, to run those lines of code I've put a simple code on the bottom of script (code below).
$('#slider-2, #slider-3').hide();
$('.tour-slider').on('click', 'li a', function(e){
e.preventDefault();
$(this).closest('.slider').hide();
var sliderHref = $(this).attr('href');
$(sliderHref).fadeIn();
if(sliderHref == '#slider-1'){
anim1.start();
anim3.pause();
}else if(sliderHref == '#slider-2'){
anim2.start();
anim3.pause();
}else if(sliderHref == '#slider-3'){
anim3.reset();
anim3.start();
anim3.pause();
}
});
As you can see, I even run a anim3.pause(); at once, after I start it - just to check, if it will stop immediately - but even one chart-bar didn't stop..
So now, can somebody tell my please, how can I stop (and reset) these animated elements? I just need to get one working example and rest I can do by my own.
I will be grateful for any help
Cheers!
Ok, I found a solution.
1st of I modify a bars() function (add if statement)
function bars() {
var barHeight = 0;
var loop = true;
$('.chart-bar').each(function () {
barHeight = Math.floor(Math.random() * 100);
$(this).delay(1000).animate({
'height': barHeight + '%',
'min-height': '20px'},
700, function(){
if (loop) {
bars();
}
});
});
}
And then all I need was those two line of code added into my pause method:
pause: function() {
var $this = this;
$('#animation-3').find('*').stop(true, false);
$this.loop = false;
}
Thanks everyone for your time :)
I would like to replicate the same functionality as at ign.com, where the indicator bar fills up over time. I got it working but I got some sync issues after a while. So i'm open to suggestions to do it from scratch (I'm beginner with all this animation stuff).
This is the code.
function GoProgressBar() {
var $lineStatus = $('.featured-articles-line-status');
$lineStatus.css('width', '0px');
$lineStatus.animate({ width: '694px' }, 12000, 'linear', GoProgressBar);
};
function GoOverlay(width, isLast, currentWidth) {
var $overlayLine = $('.status-overlay');
if (isLast) {
$overlayLine.css('width', '0px');
return;
}
if (currentWidth) {
$overlayLine.css('width', currentWidth);
$overlayLine.animate({ width: width }, 700);
} else {
$overlayLine.css('width', '0px');
$overlayLine.animate({ width: width }, 700);
}
};
function ShowNextElement() {
var $elements = $('.element'),
$overlayLine = $('.status-overlay'),
$liElements = $('#elements li'),
width;
if (currentElement === elements[elements.length - 1]) {
currentWidth = $overlayLine.width() + 'px',
width = currentWidth + $($liElements[(elements.length - 1)]).outerWidth() + 'px';
GoOverlay(width, true, currentWidth);
currentElement = elements[0];
$elements.hide();
$(currentElement).fadeIn(1000);
return;
}
i = elements.indexOf(currentElement) + 1;
var currentTab = $liElements[(i - 1)],
currentWidth = $overlayLine.width();
if (currentWidth) {
width = currentWidth + $(currentTab).outerWidth() + 'px';
GoOverlay(width, false, currentWidth);
} else {
width = $(currentTab).outerWidth() + 'px';
GoOverlay(width, false, false);
}
currentElement = elements[i];
$elements.hide();
$(currentElement).fadeIn(1000);
}
Thanks!
http://jqueryui.com/progressbar/
You could try this..
There are more features in addition to this,check it out.
Might come useful :)
There are a wealth of ways in which you could do this.
You should have some kind of controller to manage the show and hide.
var Application = {
show : function() {
jQuery('.application-overlay').stop().animate({ top: 40 }, 500);
jQuery('.cf-ribbon').stop().animate({height: 1000},500);
},
hide : function() {
jQuery('.application-overlay').stop().animate({ top: -1200 }, 500);
jQuery('.cf-ribbon').stop().animate({height: 200},500);
}
};
Then you have your triggers : Application.show();
jQuery(document).ready(function() {
jQuery('.cf-speakers .span2 a').hover(function() {
jQuery('span',this).stop().animate({ opacity: 1.0 },100);
}, function() {
jQuery('span',this).stop().animate({ opacity: 0.0 },100);
});;
jQuery('.apply-now').click(function(e) {
Application.show();
e.stopPropagation();
e.preventDefault();
});
jQuery('body').click(function(e) {
var application = jQuery('.application-overlay');
if( application.has(e.target).length === 0)
Application.hide();
});
jQuery('.gallery a').click(function(e) {
var src = jQuery(this).attr('href');
jQuery('.main-container img').hide().attr('src', src).fadeIn('fast');
jQuery('.gallery a').each(function() {
jQuery(this).removeClass('active');
});
jQuery(this).addClass('active');
e.stopPropagation();
e.preventDefault();
});
});
Your css would of course come into play also but that can be left to you!
This should give you an example of what you need .. But you're already on the right track, sometimes there is merit in reusing other people code too you know! :)
What I would like to do, is to have a CSS style saved when a user resreshes the page. This is my jQuery code:
$(function() {
$("#slider").draggable({
axis: 'x',
containment: 'parent',
drag: function(event, ui) {
if (ui.position.left > 230) {
$("#well").fadeOut();
$( "#well" ).addClass( "disappear" );
} else {
// Apparently Safari isn't allowing partial opacity on text with background clip? Not sure.
// $("h2 span").css("opacity", 100 - (ui.position.left / 5))
}
},
stop: function(event, ui) {
if (ui.position.left < 231) {
$(this).animate({
left: 0
})
}
}
});
$('#slider')[0].addEventListener('touchmove', function(event) {
event.preventDefault();
var el = event.target;
var touch = event.touches[0];
curX = touch.pageX - this.offsetLeft - 73;
if(curX <= 0) return;
if(curX > 230){
$('#well').fadeOut();
}
el.style.webkitTransform = 'translateX(' + curX + 'px)';
}, false);
$('#slider')[0].addEventListener('touchend', function(event) {
this.style.webkitTransition = '-webkit-transform 0.3s ease-in';
this.addEventListener( 'webkitTransitionEnd', function( event ) { this.style.webkitTransition = 'none'; }, false );
this.style.webkitTransform = 'translateX(0px)';
}, false);
});
When the class "disappear" is added I would like to keep it added even if the page reloads. I found a useful post here, but since I am a beginner at Javascript, I am not sure how to use it in my case, and I would be really happy if someone could give me a personalized answer.
Thanks in advance!
After $( "#well" ).addClass( "disappear" ); add
localStorage['wellClass'] = 'disappear';
And in the line below $(function() { add
previousWellClass = localStorage['wellClass'];
if (previousWellClass) $('#well').addClass(previousWellClass);
This will do most of the work for you.
var setClass = JSON.parse(localStorage.getItem('setClass')) || {};
$.each(setClass, function () {
$(this.selector).addClass(this.className);
});
var addClassToLocalStorage = function(selector, className) {
setClass[selector + ':' + className] = {
selector: selector,
className: className
};
localStorage.setItem('setClass', JSON.stringify(setClass));
};
var removeClassFromLocalStorage = function(selector, className) {
delete setClass[selector + ':' + className];
localStorage.setItem('setClass', JSON.stringify(setClass));
};
Then you can just do this:
$("#well").fadeOut();
$("#well").addClass("disappear");
addClassToLocalStorage('#well', 'disappear');
// remove it removeClassFromLocalStorage('#well', 'disappear');
FIDDLE
Then you can reuse it if you need to later.
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?
Can someone give me a hand with this script? I wonder how to put in previous and next function? Start and stop function is working great. Hope that script is readable ok.
Another question.
Is it possible to make previous and next function like when you press previous bttn that script stops and you need to press play bttn to start it again?
Thanks for help.
<script type="text/javascript">
// SET THIS VARIABLE FOR DELAY, 1000 = 1 SECOND
var delayLength = 10000;
function doMove(panelWidth, tooFar) {
var leftValue = $("#mover").css("left");
// Fix for IE
if (leftValue == "auto") { leftValue = 0; };
var movement = parseFloat(leftValue, 10) - panelWidth;
if (movement == tooFar) {
$(".slide img").animate({
"top": -200
}, function() {
$("#mover").animate({
"left": 0
}, function() {
$(".slide img").animate({
"top": 80
});
});
});
}
else {
$(".slide img").animate({
"top": -200
}, function() {
$("#mover").animate({
"left": movement
}, function() {
$(".slide img").animate({
"top": 80
});
});
});
}
}
jQuery(function($){
var $slide1 = $("#slide-1");
var panelWidth = $slide1.css("width");
var panelPaddingLeft = $slide1.css("paddingLeft");
var panelPaddingRight = $slide1.css("paddingRight");
panelWidth = parseFloat(panelWidth, 10);
panelPaddingLeft = parseFloat(panelPaddingLeft, 10);
panelPaddingRight = parseFloat(panelPaddingRight, 10);
panelWidth = panelWidth + panelPaddingLeft + panelPaddingRight;
var numPanels = $(".slide").length;
var tooFar = -(panelWidth * numPanels);
var totalMoverwidth = numPanels * panelWidth;
$("#mover").css("width", totalMoverwidth);
$("#slider").append('Stop');
sliderIntervalID = setInterval(function(){
doMove(panelWidth, tooFar);
}, delayLength);
$("#slider-stopper").click(function(){
if ($(this).text() == "Stop") {
clearInterval(sliderIntervalID);
$(this).text("Start");
}
else {
sliderIntervalID = setInterval(function(){
doMove(panelWidth, tooFar);
}, delayLength);
$(this).text("Stop");
}
});
});
</script>