micro-fps
Version:
A super lightweight fps meter, with near zero overhead
101 lines (81 loc) • 3.68 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.microFps = factory());
}(this, (function () { 'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
/**
* @typedef {function(FpsInfo)} fpsCallback
* @callback fpsCallback
* @param {FpsInfo} fps Fps info object
*/
/**
* @typedef {Object} FpsInfo
* @property {number} fps The calculated frames per second
* @property {number} jitter The absolute difference since the last calculated fps
* @property {number} elapsed Milliseconds ellapsed since the last computation
* @property {number} frames Number of frames since the last computation
* @property {number} trigger Next computation will happen at this amount of frames
*/
/**
* FPS Meter - Returns a function that is used to compute the framerate without the overhead of updating the DOM every frame.
* @param {fpsCallback} callback Callback fired every time the FPS is computed
* @param {number} [refreshRate=1] Refresh rate which the fps is computed and the callback is fired (0 to compute every frame, not recommended)
* @return {function} Returns a function that should be called on every the loop tick
* @author Victor B - www.vitim.us - github.com/victornpb/fpsMeter
*/
function microFps(callback) {
var refreshRate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
if (typeof callback !== 'function') throw new Error('Callback is not a function');
if (typeof refreshRate !== 'number' || isNaN(refreshRate) || refreshRate < 0 || refreshRate === Infinity) throw new Error('refreshRate should be a positive number! e.g. 2 (fps)');
/** number of frames since last computation */
var frames = -1;
/** compute fps at this amount of frames (it will try to match the refresh rate) */
var trigger = 0;
/** previous timestamp */
var lastTimestamp = undefined;
/** last computed fps value */
var lastFps = 0;
/** computed jitter */
var jitter = 0;
// use performance.now() or fallback to Date.now() only check on initialization
var millis = (typeof performance === 'undefined' ? 'undefined' : _typeof(performance)) === 'object' && 'now' in performance ? performance.now.bind(performance) : Date.now.bind(Date);
return function fpsMeterTick() {
if (frames >= trigger) {
var now = millis();
if (lastTimestamp === undefined) lastTimestamp = now;
var elapsed = now - lastTimestamp;
if (elapsed > 0) {
// calculate fps
var fps = frames > 0 ? 1000 / (elapsed / frames) : 0;
// calculate jitter
jitter = Math.abs(lastFps - fps);
if (refreshRate > 0) {
// converge the trigger value exponentialy to match the current refresh rate.
trigger = trigger * 0.5 + fps / refreshRate * 0.5;
if (trigger < 0) trigger = 0;
} else {
trigger = 0;
}
var info = {
fps: fps,
jitter: jitter,
elapsed: elapsed,
frames: frames,
trigger: trigger
};
// reset variables for the next measurement
lastTimestamp = now;
lastFps = fps;
frames = 0;
callback(info);
} else {
// 2 frames on the same milliseconds, ramp the trigger up
trigger *= 2;
}
}
frames++;
};
}
return microFps;
})));