API Docs for: 1.0.0
Show:

File: src\core\Stage.ts

/**
* 
* @module Kiwi
* 
*/ 

module Kiwi {

    /**
    * Each game contains a single Stage which controls the creation and management of main domElements required for a Kiwi game to work. 
    * Such as the Canvas and the rendering contexts, as well as the width/height of the game and the position it should be on the screen.
    *
    * @class Stage
    * @namespace Kiwi
    * @constructor
    * @param game {Kiwi.Game} The game that this Stage belongs to. 
    * @param name {String} The name of the kiwi game.
    * @param width {Number} The initial width of the game. 
    * @param height {Number} The initial heihgt of the game.
    * @param scaleType {Number} The scale method that should be used for the game.
    * @return {Kiwi.Stage}  
    *
    */
    export class Stage {
         
        constructor(game: Kiwi.Game, name: string, width: number, height: number,scaleType:number) {

            this._game = game;

            this.name = name;

            this.domReady = false;
             
            //  Properties
            this._alpha = 1;
            
            this._x = 0;
            this._y = 0;

            this._width = width;
            this._height = height;
            this.color = 'ffffff';

            this._scale = new Kiwi.Geom.Point(1, 1);
            this._scaleType = scaleType;

            this.onResize = new Kiwi.Signal();
            this.onWindowResize = new Kiwi.Signal();
        }

        /**
        * Returns the type of this object.
        * @method objType
        * @return {string} "Stage"
        * @public
        */
        public objType():string {
            return "Stage";
        }

        /**
        * The default width of the stage.
        * @property DEFAULT_WIDTH
        * @type number
        * @default 800
        * @public
        * @static
        */
        public static DEFAULT_WIDTH: number = 800;

        /**
        * The default height of the stage.
        * @property DEFAULT_HEIGHT
        * @type number
        * @default 600
        * @public
        * @static
        */
        public static DEFAULT_HEIGHT: number = 600;


        /**
        * The default scaling method used on Kiwi Games. 
        * This scaling method will set the containers width/height to static values.
        * @property SCALE_NONE
        * @type number
        * @default 0 
        * @public 
        * @static
        */
        public static SCALE_NONE: number = 0;
        
        /**
        * Scale Fit will scale the stages width to fit its parents width.
        * The height is then calculated to maintain the aspect ratio of the width/height of the Stage.
        * @property SCALE_FIT
        * @type number
        * @default 1 
        * @public 
        * @static
        */
        public static SCALE_FIT: number = 1;
        
        /**
        * Stretch will make the stage scale to fit its parents width/height (by using max/min height of 100%).
        * If the parent doesn't have a height set then the height will be the height of the stage. 
        * @property SCALE_STRETCH
        * @type number
        * @default 2 
        * @public 
        * @static
        */
        public static SCALE_STRETCH: number = 2;
        
        /**
        * Private property that holds the scaling method that should be applied to the container element. 
        * @property _scaleType
        * @type number
        * @default Kiwi.Stage.SCALE_NONE
        * @private
        */
        private _scaleType: number = Kiwi.Stage.SCALE_NONE;
        
        /**
        * Holds type of scaling that should be applied the container element. 
        * @property scaleType
        * @type number
        * @default Kiwi.Stage.SCALE_NONE
        * @private
        */
        public set scaleType(val: number) {
            this._scaleType = val;
            this._scaleContainer();
        }

        public get scaleType():number {
            return this._scaleType;
        }


        /**
        * The alpha of the stage. 
        * @property _alpha
        * @type number
        * @default 1
        * @private
        */
        private _alpha: number;

        /**
        * Sets the alpha of the container element. 0 = invisible, 1 = fully visible.
        * Note: Because the alpha value is applied to the container, it will not work in CocoonJS.
        *
        * @property alpha
        * @type number
        * @default 1
        * @public
        */
        public get alpha():number {
            return this._alpha;
        }
        public set alpha(value: number) {
            if (this._game.deviceTargetOption === Kiwi.TARGET_BROWSER) {
                this.container.style.opacity = String(Kiwi.Utils.GameMath.clamp(value, 1, 0));
            }
            // Doesnt work in cocoon

            this._alpha = value;
        }

        /**
        * The X coordinate of the stage.
        * @property _x
        * @type number
        * @private 
        */
        private _x: number;

        /**
        * The X coordinate of the stage. This number should be the same as the stages left property.
        * @property x
        * @type number
        * @public
        */
        public get x(): number {
            return this._x;
        } 
        public set x(value: number) {
            if (this._game.deviceTargetOption === Kiwi.TARGET_BROWSER) {
                this.container.style.left = String(value + 'px');
            } else if (this._game.deviceTargetOption === Kiwi.TARGET_COCOON) {
                this.canvas.style.left = String(value + 'px');
            }
            this._x = value;
        }

        /**
        * The Y coordinate of the stage.
        * @property _y
        * @type number
        * @private
        */
        private _y: number;

        /**
        * Get the Y coordinate of the stage. This number should be the same as the stages top property.
        * @property y
        * @type number
        * @public
        */
        public get y(): number {
            return this._y;
        }
        public set y(value: number) {
            if (this._game.deviceTargetOption === Kiwi.TARGET_BROWSER) {
                this.container.style.top = String(value + 'px');
            } else if (this._game.deviceTargetOption === Kiwi.TARGET_COCOON) {
                this.canvas.style.top = String(value + 'px');
            }
            this._y = value;
        }

        /**
        * The width of the stage.
        * @property _width
        * @type number
        * @private
        */
        private _width: number;
        
        /**
        * The width of the stage. This is READ ONLY. See the 'resize' method if you need to modify this value.
        * @property width
        * @type number
        * @public 
        * @readonly
        */
        public get width(): number {
            return this._width;
        }
      
        /**
        * The height of the stage
        * @property _height
        * @type number
        * @private
        */
        private _height: number;
        
        /**
        * The height of the stage. This is READ ONLY. See the 'resize' method if you need to modify this value.
        * @property height
        * @type number
        * @public
        * @readonly
        */
        public get height(): number {
            return this._height;
        }
       
        /**
        * A Signal that dispatches an event when the stage gets resized.
        * @property onResize
        * @type Kiwi.Signal
        * @public
        */
        public onResize: Kiwi.Signal;


        /**
        * A Signal which dispatches events when the window is resized. 
        * Useful to detect if the screen is now in a 'landscape' or 'portrait' view on Mobile/Cocoon devices. 
        * @property onWindowResize
        * @type Kiwi.Signal
        * @public
        */
        public onWindowResize: Kiwi.Signal;

        /**
        * Calculates and returns the amount that the container has been scale by.  
        * Mainly used for re-calculating input coordinates. 
        * Note: For COCOONJS this returns 1 since COCOONJS translates the scale itself.
        * This property is READ ONLY.
        * @property scale
        * @type Kiwi.Geom.Point
        * @default 1
        * @public
        */
        private _scale: Kiwi.Geom.Point;

        public get scale(): Kiwi.Geom.Point {
            return this._scale;
        }

        /**
        * Calculates and returns the amount that the container has been scale by on the X axis.  
        * @property scaleX
        * @type Number
        * @default 1 
        * @public
        */
        public get scaleX(): number {
            return this._scale.x;
        }

        /**
        * Calculates and returns the amount that the container has been scale by on the Y axis.
        * @property scaleY
        * @type Number
        * @default 1
        * @public
        */
        public get scaleY(): number {
            return this._scale.y;
        }

        /**
		* A point which determines the offset of this Stage
        * @property offset
        * @type Kiwi.Geom.Point
        * @public
    	*/
        public offset: Kiwi.Geom.Point = new Kiwi.Geom.Point();
        
        /**
        * The game this Stage belongs to
        * @property _game
        * @type Kiwi.Game
        * @private 
        */
        private _game: Kiwi.Game;

        /**
        * The title of your stage
        * @property name
        * @type string
        * @public
        */
        public name: string;

        /**
        * Whether or not this Stage is DOM ready.
        * @property domReady
        * @type boolean
        * @public
        */
        public domReady: boolean;

        /**
        * The background color of the stage. 
        * This must be a valid 6 character hex color string such as "ffffff". 
        *
        * @property _color
        * @type string
        * @default 'ffffff'
        * @public
        */
        public _color: string;
        
        /**
        * Sets the background color of the stage via a hex value. 
        * The hex colour code should not contain a hashtag '#'.
        * 
        * @property color
        * @type string
        * @public
        */
        public get color(): string {
            return this._color;
        }

        public set color(val: string) {
            this._color = val;
            var bigint = parseInt(val, 16);

            var r = (bigint >> 16) & 255;
            var g = (bigint >> 8) & 255;
            var b = bigint & 255;

            //Converts the colour to normalized values.
            this._normalizedColor = { r: r / 255, g: g / 255, b: b / 255, a: 1 };
        }

        /**
        * Allows the setting of the background color of the stage through component RGB colour values. 
        * This property is an Object Literal with 'r', 'g', 'b' colour streams of values between 0 and 255. 
        *
        * @property rgbColor
        * @type Object
        * @public
        */
        public get rgbColor():any {
            return { r: this._normalizedColor.r * 255, g: this._normalizedColor.g * 255, b: this._normalizedColor.b * 255 };
        }

        public set rgbColor(val: any) {
            this.color = this.componentToHex(val.r) + this.componentToHex(val.g) + this.componentToHex(val.b);
        }

        /**
        * Stores the normalized background color of the stage as a RGBA values between 0 and 1.
        * @property _normalizedColor
        * @type object
        * @public
        */
        private _normalizedColor: any;
        
        /**
        * Get the normalized background color of the stage. Returns a object with rgba values, each being between 0 and 1.
        * This is READ ONLY.
        * @property normalizedColor
        * @type string
        * @public
        */
        public get normalizedColor(): any {
           return this._normalizedColor;
        }

        /**
        * The webgl rendering context.
        * @property gl
        * @type WebGLRenderingContext
        * @public
        */
        public gl: WebGLRenderingContext;


        /**
        * The canvas rendering context.
        * @property ctx
        * @type CanvasRenderingContext2D
        * @public
        */
        public ctx: CanvasRenderingContext2D;


        /**
        * The canvas element that is being rendered on.
        * @property canvas
        * @type HTMLCanvasElement
        * @public
        */
        public canvas: HTMLCanvasElement;
        

        /**
        * The debugging canvas.
        * @property debugCanvas
        * @type HTMLCanvasElement
        * @public
        */
        public debugCanvas: HTMLCanvasElement;


        /**
        * The debug canvas rendering context.
        * @property dctx
        * @type CanvasRenderingContext2D
        * @public
        */
        public dctx: CanvasRenderingContext2D;


        /**
        * The parent div in which the layers and input live
        * @property container
        * @type HTMLDivElement
        * @public
        */
        public container:HTMLDivElement = null;
         

        /**
        * Is executed when the DOM has loaded and the game is just starting. 
        * This is a internal method used by the core of Kiwi itself. 
        * @method boot
        * @param dom {HTMLElement} The
        * @public
        */
        public boot(dom: Kiwi.System.Bootstrap) {
             
            this.domReady = true;
            this.container = dom.container;

            if (this._game.deviceTargetOption === Kiwi.TARGET_BROWSER) {

                this.offset = this.getOffsetPoint(this.container);

                this._x = this.offset.x;
                this._y = this.offset.y;

                window.addEventListener("resize", (event: UIEvent) => this._windowResized(event), true);
            }

            
            this._createCompositeCanvas();


            if (this._game.deviceTargetOption === Kiwi.TARGET_COCOON) {
                this._scaleContainer();
            } else {
                this._calculateContainerScale();
            }
        }
        
        /**
        * Gets the x/y coordinate offset of any given valid DOM Element from the top/left position of the browser
        * Based on jQuery offset https://github.com/jquery/jquery/blob/master/src/offset.js 
        * @method getOffsetPoint
        * @param {Any} element
        * @param {Kiwi.Geom.Point} output
        * @return {Kiwi.Geom.Point}
        * @public
        */
        public getOffsetPoint(element, output: Kiwi.Geom.Point = new Kiwi.Geom.Point): Kiwi.Geom.Point {

            var box = element.getBoundingClientRect();

            var clientTop = element.clientTop || document.body.clientTop || 0;
            var clientLeft = element.clientLeft || document.body.clientLeft || 0;
            var scrollTop = window.pageYOffset || element.scrollTop || document.body.scrollTop;
            var scrollLeft = window.pageXOffset || element.scrollLeft || document.body.scrollLeft;

            return output.setTo(box.left + scrollLeft - clientLeft, box.top + scrollTop - clientTop);

        }

        /**
        * Method that is fired when the window is resized. 
        * @method _windowResized
        * @param event {UIEvent}
        * @private
        */
        private _windowResized(event:UIEvent) {
            this._calculateContainerScale();

            //Dispatch window resize event
            this.onWindowResize.dispatch();
        }

        /**
        * Used to calculate the new offset and the scale of the stage currently is at.
        * @method _calculateContainerScale
        * @private
        */
        private _calculateContainerScale() {
            this.offset = this.getOffsetPoint(this.container);
            this._scaleContainer();

            this._scale.x = this._width / this.container.clientWidth;
            this._scale.y = this._height / this.container.clientHeight;

        }

        /**
        * Handles the creation of the canvas that the game will use and retrieves the context for the renderer. 
        *
        * @method _createComponsiteCanvas
        * @private
        */
        private _createCompositeCanvas() {
            
            //If we are using cocoon then create a accelerated screen canvas
            if (this._game.deviceTargetOption == Kiwi.TARGET_COCOON) {
                this.canvas = <HTMLCanvasElement>document.createElement(navigator['isCocoonJS'] ? 'screencanvas' : 'canvas');
            
            //Otherwise default to normal canvas
            } else {
                this.canvas = <HTMLCanvasElement>document.createElement("canvas");
                this.canvas.style.width = '100%';
                this.canvas.style.height = '100%';

            }

            this.canvas.id = this._game.id + "compositeCanvas";
            this.canvas.style.position = "absolute";
            this.canvas.width = this.width;
            this.canvas.height = this.height;
            

            //Get 2D or GL Context - Should add in error checking here

            if (this._game.renderOption === Kiwi.RENDERER_CANVAS) {
                this.ctx = this.canvas.getContext("2d");
                this.ctx.fillStyle = '#fff';
                this.gl = null;

            } else if (this._game.renderOption === Kiwi.RENDERER_WEBGL) {
                this.gl = this.canvas.getContext("webgl");
                if (!this.gl) {
                    this.gl = this.canvas.getContext("experimental-webgl");
                    if (!this.gl) {
                        console.error("Kiwi.Stage: WebGL rendering is not available despite the device apparently supporting it."); 
                    } else {
                        console.warn ("Kiwi.Stage: 'webgl' context is not available. Using 'experimental-webgl'");
                    }
                }
                this.gl.clearColor(1, 1, .95, .7);
                this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
                this.ctx = null;

            } 
            
            if (this._game.deviceTargetOption === Kiwi.TARGET_BROWSER) {
                this.container.appendChild(this.canvas);
            } else {
                document.body.appendChild(this.canvas);
            }
        
        }
        

        /**
        * Set the stage width and height for rendering purposes.
        * This will not effect that 'scaleType' that it has been set to.
        *
        * @method resize
        * @param width {number} The new Stage width.
        * @param height {number} The new Stage height.
        * @public
        */
        public resize(width: number, height: number) {

            this.canvas.height = height;
            this.canvas.width = width;
            this._height = height;
            this._width = width;

            if (this._game.deviceTargetOption === Kiwi.TARGET_BROWSER) {
                this._calculateContainerScale();
            }

            this.onResize.dispatch(this._width, this._height);
        }

        
        /**
        * Sets the background color of the stage through component RGB colour values. 
        * Each parameter pass is a number between 0 and 255. This method also returns a Object Literal with 'r', 'g', 'b' properties.
        *
        * @method setRGBColor
        * @param r {Number} The red component. A value between 0 and 255.
        * @param g {Number} The green component. A value between 0 and 255.
        * @param b {Number} The blue component. A value between 0 and 255.
        * @return {Object} A Object literal containing the r,g,b properties. 
        * @public
        */
        public setRGBColor(r: number, g: number, b: number):any {
            this.rgbColor = { r: r, g: g, b: b };
            return this.rgbColor;
        }


        /**
        * Converts a component colour value into its hex equivalent. Used when setting rgb colour values.
        * 
        * @method componentToHex
        * @param c {Number} The components colour value. A number between 0 and 255.
        * @return {string} The hex equivelent of that colour string. 
        * @private
        */
        private componentToHex(c: number): string {
            var hex = c.toString(16);
            return hex.length == 1 ? "0" + hex : hex;
        }


        /**
        * Creates a debug canvas and adds it above the regular game canvas.
        * The debug canvas is not created by default (even with debugging on) and rendering/clearing of the canvas is upto the developer. 
        * The context for rendering can be access via the 'dctx' property and you can use the 'clearDebugCanvas' method to clear the canvas.
        *
        * @method createDebugCanvas
        * @public
        */
        public createDebugCanvas() {
            if (this._game.deviceTargetOption === Kiwi.TARGET_COCOON) {
                //Not supported in CocoonJS only because we cannot add it to the container (as a container does not exist) and position will be hard.
                console.log('Debug canvas not supported in cocoon, creating canvas and context anyway');                
            } 

            this.debugCanvas = <HTMLCanvasElement>document.createElement("canvas");
            this.debugCanvas.id = this._game.id + "debugCanvas";
            this.debugCanvas.style.position = "absolute";
            this.debugCanvas.width = this.width;
            this.debugCanvas.height = this.height;
            this.dctx = this.debugCanvas.getContext("2d");
            this.clearDebugCanvas();

            if (this._game.deviceTargetOption === Kiwi.TARGET_BROWSER) {
                this.container.appendChild(this.debugCanvas);
            }
          
        }
        

        /**
        * Clears the debug canvas and fills with either the color passed. 
        * If not colour is passed then Red at 20% opacity is used.
        * 
        * @method clearDebugCanvas
        * @param [color='rgba(255,0,0,0.2)'] {string} The debug color to rendering on the debug canvas.
        * @public
        */
        public clearDebugCanvas(color?:string) {
            this.dctx.fillStyle = color || "rgba(255,0,0,.2)";
            this.dctx.clearRect(0, 0, this.width, this.height);
            this.dctx.fillRect(0, 0, this.width, this.height)
        }

        /**
        * Toggles the visibility of the debug canvas. 
        * @method toggleDebugCanvas
        * @public
        */
        public toggleDebugCanvas() {
            this.debugCanvas.style.display = (this.debugCanvas.style.display === "none") ? "block" : "none";
        }

        /**
        * Handles the scaling/sizing based upon the scaleType property.
        * @method _scaleContainer
        * @private
        */
        private _scaleContainer() {

            if (this._game.deviceTargetOption == Kiwi.TARGET_BROWSER) {

                this.container.style.width = String(this._width + 'px');
                this.container.style.height = String(this._height + 'px');

                if (this._scaleType == Kiwi.Stage.SCALE_NONE) {
                    this.container.style.maxWidth = '';
                    this.container.style.minWidth = '';
                }

                //To Fit or STRETCH 
                if (this._scaleType == Kiwi.Stage.SCALE_STRETCH || this._scaleType == Kiwi.Stage.SCALE_FIT) {
                    this.container.style.minWidth = '100%';
                    this.container.style.maxWidth = '100%';
                }

                //If scale stretched then scale the containers height to 100% of its parents.
                if (this._scaleType == Kiwi.Stage.SCALE_STRETCH) {
                    this.container.style.minHeight = '100%';
                    this.container.style.maxHeight = '100%';
                } else {
                    this.container.style.minHeight = '';
                    this.container.style.maxHeight = '';
                }

                //If it is SCALE to FIT then scale the containers height in ratio with the containers width.
                if (this._scaleType == Kiwi.Stage.SCALE_FIT) {
                    this.container.style.height = String((this.container.clientWidth / this._width) * this._height) + 'px';
                }

            }

            if (this._game.deviceTargetOption == Kiwi.TARGET_COCOON) {

                switch (this._scaleType) {
                    case Kiwi.Stage.SCALE_FIT:
                        this.canvas.style.cssText = 'idtkscale:ScaleAspectFit';
                        break;

                    case Kiwi.Stage.SCALE_STRETCH:
                        this.canvas.style.cssText = 'idtkscale:ScaleToFill';
                        break;

                    case Kiwi.Stage.SCALE_NONE:
                        this.canvas.style.cssText = '';
                        break;
                }

            }

        }


    }

}