Created
January 4, 2017 19:15
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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); |
Use this at your own risk:
- http://stackoverflow.com/questions/6025661/how-can-i-get-vsync-callback-on-html5-canvas
- https://hardforum.com/threads/how-vsync-works-and-why-people-loathe-it.928593/
- https://www.vsynctester.com/manual.html
- http://gamedev.stackexchange.com/questions/47665/canvas-animation-drops-to-30fps-every-3-4-seconds
- http://www.html5gamedevs.com/topic/898-framerate-on-mobile-devices/#comment-5076
- http://stackoverflow.com/questions/21979407/what-can-cause-requestanimationframe-to-drop-frames-in-an-efficient-webgl-loop
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
iOS8 and above limit the requestAnimationFrame upper bound fps (to what I've seen 30fps).