var list = document.querySelector('.cardList'), // cache the container
cards = document.querySelectorAll('.card'), // cache the list of cards
start = document.getElementById('start'), // buttons
stop = document.getElementById('stop'),
reset = document.getElementById('reset'),
raf, init = 0, counter = 0, lastCard, currentIteration = 0, // general purpose variables
settings = { // settings object to help make things configurable
'width': 100, 'height': 100, 'speed': 2,
'iterations': 2, 'count': cards.length
}
;
start.addEventListener('click', startClick); // wire up click event on buttons
stop.addEventListener('click', stopClick);
reset.addEventListener('click', resetClick);
initialize(); // initialize to arrange the cards at start
function initialize() {
// loop thru all cards and set the left property as per width and index position
[].forEach.call(cards, function(elem, idx) {
elem.style.left = (settings.width * idx) + 'px';
});
init = -(settings.width); // initialize the view cutoff
lastCard = cards[settings.count - 1]; // identify the last card
counter = 0; currentIteration = 0; // reset some counters
settings.speed = +(document.getElementById('speed').value);
settings.iterations = +(document.getElementById('iter').value);
}
function startClick() {
initialize(); raf = window.requestAnimationFrame(keyframes); // start animating
}
function stopClick() { window.cancelAnimationFrame(raf); } // stop animating
function resetClick() { // stop animating and re-initialize cards to start again
window.cancelAnimationFrame(raf);
document.getElementById('speed').value = '2';
document.getElementById('iter').value = '2';
initialize();
}
// actual animation function
function keyframes() {
var currentCard, currentLeft = 0, newLeft = 0;
// iterate all cards and decrease the left property based on speed
[].forEach.call(cards, function(elem, idx) {
elem.style.left = (parseInt(elem.style.left) - settings.speed) + 'px';
});
currentCard = cards[counter]; // identify left-most card
currentLeft = parseInt(currentCard.style.left); // get its left position
if (currentLeft <= init) { // check if it has gone out of view
// calculate position of last card
newLeft = parseInt(lastCard.style.left) + settings.width;
list.appendChild(currentCard); // move the card to end of list
currentCard.style.left = newLeft + 'px'; // change left position based on last card
lastCard = currentCard; // set this as the last card for next iteration
counter = (counter + 1) % settings.count; // set the next card index
if ((settings.iterations > 0) && (counter >= (settings.count - 1))) {
currentIteration++; // check settings for repeat iterations
}
}
if (currentIteration >= settings.iterations) { return; } // when to stop
raf = window.requestAnimationFrame(keyframes); // request another animation frame
};
* { box-sizing: border-box; padding: 0; margin: 0; }
.cardList {
position: relative; height: 100px; width: 300px;
margin: 10px; border: 2px solid #33e;
overflow: hidden; white-space: nowrap;
}
.card {
position: absolute; left: 0; top: 0; text-align: center;
height: 100px; width: 100px; line-height: 100px;
background-color: #99e;
font-family: monospace; font-size: 2em; color: #444;
border-left: 1px solid #33e; border-right: 1px solid #33e;
}
div.controls, button { margin: 10px; padding: 8px; font-family: monospace; }
div.controls input { width: 48px; padding: 2px; text-align: center; font-family: monospace; }
<div class="controls">
<label>Speed <input id="speed" type="number" min="1" max="8" value="2" />x</label>
|
<label>Iterations <input id="iter" type="number" min="0" max="8" value="2" /></label>
</div>
<div class="cardList">
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
<div class="card">4</div>
</div>
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="reset">Reset</button>