0

I want to create a 'random selector' behaviour where the function iterates through an array for a period of time (example: 3 seconds, 5 seconds) while displaying all of array elements fast throughout the iteration until the iteration ends. Just imagine seeing all the elements displayed in a label one after another until it finally stops at an element.

My code so far:

var places = ["Curry Leaf", "Subway", "Burger King"];

function execute_randomizer() {
    var place_label = document.getElementById("place_label");
    for (var i = 0; i < 100; i++) {
        var selected_place = places[Math.floor(Math.random() * places.length)];
        setTimeout(function () {
            place_label.innerText = selected_place;
        }, 400);
    }
}

This runs through the iteration and displays an element when the loop is done but it doesn't show each iteration's element. How can I amend this?

EDIT

Even if there's 3 elements, the animations must re-iterate through the array until the duration is completed

Jay
  • 4,873
  • 7
  • 72
  • 137

4 Answers4

1

Your for finishes iterating before the setTimeout runs, then the function passed to setTimeout runs 100 times using the last value of selected_place.

More about this behavior in setTimeout in for-loop does not print consecutive values


Another problem that I noticed is that your setTimeout will trigger after 400ms, since the for loop will finish in about 1 ms, the function passed to setTimeout will trigger 100 times one after another with no delay in between, for this, I replaced the delay argument of setTimeout from 400 to 400 * i.


var places = ["Curry Leaf", "Subway", "Burger King"];     
function execute_randomizer() {
    var place_label = document.getElementById("place_label");
    for (var i = 0; i < 100; i++) {
        var selected_place = places[Math.floor(Math.random() * places.length)];
        (function(selected_place){
          setTimeout(function () {
              place_label.innerText = selected_place;
          }, 400 * i);
        })(selected_place);
    }
}
execute_randomizer();
<span id="place_label"></span>
Alexandru Severin
  • 6,021
  • 11
  • 48
  • 71
  • This works but it looks quite glitchy. Anyway to make it smoother? If you know what I mean – Jay Aug 04 '17 at 08:32
  • @RickGrimesTheCoder I'm not sure I know what you mean, but if you use jQuery you could use some transition animations to make the replacement of text less "abrupt" – Alexandru Severin Aug 04 '17 at 08:44
1

You could use a closure over the value and a different time for each timeout.

var places = ["Curry Leaf", "Subway", "Burger King"];

function execute_randomizer() {
    var place_label = document.getElementById("place_label");
    for (var i = 0; i < 10; i++) {
        var selected_place = places[Math.floor(Math.random() * places.length)];
        setTimeout(function (value) {
            return function () {
                place_label.innerText = value;
            };
        }(selected_place), i * 100);
    }
}

execute_randomizer();
<div id="place_label"></div>

For a first run through, you could show each element and then take a random element at last value.

function execute_randomizer() {
    function cb (value) {
        return function () {
            place_label.innerText = value;
        };
    }

    var place_label = document.getElementById("place_label");

    place_label.innerText = '';
    for (var i = 0; i < places.length; i++) {
        setTimeout(cb(places[i]), 200 + i * 200);
    }
    setTimeout(cb(places[Math.floor(Math.random() * places.length)]), 200 + places.length * 200);
}

var places = ["Curry Leaf", "Subway", "Burger King"];

execute_randomizer();
<div id="place_label"></div>
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

You should change your loop because right now you go in loop 100 times in maybe one millisecond and order 100 of change text but once again in the same time. So better is wait for time out 400 ms and then make next iteration. Please remember time out is async.

hsd
  • 452
  • 5
  • 12
0

I think it might be better if you would put the whole function in a timeout. (I'm not sure and didn't test, but that's what I would try).

What I mean is that you just build a function that creates your randomizer and fills in your field. After that you put a timeout to call the same function again + keep a counter that you pass as parameter.

An example of what I mean below: (didn't test it)

var places = ["Curry Leaf", "Subway", "Burger King"];

execute_randomizer(0); /* Start for the first time */

function execute_randomizer(times) {
    if(times == 100)
        return; /* stop execution */

    var place_label = document.getElementById("place_label");
    var selected_place = places[Math.floor(Math.random() * places.length)];
    place_label.innerText = selected_place;
    setTimeout(function () {
        execute_randomizer(times+1)
    }, 400);
}
Dennis
  • 164
  • 1
  • 9