-
-
Save fuweichin/5362c080fd2a7debef51b22ff662e59b to your computer and use it in GitHub Desktop.
adaptive sync throttling for Canvas / WebGL applications
This file contains 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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Adaptive Sync Throttling</title> | |
<style> | |
input[type=range][orient=vertical] { | |
writing-mode: bt-lr; | |
-webkit-appearance: slider-vertical; | |
width: 8px; | |
height: 128px; | |
padding: 0 5px; | |
} | |
</style> | |
</head> | |
<body> | |
<h2>Comparison</h2> | |
<h3>Input without throttling</h3> | |
<div> | |
Color | |
<input type="color" id="color" value="#cc00ff" /> | |
</div> | |
<h3>Input throttled</h3> | |
<div> | |
Wavelength (lambda): | |
<input type="range" id="lambda" value="400" min="380" max="780" /> | |
</div> | |
<h3>Input with Adaptive Sync throttling</h3> | |
<div> | |
Transparency (alpha): | |
<input type="range" id="alpha" orient="vertical" min="0" max="255" /> | |
</div> | |
<h2>Usage</h2> | |
<ul> | |
<li>drag range slider / color picker</li> | |
<li>open browser DevTools </li> | |
<li>see Console logs and compare average throttle effect</li> | |
</ul> | |
<script type="module"> | |
import {throttle} from 'https://unpkg.com/throttle-debounce@5.0.0/esm/index.js'; | |
import {throttleAdaptiveSync} from './throttle.js'; | |
const $ = (s, c = document) => c.querySelector(s); | |
const $$ = (s, c = document) => Array.prototype.slice.call(c.querySelectorAll(s)); | |
function main() { | |
console.time('t1'); | |
$('#color').addEventListener('input', (e) => { | |
console.timeEnd('t1'); | |
console.time('t1'); | |
}); | |
console.time('t2'); | |
$('#lambda').addEventListener('input', throttle(16, (e) => { | |
console.timeEnd('t2'); | |
console.time('t2'); | |
})); | |
console.time('t3'); | |
$('#alpha').addEventListener('input', throttleAdaptiveSync((e) => { | |
console.timeEnd('t3'); | |
console.time('t3'); | |
})); | |
} | |
main(); | |
</script> | |
</body> | |
</html> |
This file contains 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
/** | |
* throttle based on requestAnimationFrame | |
* @param {Function} func | |
* @returns {Function} | |
*/ | |
export function throttleAdaptiveSync(func) { | |
let lastTriggerTime = 0; | |
let nextTimerHandle = 0; | |
let nextCallInfo = null; | |
let checkNextCall = () => { | |
let now = performance.now(); | |
nextTimerHandle = 0; | |
if (nextCallInfo !== null) { | |
lastTriggerTime = now; | |
let callInfo = nextCallInfo; | |
nextCallInfo = null; | |
func.apply(callInfo[0], callInfo[1]); | |
} | |
}; | |
let proxyFunc = function () { | |
let now = performance.now(); | |
if (lastTriggerTime === 0) { | |
lastTriggerTime = now; | |
nextTimerHandle = requestAnimationFrame(checkNextCall); | |
nextCallInfo = null; | |
func.apply(this, arguments); | |
} else { | |
if (nextTimerHandle > 0) { | |
nextCallInfo = [this, arguments]; | |
} else { | |
nextCallInfo = [this, arguments]; | |
nextTimerHandle = requestAnimationFrame(checkNextCall); | |
} | |
} | |
}; | |
return proxyFunc; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment