2015-04-30 6 views
8

Was ist der beste Weg, um den Zeitunterschied zwischen "window.requestAnimationFrame" Rückruf in Javascript zu erhalten?Javascript: So erhalten Sie den Zeitunterschied zwischen window.requestAnimationFrame

Ich habe versucht:

// 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

Potential Duplikat verwenden möchte: http://stackoverflow.com/questions/8279729/calculate-fps-in-canvas- using-requestanimationframe –

+0

Ziemlich sicher, dass der Callback einen einzelnen Parameter, ein Timestamp (in vollständigen nativen requestAnimationFrame-Implementierungen) übergeben wird, wenn Sie nach Unterstützung für die Polyfill suchen, gibt es diejenigen da draußen, die den Timestamp-Parameter besser als das, was Sie für Ihre haben window.FPS Polyfill. [This] (https://gist.github.com/timhall/4078614) ist vielleicht einer der besseren, die ich je gesehen habe. Bezogen auf [das] (http://stackoverflow.com/questions/13241314/up-to-date-polyfill-for-requestanimationframe) SO Frage – OJay

+1

Btw, Sie können vollständig IEEF und seine 'return' weglassen, einfach zuweisen' window.raf = ... || ... || function (cb) {...}; ' – Bergi

Antwort

2

Die meisten modernen Browser automatisch in einem hochgenauen Zeitstempel als Argument in jede requestAnimation Rückruf Schleife senden: http://caniuse.com/#search=performance

So einfach Sie die letzten Zeitstempel aus dem aktuellen Zeitstempel subtrahiert um die verstrichene Zeit seit dem letzten Durchlauf der Schleife zu erhalten.

Hier ist Beispielcode und eine Demo:

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>

Für das Paar von Browsern, die nicht Performance unterstützen, werden Sie Date.now() statt currentTime innerhalb der Schleife verwenden, da keine Der Zeitstempel wird automatisch von diesen Browsern in die Schleife gesendet.

+0

Was macht das dort parsInt? Als js gold badge holder solltest du es besser wissen! – Bergi

+0

@Bergi. Chuckle, einverstanden! – markE

4

hat "dt" die beste Genauigkeit?

No. Nach the docs,

Die Callback-Methode ein einziges Argument übergeben wird, ein DOMHighResTimeStamp, die die aktuelle Zeit anzeigt, wann die Warteschlange gestellt Rückrufe von requestAnimationFrame beginnen

abzufeuern

also sollten Sie lieber das verwenden, um hohe Präzision zu erhalten.

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

Es ist auch erwähnenswert, dass der rAF-Zeitstempel in jedem Fall auf 16.67ms, 16.67x2 usw. etwas quantisiert wird, da er mit der Bildwiederholfrequenz des Monitors synchronisiert ist. – K3N

+0

var last = jetzt || Date.now() ist falsch, denke ich. "now" ist der Zeitstempel seit dem Start von animationFrame, während Date.now() der Unix-Zeitstempel ist – marirena

+0

@marirena: Nein, 'now'" * zeigt die aktuelle Zeit * "entsprechend den Dokumenten an, nicht die Zeitspanne seit dem Aufruf von rAF. Es ist ein absoluter Millisekunden-Zeitstempel, genau wie "Date".jetzt, aber mit größerer Genauigkeit (und möglicherweise einer anderen Herkunft). Sie können das '|| komplett weglassen ... Teil auch, es ist nur ein Fallback für inkompatible rAF Shims. – Bergi

2

Ich werde eine klare Schlussfolgerung schreiben, für alle, die dieses Muster

// 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))' kann vereinfacht werden: '(1000/dt)'. Ich weiß nicht, warum du es so gemacht hast. –