I've trying to run jQuery inside a for loop like this:
var frameNumber = 15; // How many frames are in your animation
for(var i = 1; i < frameNumber + 1; i++){
var flipDelay = i * 100;
$('.flipbook').delay(flipDelay).addClass('flipbook-' + i);
}
I'm trying to get the equivalent of this but with more flexibility so I can change how many frames I use:
$(function(){
setTimeout(function(){ $(".flipbook").addClass("flipbook-1") }, 100 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-2") }, 200 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-3") }, 300 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-4") }, 400 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-5") }, 500 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-6") }, 600 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-7") }, 700 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-8") }, 800 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-9") }, 900 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-10") }, 1000 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-11") }, 1100 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-12") }, 1200 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-13") }, 1300 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-14") }, 1400 );
setTimeout(function(){ $(".flipbook").addClass("flipbook-15") }, 1500 );
});
The classes are defined in a CSS stylesheet and each class has a different background applied to it. I just need jQuery/JS to loop through them until the last frame is reached.
EDIT: It's not the flipbook-01 vs flipbook-1 that's preventing me from getting this to work. Sorry about that confusion.
EDIT: I need my div to look like this after the function has ran:
<div class="flipbook flipbook-1 flipbook-2 flipbook-3 flipbook-4 ... flipbook-15"></div>
You are misusing the delay() function. jQuery will only queue up effects out-of-the-box (e.g. fadeIn() or slideUp()), and not things like show(), hide(), or addClass().
Example of non-working delay() with addClass(): http://jsbin.com/hayay/4/
Instead, you should just use setTimeout like others have mentioned. I'd recommend a recursive approach, though, instead of a for loop:
var frameNumber = 15;
showFrame(1);
function showFrame(i) {
$('.flipbook').addClass('flipbook-' + i);
if (i < frameNumber) {
setTimeout(function() { showFrame(i+1); }, 100);
}
}
Try this:
addClass('flipbook-' + (i<10?("0"+i):i));
This will add the missing zero for i<10.
And about the delay - it would not work with addClass. You should stick with the setTimeout option.
Fiddle Demo
var frameNumber = 15;
for (var i = 1; i < frameNumber + 1; i++) {
(function (x) {
setTimeout(function () {
$('.flipbook').addClass('flipbook-' + x);
console.log(x);
}, x * 100)
})(i)
}
As has been said already, the addClass() method is an immediate method invocation. It does not, by default, go through the animation queue which is required in order to work with .delay().
Here's an interesting solution I came up with that allows you to make any jQuery method work via the animation queue and thus you can sequence methods via the built-in animation queue, can use .delay() to control timing, can intersperse with other animations, etc...
// generic method to allow you to run any jQuery method through the animation queue
// so they will be serialized with other asynchronous animation methods
// such as .delay(), .animate(), .slideUp(), etc...
jQuery.fn.queueMethod = function(methodName /* arg1, arg2, ... */) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
self.queue(function(next) {
self[methodName].apply(self, args);
next();
})
return this;
}
var frameNumber = 15; // How many frames are in your animation
for (var i = 1; i <= frameNumber; i++) {
$('.flipbook').delay(100).queueMethod("addClass", "flipbook-" + i);
}
This will run each addClass method, 100ms apart.
Several working examples of slightly different ways of doing it: http://jsfiddle.net/jfriend00/38BbM/
Related
So, I'm trying to use create a loop which does this:
setTimeout(function() {
console.log("Hey!");
setTimeout(function() {
console.log("Hey!");
setTimeout(function() {
console.log("Hey!");
}, 1000);
}, 1000);
}, 1000);
So, I tried it like this.
for (i = 0; 1 < 3; i++){
setTimeout(function() {
console.log("Hey!");
}, 1000);
}
How ever, it's not working.
Doing some research I've noticed this is because the timeOuts are getting added to each other with each loop. How can I work around this?
You have to recursively call the time outs, so write a function that takes an argument of the current number of attempts. Have it do an operation, and then call itself with the attempts argument += 1.
You should pass a number of attempts as a safeguard so you can tell the function not to call itself if the attempts number is > some limit, to avoid infinite loops.
Something like:
timedLog(attempts) {
console.log('Hey!');
if (attempts > 10) {
return;
} else {
setTimeout(function() { timedLog(attempts + 1); }, 1000);
}
}
It doesn't look like a for loop anymore, but it's the same principle.
If the output of each function is the same, and you want to print it in the same interval, then you could use setInterval.
function myInterval() {
return setInterval(function(){
console.log("Hey!");
}, 1000);
};
var id = myInterval();
It will repeat forever, so you would have to stop it, in this case, after 3000ms.
setTimeout(function(){
clearInterval(id);
}, 3000);
Just use a loop, increasing the timeout interval each time:
for (let i = 0; 1 < 3; i++){
setTimeout(function() {
console.log("Hey!");
}, i*1000);
}
(Note, that if your callback function depended on i, this won't work as expected if you use var instead of let in the for loop header. The reason is to do with closures - there are many questions about this on SO. But it works perfectly with let - and there are other simple enough fixes if for some reason you can't use let.)
I'm trying to create an auto-zoom but I'm stuck in here.
I have this function
panZoom.zoomOut(num);
and I need to call it n times with a little delay to create a nice zoomOut effect
I'm using
for(i=0; i<10;i++){
panZoom.zoomOut(1);
};
But it executes too fast to create an animation.
I also tried setTimeout:
function myLoop () {
setTimeout(function () {
panZoom.zoomOut(1);
i++;
if (i < 10) { // if the counter < 10, call the loop function
myLoop(); // .. again which will trigger another
} // .. setTimeout()
if (i==10){
i=1;
}
}, 100);
};
But the action after the setTimeout execute without waiting for setTimeout to finish (and it's obvious I know but there is not delay function.)
How can I make a smooth zoom effect?
You probably want to do something like this:
for ( var i = 0; i < 10; i++ ) {
setTimeout(function(){
panZoom.zoomOut(1);
}, 100 * i);
}
What is the equivalent of the following jQuery animate in pure JavaScript?
function animate(element, position, speed) {
$(element).animate({
"top": position
}, speed);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You can acheive complex animations with pure javascript by using setTimeout and setInterval methods.
Please check here.
Here is the key part of moving an element:
function move(elem) {
var left = 0
function frame() {
left++ // update parameters
elem.style.left = left + 'px' // show frame
if (left == 100) // check finish condition
clearInterval(id)
}
var id = setInterval(frame, 10) // draw every 10ms
}
This version uses vanilla javascript .animate() function, which is better or more performant
than requestAnimation frame. & it is also the proper alternative to JQuerys .animate().
you can play around with the iterations, timing functions & fill method aswell as daisy chain it with other animations
document.getElementById("Elem");
Elem.style.position = "absolute";
Elem.animate({
top: ['8px', '280px']
},{ duration: 1760, // number in ms [this would be equiv of your speed].
easing: 'ease-in-out',
iterations: 1, // infinity or a number.
// fill: ''
});
I believe the setTimeout & setInterval functions both use the unsafe eval() function under the hood, but not 100% sure about that, just remember reading an article about it...
Don't Quote me on that! just research it,
but the code I wrote out has been tested to be working..
hope this helps someone...
The setInterval() method is too heavy for the browser, so it's better to use requestAnimationFrame() for animations. The following code is an example of using this method.
let _btns = document.querySelectorAll('.btn'),
_start = null;
let _loop = function (timestamp, duration, position, wrap) {
if (!_start) _start = timestamp;
let progress = (timestamp - _start) / duration;
wrap.style.left = progress * position + 'px'
if ( progress < 1 ) {
window.requestAnimationFrame( function (timestamp){
_loop(timestamp,duration,position,wrap);
} );
} else {
_start = null;
}
},
_animation = function () {
const wrap = document.querySelector('.logo-2'),
position = 300, // 300 pixels
duration = 500; // 500 milliseconds
_loop(0,duration,position,wrap);
},
_addEvents = function () {
[].forEach.call(_btns,function(el){
el.addEventListener('click', function (e) {
_animation();
})
});
},
_init = function() {
_addEvents();
};
_init();
Element.animate() function seems to be very simple and useful. But there are for now a lot of compatibility issues. You can read about it:
https://developer.mozilla.org/en-US/docs/Web/API/Element/animate
I would recommend to get used to requestAnmationFrame. It's compatible with all browsers and it is very powerful:
https://javascript.info/js-animation
setTimeout doesn't work as expected because it will execute the codes below subsequently without waiting for the delay to run the first argument of 'setTimeout'
(function() {
var a = ['#bird','#flower','#cat'];
var totalno = settings.imageArray.length;
function rotateImages(start) {
var nextImage = start + 1;
if(nextImage % totalno == 0){
nextImage=0;
}
//do animate here
$(settings.imageArray).fadeOut();
window.setTimeout(function() {
rotateImages(++start % totalno);
}, settings.imageArray[start].delay);
}
rotateImages(0);
})();
Is there a way to write it so that it doesnt fade out right away for the first image?
a simplified version would be :
(function() {
var a = ['#bird','#flower','#cat'];
function rotateImages(start) {
//do something here
window.setTimeout(function() {
rotateImages(++start % a.length;);
}, 1000);
}
rotateImages(0);
})();
it will execute the codes below
subsequently without waiting for the
delay to run the first argument of
'setTimeout'
It looks like you're starting the first rotate directly. Instead of:
rotateImages(0);
Try to start the first rotate with a delay, like:
window.setTimeout(function() {
rotateImages(0);
}, settings.imageArray[0].delay);
I need to flash an element off and on. This works but I don't really like the code. Is there a nice way of doing this?
setTimeout(function(){
toggle();
setTimeout(function(){
toggle();
setTimeout(function(){
toggle();
setTimeout(function(){
toggle();
}, 100);
}, 100);
}, 100);
}, 100);
I'm using jQuery too if that helps.
function toggle_multiple(n)
{
var toggled = 0;
function toggle_one_time()
{
toggle();
toggled += 1;
if (toggled <= n)
setTimeout(toggle_one_time, 100);
}
toggle_one_time();
}
And just call toggle_multiple(4).
A recursive approach:
function multiTimeoutCall (callback, delay, times) {
if (times > 0){
setTimeout(function () {
callback();
multiTimeoutCall (callback, delay, times - 1);
}, delay);
}
}
Usage:
multiTimeoutCall (toggle, 100, 4);
Edit: Yet another approach, without filling the call stack:
function multiTimeoutCall (callback, delay, times) {
setTimeout(function action() { // a named function expression
callback();
if (--times > 0) {
setTimeout (action, delay); // start a new timer
}
}, delay);
}
I could used arguments.callee instead of a named function expression, but seems that it will be deprecated some day in ECMAScript 5...
Why not use setInterval?
var toggler = function() {
if (++self.counter >= self.BLINK_AMOUNT * 2) {
self.counter = 0;
window.clearInterval(self.timer);
return;
}
toggle();
};
toggler.BLINK_AMOUNT = 1;
toggler.counter = 0;
toggler.timer = window.setInterval(toggler, 100);
I can't remember whether or not IE properly implements the self variable in a timer callback - if it doesn't, use a uniquely named global variable instead.
I would use a blinking effect. For jquery there's pulsate, hope that works for you.
Here's yet another version for simplicity:
for (var i= 0; i<4; i++)
setTimeout(toggle, (i+1)*100);
For larger numbers an interval may be more appropriate, but if it's just four toggles multiple timeouts are fine.
Generalizing 'unknown's' idea of using setInterval,
function schedule(fn, max, delay)
{
var counter = 0;
var interval = setInterval(
function()
{
if(counter++ === max)
clearInterval(interval);
fn();
}
, delay);
}
Usage:
schedule(toggle, 4, 100);
If its just flashing that is required, why not use the jQuery animate ? I use the following to direct user attention to messages. But you can do this for any element -
$("#message_box").fadeOut(450).fadeIn(350);
If you want it multiple times, do this -
$("#message_box").fadeOut(450).fadeIn(350).fadeOut(450).fadeIn(350);
You can do like this:
function toggleMany(cnt) {
toggle();
if (--cnt >= 0) window.setTimeout('toggleMany('+cnt+')', 100);
}
toggleMany(4);