clearTimeout не останавливает анимацию холста

Итак, у меня есть простая анимация холста, которую я хочу запускать и останавливать с помощью тумблера. Анимация работает нормально и запускается, а вот clearTimeout похоже не работает.

Я убедился, что переменная «timeOut» определена глобально, поэтому у нее должен быть доступ к ней, что, казалось, было обычным советом в прошлых вопросах, подобных этому. Я ошибаюсь где-то еще? Пробовал на Firefox, Chrome и Chromium.

let timeOut;

function circles() {
  let canvas = document.querySelector('canvas');
  canvas.width = document.querySelector('canvas').offsetWidth;
  canvas.height = document.querySelector('canvas').offsetHeight;
  let c = canvas.getContext('2d');
  let topRadius = 30;
  let colorArray = [
    '#ff0000',
    '#00ff00',
    '#0000ff',
  ]

  let mouse = {
    x: undefined,
    y: undefined
  }

  window.addEventListener('mousemove', function(e) {
    mouse.x = e.x;
    mouse.y = e.y;
  })

  window.addEventListener('resize', function() {
    canvas.width = document.querySelector('canvas').offsetWidth;
    canvas.height = document.querySelector('canvas').offsetHeight;
    init();
  });

  function Circle(x, y, dx, dy, radius) {
    this.x = x;
    this.y = y;
    this.dx = dx;
    this.dy = dx;
    this.radius = radius;
    this.minRadius = radius;
    this.color = colorArray[Math.floor(Math.random() * colorArray.length)];

    this.draw = function() {
      if (this.radius < 0) {
        this.radius = this.minRadius;
      }
      c.beginPath();
      c.arc(this.x, this.y, this.radius, 0, Math.PI*2, false);
      c.fillStyle = this.color;
      c.fill();
    }

    this.update = function() {
      if (this.y + this.radius > innerHeight || this.y - this.radius <= 0) {
        this.dy = -this.dy;
      }
      if (this.x + this.radius > canvas.width|| this.x - this.radius <= 0) {
        this.dx = -this.dx;
      }
      this.x+=this.dx;
      this.y+=this.dy;

      if (mouse.x - this.x < 50 && mouse.x - this.x > -50 && mouse.y - this.y < 50 && mouse.y - this.y > -50) {
        if (this.radius < topRadius) {
          this.radius += 1; 
        }
      } else if (this.radius > this.minRadius){
        this.radius -= 1;
      }

      this.draw();
    }
  }

  let circleArray = [];
  function init() {
    circleArray = [];
    for (let i =0; i<50; i++) {
      let radius = Math.random() * 10;
      let x = Math.random() * (canvas.width - radius*2) + radius;
      let y = Math.random() * (canvas.height - radius * 2) + radius;
      let dx = (Math.random() - 0.5) * 4;
      let dy = (Math.random() - 0.5 )* 4;
      circleArray.push(new Circle(x, y, dx, dy, radius));
    }
  }

  function animate() {
    requestAnimationFrame(animate);
    c.clearRect(0,0, canvas.width, innerHeight);

    for(let i=0; i < circleArray.length; i++) {
      circleArray[i].update();
    }
  }
  init();
  animate();
}

$('#startstop').click(function() {
  if(!timeOut) {
    timeOut = setTimeout(circles, 1000);
  } else {
    clearTimeout(timeOut);
    timeOut = null;
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="display: flex; justify-content: space-around;">
  <canvas style="width: 100px; height: 800px; background: red;"></canvas>

<div id="startstop">toggle</div>
</div>


person Uberche    schedule 03.04.2018    source источник
comment
Ваш тайм-аут запускает его, тайм-аут не имеет ничего общего с анимацией.   -  person epascarello    schedule 03.04.2018


Ответы (2)


Вы были очень близки к разгадке ;)

в функцию animate добавьте строку №3 (перед циклом for), которая имеет это значение:

if (!timeOut) return;

Удачи!

person Eugene Chernenko    schedule 03.04.2018
comment
Holy-moly, большое спасибо. Столько раздражения... ;) Все еще учусь, но все равно добираюсь. - person Uberche; 04.04.2018

Эта анимация не останавливается, потому что вы вызываете clearTimeout на своем setTimeout, но она запускается только один раз. Ваша проблема связана с функцией animate. Это относительно зацикливает requestAnimationFrame. Вы можете сохранить это как запрос, а затем cancelAnimationFrame

person mountaindrew    schedule 03.04.2018