Reputation:
I want to make an image move with a while loop in javascript but it isn't working.
This is the javascript code:
var i = 0;
while(i != 1000){
document.getElementById("poza").style.left= i;
i = i + 20;
}
The css code:
#poza{
position: absolute;
left: 0px;
width: 500px;
height: auto;
}
And the html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<img id="poza" src="ali_si_david_camp.jpg" alt="ali_si_david_camp">
<script src="index.js"></script>
</body>
</html>
Upvotes: 1
Views: 1283
Reputation: 8150
Javascript is single-threaded - the major implication of this in your case is that nothing can happen between javascript instructions.
Judging by this code:
var i = 0;
while(i != 1000){
document.getElementById("poza").style.left= i;
i = i + 20;
}
I suspect you expect there to be 1000 / 20
graphical updates, corresponding to each time i
is modified. But javascript is single-threaded; nothing else can occur while this loop is running, including graphical updates! The result is that your loop will run 1000 / 20
times, and only then is there any chance of a graphical update.
In order to allow graphical updates you need to stop your loop from running for a moment each time you perform an update. A good way of doing this is with async
/await
. The following loop pauses for 150ms after each step:
(async () => {
let i = 0;
while(i != 1000){
document.getElementById("poza").style.left = `${i}px`;
i = i + 20;
// Pause for 150ms
await new Promise(r => setTimeout(r, 150));
}
})();
#poza {
position: absolute;
left: 0; top: 40%; height: 10%; width: 20px;
background-color: #f00;
}
<div id="poza"></div>
This loop takes control of javascript's single thread every 150ms. This means that there are regular 150ms intervals during which the thread is free, and graphical updates have an opportunity to occur. How does the browser decide when to perform graphical updates? Typically a browser simply performs 60 graphical updates per second (about 17 milliseconds separate graphical updates), but this timing is not guaranteed.
Super smooth motion can be achieved using two techniques: first, we can sync up with the browser's graphical update schedule using window.requestAnimationFrame
. This function lets us change the graphics as quickly as the browser can update. Second, we'll always be looking at a "clock" to make sure any graphical motion is regular. The best clock available in browsers is window.performance.now
, a function which returns high-precision timing information:
(async () => {
while (true) {
// Wait for the next graphical update to begin
await new Promise(r => window.requestAnimationFrame(r));
// Check the clock
let ms = window.performance.now();
// We know that `ms` milliseconds have elapsed. Where should
// "poza" be after `ms` milliseconds? Let's say it's moving at
// 30 pixels per second (note `ms / 1000` gives us seconds):
document.querySelector('#poza').style.left = `${(ms / 1000) * 30}px`;
}
})();
#poza {
position: absolute;
left: 0; top: 40%; height: 10%; width: 20px;
background-color: #f00;
}
<div id="poza"></div>
You also made one other minor mistake: the style.left
property needs to specify units. You were setting style.left
to some number (e.g. 40
) when you need to set it to a string including the units (e.g. '40px'
).
Upvotes: 1
Reputation: 3290
You can try this approach as well.
var i = 0;
var timer = setInterval(()=>{
document.getElementById("poza").style.left= i+'px';
i = i + 1
if(i > 1000) {
clearInterval(timer);
}
}, 30)
#poza{
position: absolute;
left: 0px;
width: 500px;
height: auto;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<img id="poza" src="https://s.imgur.com/images/logo-1200-630.jpg?2" alt="ali_si_david_camp">
<script src="index.js"></script>
</body>
</html>
Upvotes: 1
Reputation: 1743
style.left
usually expects a string that contains a unit. Try this
document.getElementById("poza").style.left = `${i}px`;
You just gave an integer.
Additionally I don't think that there will be much smooth moving involved, since the loop will most likely finish instantly. Therefore I would read into css-animations with keyframes
.
Upvotes: 1