-1

I am making a screensaver that displays the elements inside an array with a delay between each iteration, to display the elements slowly one by one. My "onmousemove" event successfully removes the screensaver from the page, but the for loop in my startScreensaver() function keeps running when it should in fact break. What am I doing wrong?

see JSfiddle https://jsfiddle.net/m60k75jf/

  const idletime = 2;
  const screenSaver = document.getElementById("screensaver");
  const stars = Array.from(document.querySelectorAll(".star"));
  let mousetimeout;
  let screensaverActive = false;

  window.addEventListener("mousemove", (e) => {
    clearTimeout(mousetimeout);
    if (screensaverActive) {
      stopScreensaver();
    } else {
      mousetimeout = setTimeout(function () {
        startScreensaver();
      }, 1000 * idletime);
    }
  });

  function stopScreensaver() {
    screensaverActive = false;
    stars.forEach((star) => {
      star.classList.remove("is--visible");
    });
    screenSaver.classList.remove("is--active");
  }

  function startScreensaver() {
    screensaverActive = true;
    screenSaver.classList.add("is--active");
    for (let index = 0; index < stars.length; index++) {
      if (screensaverActive) {
        setTimeout(function () {
          stars[index].classList.add("is--visible");
        }, 2000 * index);
      } else {
        break;
      }
    }
  }
jayyay
  • 3
  • 3
  • Does this answer your question? [How to stop a setTimeout loop?](https://stackoverflow.com/questions/8443151/how-to-stop-a-settimeout-loop) – Liam Mar 16 '22 at 16:27

1 Answers1

0

You can't break the loop like that. Your loop creates all these setTimeout immediately. Your condition will just never trigger. What you'll need to do is clear out all those setTimeout. You can push them into an array.

let animationTimeouts;
  function startScreensaver() {
    animationTimeouts = [];
    screensaverActive = true;
    screenSaver.classList.add("is--active");
    for (let index = 0; index < stars.length; index++) {
      if (screensaverActive) {
        animationTimeouts.push(setTimeout(function () {
          stars[index].classList.add("is--visible");
        }, 2000 * index));
      } else {
        break;
      }
    }
  }

Then clear them out on stopScreensaver

  function stopScreensaver() {
    screensaverActive = false;
    if(animationTimeouts) animationTimeouts.forEach(clearTimeout);
    stars.forEach((star) => {
      star.classList.remove("is--visible");
    });
    screenSaver.classList.remove("is--active");
  }

You might also want to reconsider moving your CSS transition to .star.is--visible

MinusFour
  • 13,913
  • 3
  • 30
  • 39