Animate.CSS Replay? - javascript

I have an animation using Animate.CSS that I would like to have replay if the user would like but what I have attempted does not work. Here is the code:
HTML:
<div class="img-center">
<img src="path.jpg" class="feature-image animated rotateInDownRight" />
</div>
<p class="textcenter"> </p>
<div class="img-center">
Replay
</div>
JS:
var $j = jQuery.noConflict();
$j("#replay").click(function() {
$j('.feature-image').removeClass('animated rotateInDownRight').addClass('animated rotateInDownRight');
});
I do know the script itself works as I can see it happen in Firebug however that animation doesn't animate again. How do I achieve this with Animate.CSS?

This is just a guess but it appears that jQuery isn't "finished" removing the class before it adds it back in. I know this makes NO sense, but it's how JavaScript works. It can call the next function in the chain before all the stuff from the first one is finished. I poked around the code on Animate.CSS's site and saw that they use a timeout in their animation function. You might try the same. Here's their code:
function testAnim(x) {
$('#animateTest').removeClass().addClass(x);
var wait = window.setTimeout( function(){
$('#animateTest').removeClass()},
1300
);
}
What this is doing is exactly like what you are doing except that it waits for the animation to finish, then removes the classes. That way when the other class is added back in, it is truely "new" to the tag. Here is a slightly modified function:
function testAnim(elementId, animClasses) {
$(elementId).addClass(animClasses);
var wait = window.setTimeout( function(){
$(elementId).removeClass(animClasses)},
1300
);
}
Notice two things: First this code would allow you to change what element gets the animation. Second, you remove the classes you added after 1300 milliseconds. Still not 100% there, but it might get you further down the road.
It should be noted that if there is already some animation classes on the object it might break this JS.

found the right answer at animate.css issue#3
var $at = $('#animateTest').removeClass();
//timeout is important !!
setTimeout(function(){
$at.addClass('flash')
}, 10);
Actually a simpler version can avoid using JQuery too.
el.classList.remove('animated','flash');
//timeout is important !!
setTimeout(function(){
el.classList.add('animated','flash');
}, 10);

I believe the issue here is that when I remove the class it was adding the class to quickly. Here is how I solved this issue:
(HTML is same as above question).
JS:
var $j = jQuery.noConflict();
window.setTimeout( function(){
$j('.feature-image').removeClass('animated rotateInDownRight')},
1300);
$j("#replay").click(function() {
$j('.feature-image').addClass('animated rotateInDownRight');
});
What I believe is happening is the jQuery code is removing and adding the class to quickly. Regardless of the reason this code works.

If you wish you can also give a try to this javaScript side development that support animate.css animations. Here is an example of usage.
//Select the elements to animate and enjoy!
var elt = document.querySelector("#notification") ;
iJS.animate(elt, "shake") ;
//it return an AnimationPlayer object
//animation iteration and duration can also be indicated.
var vivifyElt = iJS.animate(elt, "bounce", 3, 500) ;
vivifyElt.onfinish = function(e) {
//doSomething ...;
}
// less than 1500ms later...changed mind!
vivifyElt.cancel();
Take a look here

My answer is a trick to add/remove the css class with a tint delay:
$('#Box').removeClass('animated').hide().delay(1).queue(function() {
$(this).addClass('animated').show().dequeue();
});
Also you can test it without hide/show methods:
$('#Box').removeClass('animated').delay(1).queue(function() {
$(this).addClass('animated').dequeue();
});
I fill it works smooth in chrome but it works with more unexpected delay in FF, so you can test this js timeout:
$('#Box').removeClass('animated');
setTimeout(function(){
$('#Box').addClass('animated');
}, 1);

This solution relies on React useEffect, and it's rather clean, as it avoids manipulating the class names directly.
It doesn't really answers the OP question (which seems to be using jQuery), but it might still be useful to many people using React and Animate CSS library.
const [repeatAnimation, setRepeatAnimation] = useState<boolean>(true);
/**
* When the displayedFrom changes, replay the animations of the component.
* It toggles the CSS classes injected in the component to force replaying the animations.
* Uses a short timeout that isn't noticeable to the human eye, but is necessary for the toggle to work properly.
*/
useEffect(() => {
setRepeatAnimation(false);
setTimeout(() => setRepeatAnimation(true), 100);
}, [displayedFrom]);
return (
<div
className={classnames('block-picker-menu', {
'animate__animated': repeatAnimation,
'animate__pulse': repeatAnimation,
})}
...
)

Related

Replay jQuery function every 5 seconds

I want to replay my jquery function ChangeStats() every 5 seconds, it's currently doing sod all.
function ChangeStats() {
$('body').find('.admin-stats-big-figures-hidden').fadeIn(500);
setTimeout(function() {
$('body').find('.admin-stats-big-figures').fadeOut(500);
}, 500);
}
$(document).ready(function(){
setInterval(ChangeStats, 5000);
})();
Yes I have got the right class names.
No I haven't used underscores in my HTML.
I think it's something to do with my use of "find()", once the DOM has loaded and the function is set is it meant to traverse up the DOM tree instead of down?
EDIT:
Updated code, still not working.
HTML:
<span class="admin-stats-big-figures">%productCount%</span>
<span class="admin-stats-big-figures-hidden">hey</span>
Ok, I am going to go out on a limb and make several assumptions here; one is that you wish to cycle between two elements repeatedly, another is that you are using $(this) in the context of the window rather than a containing element. If either of these are incorrect then the following solution may not be suitable. However, let's give this a shot, eh?
1) You need to use setInterval rather than setTimeout to create a repeating call. You can of course "chain" your timeouts (ie: call the succeeding timeout from the code of the current timeout). This has some benefits in certain situations, but for now let's just assume you will use intervals rather than timeouts.
2) You call the find() jQuery method every time, which is a little unnecessary, especially if you will be repeating the actions so one idea would be to cache the lookup. If you are going to do that a custom object would be more suitable than separate global variables.
3) Some flexibility in terms of starting and stopping the animation could be provided. If we use a custom object as mentioned in (2) then that can easily be added.
4) You are using fadeIn and fadeOut, however if you wish the items to cycle then fadeToggle may be your best solution as it will simply allow you to do exactly that, toggle, without needing to check the current opacity state of the element.
5) Finally in my example I have provided a little extra "padding HTML" in order for the example to look good when run. Fading in jQuery will actually set the faded item to a CSS display of "none" which results in the content "jumping about" in this demo, so I have used some div's and a couple of HTML entity spaces to keep the formatting.
Ok, after all that here is the code..
// your custom animation object
var myAnim = {
// these will be cached variables used in the animation
elements : null,
interval : null,
// default values for fading and anim delays are set to allow them to be optional
delay : { fade: 500, anim: 200 },
// call the init() function in order to set the variables and trigger the animation
init : function(classNameOne, classNameTwo, fadeDelay, animDelay) {
this.elements = [$("."+classNameOne),$("."+classNameTwo)];
// if no fade and animation delays are provided (or if they are 0) the default ones are used
if (animDelay) this.delay.anim = animDelay;
if (fadeDelay) this.delay.fade= fadeDelay;
this.elements[0].fadeOut(function(){myAnim.start()});
},
// this is where the actual toggling happens, it uses the fadeToggle callback function to fade in/out one element once the previous fade has completed
update : function() {
this.elements[0].fadeToggle(this.delay.anim,function(el,delay){el.fadeToggle(delay)}(this.elements[1],this.delay.anim));
},
// the start() method allows you to (re)start the animation
start : function() {
if (this.interval) return; // do nothing if the animation is currently running
this.interval = setInterval(function(){myAnim.update()},this.delay.fade);
},
// and as you would expect the stop() stops it.
stop : function () {
if (!this.interval) return; // do nothing if the animation had already stopped
clearInterval(this.interval);
this.interval = null;
}
}
// this is the jQuery hook in order to run the animation the moment the document is ready
$(document).ready(
function(){
// the first two parameters are the two classnames of the elements
// the last two parameters are the delay between the animation repeating and the time taken for each animation (fade) to happen. The first one should always be bigger
myAnim.init("admin-stats-big-figures","admin-stats-big-figures-hidden",500,200);
}
);
OK, so now we need the HTML to compliment this (as I say I have added a little formatting):
<div><span class="admin-stats-big-figures">One</span> </div>
<div><span class="admin-stats-big-figures-hidden">Two</span> </div>
<hr/>
<input type="button" value="Start" onclick="myAnim.start()"/> | <input type="button" value="Stop" onclick="myAnim.stop()"/>
I have also provided buttons to stop/start the animation. You can see a working example at this JSFiddle - although the stop/start buttons are not working (presumably something specific to JSFiddle) they do work when in context though.
Here im gonna just replace your $(this). and maybe it'll work then.. also using callback.
function ChangeStats() {
$('body').find('.admin-stats-big-figures-hidden').fadeIn(500, function() {
$('body').find('.admin-stats-big-figures').fadeOut(500);
});
}
$(document).ready(function(){
setTimeout('ChangeStats()', 5000);
});

Mouseleave does not work with .each and delay?

I have written some code to change the colour of each letter inside an a tag and show a pop up when you hover the link.
The mouseenter function works fine but when you hover off the link I would like to do the reverse of the original change ( so change back to the origional colour ).
I take the delay out of the leave function it works but the effect is not as nice. I am confused as to why this works on the enter but not on the leave?
Another thing to mention is when it does change colour back to the grey the mouseenter function does not work again, which is kind of annoying.
Here is a link to the site so you can see what I am talking about and the link is the one at the bottom that says "Touch Marketing"
http://dev.touch-akl.com/colin/
Any help please?
My jQuery looks like this
$('#copyright a').mouseenter(function(){
var $letters = $(this).find('span'),
$sayhi = $(this).find('img'),
delay = 0;
$sayhi.animate({top:-30, 'opacity':1}, 500, "easeInOutExpo");
$letters.each(function(){
$(this).delay(delay).queue(function(){
$(this).css({'color':'#333'});
});
delay+=35;
}); // end each
}).mouseleave(function(){
var $letters = $(this).find('span'),
delay = 0;
$letters.each(function(){
$(this).delay(delay).queue(function(){
$(this).css({'color':'#333'});
});
delay+=35;
});
}); // end leave
jQuery .queue() is complicated to use correctly so unless you need to interact with other things in the jQuery animation queue, it is often much, much simpler to just use setTimeout() like this. You also should make delay a local variable so it isn't an implicit global variable.
}).mouseleave(function(){
var delay = 0;
$(this).find('span').each(function(){
var item = $(this);
setTimeout(function(){
item.css({'color':'#333'});
}, delay);
delay+=35;
});
}); // end leave
Most likely the problem is with the closure created by your functions in mouseenter and mouseleave. They're both referencing the same delay variable. You might want to separate them:
delayEnter = 0;
delayLeave = 0;

jQuery selector :not(:animated)

We're trying to make sure our JavaScript menu, which loads content, doesn't get overrun with commands before the content in question loads and is unfurled via .show('blind', 500), because then the animations run many times over, and it doesn't look so great. So I've got about six selectors that look like this:
("#center_content:not(:animated)")
And it doesn't seem to be having any effect. Trying only :animated has the expected effect (it never works, because it doesn't start animated), and trying :not(div) also has this effect (because #center_content is a div). For some reason, :not(:animated) seems not to be changing the results, because even when I trigger the selector while the div in question is visibly animated, the code runs. I know I've had success with this sort of thing before, but the difference here eludes me.
$("#center_content:not(:animated)").hide("blind", 500, function () {
var selector_str = 'button[value="' + url + '"]';
//alert(selector_str);
var button = $(selector_str);
//inspectProperties(button);
$("#center_content:not(:animated)").load(url, CenterContentCallback);
if (button) {
$("#navigation .active").removeClass("active");
button.addClass("active");
LoadSubNav(button);
}
});
I hope this provides sufficient context. I feel like the second selector is overkill (since it would only be run if the first selector succeeded), but I don't see how that would cause it to behave in this way.
Here's the snippet that seemed to be working in the other context:
function clearMenus(callback) {
$('[id$="_wrapper"]:visible:not(:animated)').hide("blind", 500, function() {
$('[id^="edit_"]:visible:not(:animated)').hide("slide", 200, function() {
callback();
});
});
}
Here, the animations queue instead of interrupt each other, but it occurs to me that the selector still doesn't seem to be working - the animations and associated loading events shouldn't be running at all, because the selectors should fail. While the queueing is nice behavior for animations to display, it made me realize that I seem to have never gotten this selector to work. Am I missing something?
Sometimes it's helpful to use .stop() and stop the current animation before you start the new animation.
$("#center_content").stop().hide("blind", 500, function () {});
Really depends on how it behaves within your environment. Remember that .stop() will stop the animation as it was (eg. halfway through hiding or fading)
I don't know if I understand it correctly, but if you want to make sure the user doesn't trigger the menu animation again while it's currently animating(causing it to queue animations and look retarded, this works and should help. I use an if-statement. And before any mouseover/off animation I add .stop(false, true).
$('whatever').click(function(){
//if center_content is not currently animated, do this:
if ($("#center_content").not(":animated")) {
$(this).hide(etc. etc. etc.)
}
//else if center_content IS currently animated, do nothing.
else {
return false;}
});
another example i found elsewhere:
if($("#someElement").is(":animated")) {
...
}
if($("#someElement:animated").length) {
...
}
// etc
then you can do:
$("#showBtn").attr("disabled", $("#someElement").is(":animated"));

A sticky situation for jQuery slideshow

I'm required to develop a slideshow (not an existing one) with jQuery. I was able to change picture with a function that I created named changePic (takes an image link). It incorporates the fading animation from the jQuery library.
For the slideshow I'm trying to use a while loop. It kind of works, except that it doesn't wait for the animation to finish.
How do I, a) wait for the animation to finish, b) delay the changing picture so it display the picture for a couple of seconds?
Also tried Settimeout, and it doesn't work.
Edit:
Basically changing image is like this:
function changePic(imglink){
var imgnode = document.getElementById("galleryimg");
$(imgnode).fadeTo(500, 0, function(){
$(imgnode).attr("src", imglink);
$(imgnode).fadeTo(1000, 1);
})
}
and the slideshow code is like this, but obviously it shouldn't.
function slideshow(gallerylinks){
var i=0;
while (i<gallerylinks.length){
changePic(gallerylinks[i]);
i++;
}
}
You could always try ditching the while loop, and going with a perpetually recursive function...
on the .animate, you could add a timeout function (at whatever interval) that calls the changePic function. As I have no idea what your code looks like, I will provide a fantastically generic outline.
/* array of imgUrls */
var imgUrls = new Array(); //populate it however
changePic(slideToShowIndex, fadeOutSpeed, fadeInSpeed, slideDelay)
{
$('#slideHolder').animate({ opacity: 0}, fadeOutSpeed , function(){
$('#slideHolder').attr('src', imgUrls[slideToShowIndex]);
$('#slideHolder').animate({ opacity: 1 }, fadeInSpeed, function() {
setTimeout(function() { changePic(slideToShowIndex+1, fadeOutSpeed, fadeInSpeed, slideDelay);}, slideDelay});
});
}});
}
$(document).ready(function() {
changePic(0, 5000, 5000, 10000);
});
This should (in theory) fade the image out, swap it with the new one, and fade it in (both taking 5 seconds) and then adding a delay to call itself with the next slide index in 10 seconds.
This is in no way perfect, but does outline the general idea. Since we have no idea what your code looks like, I can only assume your setTimeout was in the wrong spot. Doing it like this will make sure that the animation has finished before the timeout is set. This guarantees that the slide wont change until after the animation has changed.
of course you could always use a combination of the ':not(:animated)' selector and a setInterval to achieve much the same effect.
EDIT: made a slight change to stack the animations properly. The thoery behind this still works even with the OPs addition of code.
You could have provided more details or example code but have a look at stop() and delay() functions.

Resizing images on mouse over (Javascript/MooTools)

I've built a webpage that's supposed to increase the size of images onmouseover.
I'm not replacing the images with bigger ones but rather "stretch" the existing ones because of system limitations.
Here's the webpage:
http://www.catmoviez.com/IMDBQueries.aspx
You can see that the movie images get bigger when you're on them.
Problem is when I move my mouse too quick that sometimes an image gets stuck open or it causes inifinite flickering.
attached is also the code I'm using for the resize:
function resizeImage(elem,width,height){
var myEffect = new Fx.Morph(elem, {duration: 350});
myEffect.start({'height': height,'width': width});
}
First thing, set this variable outside your functions
var imagegrow
And then mouseover this
function () {
imagegrow = setTimeout(function(){ resizeImage(elem,width,height); },1000);
}
And the mouseout this:
function () {
clearTimeout(imagegrow);
}
Adjust the 1000 number to suit your preferred delay (it's in milliseconds). I'd write the whole code for you, but I haven't used MooTools for a while.
Comment if you have any questions
Faruz, Gaussie is right you need to use a timeout. However, consider using mootools' addEvent function as described in the mootools docs as well as the $$ function which will allow you to achieve something much more elegant, along the lines of:
window.addEvent('domready', function() {
$$("tr td input").addEvent("mouseover", function() {
//anonymous function like Gaussie's here
});
});
Note that this isn't the exact code, it will take some modification but it is cleaner and should be more efficient then setting the onmouseover property of every image. Also, remember this goes in the head of your HTML document.

Categories

Resources