Newer
Older
pixi.js / src / loaders / AssetLoader.js
@Chad Engler Chad Engler on 28 Dec 2014 4 KB initial move to new module folders
var core = require('../core'),
    ImageLoader = require('./ImageLoader'),
    JsonLoader = require('./JsonLoader'),
    AtlasLoader = require('./AtlasLoader'),
    SpineLoader = require('./SpineLoader'),
    BitmapFontLoader = require('./BitmapFontLoader');

/**
 * A Class that loads a bunch of images / sprite sheet / bitmap font files. Once the
 * assets have been loaded they are added to the PIXI Texture cache and can be accessed
 * easily through Texture.fromImage() and Sprite.fromImage()
 * When all items have been loaded this class will dispatch a 'onLoaded' event
 * As each individual item is loaded this class will dispatch a 'onProgress' event
 *
 * @class
 * @namespace PIXI
 * @mixes EventTarget
 * @param assetURLs {string[]} An array of image/sprite sheet urls that you would like loaded
 *      supported. Supported image formats include 'jpeg', 'jpg', 'png', 'gif'. Supported
 *      sprite sheet data formats only include 'JSON' at this time. Supported bitmap font
 *      data formats include 'xml' and 'fnt'.
 * @param crossorigin {boolean} Whether requests should be treated as crossorigin
 */
function AssetLoader(assetURLs, crossorigin) {
    /**
     * The array of asset URLs that are going to be loaded
     *
     * @member {string[]}
     */
    this.assetURLs = assetURLs;

    /**
     * Whether the requests should be treated as cross origin
     *
     * @member {boolean}
     */
    this.crossorigin = crossorigin;

    /**
     * Maps file extension to loader types
     *
     * @member {object}
     */
    this.loadersByType = {
        'jpg':  ImageLoader,
        'jpeg': ImageLoader,
        'png':  ImageLoader,
        'gif':  ImageLoader,
        'webp': ImageLoader,
        'json': JsonLoader,
        'atlas': AtlasLoader,
        'anim': SpineLoader,
        'xml':  BitmapFontLoader,
        'fnt':  BitmapFontLoader
    };
}

// constructor
AssetLoader.prototype.constructor = AssetLoader;
module.exports = AssetLoader;

core.utils.EventTarget.mixin(AssetLoader.prototype);

/**
 * Fired when an item has loaded
 * @event onProgress
 */

/**
 * Fired when all the assets have loaded
 * @event onComplete
 */

/**
 * Given a filename, returns its extension.
 *
 * @param str {string} the name of the asset
 */
AssetLoader.prototype._getDataType = function (str) {
    var test = 'data:';
    var start = str.slice(0, test.length).toLowerCase();

    if (start === test) {
        var data = str.slice(test.length);
        var sepIdx = data.indexOf(',');

        // check for malformed data URI scheme
        if (sepIdx === -1) {
            return null;
        }

        //e.g. 'image/gif;base64' => 'image/gif'
        var info = data.slice(0, sepIdx).split(';')[0];

        //We might need to handle some special cases here...
        //standardize text/plain to 'txt' file extension
        if (!info || info.toLowerCase() === 'text/plain') {
            return 'txt';
        }

        //User specified mime type, try splitting it by '/'
        return info.split('/').pop().toLowerCase();
    }

    return null;
};

/**
 * Starts loading the assets sequentially
 *
 */
AssetLoader.prototype.load = function () {
    var scope = this;

    function onLoad(evt) {
        scope.onAssetLoaded(evt.data.content);
    }

    this.loadCount = this.assetURLs.length;

    for (var i=0; i < this.assetURLs.length; i++) {
        var fileName = this.assetURLs[i];
        //first see if we have a data URI scheme..
        var fileType = this._getDataType(fileName);

        //if not, assume it's a file URI
        if (!fileType) {
            fileType = fileName.split('?').shift().split('.').pop().toLowerCase();
        }

        var Constructor = this.loadersByType[fileType];
        if (!Constructor) {
            throw new Error(fileType + ' is an unsupported file type');
        }

        var loader = new Constructor(fileName, this.crossorigin);

        loader.on('loaded', onLoad);
        loader.load();
    }
};

/**
 * Invoked after each file is loaded
 *
 * @private
 */
AssetLoader.prototype.onAssetLoaded = function (loader) {
    this.loadCount--;
    this.emit('onProgress', { content: this, loader: loader });

    if (this.onProgress) {
        this.onProgress(loader);
    }

    if (!this.loadCount) {
        this.emit('onComplete', { content: this });

        if (this.onComplete) {
            this.onComplete();
        }
    }
};