首页 > 解决方案 > Javascript binary animation infinite loop

问题描述

I have made a binary animation script which is activated by a button click.

Using the current code you can click multiple times and it will stop after each itteration. However, when I tried to refactor the code (currently commented out below), it works fine with one click, but does not stop looping if you click more than once.

Can anyone please help stop the infinite loop, or know of a better way of achieving the same result?

Here is the codepen: https://codepen.io/rbradshaw/pen/ZEYmjpx

Here is the code:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Binary</title>
</head>
<body>
  <svg xmlns="http://www.w3.org/2000/svg" xml:lang="en" id="binaryarea" width="400px" height="95px">
    <rect id="binarybackground" width="100%" height="100%" />
    <text>
        <tspan x="2" y="15" id="binary"></tspan>
        <tspan x="2" y="30" id="binary"></tspan>
        <tspan x="2" y="45" id="binary"></tspan>
        <tspan x="2" y="60" id="binary"></tspan>
        <tspan x="2" y="75" id="binary"></tspan>
        <tspan x="2" y="90" id="binary"></tspan>
    </text>
  </svg>
  <br><br>
  <button onclick="runBinary()">Click me</button>

  <script src="script.js"></script>
</body>
</html>
const binary = document.querySelectorAll('#binary');
document.getElementById("binaryarea").addEventListener("load", setBinary);

function runBinary(){
  //uncomment out from here
  // binActions = [];
  // iterations = 10;
  //to here
  iterLength = 20;

  //comment from here
  var binActions1 = setInterval(changeBinary, iterLength);
  var binActions2 = setInterval(changeBinary, iterLength);
  var binActions3 = setInterval(changeBinary, iterLength);
  var binActions4 = setInterval(changeBinary, iterLength);

  setTimeout(() => {
    clearTimeout(binActions1);
    clearTimeout(binActions2);
    clearTimeout(binActions3);
    clearTimeout(binActions4);
  }, 2000)
  //to here

  //uncomment out below from here
//   for(i = 0; i < iterations; i++) {
//     binActions[i] = setInterval(changeBinary, iterLength);
//   }   

//   setTimeout(() => {
//     binActions.forEach((_, idx) => {
//       clearTimeout(binActions[idx])
//     })
//   }, 2000)
  //to here
}

function changeBinary() {
  var rec = Math.floor(Math.random() * binary.length);
  var position = Math.floor(Math.random() * binary[0].textContent.length);
  oldtext = binary[rec].textContent;

  if (binary[rec].textContent[position] == "1") {
    newtext = getNewStr(oldtext, position, "0");
    binary[rec].textContent = newtext;
  } else {
      newtext = getNewStr(oldtext, position, "1");
    binary[rec].textContent = newtext;
  }   
}

function getNewStr(string, index, replace) {
  return string.substring(0, index) + replace + string.substring(index + 1);
}

function binaryString(charlen) {
  var str = "";
  for(i = 0; i < charlen; i++) {
      str += Math.floor(Math.random() * 2)
  }  
  return str
}

function setBinary() {
  binary.forEach(row => {
    row.textContent = binaryString(45);
  })
}

Any help is appreciated, thank you.

标签: javascript

解决方案


You need to clear the interval with the old intervalID before you start a new interval.

The shortest way is to use global variables for the intervalID supplied from setInterval and clear the intervals if needed, without having a fixed interval.

Thinkable would be global array of running intervalId, like

// global
var intervals = [];

and a function for clearing all intervals

function clearIntervals() {
    intervals.forEach(clearTimeout);
    intervals.length = 0;            // empty array by keeping the object reference
}

Then in

function runBinary() {

clear the old intervals

clearIntervals();

and add the intervals to intervals

intervals.push(binActions1, binActions2, binActions3, binActions4);

as well as the clearance of the intervals.

intervals.push(setTimeout(clearIntervals, 3000));

The last one prevent hanging over intervals with a fixed interval.


推荐阅读