Search code examples
javascripteasing

Number increment animation duration slow as numbers increase


I have a count up code here:

HTML:

<div id="value">700</div>
<div id="value2">1000</div>

JavaScript:

function animateValue(id, start, end, duration) {
    var start= 0 ;
    var end = parseInt(document.getElementById(id).textContent, 10);
    var duration = 10000;
    var range = end - start;
    var current = start;
    var increment = end > start? 1 : -1;
    var stepTime = Math.abs(Math.floor(duration / range));
    var obj = document.getElementById(id);
    var timer = setInterval(function() {
        current += increment;
        obj.innerHTML = current;
        if (current == end) {
            clearInterval(timer);
        }
    }, stepTime);
}
animateValue("value2",0,0,0);
animateValue("value",0,0,0);

In this code numbers start from 0 to end with 10000ms duration. How can I set this duration be slower than this when it's close to the end?

For example:

Numbers: 0 To 100.

Duration : 50ms To 10ms.


Solution

  • Use some easing functions instead of incrementing at a constant rate.

    Please note, however, that your total execution time will likely always be at least somewhat inaccurate due to the fact that each increment of the value takes some execution time which is not accounted for using this setTimeout approach. The problem is exacerbated by higher values.

    //No easing
    function constant (duration, range, current) {
      return duration / range;
    }
    
    //Linear easing
    function linear (duration, range, current) {
      return ((duration * 2) / Math.pow(range, 2)) * current;
    }
    
    //Quadratic easing
    function quadratic (duration, range, current) {
      return ((duration * 3) / Math.pow(range, 3)) * Math.pow(current, 2);
    }
    
    function animateValue(id, start, duration, easing) {
      var end = parseInt(document.getElementById(id).textContent, 10);
      var range = end - start;
      var current = start;
      var increment = end > start? 1 : -1;
      var obj = document.getElementById(id);
      var startTime = new Date();
      var offset = 1;
      var remainderTime = 0;
      
      var step = function() {
        current += increment;
        obj.innerHTML = current;
        
        if (current != end) {
          setTimeout(step, easing(duration, range, current));
        }
        else {
          console.log('Easing: ', easing);
          console.log('Elapsed time: ', new Date() - startTime)
          console.log('');
        }
      };
      
      setTimeout(step, easing(duration, range, start));
    }
    
    animateValue("value", 0, 10000, constant);
    animateValue("value2", 0, 10000, linear);
    animateValue("value3", 0, 10000, quadratic);
    <div id="value">100</div>
    <div id="value2">100</div>
    <div id="value3">100</div>