will move to https://github.com/felixroos/zyklus TODO: started flag
4function createClock( 5 getTime, 6 callback, // called slightly before each cycle 7 duration = 0.05, // duration of each cycle 8 interval = 0.1, // interval between callbacks 9 overlap = 0.1, // overlap between callbacks 10 setInterval = globalThis.setInterval, 11 clearInterval = globalThis.clearInterval, 12 round = true, 13) { 14 let tick = 0; // counts callbacks 15 let phase = 0; // next callback time 16 let precision = 10 ** 4; // used to round phase 17 let minLatency = 0.01; 18 const setDuration = (setter) => (duration = setter(duration)); 19 overlap = overlap || interval / 2; 20 const onTick = () => { 21 const t = getTime(); 22 const lookahead = t + interval + overlap; // the time window for this tick 23 if (phase === 0) { 24 phase = t + minLatency; 25 } 26 // callback as long as we're inside the lookahead 27 while (phase < lookahead) { 28 phase = round ? Math.round(phase * precision) / precision : phase; 29 callback(phase, duration, tick, t); // callback has to skip / handle phase < t! 30 phase += duration; // increment phase by duration 31 tick++; 32 } 33 }; 34 let intervalID; 35 const start = () => { 36 clear(); // just in case start was called more than once 37 onTick(); 38 intervalID = setInterval(onTick, interval * 1000); 39 }; 40 const clear = () => { 41 intervalID !== undefined && clearInterval(intervalID); 42 intervalID = undefined; 43 }; 44 const pause = () => clear(); 45 const stop = () => { 46 tick = 0; 47 phase = 0; 48 clear(); 49 }; 50 const getPhase = () => phase; 51 // setCallback 52 return { setDuration, start, stop, pause, duration, interval, getPhase, minLatency }; 53} 54export default createClock;