2012-02-16 2 views
12

Как я понимаю, использование API JS requestAnimationFrame предназначено для случаев, когда частота кадров не нуждается в управлении, но у меня есть вариант использования, когда важно, чтобы <canvas> обновлялся только при определенный интервал fps, который может быть где-то между 1 и 25 (от 1 до 25 кадров в секунду, то есть). Могу ли я затем каким-то образом эффективно использовать rAF для получения оптимизаций, которые он предлагает?requestAnimationFrame при ограниченной частоте кадров

This question имеет сходство с моим, но принятый ответ там дал мне почти что смысл в контексте этого вопроса.

У меня есть два возможных решения для этого. Первый включает использование цикла while, чтобы остановить выполнение скрипта за указанную задержку до вызова requestAnimationFrame из обратного вызова. В примере, где я видел это, он фактически ограничивал fps анимации, но также, казалось, замедлял всю вкладку. Действительно ли это на самом деле хорошее решение? Второй вариант, упомянутый в вопросе I, который связан выше, вызывает requestAnimationFrame в пределах setInterval. Для меня это кажется немного запутанным, но может быть, это лучший вариант?

Или есть лучшая альтернатива для этого?

+0

Я просто тестирование код теперь ... :) –

+0

Нужна ли вам фиксированную частоту кадров, чтобы вычислить вещи или просто для отображения цели? – Yoshi

+0

Фиксированная частота кадров предназначена для отображения. – fredrikekelund

ответ

12

Ответ Yoshi, вероятно, является лучшим решением для решения этой проблемы. Но все же я буду отмечать этот ответ как правильный, потому что после некоторого исследования я в основном обнаружил, что мой вопрос недействителен. requestAnimationFrame действительно предназначен для того, чтобы максимально снизить частоту кадров, и он оптимизирует сценарии, в которых анимация должна быть последовательной и плавной.

Стоит отметить, что вам не нужно requestAnimationFrame, чтобы получить оптимизацию (хотя rAF рекламировался как отличный усилитель производительности), поскольку браузеры все еще оптимизируют регулярный рисунок <canvas>. Например, когда вкладка не сфокусирована, Chrome за один раз рисует свои холсты.

Таким образом, мой вывод состоял в том, что этот вопрос был недействительным. Надеюсь, это поможет любому, кто интересуется чем-то похожим на меня.

+0

Думаю, вы абсолютно правы с вашим заключением. Поэтому принятие этого принятого ответа, вероятно, намного более полезно для будущих читателей. – Yoshi

5

Что вы можете сделать, хотя я не знаю, действительно ли это лучше есть:

  • оказывать невидимый контекст с requestAnimationFrame
  • обновлением видимого контекстом с setInterval использованием фиксированных кадров в секунду

Пример:

<canvas id="canvas"></canvas>​ 

<script type="text/javascript"> 
    (function() { 
    var 
     ctxVisible = document.getElementById('canvas').getContext('2d'), 
     ctxHidden = document.createElement('canvas').getContext('2d'); 

    // quick anim sample 
    (function() { 
     var x = 0, y = 75; 

     (function animLoop() { 
     // too lazy to use a polyfill here 
     webkitRequestAnimationFrame(animLoop); 

     ctxHidden.clearRect(0, 0, 300, 150); 
     ctxHidden.fillStyle = 'black'; 
     ctxHidden.fillRect(x - 1, y - 1, 3, 3); 

     x += 1; 
     if (x > 300) { 
      x = 0; 
     } 
     }()); 
    }()); 

    // copy the hidden ctx to the visible ctx on a fixed interval (25 fps) 
    setInterval(function() { 
     ctxVisible.putImageData(ctxHidden.getImageData(0, 0, ctxHidden.canvas.width, ctxHidden.canvas.height), 0, 0); 
    }, 1000/40); 
    }()); 
</script> 

Демонстрация: http://jsfiddle.net/54vWN/

+1

Большое спасибо за ваш ответ, и скрипка - очень ценится! Однако я думаю, что мой вопрос действительно недействителен, поэтому я не чувствую, что могу отметить это как принятый ответ. Приобретено, хотя и снова спасибо :) – fredrikekelund

9

Это просто доказательство концепции.

Все, что мы делаем, это установить наши кадры в секунду и интервалы между каждым кадром. В функции рисования мы вычитаем время выполнения нашего последнего кадра с текущего времени, чтобы проверить, прошло ли время, прошедшее с момента последнего кадра, больше нашего интервала (который основан на fps) или нет. Если условие оценивается как true, мы устанавливаем время для нашего текущего кадра, который будет «последним временем выполнения кадра» в следующем вызове рисования.

var Timer = function(callback, fps){ 
    var now = 0; 
    var delta = 0; 
    var then = Date.now(); 

    var frames = 0; 
    var oldtime = 0; 

    fps = 1000/(this.fps || fps || 60); 

    return requestAnimationFrame(function loop(time){ 
    requestAnimationFrame(loop); 

    now = Date.now(); 
    delta = now - then; 

    if (delta > fps) { 
     // Update time stuffs 
     then = now - (delta % fps); 

     // Calculate the frames per second. 
     frames = 1000/(time - oldtime) 
     oldtime = time; 

     // Call the callback-function and pass 
     // our current frame into it. 
     callback(frames); 
    } 
    }); 
}; 

Использование:

var set; 
document.onclick = function(){ 
    set = true; 
}; 

Timer(function(fps){ 
    if(set) this.fps = 30; 
    console.log(fps); 
}, 5); 

http://jsfiddle.net/ARTsinn/rPAeN/

+3

Не могли бы вы добавить некоторые рассказы, чтобы объяснить, почему этот код работает, и что делает его ответом на вопрос? Это было бы очень полезно для человека, задающего вопрос, и любого другого, кто приходит. –

+0

Здесь довольно много вещей, но это довольно умное решение. Я мог бы попытаться интегрировать это в свой код, попытаюсь вернуться сюда и добавить некоторые изменения с дальнейшими объяснениями, как только я его заработаю, если раньше ничего не случилось. – fredrikekelund

+2

Я добавил немного текста объяснения. Надеюсь, это поможет. – yckart

Смежные вопросы