Skip to content

Instantly share code, notes, and snippets.

@pgarciacamou
Created January 4, 2017 19:15
Show Gist options
  • Save pgarciacamou/9a297d136695eac9fa43f3bdf4644a20 to your computer and use it in GitHub Desktop.
Save pgarciacamou/9a297d136695eac9fa43f3bdf4644a20 to your computer and use it in GitHub Desktop.
Request Animation Frame HOAX! requestAnimationFrame with setTimeout to push the fps-limited browsers like iOS8.
/*
* Tasks that are supposed to be executed every screen paint.
*/
var tasks = [
() => {
var now = Date.now();
// heavy algorithm example
for(var i = 0; i < 200/*000*/; i+=1){
var dummy = i * 0.1;
}
var milliseconds = Date.now() - now;
// console.log(`algorithm milliseconds: ${milliseconds}`);
}
];
/*
* HELPER: applies a linear transformation to a range to convert it
* to a different range.
*
* E.g. from range [-20, 20] TO [-90, 90]
*/
function linearTransformation(value, sourceMin, sourceMax, destMin, destMax) {
return ((value - sourceMin) / (sourceMax - sourceMin)) * (destMax - destMin) + destMin;
}
/*
* requestAnimationFrame loop
*
* Computes the top speed at which the screen can render
* by keeping track of the highest fps ever (fpsHighestRecord) gotten.
*
* The renderer's speed becomes a function of this fpsHighestRecord.
*
* E.g. iOS8 and above, where fpsHighestRecord is limited to 30fps;
* speed would transform from 0->30fps to 0->16ms (roughly 60fps).
* Thus hacking around the limits.
*
* BUT devices that are not limited;
* speed would transform from 0->~60fps to 0->16ms.
* Thus no change.
*/
var previousTimestamp;
var renderSpeedUpperBound = Math.floor(1000/60);
var renderCurrentSpeed = renderSpeedUpperBound;
var fpsHighestRecord = 0;
requestAnimationFrame(function speedLoop(currentTimestamp){
previousTimestamp = isNaN(previousTimestamp) ? currentTimestamp : previousTimestamp;
if(currentTimestamp > previousTimestamp) {
var tick = currentTimestamp - previousTimestamp;
var fps = Math.floor(1000 / tick);
fpsHighestRecord = Math.max(fpsHighestRecord, fps);
renderCurrentSpeed = linearTransformation(fps, 0, fpsHighestRecord, 0, renderSpeedUpperBound);
previousTimestamp = currentTimestamp;
// console.log(fpsHighestRecord);
// console.log(fps);
}
requestAnimationFrame(speedLoop);
});
/*
* renderLoop
*
* It is a requestAnimationFrame HOAX!.
*
* By using a timeout loop, we can use the renderSpeed computed
* to push the limits of which the device can paint the screen.
*
* An arbitraryInitialWaitingTime is used to allow the requestAnimationFrame
* to compute the fastest the device can go before starting to execute the tasks.
*
* NOTE: this is NOT the same as an interval (but very simillar).
*/
var arbitraryInitialWaitingTime = 500;
setTimeout(function renderLoop(){
setTimeout(renderLoop, renderCurrentSpeed);
tasks.forEach(fn => fn());
}, arbitraryInitialWaitingTime);