0

I am trying to color some rectangles, but want it done with one second intervals so I can see them changing color one by one. enter image description here

enter image description here

I have tried using setTimeout(); and have looked at many different answers in stack overflow but I have not been able to get it to work, currently when I use this code the time delay seems to add up and then all the blocks change color at the same time.

function dijkstra(){
for (y = 0; y < 10; y++){
    for(x = 0; x < 10; x++){
        const div = document.getElementById(`${x} ${y}`);
        setTimeout(function() { 
            div.setAttribute('class', 'searched') 
        }, 500); 

    }
}  

}

I am using the code below to generate the code

for (y = 0; y < 10; y++){
const row = document.createElement('div');
row.setAttribute('class', y);
for(x = 0; x < 10; x++){
    const block = document.createElement('div');

    block.setAttribute('class', 'unsearched');
    block.setAttribute('id', `${x} ${y}`);
    row.appendChild(block);
}
body.appendChild(row);
}

and this is what my html looks like

    <!DOCTYPE html>
    <head>
        <title>Path Finding</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div id = "navbar">
            <ul id="ulist">
                <li id="start" onclick="dijkstra()"><a>start</a></li>
            </ul> 
        </div>
        <div class="big_div">
            <div class="big_container">
            </div>
        </div>
        <script type="text/javascript" src="script.js"></script>
    </body>
Rios
  • 71
  • 1
  • 6
  • 2
    can you put your html as well – Sunil Lama Mar 06 '20 at 18:26
  • Why not make a function that sets a color of one element, store the current square in a variable - and call the function for setting the first square, at the end of which you'll have setTimeout, & in the callback of it you'll call the same function for the next square. A recursion basically. – pesho hristov Mar 06 '20 at 18:29

3 Answers3

1

I think this is what you are looking for, I added a script to generate the grid since you didn't provide it, you can manipulate the animation by adding/removing x and y from the timeout function and also change 100 MS in y * x * 100.

const container = document.getElementById("container");
for (let i = 0; i < 10; i++) {
  for (let j = 0; j < 10; j++) {
    let box = document.createElement("div");
    box.classList.add("box");
    box.classList.add(`box_${i}_${j}`);
    container.append(box);
  }
}

function dijkstra() {
  for (y = 0; y < 10; y++) {
    for (x = 0; x < 10; x++) {
      const div = document.querySelector(`.box_${x}_${y}`);
      setTimeout(() => {
        div.classList.add("searched");
      }, y * x * 100);
    }
  }
}

setTimeout(() => {dijkstra();}, 800)
.box {
  width: 20px;
  height: 20px;
  background-color: gray;
  display:inline-block;
  margin: 1px;
  transition: background-color 1.5s ease;
}
#container {
  width: 220px;
  line-height: 10px;
}

.searched {
  background-color: #84dde4;
}
<div id="container">
</div>
ROOT
  • 11,363
  • 5
  • 30
  • 45
  • 1
    it is elegant that you kept OP code and just multiplied the snooze time, I like it :) – Jamesgt Mar 06 '20 at 18:47
  • Thank you, its better to keep changes as little as possible ;) Thank you! your answer is good too I would have upvoted yours too but I already reached my upvote limit for today! maybe tomorrow. – ROOT Mar 06 '20 at 18:50
1

You request 10x10 callback at the same time, this is why all the squares are changed at the same time. Learn more about how setTimeout() works, this is a great video about it.

One solution is to use the setInterval(), and by the way, it is not really a standard to use space in the id field, so I used underscore instead.

const queue = []
for (y = 0; y < 3; y++){
    for(x = 0; x < 3; x++){
        const div = document.getElementById(`${x}_${y}`);
        queue.push(div)
    }
} 

const ticker = setInterval(function() {
  const div = queue.shift()
  div.classList.add('searched') 
  if (queue.length == 0) {
    clearInterval(ticker)
  }
}, 500)
.line > div {
  display: inline-block;
  width: 10px;
  height: 10px;
  background-color: teal;
}

.line > div.searched {
  background-color: red;
}
<div class="line">
  <div id="0_0"></div>
  <div id="0_1"></div>
  <div id="0_2"></div>
</div>
<div class="line">
  <div id="1_0"></div>
  <div id="1_1"></div>
  <div id="1_2"></div>
</div>
<div class="line">
<div id="2_0"></div>
<div id="2_1"></div>
<div id="2_2"></div>
</div>
Jamesgt
  • 565
  • 5
  • 17
0

Because of the JS EventLoop all the setTimeout functions are running (almost) at the same time (Because of the single-thread property of js they are running one after another, but you won).

So you need to customize delay variable for each of the setTimeouts
to make them run with the delay of 500ms after the previous function call.

Below I tried to change a part of code to work:

function dijkstra(){
    for (y = 0; y < 10; y++){
        for(x = 0; x < 10; x++){
            const div = document.getElementById(`${x} ${y}`);
            setTimeout(function() { 
                div.setAttribute('class', 'searched') 
            }, 500 + (y*10 + x)*500);  // change this line

        }
    }
}

So setTimeouts are being executed in the below sequence:

0.5s 1s ...


You can read more about of Eventloop from here: JavaScript Event Loop Explained

Alireza HI
  • 1,873
  • 1
  • 12
  • 20
  • 1
    function calls in the event loop are processed one after another (JS is single-threaded so you can't have many functions running at the same time). Also, the time mentioned in setTimeout is the fastest time in which the function can run. – Rahul Padalkar Mar 06 '20 at 18:42
  • 1
    @RahulPadalkar thanks for the explanation. I add the `single-thread` to my description. And for the faster time that you mentioned, I have used the word `at least after 500ms` to describe it. Thanks for mentioning anyway. – Alireza HI Mar 06 '20 at 18:45