Okay, I don't use jquery and in all probability I have no clue as to what you're trying to achieve. However from what I understand I think you should do something like this:
var i = 0;
var t = this;
var timer = new DeltaTimer(function (time) {
// your animation
var x = t.s[i];
x.delay("1000").css("background-color", "#FAAF16");
delete t.s[i];
t.s.push(x);
// increment i
i++;
}, 1000);
var start = timer.start();
You will notice here that I've used a constructor called DeltaTimer
. This constructor is defined in this gist. It allows you to control your animations precisely using start
and stop
functions. The render
function which is passed is given a time
argument which is a Date
. The expression time - start
gives the exact time when the function was called (e.g. 4
, 1000
, 2000
, ...).
The advantage of using DeltaTimer
over setTimeout
or setInterval
is:
- It corrects itself. This means that animations are smoother and there's less lag.
- The animation can be controlled by starting and stopping the timer.
- The exact time of the function call is passed to the function. This helps in keeping track of which frame is being rendered, where should the sprite be rendered, etc.
- The logic for animation is separated from the logic of timing control. Thus code is more cohesive and more loosely coupled.
You can read my other answers regarding delta timing here, here and here.
Edit 1: That's actually pretty simple. We simply shift out the first element of the array, process it and then push it back at the end. Here's the logic:
function loopIterate(array, callback, interval) {
var timer = new DeltaTimer(function (time) {
var element = array.shift();
callback(element, time - start);
array.push(element);
}, interval);
var start = timer.start();
};
Now we can create an array and loop through it as follows:
var body = document.body;
loopIterate([1, 2, 3], function (element, time) {
body.innerHTML += element + ": " + time + "<br/>";
}, 1000);
You can see the output here: http://jsfiddle.net/aGQfr/
Edit 2: Oops, I found a problem. From what I understand you want to process the next element a certain amount of time after the current element is finished processing. My delta timing script doesn't do that. It only executes functions at fixed intervals of time.
So, you don't need delta timing at all. You need to call setTimeout
after each element has been processed:
function loopIterate(array, callback, interval) {
var start = + new Date;
process();
function process() {
var element = array.shift();
callback(element, new Date - start);
array.push(element);
setTimeout(process, interval);
}
};
After that just create an array and loop through it as follows:
loopIterate([1, 2, 3], function (element, time) {
alert(element);
}, 1000);
You can see the demo here (note that your browser may not like it): http://jsfiddle.net/aGQfr/1/
Edit 3: You may also combined methods one and two so that you have a script which:
- Waits for the processing to finish before adding the next element to process to the event queue.
- Can be controlled using a
start
and stop
function.
- Gives the exact time the callback is called.
- Separates processing from timing control.
We'll create a constructor function called LoopIterator
which returns an iterator object with start
and stop
methods:
function LoopIterator(array, callback, interval) {
var start, iterate, timeout;
this.start = function () {
if (!iterate) {
start = + new Date;
iterate = true;
loop();
}
};
this.stop = function () {
if (iterate) {
clearTimeout(timeout);
iterate = false;
}
};
function loop() {
var element = array.shift();
callback(element, new Date - start);
array.push(element);
if (iterate) timeout = setTimeout(loop, interval);
}
}
Now we can create and start a new iterator as follows:
var iterator = new LoopIterator([1, 2, 3], function (element, time) {
alert(element);
}, 3000);
iterator.start();
If you wish you may even stop and start the iterator when the mouse moves over an element or out of an element respectively:
var div = document.getElementsByTagName("div")[0];
div.addEventListener("mouseout", iterator.start, false);
div.addEventListener("mouseover", iterator.stop, false);
When stopped the iterator's state is preserved and when started again it continues from where it left off.
You may see the demo here: http://jsfiddle.net/PEcUG/
Edit 4: So you want to create a simple slider? Let's start with the HTML, then the CSS and then the JavaScript.
The HTML:
<div class="slider">
<div class="slide">Slide 1</div>
<div class="slide">Slide 2</div>
<div class="slide">Slide 3</div>
</div>
We have a div
element with a class called slider
(because there may be more than one slider on the page). Each slider has zero or more div
elements with the class slide
. Each slide may have arbitrary content. The slider will also have buttons, but we don't include this in the HTML as it will be generated automatically by JavaScript. No redundancy. Also note that none of the slides are manually numbered. Everything is handled by JavaScript.
The CSS:
.slide {
background-color: #EEEEEE;
-moz-border-radius: 0.25em;
-webkit-border-radius: 0.25em;
border-radius: 0.25em;
display: none;
padding: 1em;
}
.slider-button {
background-color: #CCCCCC;
-moz-border-radius: 0.25em;
-webkit-border-radius: 0.25em;
border-radius: 0.25em;
cursor: pointer;
float: right;
height: 1.25em;
margin: 0.5em;
width: 1.25em;
}
You may supply arbitrary CSS to suit your taste. An important point however is that .slide
must have display: none;
because the slides must initially be hidden. Also .slider-button
must have float: right;
. This is important as elements floated to the right have their order reversed. Thus the first button is actually the last button. This must be handled correctly by JavaScript so don't change it unless you know what you're doing.
The JavaScript:
Alright, I'll explain this bottom up:
window.addEventListener("DOMContentLoaded", function () {
var sliders = document.querySelectorAll(".slider");
var length = sliders.length;
for (var i = 0; i < length; i++)
new Slider(sliders[i], 2000);
}, false);
Here Slider
is a constructor function which initializes and starts the slider element it passed. It accepts the time interval between two slides as the second argument. Here's the code for Slider
:
function Slider(slider, interval) {
var slides = slider.querySelectorAll(".slide");
var iterate, start, timeout, delay = interval;
slides = Array.prototype.slice.call(slides);
var buttons = [], numbers = [], goto = [];
var length = slides.length;
for (var i = 0; i < length; i++) {
var button = document.createElement("div");
button.setAttribute("class", "slider-button");
slider.appendChild(button);
buttons.unshift(button);
numbers.push(i + 1);
var handler = getHandler(length - i);
button.addEventListener("click", handler, false);
goto.unshift(handler);
}
this.goto = function (index) {
var gotoSlide = goto[index];
if (typeof gotoSlide === "function")
gotoSlide();
};
slider.addEventListener("mouseover", stop, false);
slider.addEventListener("mouseout", start, false);
this.start = start;
this.stop = stop;
showSlide();
start();
function start() {
if (!iterate) {
iterate = true;
start = + new Date;
timeout = setTimeout(loop, delay);
}
}
function stop() {
if (iterate) {
iterate = false;
clearTimeout(timeout);
delay = interval - new Date + start;
}
}
function loop() {
hideSlide();
slideSlider();
showSlide();
if (iterate) {
start = + new Date;
timeout = setTimeout(loop, interval);
}
}
function hideSlide() {
slides[0].style.display = "none";
buttons[0].style.backgroundColor = "#CCCCCC";
}
function slideSlider() {
slides.push(slides.shift());
buttons.push(buttons.shift());
numbers.push(numbers.shift());
}
function showSlide() {
slides[0].style.display = "block";
buttons[0].style.backgroundColor = "#FAAF16";
}
function getHandler(number) {
return function () {
hideSlide();
while (numbers[0] !== number) slideSlider();
showSlide();
};
}
}
The code is pretty self-explanatory. Every instance of Slider
has a start
, stop
and goto
method for finer control. The goto
method takes a slide index number. For n
slides the indices range from 0
to n - 1
. That's it.
The demo of the slider is here: http://jsfiddle.net/SyTFZ/4/