Reputation: 47
based on this this tutorial on w3 schools I wrote a function(move) that animates an element(div) using the setInterval() method, my problem is when I try to call the function move() several times the div does an unexpected behavior, I tried to use async/await but it didn't work.
async function moveArray(destination) {
//move through array of addresses
for (let i = 0; i < destination.length - 1; i++) {
await move(destination[i], destination[i + 1]);
}
}
async function move(pos, add) {
//moves element from position to address
var elem = document.getElementById("object");
var id = setInterval(frame, 15);
function frame() {
if (pos.x == add.x && pos.y == add.y) {
clearInterval(id);
return;
} else {
//if element haven't reached its target
// we add/substract 1 from the address and update styling
if (pos.x != add.x) {
pos.x += add.x > pos.x ? 1 : -1;
elem.style.left = pos.x + "px";
}
if (pos.y != add.y) {
pos.y += add.y > pos.y ? 1 : -1;
elem.style.top = pos.y + "px";
}
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#object {
width: 50px;
height: 50px;
position: absolute;
background: red;
}
<button onclick="moveArray( [{x:0,y:0}, {x:140, y:150}, {x:130, y:110}, {x:70, y:65}] )">
move
</button>
<div id="container">
<div id="object"></div>
//object to be animated
</div>
Upvotes: 1
Views: 168
Reputation: 20944
The weird behavior is caused because the move
function is being called multiple times simultaneously in the for
loop. This happens because your async functions do not know when they are done.
Instead of making move
async, which it doesn't have to if it is not awaiting anything, return a Promise
from the start and call you animation code inside of it. When the point is reached when animation has to end, resolve
the promise.
Doing it like this will make your await
statement in the for
loop wait for the move
function to reach the resolve
call before continuing with the next animation.
async function moveArray(destination) {
//move through array of addresses
for (let i = 0; i < destination.length - 1; i++) {
await move(destination[i], destination[i + 1]);
}
}
function move(pos, add) {
return new Promise(resolve => {
var elem = document.getElementById("object");
var id = setInterval(frame, 15);
function frame() {
if (pos.x == add.x && pos.y == add.y) {
clearInterval(id);
// Fulfill promise when position is reached.
resolve();
} else {
if (pos.x != add.x) {
pos.x += add.x > pos.x ? 1 : -1;
elem.style.left = pos.x + "px";
}
if (pos.y != add.y) {
pos.y += add.y > pos.y ? 1 : -1;
elem.style.top = pos.y + "px";
}
}
}
});
}
<!DOCTYPE html>
<html>
<head>
<style>
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#object {
width: 50px;
height: 50px;
position: absolute;
background: red;
}
</style>
</head>
<body>
<button onclick="moveArray( [{x:0,y:0}, {x:140, y:150}, {x:130, y:110}, {x:70, y:65}] )">
move
</button>
<div id="container">
<div id="object"></div>
//object to be animated
</div>
<script src="animation.js"></script>
</body>
</html>
Upvotes: 1