I have a gif image in my html. I want to make the image "walk" so I'm using jquery .animate() the walking is fine, now, once it reaches the other side of the screen, I'd like to hide the image so I'm trying to use the complete option. My code looks like so:
$(document).ready(function() {
for(var i = 0; i < 500; i = i + 20) {
$("#animate-gif").animate({backgroundPositionX: i}, 50,
function() { alert("finished"); }); }
});
However, the alert does not show. I've also tried doing the following:
duration : 50, complete : function()
{backgroundPositionX: i}, {duration : 50, complete :function()
But neither worked and I'm getting a warning in my debugger "Unexpected token :". So my question is, how exactly do you add a complete option for the animate function in jquery? I've tried looking through the documentation and some examples and what i've tried are pretty much what I've seen.
I don't understand the purpose of the for loop. Try just calling animate() once:
http://jsfiddle.net/W5SjR/1/
$(document).ready(function() {
$("#animate-gif").animate({backgroundPositionX: "100%"}, 500, function() { alert("finished"); });
});
Your complete function looks fine. Is it possible that you checked "don't allow this page to show popups"?
I would also suggest using console.log() instead of alert().
the general syntax of .animate is
$("selector").animate({"param":"value","param","value"},time,callback_function);
The callback function will be called after the completion of the animation
there are also other options like "step", "complete" and much more
You can check this fiddle where i would used some of them
Related
I'm using JS to make a simple function that displays 3 items one at a time. Works well when you're looking at the page, but when you minimize or change tabs then return, all three items are shown.
Anyone know why? It's as if fadeIn(x) keeps running but hide() stops working. I even checked with different classes.
Here is the code:
$(document).ready(function () {
function start() {
$(".featured-items").hide();
$( ".item-1" ).fadeIn('slow');
setTimeout(one, 5000);
}
function one() {
$(".featured-items").hide();
$( ".item-2" ).fadeIn('slow');
setTimeout(two, 5000);
}
function two() {
$(".featured-items").hide();
$( ".item-0" ).fadeIn('slow');
setTimeout(start, 5000);
}
setTimeout(start, 5000);
});
Problem solved, check the best answer below and make sure to read comments to get a good understanding. Thanks to all
(Updated to provide complete answer)
Your original code is too complex, and a more flexible and simpler implementation is to have just one function, and an array of items in the gallery. Secondly, you should modify your code so the fadeIn animation starts immediately instead of getting queued. Having only one function instead of several makes alterations such as this easier.
Note that in the code below, as in your original code, the various gallery items are classes rather than single element ids and could fade in multiple items.
var gallery = [ '.item-1', '.item-2', '.item-3' ];
var i = 0;
function galleryEvent() {
$(".featured-items").hide();
$( gallery[i] ).fadeIn({duration: 'slow', queue: false});
i = (i + 1) % gallery.length;
setTimeout(galleryEvent, 5000);
}
// start everything off....
galleryEvent();
I'm making a very simple pop up where I can choose from 8 types of content, all using the same format. It works by clicking on hidden divs that show on hover on the top section, of course as you can see I came up with a very long and large code for something that can probably be done with much less bolts and wires.
Since it's a lot of lines I pasted all this in jsFiddle
Is there a way to make this lighter?
SOLVED... Yeees!
Thanks to all... here is the final script: jsFiddle Final in case someone else has the same difficulty
I see three things you could do to end up with less code:
Use the hover shortcut
Use anonymous functions
Use a parameterized function
First, jQuery has the hover method to replace mouseover/mouseout behavior:
$('#scrollbtnR8').bind('mouseover', R8);
$('#scrollbtnR8').bind('mouseout', R8b);
Can be replaced as
$('#scrollbtnR8').hover(R8, R8b);
That's just a little less code though :)
Second, you are now defining a function for each eventhandler but you are only using these functions once. If you only use them once, you could create anonymous functions like this:
$('#scrollbtnR1').bind('click', esta1);
becomes
$('#scrollbtnR1').click(function() {
$("#scrollcontrol").animate({"left":-240},500, "swing", null);
});
Finally, you can use a function to encapsulate the common parts of the code and pass the changing parts as parameters.
You could implement it like this:
<div id="scrollcontrol" animate="swing" swingLeft="-240">
$('div[animate='swing']').click(function() {
$(this).animate({"left": $(this).attr("swingLeft")}, 500, "swing", null);
});
The "div" selector uses the Attribute Equals Selector. You could also assign a class to all "animate" divs and select them using the class selector: $("div.animate") which would select all <div class="animate">.
What happens here is:
Select all divs that have the value 'swing' for the animate attribute.
Call jQuery swing animate BUT use $(this).attr("swingLeft") as the left property.
attr("wingLeft") gets the value for the swingLeft property as defined in your HTML markup.
I stopped looking at your code at this point, the key is: Look at the code to be executed and see if you notice a pattern, something that you can generalize. You could then perhaps simplify the code further.
Also worth noting: Some people don't like adding properties like "animate", "swingLeft" etc to the HTML. Update As per pimvdb's comment, you can use the jQuery data to be a bit 'cleaner'.
The code could look like this then:
<div id="scrollcontrol" class="swing" data-swingLeft="-240">
$('.swing').click(function() {
$(this).animate({"left": $(this).data("swingLeft")}, 500, "swing", null);
});
Refactor out all of the repeated behavior into a function and then pass the different pieces in as parameters, e.g. this:
function esta1(event) {
$("#scrollcontrol").animate({"left":-240},500, "swing", null);
}
function esta2(event) {
$("#scrollcontrol").animate({"left":0},500, "swing", null);
}
...
$('#scrollbtnR1').bind('click', esta1);
$('#scrollbtnL2').bind('click', esta2);
Becomes this:
function functionName(event, left) {
$("#scrollcontrol").animate({"left": left},500, "swing", null);
}
$('#scrollbtnR1').bind('click', function (e) {
functionName(e, -240);
});
$('#scrollbtnL2').bind('click', function (e) {
functionName(e, 0);
});
Continue this refactoring process until you're left with a single generic function, and everything else passes parameters to that function.
If you find your parameter list getting long and unweildy, consider passing a parameter object instead:
function functionName(event, params) {
$("#scrollcontrol").animate({"left": params.left},
params.duration,
params.animation, null);
}
$('#scrollbtnR1').bind('click', function (e) {
functionName(e, { left: -240, duration: 500, animation: "swing" });
});
For a start, stop referencing everything with IDs. Use classes, like this:
$('.scrollbtn').hover(function(){
$(this).css("opacity","0")
.animate({"opacity":1},500, "linear");
}, function() {
$(this).css("opacity","1")
.animate({"opacity":0},500, "linear");
});
In the following code, the animate() function in click() works.
However, animate() or pulse() (when uncommented) in mouseenter() does not work either.
The pulse() function is provided by Jarrod Overson...
http://jarrodoverson.com/static/demos/jquery.pulse.html
sectionTitle = $j(this).find(".sectionTitle");
sectionTitle.click(function(){
if($j(this).parent().height() == sections[$j(this).parent().attr("id")]["height"]){
origHeight = sections[$j(this).parent().attr("id")]["origHeight"];
$j(this).parent().animate({height:origHeight},"slow");
}else{
height = sections[$j(this).parent().attr("id")]["height"];
$j(this).parent().animate({height:height},"slow");
}
})
sectionTitle.mouseenter(function(){
var properties = { "color" : '#F00' };
// $j(this).pulse(properties, 500, 3);
$j(this).animate({"background-color":'#F00'},"slow");
})
A live example of my code is here.
http://fantasticvisions.net/test/me/
The classs sectionTitle is applied to a number of the H2 elements on the above page. Clicking them will cause the content to expand, using jQuery animate(). However, the mouseenter() fails.
What am I missing here? I have tried a number of other variations on this, and none work. The mouseenter() event does fire, and the code is executed (I have traced this) but the effect never seems to happen.
.animate() is not working because jQuery by itself does not support animation of colors.
If you include jQuery UI, or a color animation plugin, this should work.
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"));
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.