timing/AnimationLoop.js

class AnimationLoop {
    /**
     * requestAnimationFrame based loop, cb is called as fast as the browser wants, this usually matches the screen refresh rate
     * @param {Function} cb
     * @param {Boolean} autostart 
     */
    constructor(cb, autostart = true) {
        this.cb = cb;

        /**
         * ms timestamp of the last time
         */
        this.lasttick = null;

        this.running = false;

        if (autostart) this.start();
    }

    /**
     * start the loop
     */
    start() {
        if (!this.running) {
            this.tick();
            this.running = true;
        }
    }

    /**
     * stop the loop
     */
    stop() {
        if (this.running && this.to) {
            cancelAnimationFrame(this.to);
            this.running = false;
        }
    }

    tick() {
        let dt = this.lasttick !== null ? Date.now() - this.lasttick : 0;

        this.cb(dt);

        this.to = requestAnimationFrame(() => {
            this.tick();
        });

        this.lasttick = Date.now();
    }
}

export default AnimationLoop