I have this pseudo code. I need to check that all animations have ended.
My function with many animations inside:
function animateText($element, $callback) {
var $this = $element;
var $wordList = $this.text().split("");
$this.text("");
$this.css('opacity', 1);
$.each($wordList, function (idx, elem) {
var newEL = $("<span/>").text(elem).css({
opacity: 0
});
newEL.appendTo($this);
newEL.delay(idx * 125);
newEL.animate({
opacity: 1
}, 500, 'swing', function () {
// now are animations are done
if ($wordList.length === idx + 1) {
$callback();
}
});
});
};
We started!
animateText('#myText', function(){
console.log('ALL ANIMATIONS ARE DONE!');
});
I need to know when all the animations have ended and after call my callback. This approach works, but is possible to write it somehow better?
Related
I am not sure how to ask this question. I made a jQuery function for a banner.
$(document).ready(function() {
ionanim();
setInterval(ionanim, 12000);
function ionanim() {
$(function () {
$('.ion1anim').fadeIn(500, function () {
$(this).delay(5000).fadeOut(500);
});
});
$(function () {
$('.ion2anim').delay(6000).fadeIn(500, function () {
$(this).delay(5000).fadeOut(500);
});
});
};
});
Link for the full animation : http://jsfiddle.net/L8XHL/11/
But with each intervatl on the setInverval the animations go close to each other after some time they overlap each other.
Did i do anything wrong?
Intervals and animations aren't exact enough to handle the timing that you require. I'd suggest using a self-executing function instead so that it will never overlap.
Also, you are over-using the document ready handler. Please stop.
http://jsfiddle.net/L8XHL/13/
$(document).ready(function () {
ionanim();
function ionanim() {
$('.ion1anim').fadeIn(500, function () {
$(this).delay(5000).fadeOut(500, function () {
$('.ion2anim').fadeIn(500, function () {
$(this).delay(5000).fadeOut(500,ionanim);
});
});
});
}
});
I would further modify this to work more like a slider so that you can add an infinite number of items without having a huge pyramid of code.
http://jsfiddle.net/L8XHL/17/
$(document).ready(function () {
$(".ionbanner .bottom div").first().siblings().hide();
anim();
function anim() {
var curr = $(".ionbanner .bottom :visible");
var next = curr.next();
if (next.length == 0) {
next = curr.siblings().first();
}
curr.delay(5000).fadeOut(500,function(){
next.fadeIn(500,anim);
});
}
});
Or you could try something like this: http://jsfiddle.net/L8XHL/16/
$(document).ready(function() {
var anim1 = function() {
$('.ion1anim').fadeIn(1000, anim1Callback);
},
anim1Callback = function() {
$('.ion1anim').fadeOut(1000, anim2);
},
anim2 = function() {
$('.ion2anim').fadeIn(1000, anim2Callback);
},
anim2Callback = function() {
$('.ion2anim').fadeOut(1000, anim1);
};
anim1();
});
I want to put a little delay for onmouseout event for a group of sub items in a drop down menu. But I don't want to use css transitions.
I set it with .hover() and setTimeout method but I wanted to put it only for a specific elements in menu - in this case just for sub items so I used if else statement for them. I have no idea why this if else statement does't work.
Here is my javascript code:
var selectors =
{
element: '.main-menu li:has(ul)'
}
var opacityWorkaround = function ($element, value) {
$element.css('opacity', value);
};
var getAnimationValues = function (visible) {
var result = {
visibility: visible
};
result.opacity = visible === 'visible' ? 1 : 0;
};
var mouseActionHandler = function ($element, visible, opacityValue) {
$element
.stop()
.css("visibility", 'visible')
.animate(getAnimationValues(visible),
3000,
function () {
$(this).css("visibility", visible);
opacityWorkaround($(this), opacityValue);
});
};
var onMouseIn = function () {
var $submenu = $(this).children("ul:first");
if ($submenu) {
mouseActionHandler($submenu, 'visible', 1);
}
};
var onMouseOut = function () {
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($submenu) {
mouseActionHandler($submenu, 'hidden', 0);
} else if ($global) {
setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}
};
$(selectors.element).hover(onMouseIn, onMouseOut);
I put 1500ms delay and the $global variable is referring to sub items in menu that I want to make disapear with that delay. I wanted to achieve this when user move mouse cursor out of 'some items >' tab.
Here is my fiddle example.
http://jsfiddle.net/PNz9F/1/
Thanks in advance for any help!
In the example you have in your question $submenu always has a value so the else if statement is never run. You can check for a class instead.
var timeout;
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($(this).hasClass('menu-item')) {
mouseActionHandler($submenu, 'hidden', 0);
mouseActionHandler($global, 'hidden', 0);
clearTimeout(timeout);
} else if ($(this).hasClass('global')) {
timeout = setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}
you should be able to just use the :hover selector in your code to check whether the user is hovering over the element or not and run code accordingly
i wrote a jquery plugin to make a div auto scroll,i used function setInterval to make the div stop for a while and then keeps on scroll.
here is the code
(function($){
"use strict";
function scrolltotop(obj,height,speed){
var ch=parseInt($(obj).css("margin-top"))+29;
$(obj).parent().find(".moving").remove();
$(obj).after($(obj).clone().addClass("copy"));
$(obj).addClass("moving").removeClass("copy").animate({
"margin-top":-27
},speed);
loop=setInterval(function(){
ch+=27;
if(ch < height+27){
$(obj).animate({
"margin-top":-ch
},speed,function(){
loop;
})
}else{
clearInterval(loop);
scrolltotop($(obj).next(".copy"),height,speed);
}
},4000)
}
$.fn.extend({
autoscroll: function(options) {
var defaults = {
speed: 1000,
scroller : '#scroller',
scroller_container : '#scroller_container'
}
var options = $.extend(defaults, options);
var height=$(options.scroller).height();
var stop=stopscroll();
//console.log(height)
scrolltotop(options.scroller,height,options.speed);
},
});
}(jQuery));
$("#list2").autoscroll({scroller:"#list2",scroller_container:"#container_2"});
it works well,but idont know how to make the div stop scroll after i init the plugin.
if I understand the problem you want to move the div scroll line by line waiting 4s until you reach the end.
I simplified your scrolltotop function
function scrolltotop(obj,height,speed){
var ch = 0;
var loop = setInterval(function(){
ch+=27;
$('#container_2').animate({
scrollTop: ch
}, speed);
if(ch >= height){
console.log('Out of loop');
clearInterval(loop);
}
},4000);
}
You can see a working example here http://jsfiddle.net/jCw3y/
May be you can adapt my code to use it in your plugin.
(You're using "use strict". Remember to declare javascript variables always. var loop, var ch e.t.c)
To stop manually you can save the intervalId and call clearInterval when you want.
Check this example: http://jsfiddle.net/ccR4t/
And finally, another example with pure jquery. Using animate and stop functions to control all.
(function ($) {
"use strict";
function scrolltotop($container, options) {
$container.animate({
scrollTop: options.scrollerHeight
}, options.speed, function () {
console.log('Animation completed');
});
}
$.fn.extend({
autoscroll: function (options) {
var $me = this;
var defaults = {
speed: 1000,
scroller_container: '#scroller_container',
scroller: '#list2'
}
var options = $.extend(defaults, options);
options.scrollerHeight = $(options.scroller).height();
scrolltotop($me, options);
},
});
}(jQuery));
$("#container_2").autoscroll({
scroller: '#list2',
speed: 10000
});
// stop scroll after 4 sec
setTimeout(function () {
$('#container_2').stop();
alert('scroll manually stopped')
}, 4000);
Working example:
http://jsfiddle.net/c8Ns8/
What I need to achieve is if we click on submit button, there is particular div should show up.
Here is my code:
http://jsfiddle.net/7tn5d/
But if I click on submit button multiple times, the function calls sort of queue up and run one after other.
Is there a way to invalidate other onclicks when current animation is running?
Code:
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", {}, 1000);
animating = 0;
});
});
To prevent it from performing the action multiple times, simple cease the previous animation. So:
$('#submit_cont').stop().show("blind",{},1000);
However, I have noticed that you have attempted to prevent the animation from running, if an animation is already running. Although it takes 1 second or 1000 milliseconds to show the div, the execution of the condition does not pause until the animation is complete. You must define a function to run after the animation is complete, like so:
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", 1000, function() { animation = 0; });
});
});
Hope that helped...
You almost got it right with the semaphore! It's just that, in jQuery's show(), you would have to put the semaphore reset as an argument. Here's the fixed version - http://jsfiddle.net/snikrs/xe5A3/
animating = 0;
doneanim = 0;
$(function () {
$("#submit_tab").click(function (e) {
if (animating == 1) return;
animating = 1;
$("#submit_cont").show("blind", 1000, function() {
animating = 0;
});
});
});
You can use the :animated selector to check:
$(function () {
$("#submit_tab").click(function (e) {
var $cont = $("#submit_cont");
if (!$cont.is(':animated')) {
$cont.show("blind", {}, 1000);
}
});
});
Now if you stick with the external semaphore idea then its better to stick that on the elemnt with .data() instead of using a global variable:
$(function () {
$("#submit_tab").click(function (e) {
var $cont = $('#submit_cont'),
animating = $cont.data('isAnimating');
if (animating) {
return;
} else {
$cont.data('isAnimating', 1);
$("#submit_cont").show("blind", 1000, function() { $cont.data('isAnimating', 0); });
}
});
});
Something like this (see documentation) :)
$("#submit_cont").show("blind", function(){
animating = 0;
});
You can add a $("#submit_cont").clearQueue(); after the animation finished :
$("#submit_tab").click(function (e) {
$("#submit_cont").show("blind", 1000, function() {
$("#submit_cont").clearQueue();
});
});
Updated JSFiddle
I found a different solution for this, which in my opinion looks cleaner:
var tab = $("submit_tag");
tab.on("click", function(){
var cont = $("submit_cont");
var animating = tab.queue("fx").length;
if(animating === 0){
cont.show("blind", {}, 1000);
}
});
Can anybody help me on this one...I have a button which when is hovered, triggers an action. But I'd like it to repeat it for as long as the button is hovered.
I'd appreciate any solution, be it in jquery or pure javascript - here is how my code looks at this moment (in jquery):
var scrollingposition = 0;
$('#button').hover(function(){
++scrollingposition;
$('#object').css("right", scrollingposition);
});
Now how can i put this into some kind of while loop, so that #object is moving px by px for as #button is hovered, not just when the mouse enters it?
OK... another stab at the answer:
$('myselector').each(function () {
var hovered = false;
var loop = window.setInterval(function () {
if (hovered) {
// ...
}
}, 250);
$(this).hover(
function () {
hovered = true;
},
function () {
hovered = false;
}
);
});
The 250 means the task repeats every quarter of a second. You can decrease this number to make it faster or increase it to make it slower.
Nathan's answer is a good start, but you should also use window.clearInterval when the mouse leaves the element (mouseleave event) to cancel the repeated action which was set up using setInterval(), because this way the "loop" is running only when the mouse pointer enters the element (mouseover event).
Here is a sample code:
function doSomethingRepeatedly(){
// do this repeatedly when hovering the element
}
var intervalId;
$(document).ready(function () {
$('#myelement').hover(function () {
var intervalDelay = 10;
// call doSomethingRepeatedly() function repeatedly with 10ms delay between the function calls
intervalId = setInterval(doSomethingRepeatedly, intervalDelay);
}, function () {
// cancel calling doSomethingRepeatedly() function repeatedly
clearInterval(intervalId);
});
});
I created a sample code on jsFiddle which demonstrates how to scroll the background-image of an element left-to-right and then backwards on hover with the code shown above:
http://jsfiddle.net/Sk8erPeter/HLT3J/15/
If its an animation you can "stop" an animation half way through. So it looks like you're moving something to the left so you could do:
var maxScroll = 9999;
$('#button').hover(
function(){ $('#object').animate({ "right":maxScroll+"px" }, 10000); },
function(){ $('#object').stop(); } );
var buttonHovered = false;
$('#button').hover(function () {
buttonHovered = true;
while (buttonHovered) {
...
}
},
function () {
buttonHovered = false;
});
If you want to do this for multiple objects, it might be better to make it a bit more object oriented than a global variable though.
Edit:
Think the best way of dealing with multiple objects is to put it in an .each() block:
$('myselector').each(function () {
var hovered = false;
$(this).hover(function () {
hovered = true;
while (hovered) {
...
}
},
function () {
hovered = false;
});
});
Edit2:
Or you could do it by adding a class:
$('selector').hover(function () {
$(this).addClass('hovered');
while ($(this).hasClass('hovered')) {
...
}
}, function () {
$(this).removeClass('hovered');
});
var scrollingposition = 0;
$('#button').hover(function(){
var $this = $(this);
var $obj = $("#object");
while ( $this.is(":hover") ) {
scrollingposition += 1;
$obj.css("right", scrollingposition);
}
});