2016-07-08 1 views
1

Я использую setInterval для вызова функции, которая анимирует фрактал на холсте HTML5. Существует также ползунок, позволяющий пользователю изменять качество фрактала. Все работает нормально, пока я не начну менять слайдер. Когда я меняю его, фрактальная анимация становится изменчивой, и в конечном итоге функция drawFractal перестает быть вызванной. Вот слайдер HTML:Javascript setInterval случайно останавливается

<input type="range" id="qualitySlider" min="1" max="10"></input> 

Вот Javascript (он просто создает фрактал):

var count = 0.5; 

var slider = document.getElementById("qualitySlider"); 
var g = document.getElementById("drawingCanvas").getContext("2d"); 

function drawFractal() { 
    var cellSize = Math.ceil(slider.value); 
    //canvas is 700 by 400 
    g.fillStyle = "black"; 
    g.clearRect(0, 0, 700, 400); 

    //Eveything from here to the end of this function generates the fractal 
    var imagC = Math.cos(count)*0.8; 
    var realC = Math.sin(count)*0.5; 
    for (x = 0; x < 700; x+=cellSize) { 
     for (y = 0; y < 400; y+=cellSize) { 
      var yCoord = (x/700.0 - 0.5)*3; 
      var xCoord = (y/400.0 - 0.5)*3; 
      var real = xCoord; 
      var imag = yCoord; 

      var broken = 0; 
      for (i = 0; i < 8; i++) { 
       var temp = real*real - imag*imag + realC; 
       imag = 2*imag*real + imagC; 
       real = temp; 
       if (real*real + imag*imag >= 4) { 
        broken = true; 
        break; 
       } 
      } 

      if (!broken) { 
       g.fillRect(x, y, cellSize, cellSize); 
      } 
     } 
    } 
    count = count + 0.04; 
} 

setInterval(drawFractal, 60); 

Я просто нужна функция "drawFractal" будет называться надежно каждые 60 миллисекунд.

+4

использование 'запросAnimationFrame'. сафари известен тем, что пропускает события таймера. –

+3

Вы можете выполнить эту функцию менее чем за 60 мс? Ваш внутренний цикл 'for' будет выполняться до 2.2 миллионов раз (700 * 400 * 8) каждый раз, когда он вызывается. Интересно, просто ли браузер понимает бесполезность вызова этого каждые 60 мс, когда он не заканчивается менее чем. – jfriend00

+0

Рекурсивный setTimeout может быть лучшим подходом, если метод может занять больше времени, чем заданный интервал для вычисления, лучше по-прежнему запрашивать анимационный фрейм, как было предложено. – ste2425

ответ

-2

Вы используете setInterval() для вызова drawFractal каждые 60 мс, а затем каждый раз, когда выполняется drawFractal, вы вызываете setInterval() снова, что не является необходимым. У вас теперь есть два таймера, пытающихся рисовать фракталы каждые 60 мс ... тогда у вас будет 4, затем 8 и т. Д.

Вам необходимо либо (1) вызвать setInterval() один раз в начале выполнения программы, не называть его снова или (2) переключиться на использование setTimeout() и вызвать его в конце каждого drawFractal().

Я бы воспользовался вторым вариантом, на случай, если ваш фрактал займет больше 60 мс.

+0

Это не то, что происходит. –

0

Это мой улучшенный код. Я просто использовал requestAnimationFrame для рекурсивного вызова функции drawFractal. Я также ограничил анимацию 24 кадрами/сек функцией setTimeout.

var count = 0.5; 

var qualitySlider = document.getElementById("qualitySlider"); 
var g = document.getElementById("drawingCanvas").getContext("2d"); 

function drawFractal() { 
    var cellSize = Math.ceil(qualitySlider.value); 
    //canvas is 700 by 400 
    g.fillStyle = "black"; 
    g.clearRect(0, 0, 700, 400); 
    var imagC = Math.cos(count)*0.8; 
    var realC = Math.sin(count)*0.5; 
    for (x = 0; x < 700; x+=cellSize) { 
     for (y = 0; y < 400; y+=cellSize) { 
      var yCoord = (x/700.0 - 0.5)*3; 
      var xCoord = (y/400.0 - 0.5)*3; 
      var real = xCoord; 
      var imag = yCoord; 

      var broken = 0; 
      for (i = 0; i < 8; i++) { 
       var temp = real*real - imag*imag + realC; 
       imag = 2*imag*real + imagC; 
       real = temp; 
       if (real*real + imag*imag >= 4) { 
        broken = true; 
        break; 
       } 
      } 

      if (!broken) { 
       g.fillRect(x, y, cellSize, cellSize); 
      } 
     } 
    } 
    count = count + 0.04; 
    setTimeout(function() { 
     requestAnimationFrame(drawFractal); 
    }, 41); 
} 

drawFractal();