how to make a traffic light count properly

64 Views Asked by At

how do i make this traffic light count properly the duration ("duração"), after the first cicle, starts a visual glitch on the timer glitch

var sinal = setTimeout(red, 0)
function red() {
    let i = 0
    vermelho.style.backgroundColor = cores[0];
    amarelo.style.backgroundColor = cores_off[1];
    verde.style.backgroundColor = cores_off[2];
    setTimeout(yellow, 60000)
    var d1 = setInterval(function duração1() {
        i++
        cromonometro.innerHTML = `${i}`
    }, 1000)
}
function yellow() {
    let i = 0
    vermelho.style.backgroundColor = cores_off[0];
    amarelo.style.backgroundColor = cores[1];
    verde.style.backgroundColor = cores_off[2];
    setTimeout(green, 7000)
    var d2 = setInterval(function duração2() {
        i++
        cromonometro.innerHTML = `${i}`
    }, 1000)
}
function green() {
    let i = 0
    vermelho.style.backgroundColor = cores_off[0];
    amarelo.style.backgroundColor = cores_off[1];
    verde.style.backgroundColor = cores[2];
    setTimeout(red, 60000)
    var d3 = setInterval(function duração3() {
        i++
        cromonometro.innerHTML = `${i}`
    }, 1000)
}

i tried to use clear interval, but i don't have the knowledge yet

2

There are 2 best solutions below

0
Thomas Frank On BEST ANSWER

There is a way of doing this that might be easier to follow. By using async/await you can write a function that 'sleeps' for a number of seconds, we can then use that function instead of calling setTimeout and setInterval.

(Unfortunately there is no built in sleep function in JavaScript, but we can create one with a oneliner, basically we create a promise that will resolve after a number of ms that you choose when you call the sleep function. And since await is just one way of calling promises await sleep(milliseconds) then works fine inside an async function.)

We create an array with the sequence and time each light should be on, easy to find and change since it is separate from the rest of the programming logic.

Then we just loop through that array, turn the right light on, sleep for the duration specified in the array and turn the light off, moving on to the next part of the sequence in the next iteration of the loop, and so on...

At the end of our function we call the function again (recursion) to repeat the sequence.

async function trafficLight() {
  // a function that let us sleep/pause for a number of ms
  const sleep = ms => new Promise(res => setTimeout(res, ms));
  // get the div for each light
  const [red, yellow, green] =
    [...document.querySelectorAll('.traffic-light div')];
  // how many seconds should each light be on in a sequence
  const onForSeconds = [
    [red, 5],
    [yellow, 1],
    [green, 4],
    [yellow, 1]
  ];
  // run the sequence
  for (let [light, seconds] of onForSeconds) {
    light.classList.add('active');
    await sleep(seconds * 1000);
    light.classList.remove('active');
  }
  // call trafficLight again to repeat the sequence
  trafficLight();
}

trafficLight();
.traffic-light {
  display: inline-block;
  background: black;
}

.traffic-light div {
  border-radius: 50%;
  width: 50px;
  height: 50px;
  margin: 10px;
  background-color: rgba(255, 255, 255, 0.3);
  transition: background-color 0.5s;
}

.red.active {
  background-color: red;
}

.yellow.active {
  background-color: yellow;
}

.green.active {
  background-color: green;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Traffic-lights</title>
</head>

<body>
  <div class="traffic-light">
    <div class="red"></div>
    <div class="yellow"></div>
    <div class="green"></div>
  </div>
</body>

</html>

0
Barmar On

Make d1, d2, and d3 global variables. Then each function can clear the previous interval.

var sinal = setTimeout(red, 0)
let d1, d2, d3;

function red() {
  clearInterval(d3);
  let i = 0
  vermelho.style.backgroundColor = cores[0];
  amarelo.style.backgroundColor = cores_off[1];
  verde.style.backgroundColor = cores_off[2];
  setTimeout(yellow, 60000)
  d1 = setInterval(function duração1() {
    i++
    cromonometro.innerHTML = `${i}`
  }, 1000)
}

function yellow() {
  clearInterval(d1);
  let i = 0
  vermelho.style.backgroundColor = cores_off[0];
  amarelo.style.backgroundColor = cores[1];
  verde.style.backgroundColor = cores_off[2];
  setTimeout(green, 7000)
  d2 = setInterval(function duração2() {
    i++
    cromonometro.innerHTML = `${i}`
  }, 1000)
}

function green() {
  clearInterval(d2);
  let i = 0
  vermelho.style.backgroundColor = cores_off[0];
  amarelo.style.backgroundColor = cores_off[1];
  verde.style.backgroundColor = cores[2];
  setTimeout(red, 60000)
  d3 = setInterval(function duração3() {
    i++
    cromonometro.innerHTML = `${i}`
  }, 1000)
}

BTW, your cycle is backwards. The normal order is green -> yellow -> red.