2

what i am trying to do is a function that prints out a sequence of numbers (eg. 1-100) in a given time (eg. 2 seconds). super easy.

The hardest part is that the sequence animation should begin slowly and speed up exponentially. This is what i have so far:

var animationLength = 2000; //ms

var counter = 0,
    counterEnd = 100,
    countInterval = animationLength / counterEnd; // 20ms

function animate() {
  $('#result').text(counter++);
  if (counter <= counterEnd) {

    //Calculate here dynamically newInterval
    var newInterval = countInterval;

    countInterval = newInterval;
    setTimeout(animate, newInterval);
  }
}

animate();

So, now countInterval is constantly 20ms, but it should be variable, decreasing exponentially. Eg:

counter = 1; => countInterval = 40ms //not sure about that
...
counter = 100; => countInterval = 1ms

And the summatory of these intervals has to be 2000ms

https://jsfiddle.net/fvxf7mby/5/


UPDATE:

thanks to @Mats Lind i finally found out. That's the final code (JSFIDDLE)

var animationLength = 2000; //ms

var counter = 0,
    counterEnd = 100,
    countInterval = animationLength / counterEnd, // 20 ms,
    a = 1.05; //speed factor

var summatory = 0;

function animate() {
  $('#result').text(counter++);
  if (counter <= counterEnd) {

    //that's the formula:
    var newInterval = (animationLength-summatory) / ( (a - Math.pow(a, -(counterEnd-1))) / (a-1))

    summatory += newInterval;
    countInterval = newInterval;
    setTimeout(animate, newInterval);
  } else {
    $('#summatory').text(summatory); //should be 2000
  }
}

animate();
pumpkinzzz
  • 2,907
  • 2
  • 18
  • 32

3 Answers3

2

Looking at the "hardest part", the math question about speeding up exponentially:

With time-interval inversely proportional to speed, we like the time-interval to decrease. Exponentially mean a decrease with the same factor between each interval.

Call the factor 1/a and set the first time-interval to b, then next time-interval will be be b/a, the third b/a^2 and the n:th b/a^(n-1).

Total time for N timesteps is b*(a-a^-(N-1))/(a-1) (summation formula for an exponential series), excel formula; =(a-a^-(N-1))/(a-1)

Now we know total time 2000ms and number of steps 100, and have two unknown, b and a, but only one equation. So we can set a and have b given via the equation above b=total_time/((a-a^-(N-1))/(a-1)). The more we want time to "accelerate" the higher we should set a. To conclude:

time interval length for interval n>0: b/a^(n-1)

total_time: choose, in this example total_time = 2000ms

N: choose, in this example N=100

a: choose, higher the faster you want speed to increase

b=total_time/((a-a^-(N-1))/(a-1)).

Try for instance a = 1.05 which gives b = 95.96788204ms and all timesteps:

95.96788204 91.39798289 87.04569799 82.90066476 78.95301405 75.19334672 71.61271116 68.20258206 64.95484005 61.86175243 58.9159547 56.11043304 53.43850766 50.89381682 48.47030173 46.16219213 43.9639925 41.87046905 39.87663719 37.97774971 36.16928543 34.44693851 32.8066081 31.24438867 29.75656064 28.33958156 26.99007768 25.70483588 24.48079608 23.31504388 22.2048037 21.14743209 20.14041152 19.1813443 18.26794696 17.39804472 16.5695664 15.78053943 15.02908517 14.31341445 13.63182328 12.98268884 12.36446556 11.77568149 11.21493475 10.68089024 10.17227642 9.687882303 9.226554574 8.787194832 8.368756983 7.970244746 7.590709282 7.229246935 6.884997081 6.557140077 6.244895312 5.947519344 5.664304138 5.394575369 5.137690828 4.893038884 4.660037032 4.438130507 4.226790959 4.025515199 3.833823999 3.651260951 3.477391382 3.311801316 3.154096492 3.003901421 2.860858496 2.724627139 2.594882989 2.471317133 2.353635365 2.24155749 2.134816657 2.033158721 1.936341639 1.844134894 1.756318947 1.672684712 1.593033059 1.517174342 1.444927944 1.376121852 1.31059224 1.248183085 1.188745796 1.132138853 1.078227479 1.026883313 0.977984108 0.931413436 0.887060415 0.844819443 0.804589946 0.766276139

Mats Lind
  • 914
  • 7
  • 19
  • whoa, this looks like what i'm looking for, but i can't make it works that formula: `b=total_time/(*(a-a^-(N-1))/(a-1))`. what's that `*` ? – pumpkinzzz Aug 31 '16 at 14:00
  • i must be missing something. i tried formula `b = total_time/((a-a^-(N-1))/(a-1))` replacing the variables with values you said: `b = 2000/((1.05-1.05^-(100-1))/(1.05-1))` but the result is `-1.010101010101011` – pumpkinzzz Aug 31 '16 at 14:30
  • I'm cutting and pasting into excel and getting 95.96788204: exponent first -(100-1)= -99, Power then: -1.05^-99 = -0.00798... so we have 1.05-1.05^-(100-1) = 1.042.. so 2000/((1.05-1.05^-(100-1))/(1.05-1))=2000/(1.042/0.5)=2000/20.84...=95.96... You don't go wrong there, do you? What do you mean with "the result", not "b", then what? – Mats Lind Aug 31 '16 at 14:57
  • big N is fixed at 100 so b is fixed and ready as per above. Now time interval length number two: small n is 2, interval length is b/(a^(n-1))=b/a = 91.39... – Mats Lind Aug 31 '16 at 15:47
  • thanks! it works, check out https://jsfiddle.net/fvxf7mby/6/ :) last thing i don't get is why at the end summatory value is `1985.3628196047` instead of `2000`? check out that link – pumpkinzzz Aug 31 '16 at 15:47
  • Try starting at n=1 instead of 0! – Mats Lind Aug 31 '16 at 15:52
0

This would be much easier with setTimeout:

var animationLength = 1000; // 1 second
var counter = 0;
var counterEnd = 100;

function animate() {
  // Do stuff
  $('#output').text(counter++);
  animationLength *= 0.5; // not exponential - but speed will half on each iteration
  if (counter <= counterEnd) { // Stopping condition
    setTimeout(animate, animationLength);
  }
}

animate(); // Starting the "loop"
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output"></div>
Nicholas Robinson
  • 1,359
  • 1
  • 9
  • 20
  • formula `animationLength *= 0.5` means that when counter = 1 `animationLength` value will be 1000, 2: 500ms, 3: 250ms... and 11: 1ms. What i expected was **100**: 1ms – pumpkinzzz Aug 31 '16 at 09:22
  • Fair enough, I will post an update on that. But if you want 100 to be 1ms, your starting number will have to be outrageously huge for an exponential speed up. – Nicholas Robinson Aug 31 '16 at 09:29
  • be aware the animation should finish in exactly 2 seconds (`animationLength`) – pumpkinzzz Aug 31 '16 at 09:31
  • 2 seconds ? and you want to see the exponential speed up in 2 secs ? – Amar Singh Aug 31 '16 at 09:33
  • @YoYo why not? anyway that's an arbitrary value, you can set it to 5 seconds if you're more comfortable with that – pumpkinzzz Aug 31 '16 at 09:36
  • You are going to battle with to get that right with timeout and interval. As Seb commented on your question, there is a min speed on the two - If you want exponential speedup – Nicholas Robinson Aug 31 '16 at 09:36
  • @NicholasRobinson i am aware of that, but is not that important. Anyway, i expect a sequence of exactly **100** numbers from 40 to 1, like this: [40, 40, ... 40, 39, 39, 38, ... 2, 2, 1, 1, 1] where the sum of all those numbers is **2000** – pumpkinzzz Aug 31 '16 at 09:50
  • @NicholasRobinson anyway that initial 40 is just a guess, it should be calculated – pumpkinzzz Aug 31 '16 at 09:58
  • @pumpkinzzz what is exponential about that? – Nicholas Robinson Aug 31 '16 at 10:03
  • @NicholasRobinson what's the term then? – pumpkinzzz Aug 31 '16 at 10:06
  • I have no idea, I don't think there is a term for that. For this to be exponential each delay should be double the speed (half the time) of that of the last delay. [1,2,4,8,16,32...] – Nicholas Robinson Aug 31 '16 at 10:14
0

Using the fiddle mentioned in A.Wolf 's comment. Just edited his jsfiddle as per your require ment

var counter = 1000;

var num = 1;
var myFunction = function(){
    counter = counter -20;
    
   $("#result").html(num);
   num++;
    if(num <=100)
    {
    timeout = setTimeout(myFunction, counter);
    }
}

var timeout = setTimeout(myFunction, counter);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="result">

</div>
Community
  • 1
  • 1
Amar Singh
  • 5,464
  • 2
  • 26
  • 55
  • line `counter = counter -20;` seems to very arbitrary. the animation should finish exactly in the given time: 1 second in your example (2 in mine) – pumpkinzzz Aug 31 '16 at 09:29
  • Exactly at what time interval you want to finish ? – Amar Singh Aug 31 '16 at 09:32
  • @pumpkinzzz : How about this demo https://jsfiddle.net/amarsingh/86d4xhoz/ – Amar Singh Aug 31 '16 at 09:39
  • Then You need to tell me what should be the start interval and the end interval. You are not clear – Amar Singh Aug 31 '16 at 09:48
  • if you see in the OP i calculated an average speed of 20ms. So i guess it should be a sequence of exactly **100** numbers (`counterEnd`) from 40 to 1, like this: [40, 40, ... 40, 39, 39, 38, ... 2, 2, 1, 1, 1] where the sum of all these numbers is 2000 (`animationLength`) – pumpkinzzz Aug 31 '16 at 09:59