2015-04-30 2 views
8

Каков наилучший способ получить разницу во времени между обратным вызовом «window.requestAnimationFrame» в javascript?Javascript: Как получить разницу во времени между window.requestAnimationFrame

Я попытался:

// create the best .requestAnimationFrame callback for each browser 
window.FPS = (function() { 
    return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || 
    function(callback) {window.setTimeout(callback, 1000/60);}; 
})(); 

// start animation loop 
var dt, stamp = (new Date()).getTime(); 
function loop() { 
    window.FPS(loop); 
    var now = (new Date()).getTime(); 
    var dt = now - stamp; 
    stamp = now; 
} 
// has "dt" the best accuracy? 
+1

потенциал Дубликат: http://stackoverflow.com/questions/8279729/calculate-fps-in-canvas- using-requestanimationframe –

+0

Справедливо уверен, что обратный вызов передается одним параметром, временной меткой (в полной реализации nativeAnimationFrame), если вы ищете поддержку для заполнения полиса, есть те, которые эмулируют параметр timestamp лучше, чем то, что у вас есть для вашего окно.FPS полипол. [Это] (https://gist.github.com/timhall/4078614), возможно, является одним из лучших, которые я видел. Связано с [this] (http://stackoverflow.com/questions/13241314/up-to-date-polyfill-for-requestanimationframe) Вопрос SO – OJay

+1

Кстати, вы можете полностью исключить IEFE и его 'return', просто назначьте' window.raf = ... || ... || function (cb) {...}; ' – Bergi

ответ

2

Большинство современных браузеров автоматически отправлять в высокоточной временной метки в качестве аргумента в каждом цикле requestAnimation обратного вызова: http://caniuse.com/#search=performance

Таким образом, вы просто вычесть последнюю метку из текущего времени для получения прошедшего времени с момента последнего запуска цикла.

Вот пример кода и демо:

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 

 
var startingTime; 
 
var lastTime; 
 
var totalElapsedTime; 
 
var elapsedSinceLastLoop; 
 

 
var $total=$('#total'); 
 
var $loop=$('#loop'); 
 

 
requestAnimationFrame(loop); 
 

 
function loop(currentTime){ 
 
    if(!startingTime){startingTime=currentTime;} 
 
    if(!lastTime){lastTime=currentTime;} 
 
    totalElapsedTime=(currentTime-startingTime); 
 
    elapsedSinceLastLoop=(currentTime-lastTime); 
 
    lastTime=currentTime; 
 
    $total.text('Since start: '+totalElapsedTime+' ms'); 
 
    $loop.text('Since last loop: '+elapsedSinceLastLoop+' ms'); 
 
    requestAnimationFrame(loop); 
 
}
body{ background-color: ivory; } 
 
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
 
<p id=total>T1</p> 
 
<p id=loop>T2</p> 
 
<canvas id="canvas" width=300 height=300></canvas>

Для нескольких браузеров, которые не поддерживают Performance, вы должны будете использовать Date.now() вместо currentTime внутри цикла, так как нет timestamp автоматически отправляется этими браузерами в цикл.

+0

Что там делает 'parseInt'? Как обладатель значка js gold вы должны знать лучше! – Bergi

+0

@Bergi. Смех, согласился! – markE

4

имеет "DT" лучшую точность?

Нет. В соответствии с the docs,

Метод обратного вызова передается единственный аргумент, DOMHighResTimeStamp, который указывает текущее время, когда обратные вызовы в очереди с помощью requestAnimationFrame начинают стрелять

, поэтому вы должны использовать его для получения высокой точности.

function loop(now) { 
    var last = now || Date.now(); // fallback if no precise time is given 
    window.FPS(function(now) { 
     now = now || Date.now(); 
     var dt = now - last; 
     if (dt != 0) // something might be wrong with our frames 
      console.log(dt); 
     loop(now); 
    }); 
} 
window.FPS(loop); 

(jsfiddle demo)

+0

Также стоит заметить, что временная метка rAF будет в какой-то мере квантована на 16,67 мс, 16,67x2 и т. д., поскольку она синхронизируется с частотой обновления монитора. – K3N

+0

var last = now || Date.now() ошибочно, я думаю. «now» - это отметка времени с момента начала анимации, а Date.now() - временная отметка Unix – marirena

+0

@marirena: Нет, 'now'" * указывает текущее время * "в соответствии с документами, а не время с момента вызова rAF. Это абсолютная миллисекундная метка времени, как «Дата.теперь ', но с большей точностью (и, возможно, другим происхождением). Вы можете полностью опустить '|| ... 'также, это просто резерв для несовместимых прошивок rAF. – Bergi

2

Напишу однозначный вывод, что для всех, кто хочет использовать этот шаблон

// CREATING AN FPS ENGINE 

window.FPS = (function() { 
    return window.requestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.mozRequestAnimationFrame || 
    window.oRequestAnimationFrame || 
    window.msRequestAnimationFrame || 
    function(callback) {window.setTimeout(callback, 1000/60);}; 
})(); 

var FPS = { 
    loop: function(canvas_object) { // OPTIONAL canvas_object, I think it increases performance | canvas_object = document.getElementById("canvas_id") 
     var ticks = window.FPS(function(now){ 
      var dt = now - FPS.stamp || 0; 
      FPS.stamp = now; 
      FPS.update(dt, FPS.stamp, ticks); 
      FPS.loop(canvas_object); 
     }, canvas_object); 

    }, 
    update: undefined, 
    stamp: undefined 
}; 

// USING THE FPS ENGINE 

FPS.loop(the_canvas_object); // starts the engine 
FPS.update = function(dt, stamp, ticks) { 
    // The game/video loop, using accurate dt. Stamp is the time since engine started. Ticks is the number of the loop cycles 
    console.log("dt: " + dt + ", Stamp: " + stamp + ", Ticks: " + ticks); // check output 
    // HAPPY GAME CREATING 
    var fps= (1/(dt/1000)).toFixed(1); 
}; 
+1

'(1/(dt/1000))' можно упростить: '(1000/dt)'. Не знаю, почему ты это сделал. –

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