jQuery animate() producing wild results - javascript

I'm pretty new to jQuery and I've been fooling around with its animate() but I've run into two problems. My code below is basically supposed to expand the characterwindow when the mouse is hovering over it, changing the text inside once it's expanded. Then characterwindow should retract back to it's original size when the mouse goes off the now larger version of it, changing the text as it starts to retract.
My problem is that this is just generally screwy as hell. If you just zoom your mouse in and out a few times it constantly expands and retracts for a bit without you doing anything, and the text flickers when you go in and out and doesn't even disappear before the retraction like it should.
I tried using the callback parameter for the mouseover, but sometimes the text would show up before the animation actually finished.
Is this a limitation of jQuery, JavaScript, my server, my client, or what? If there's a better/more efficient way to implement this I'd be grateful if you showed it.
<html>
<body>
<div id="characterwindow" style="width:80px;height:23px;border-radius:15px;">
<div id="characterwindowgraphic" style="border-radius:15px;background-color:#1C1C1C;height:23px;width:80px;">
<center><p1 id="characterwindowtext" style="color:white;">Character</p1></center>
</div></div>
<script>
$("#characterwindow").mouseover(function() {
setTimeout(function(){$("#characterwindowtext").html("Character<br><br>Name<br>Details");},500);
$("#characterwindow").css({"width":"300px","height":"250px"});
$("#characterwindowgraphic").animate({
width:'300px',
height:'250px'
},500);
});
$("#characterwindow").mouseleave(function() {
$("#characterwindowtext").text("Character");
$("#characterwindow").css({"width":"80px","height":"23px"});
$("#characterwindowgraphic").animate({
width:'80px',
height:'23px'
},500);
});
</script>
</body>
</html>

Your animation are getting queued. So it will not start another animation before the first one is done.
To stop that you can use stop() before the animation like that :
$("#characterwindowgraphic").stop().animate({
width:'300px',
height:'250px'
},500);
it will clear the queue.
Or you can call your animate like that :
$("#characterwindowgraphic").stop().animate({
width:'300px',
height:'250px'
},{duration : 500, queue : false});
Also as winterblood said in the comments, use mouseleave and mouseenter.
Here's a fiddle : http://jsfiddle.net/U6S3S/
EDIT : Also, instead of using a timeout for the html, use animate callback function. If you take the first method, it will be like that :
$("#characterwindowgraphic").stop().animate({
width:'300px',
height:'250px'
},500, function(){
$("#characterwindowtext").html("Character<br><br>Name<br>Details")
});
And if you choose the second method, it will be like that :
$("#characterwindowgraphic").stop().animate({
width:'300px',
height:'250px'
},{
duration : 500,
queue : false,
complete : function(){
$("#characterwindowtext").html("Character<br><br>Name<br>Details")
}
});

Related

How to make the show / hide transaction in jquery slower?

Currently I am using one pic for mouse on state, one pic for mouse off state, so , what I am doing is when the mouse is over the pic, it hide, than show the other one, for the detail , please have a look at my site.
http://rsvp.com.hk/tmp_web/
You can see the effect when mouseover the right side phone, but the transaction time is very quick, how can I slow down? Thanks
Here is my code
$(".phone.off").on("mouseover",function(){
$(this).hide();
$(".phone.on").show();
});
$(".phone.on").on("mouseover",function(){
$(this).hide();
$(".phone.off").show();
});
phone.on is the image of mouseover, and phone.off is on leave, the animation right now is correct but it go too fast, what I would like is slow it down. That 's all , thanks for helping.
Hhmm bad idea. Try using CSS3 animations, that's what they are for. Javascript should be second choice.
Although #micea is answering your question, maybe you are looking for something like that, for a smoother behaviour:
$(".phone.on").fadeIn(1000);
or
$(".phone.on").fadeOut(1000);
Where the number represents the duration of the animation.
Just add time to the .show() and .hide() like this
$(".phone.off").on("mouseover",function(){
$(this).hide('1000');
$(".phone.on").show('1000');
});
$(".phone.on").on("mouseover",function(){
$(this).hide('1000');
$(".phone.off").show('1000');
});
Where 1000 is one second, change to whatever you like.

Adding a SetTimeout and transition to jQuery Show / Hide

I am trying to add a SetTimeout and animation type transition to jQuery Show / Hide call. Below is how I currently have it but am wanting to add the a specific amount of time the 'show' div remains displayed before it reverts back to the orginal #bg_dv. I also want to add animated transitions between the effects if possible.
function tilt(){
$("#area1").click(function(){
$("#bg_div").hide();
$("#bg_skew").show(); // I would like to show this Div for about 5 seconds
// and then have original back.
});
}
$("#bg_div").hide(0).delay(5000).show(0);
$("#bg_skew").show(0).delay(5000).hide(0);
If you want animations, you can replace the calls to hide() and show() with something appropriate. For example fadeIn() and fadeOut().
$("#area1").click(function(){
$("#bg_div").fadeOut('fast',function(){
$("#bg_skew").delay(5000).fadeIn('fast');
});
});
In order to prevent caching of multiple clicks and have the animation play many times
you should also take a look at
.stop(true,true)
before any animation.Also take a look at this animation option - property.
{cache:false}
it's so simple. just put milliseconds in show.delay(5000) it will delay it for 5 seconds.
syntax:
$(selector).delay(speed)
speed: time in millsecnds e.g. 5000 for 5 seconds.
$(selector).show(speed,easing,callback)
speed: here put time in milliseconds like 1000 for 1 second.
easing: it defins speed of elements at different points i.e. "linear" "swing".
callback: here you can put your function it will execute after completing show method. For example when you will click button to show image after showing image it will exexcute funxtion e.g. .show(1000,function(){alert("hello")};);
Hope i helped you.

Trigger event on animation complete (no control over animation)

I've a scenario that requires me to detect animation stop of a periodically animated element and trigger a function. I've no control over the element's animation. The animation can be dynamic so I can't use clever setTimeout.
Long Story
The simplified form of the problem is that I'm using a third party jQuery sliding banners plugin that uses some obfuscated JavaScript to slide banners in and out. I'm in need of figuring out a hook on slideComplete sort of event, but all I have is an element id. Take this jsfiddle as an example and imagine that the javascript has been obfuscated. I need to trigger a function when the red box reaches the extremes and stops.
I'm aware of the :animated pseudo selector but I think it will need me to constantly poll the required element. I've gone through this, this, and this, but no avail. I've checked jquery promise but I couldn't figure out to use that in this scenario. This SO question is closest to my requirements but it has no answers.
P.S. Some more information that might be helpful:
The element isn't created by JavaScript, it is present on page load.
I've control over when to apply the plugin (that makes it periodically sliding banner) on the element
Most of the slideshow plugins I have used use changing classes at the end of the animation... You could extend the "addClass" method of jQuery to allow you to capture the class change as long as the plugin you use is using that method like it should:
(function($){
$.each(["addClass","removeClass"],function(i,methodname){
var oldmethod = $.fn[methodname];
$.fn[methodname] = function(){
oldmethod.apply( this, arguments );
this.trigger(methodname+"change");
return this;
}
});
})(jQuery);
I threw together a fiddle here
Even with obfuscated code you should be able to use this method to check how they are sending in the arguments to animate (I use the "options" object when I send arguments to animate usually) and wrap their callback function in an anonymous function that triggers an event...
like this fiddle
Here is the relevant block of script:
(function($){
$.each(["animate"],function(i,methodname){
var oldmethod = $.fn[methodname];
$.fn[methodname] = function(){
var args=arguments;
that=this;
var oldcall=args[2];
args[2]=function(){
oldcall();
console.log("slideFinish");
}
oldmethod.apply( this, args );
return this;
}
});
})(jQuery);
Well since you didn't give any indication as to what kind of animation is being done, I'm going to assume that its a horizontal/vertical translation, although I think this could be applied to other effects as well. Because I don't know how the animation is being accomplished, a setInterval evaluation would be the only way I can guess at how to do this.
var prevPos = 0;
var isAnimating = setInterval(function(){
if($(YOUROBJECT).css('top') == prevPos){
//logic here
}
else{
prevPos = $(YOUROBJECT).css('top');
}
},500);
That will evaluate the vertical position of the object every .5 seconds, and if the current vertical position is equal to the one taken .5 seconds ago, it will assume that animation has stopped and you can execute some code.
edit --
just noticed your jsfiddle had a horizontal translation, so the code for your jsfiddle is here http://jsfiddle.net/wZbNA/3/

Javascript sliding Image Gallery - no jQuery

Does anyone have any tips on making a pure JS image slider? I am looking to have it pause after each image and restart after going through all the images. All that I can find are jQuery plugins and I am look to do this with only JS.
i'd go for something like this:
var sliderTool = {
_totalItems : 0,
_visibleItems : 6,
_currentOffset : 0,
_timeout : null,
next : function(){
...
},
prev : function(){
...
},
play : function(){
...
},
pause : function(){
...
}
};
as a base.
every time you set timeout, save it into the _timeout field so you can clearTimeout(sliderTool._timeout) whenever you want.
next and prev can contain animations or just a simple image replacement. you can add a separate timeout for animation and for intervals between slides.
you can add an "add()" method to the sliderTool and on window.load or "body onload" add all the images and then run the start() method. you can also dynamically add images after page is loaded
maybe also add init() for autoloading and basic setup.
again, this is a basic draft of a possible solution. once you get running you'll probably run into more specific questions. Overall, as an approach, i recommend trying to come up with some solution first before asking for a general advice ;)

setTimeout speeds up with multiple tabs

I’m having a setTimeout problem similar to this one. But that solution doesn't help me since I can’t use php in my file.
My site has a slider with a list of images that move every 8 seconds.However, when I have opened a few tabs in the browser and then switch back again, it goes nuts.
The slider proceeds to move the images one after the other immediately without the 8 second timedelay.
I'm only seeing it in Chrome and the latest Firefox.
**EDIT: I checked with console.log() and the setTimeout returns the same number before and after the clearTimeout. Not sure why. Maybe that also has something to do with it? **
EDIT 2: I added a fiddle: http://jsfiddle.net/Rembrand/qHGAq/8/
The code looks something like:
spotlight: {
i: 0,
timeOutSpotlight: null,
init: function()
{
$('#spotlight .controls a').click(function(e) {
// do stuff here to count and move images
// Don't follow the link
e.preventDefault();
// Clear timeout
clearTimeout(spotlight.timeOutSpotlight);
// Some stuff here to calculate next item
// Call next spotlight in 8 seconds
spotlight.timeOutSpotlight = setTimeout(function () {
spotlight.animate(spotlight.i);
}, 8000);
});
// Select first item
$('#spotlight .controls a.next:first').trigger('click');
},
animate: function(i)
{
$('#spotlight .controls li:eq(' + (spotlight.i) + ') a.next').trigger('click');
}
}
From the jQuery documentation:
Because of the nature of requestAnimationFrame(), you should never
queue animations using a setInterval or setTimeout loop. In order to
preserve CPU resources, browsers that support requestAnimationFrame
will not update animations when the window/tab is not displayed. If
you continue to queue animations via setInterval or setTimeout while
animation is paused, all of the queued animations will begin playing
when the window/tab regains focus. To avoid this potential problem,
use the callback of your last animation in the loop, or append a
function to the elements .queue() to set the timeout to start the next
animation.
I finally found my answer and it’s not at all what I was expecting.
It seems the culprit is jQuery’s .animate(), which I use to move the images in the slider.
I calculate and move my images positions with this:
$('.spotlight-inner')
.animate(
{ left: scrollToVal },
{duration: 'slow'}
)
;
Now the problem seems to be that in some browsers, after you switch to a new tab and back, jQuery’s .animate() saves up the animations and fires them all at once. So I added a filter to prevent queueing. That solutions comes from CSS-Tricks.com :
$('.spotlight-inner')
.filter(':not(:animated)')
.animate(
{ left: scrollToVal },
{duration: 'slow'}
)
;
The first slide you see when you go back can act a little jumpy but it’s better than the superspeed carousel from before.
Fiddle with the full code here
There is an easier way using the jquery animate queue property:
$(this).animate({
left: '+=100'
}, {duration:500, queue:false});
I don't know if this will help you, but it helped me with my slideshow. What I did was everytime I called an animation that was supposed to happen at a set interval because of the setTimeout, I called clearQueue() which would get rid of any other animations that had been set to happen. then i'd call the animation. That way when you come back to that tab, you don't have all these animations queued up and it goes crazy. at max you'll only have one set up.
So something like this:
spotlight.timeOutSpotlight = setTimeout(function () {
spotlight.clearQueue(); // get rid of other instances of the animation
spotlight.animate(spotlight.i);
}, 8000);
It may not work in all cases (depending on timing), but I hope that helps somebody!
You must also think you use clearTimeout.
As you call setTimeout function it returns an ID you can save this ID in a variable like
timeoutID = setTimeout(function () {
spotlight.animate(spotlight.i);
}, 8000);
and before setting a new timeout you can call the function like
clearTimeout(timeoutID)
My suspicion is that the browser queues input events like 'click' but only fires them when the tab where the event occurs actually has focus.
Perhaps you should try calling your click callbacks directly instead of using trigger('click').
Something like this:
spotlight: {
i: 0,
timeOutSpotlight: null,
clickFunc: function(element) {
// do stuff here to count and move images
// Clear timeout
clearTimeout(spotlight.timeOutSpotlight);
// Some stuff here to calculate next item
// Call next spotlight in 8 seconds
spotlight.timeOutSpotlight = setTimeout(function () {
spotlight.animate(spotlight.i);
}, 8000);
},
init: function()
{
$('#spotlight .controls a').click(function (e) {
// Don't follow the link
e.preventDefault();
spotlight.clickFunc(this);
});
// Select first item
spotlight.clickFunc($('#spotlight .controls a.next:first'));
},
animate: function(i)
{
var element = $('#spotlight .controls li:eq('+spotlight.i+') a.next');
spotlight.clickFunc(element);
}
}
What version of jQuery are you running? Apparently this problem was 'fixed' for version 1.6.3 - they reverted the change that caused this to happen. Discussions here and here.
Though this issue will likely have to be addressed in the future, it seems as though we're off the hook for now.

Categories