Repository

js/Mobilizing/core/Runner.js

import CSSLoader from "./util/CSSLoader";

/**
A runner is used to instanciate a Mobilizing.js user's script inside a specific context. It is requiered to use a Runner to initiate a context and to attech a script to it.
*/
export default class Runner {
    /**
    @param {Object} params Parameters object, given by the constructor.
    @param params.context {Context} Mobilizing context to run
    @example
    */
    constructor({
        context = undefined,
        useCSSLoader = true,
        autoPrepare = false
    } = {}) {
        //should call autoPrepare automatically or not (default = false)
        this.autoPrepare = autoPrepare;
        //for the CSS loader
        this.useCSSLoader = useCSSLoader;

        if (this.useCSSLoader) {
            new CSSLoader();
        }

        //we need acces to context from outside
        this.context = context;

        if (document.readyState === "complete") {
            this.run();
        }
        else {
            window.addEventListener("load", this.run.bind(this));
        }
        this.frame = 0;
    }

    /**
    * Runs the runner, create the preLoader and launch it, then execute the script. NB : this fires a "setupDone" event to inform any exterior process that setup has ended
    * @private
    */
    run() {

        if (this.autoPrepare) {
            if (typeof this.context.prepare === "function") {
                this.context.prepare();
            }
        }

        this.context.preLoad();

        //when loading is completed
        this.context.loader.events.on("complete", () => {
            //fires an event from the context to inform of setupDone
            this.context.events.trigger("preLoadDone");
            //start update loop
            this.startLoop();
            //removes the css loader if any
            const cssLoader = document.getElementById("loaderContainer");
            if (cssLoader) {
                cssLoader.remove();
            }
        });

        this.context.loader.consumeAll();
    }

    /**
    * Starts the loop of the user's script, that is the update function
    * @private
    */
    startLoop() {
        this.context.setup(); //call all components setups
        //fires an event from the context to inform of setupDone
        this.context.events.trigger("setupDone");
        this.loop(); //start the main loop
    }

    /**
    * onFrameBegin
    */
    onFrameBegin() {
        //move to a component ?
        this.frame++;

        if (this.context.stats) {
            this.context.stats.begin();
        }
    }

    /**
    * onFrameEnd
    */
    onFrameEnd() {
        if (this.context.stats) {
            this.context.stats.end();
        }
    }

    /**
    * Runner's requestAnimationFrame loop manager
    * @private
    */
    loop() {
        this.onFrameBegin();
        this.context.update();//engine update
        this.onFrameEnd();

        requestAnimationFrame(this.loop.bind(this));//schedule next
    }
}