Newer
Older
pixi.js / src / core / utils / index.js
@Juha Rantanen Juha Rantanen on 25 Sep 2016 8 KB Better SVG support (#2614)
import CONST from '../const';
import EventEmitter from 'eventemitter3';
import pluginTarget from './pluginTarget';

/**
 * @namespace PIXI.utils
 */
const utils = {
    _uid: 0,
    _saidHello: false,

    EventEmitter,
    pluginTarget,

    /**
     * Gets the next unique identifier
     *
     * @memberof PIXI.utils
     * @return {number} The next unique identifier to use.
     */
    uid ()
    {
        return ++utils._uid;
    },

    /**
     * Converts a hex color number to an [R, G, B] array
     *
     * @memberof PIXI.utils
     * @param hex {number}
     * @param  {number[]} [out=[]] If supplied, this array will be used rather than returning a new one
     * @return {number[]} An array representing the [R, G, B] of the color.
     */
    hex2rgb (hex, out)
    {
        out = out || [];

        out[0] = (hex >> 16 & 0xFF) / 255;
        out[1] = (hex >> 8 & 0xFF) / 255;
        out[2] = (hex & 0xFF) / 255;

        return out;
    },

    /**
     * Converts a hex color number to a string.
     *
     * @memberof PIXI.utils
     * @param hex {number} Number in hex
     * @return {string} The string color.
     */
    hex2string (hex)
    {
        hex = hex.toString(16);
        hex = '000000'.substr(0, 6 - hex.length) + hex;

        return '#' + hex;
    },

    /**
     * Converts a color as an [R, G, B] array to a hex number
     *
     * @memberof PIXI.utils
     * @param rgb {number[]} rgb array
     * @return {number} The color number
     */
    rgb2hex (rgb)
    {
        return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255);
    },


    /**
     * get the resolution / device pixel ratio of an asset by looking for the prefix
     * used by spritesheets and image urls
     *
     * @memberof PIXI.utils
     * @param url {string} the image path
     * @return {number} resolution / device pixel ratio of an asset
     */
    getResolutionOfUrl (url)
    {
        const resolution = CONST.RETINA_PREFIX.exec(url);

        if (resolution)
        {
           return parseFloat(resolution[1]);
        }

        return 1;
    },

    /**
     * Typedef for decomposeDataUri return object.
     *
     * @typedef {object} DecomposedDataUri
     * @property {mediaType} Media type, eg. `image`
     * @property {subType} Sub type, eg. `png`
     * @property {encoding} Data encoding, eg. `base64`
     * @property {data} The actual data
     */

    /**
     * Split a data URI into components. Returns undefined if
     * parameter `dataUri` is not a valid data URI.
     *
     * @memberof PIXI.utils
     * @param dataUri {string} the data URI to check
     * @return {DecomposedDataUri|undefined} The decomposed data uri or undefined
     */
    decomposeDataUri (dataUri)
    {
        const dataUriMatch = CONST.DATA_URI.exec(dataUri);

        if (dataUriMatch)
        {
            return {
                mediaType: dataUriMatch[1] ? dataUriMatch[1].toLowerCase() : undefined,
                subType: dataUriMatch[2] ? dataUriMatch[2].toLowerCase() : undefined,
                encoding: dataUriMatch[3] ? dataUriMatch[3].toLowerCase() : undefined,
                data: dataUriMatch[4]
            };
        }

        return undefined;
    },

    /**
     * Get type of the image by regexp for extension. Returns undefined for unknown extensions.
     *
     * @memberof PIXI.utils
     * @param url {string} the image path
     * @return {string|undefined} image extension
     */
    getImageTypeOfUrl (url)
    {
        const extension = CONST.IMAGE_TYPE.exec(url);

        if (extension)
        {
            return extension[1].toLowerCase();
        }

        return undefined;
    },

    /**
     * Typedef for Size object.
     *
     * @typedef {object} Size
     * @property {width} Width component
     * @property {height} Height component
     */

    /**
     * Get size from an svg string using regexp.
     *
     * @memberof PIXI.utils
     * @param svgString {string} a serialized svg element
     * @return {Size|undefined} image extension
     */
    getSvgSize (svgString)
    {
        const sizeMatch = CONST.SVG_SIZE.exec(svgString);
        const size = {};

        if (sizeMatch)
        {
            size[sizeMatch[1]] = Math.round(parseFloat(sizeMatch[2]));
            size[sizeMatch[3]] = Math.round(parseFloat(sizeMatch[4]));
        }

        return size;
    },

    /**
     * Logs out the version and renderer information for this running instance of PIXI.
     * If you don't want to see this message you can set `PIXI.utils._saidHello = true;`
     * so the library thinks it already said it. Keep in mind that doing that will forever
     * makes you a jerk face.
     *
     * @memberof PIXI.utils
     * @param {string} type - The string renderer type to log.
     * @constant
     * @static
     */
    sayHello (type)
    {
        if (utils._saidHello)
        {
            return;
        }

        if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1)
        {
            const args = [
                `\n %c %c %c Pixi.js ${CONST.VERSION} - ✰ ${type} ✰  %c  %c  http://www.pixijs.com/  %c %c ♥%c♥%c♥ \n\n`,
                'background: #ff66a5; padding:5px 0;',
                'background: #ff66a5; padding:5px 0;',
                'color: #ff66a5; background: #030307; padding:5px 0;',
                'background: #ff66a5; padding:5px 0;',
                'background: #ffc3dc; padding:5px 0;',
                'background: #ff66a5; padding:5px 0;',
                'color: #ff2424; background: #fff; padding:5px 0;',
                'color: #ff2424; background: #fff; padding:5px 0;',
                'color: #ff2424; background: #fff; padding:5px 0;'
            ];

            window.console.log.apply(console, args);
        }
        else if (window.console)
        {
            window.console.log(`Pixi.js ${CONST.VERSION} - ${type} - http://www.pixijs.com/`);
        }

        utils._saidHello = true;
    },

    /**
     * Helper for checking for webgl support
     *
     * @memberof PIXI.utils
     * @return {boolean} is webgl supported
     */
    isWebGLSupported ()
    {
        const contextOptions = { stencil: true, failIfMajorPerformanceCaveat: true };
        try
        {
            if (!window.WebGLRenderingContext)
            {
                return false;
            }

            const canvas = document.createElement('canvas');
            let gl = canvas.getContext('webgl', contextOptions) || canvas.getContext('experimental-webgl', contextOptions);

            const success = !!(gl && gl.getContextAttributes().stencil);
            if (gl)
            {
                const loseContext = gl.getExtension('WEBGL_lose_context');

                if(loseContext)
                {
                    loseContext.loseContext();
                }
            }
            gl = null;

            return success;
        }
        catch (e)
        {
            return false;
        }
    },

    /**
     * Returns sign of number
     *
     * @memberof PIXI.utils
     * @param n {number}
     * @returns {number} 0 if n is 0, -1 if n is negative, 1 if n i positive
     */
    sign (n)
    {
        return n ? (n < 0 ? -1 : 1) : 0;
    },

    /**
     * Remove a range of items from an array
     *
     * @memberof PIXI.utils
     * @param {Array<*>} arr The target array
     * @param {number} startIdx The index to begin removing from (inclusive)
     * @param {number} removeCount How many items to remove
     */
    removeItems (arr, startIdx, removeCount)
    {
        const length = arr.length;

        if (startIdx >= length || removeCount === 0)
        {
            return;
        }

        removeCount = (startIdx+removeCount > length ? length-startIdx : removeCount);
        const len = length-removeCount;
        for (let i = startIdx; i < len; ++i)
        {
            arr[i] = arr[i + removeCount];
        }

        arr.length = len;
    },

    /**
     * @todo Describe property usage
     *
     * @memberof PIXI.utils
     * @private
     */
    TextureCache: {},

    /**
     * @todo Describe property usage
     *
     * @memberof PIXI.utils
     * @private
     */
    BaseTextureCache: {}
};

export default utils;