user16113541
user16113541

Reputation:

How to move a image smoothly with javascript?

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

Answers (3)

Gershom Maes
Gershom Maes

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

Abhishek Sharma
Abhishek Sharma

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

acincognito
acincognito

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

Related Questions