0

I am looking to increment the value of "time" with 0.01 each 10 miliseconds until it gets to the desired value. Right now it just increases it instantly to the conditioned value.

var time = 0;

function animate() {
  decreaseIncrement = -0.78;
  increaseIncrement = 0.78;

  if (
    (document.getElementById("but5").onclick = function () {
      if (time < increaseIncrement) {
        do {
          time += 0.01;
        } while (time < increaseIncrement);
      }
    })
  )
    if (
      (document.getElementById("but3").onclick = function () {
        if (decreaseIncrement < time) {
          do {
            time -= 0.01;
          } while (decreaseIncrement < time);
        }
      })
    )
      increaseIncrement = time + increaseIncrement;
  decreaseIncrement = time + decreaseIncrement;

}

https://jsfiddle.net/2epqg1wc/1/

Mark t
  • 95
  • 5
  • 2
    You may need to make your functions async and add `await new Promise(r => setTimeout(r, 10))` to your loops to block the next iteration of the loop from running. – async await Aug 27 '21 at 20:53
  • because a while loop will sit there until it is done.... You are going to have to use an interval/timeout – epascarello Aug 27 '21 at 21:14
  • `await new Promise(r => setTimeout(r, 10))` would paus for at least 10ms but the time could be larger. So if you want to have a smooth animation neither this nor `setInterval` will work reliably in combination with `time += 0.01` @AsyncAwaitFetch – t.niese Aug 27 '21 at 21:32

2 Answers2

1

You can solve that problem using setInterval which repeatedly runs a task every x milliseconds until you cancel it. Below code reduces the value to 0 in 0.01 steps with a step performed every 10 milliseconds.

var value = 1.0;
var decrement = 0.01;


function decreaseAnimation() {
  var interval = setInterval(() => {
    value -= decrement;
    console.log(value);
    if (value <= 0) {
      clearInterval(interval);
    }
  }, 10);
}

decreaseAnimation();
chingucoding
  • 894
  • 7
  • 17
1

You have 3 options:

  • requestAnimationFrame (rAF)
  • setTimeout/setInterval (sTo)
  • messageChannel

The first 2 options are more straightforward but they will lack the precision, because rAF fires every 17 milliseconds (assuming 60Hz) and sTO will fire at most 4ms after 4 successive recursions. Usually rAF is preferred over sTo because of better reliability in timing of firing these callbacks. Use sTO as a fallback if rAF is not supported.

Here is an implementation from a library for similar purposes:

var rafx = require("rafx");
rafx.async({ //create a ledger object to store values
   curr_time:0,
   desired:Math.random(),
   frames:0
}).animate(function(obj){ 
    //obj is the ledger above
    //increment obj.frames here if you want to
    return obj;
},).until(function(obj){
    obj.frames++;
    obj.curr_time = obj.frames * 17 / 10 * 0.01;
    return obj.curr_time >= obj.desired;
}).then(function(obj){
    console.log("sequence ended with values:" + JSON.stringify(obj));
});

You can copy paste the code above here and test it.

The last option uses MessageChannel to post message between ports, which gives extremely high precision because it is fired at the next event loop. You can combine this with performance.now to determine whether to increment your time or not.

Disclosure: I am the author of the aforementioned lib.

ibrahim tanyalcin
  • 5,643
  • 3
  • 16
  • 22