API Docs for: 1.0.1

File: js\grape\resource\resource-collection.js

define(['../class', './audio', './json-scene-source', './resource', './sprite'], function (Class, GrapeAudio, JSONSceneSource, Resource, Sprite) {
    function empty() {
    }

    /**
     * Represents a collection of resources. You can add, get different kind of resources (nested collections are
     * allowed) and load resources at once.
     *
     * @class Grape.ResourceCollection
     * @uses Grape.Resource
     * @constructor
     * @param {Object} opts Initial properties
     */
    return Class('ResourceCollection', Resource, {
        init: function (opts) {
            opts = opts || {};
            /**
             * When you create new items with the helpers(sprite(), audio()) this prefix is added to the url.
             * Does NOT affect resources you manually add to the collection.
             *
             * @property prefix
             * @type String
             */
            this.prefix = opts.prefix || '';
            this.resources = [];
            this.resourcesByName = {};
        },
        /**
         * Adds a new resource to the collection.
         *
         * @method add
         * @param {String} [name] The unique name of the resource
         * @param {Grape.Resource} Resource
         */
        add: function (name, res) {
            if (!res) { //no name given
                res = name;
                name = null;
            }
            if (name !== null) {
                if (this.resourcesByName[name]) {
                    throw new Error('resource with name "' + name + '" already exists.');
                }
                this.resourcesByName[name] = res;
            }
            this.resources.push(res);

        },
        /**
         * Get a previously added resource by name.
         *
         * @method get
         * @param {String} name Name
         * @return {Grape.Resource} the resource
         */
        get: function (name) {
            if (!this.resourcesByName[name]) {
                throw new Error('Resource "' + name + '" not found');
            }
            return this.resourcesByName[name];
        },
        /**
         * Loads all resources.
         *
         * @method load
         * @param {Function} onFinish Called when all resource is loaded
         * @param {Function} onError Called when an error happens
         * @param {Function} onProgress Called when a resource is loaded or progress changed
         */
        'override load': function (onFinish, onError, onProgress) {
            var i, estimated, originalTimes = [], times = [],
                estimatedTime = 0,
                remainingTime,
                hasError = false,
                remaining = this.resources.length;
            onFinish = onFinish || empty;
            onError = onError || empty;
            onProgress = onProgress || empty;

            for (i = 0; i < this.resources.length; i++) {
                estimated = this.resources[i].getEstimatedTime();
                times[i] = originalTimes[i] = estimated;
                estimatedTime += estimated;
            }
            remainingTime = estimatedTime;

            function createOnLoad(i) {
                return function () {
                    remaining--;
                    if (times[i] > 0) {
                        remainingTime -= times[i];
                        times[i] = 0;
                        onProgress((1 - remainingTime / estimatedTime) * 100);
                    }
                    if (remaining === 0) {
                        onFinish();
                    }
                };
            }

            function createOnProgress(i) {
                return function (progress) {
                    var n = originalTimes[i] * (1 - progress / 100);
                    if (times[i] !== n) {
                        remainingTime -= [times[i] - n];
                        times[i] = n;
                        onProgress((1 - remainingTime / estimatedTime) * 100);
                    }
                };
            }

            if (this.resources.length === 0) {
                onFinish();
            }

            for (i = 0; i < this.resources.length; i++) {
                /*jshint -W083 */
                this.resources[i].load(createOnLoad(i), function () {
                    if (!hasError) {
                        onError();
                        hasError = true;
                    }
                }, createOnProgress(i));
            }
        },
        /**
         * Returns the sum of the estimated time of all resource.
         *
         * @method getEstimatedTime
         * @return {Number} Sum
         */
        'override getEstimatedTime': function () {
            var i, time = 0;
            for (i = 0; i < this.resources.length; i++) {
                time += this.resources[i].getEstimatedTime();
            }
            return time;
        },
        /**
         * Creates a new sprite and adds to the collection.
         *
         * @method sprite
         * @param {String} name Key
         * @param {String} url Sprite URL
         * @param {Object} settings Settings passed to the Sprite constructor
         * @return {Grape.Sprite} The defined sprite
         */
        sprite: function (name, url, settings) {
            var spr = new Sprite(this.prefix + url, settings);
            this.add(name, spr);
            return spr;
        },
        /**
         * Creates multiple sprites and adds to the collection. The sprites should have the same dimensions.
         *
         * @method tile
         * @param {String} url Image url
         * @param {Number} width Width of all sprite
         * @param {Number} height Height of all sprite
         * @param {Object} sprites Sprite names and positions as key:[left, top, subimages] The positions array is
         * multiplied with the width and height, and the 'subimages' part is optional.
         * @return {Object} The created sprites by name
         */
        tile: function (url, width, height, sprites) {
            var i, coords, res = {};
            for (i in sprites) {
                coords = sprites[i];
                res[i] = this.sprite(i, this.prefix + url, {
                    subimages: coords.length === 2 ? 1 : coords[2],
                    left: coords[0] * width,
                    top: coords[1] * height,
                    width: width,
                    height: height
                });
            }
            return res;
        },
        /**
         * Creates an Audio resource and adds to the collection. Check Grape.Audio for more information.
         *
         * @method audio
         * @param {String} name Key
         * @param {Object} opts Audio options
         * @param {String} url1 Audio URL
         * @param {String} url2 Audio URL fallback if url1 extension is not supported
         * @param {String} url3 Audio URL fallback if url2 extension is not supported
         * @return {Grape.Audio} The Audio resource
         */
        audio: function (name, opts, url1, url2, url3) { //TODOv2 add from audio.js
            if (typeof opts === 'string') {
                url3 = url2 ? this.prefix + url2 : url2;
                url2 = url1 ? this.prefix + url1 : url1;
                url1 = opts ? this.prefix + opts : opts;
                opts = {};
            }
            var audio = new GrapeAudio(opts, url1, url2, url3);
            this.add(name, audio);
            return audio;
        },
        /**
         * Creates a new JSONSceneSource, and adds to the collection.
         *
         * @method scene
         * @param {String} name Key
         * @param {String} url Scene JSON URL
         * @param {Object} settings Settings passed as constructor parameter to JSONSceneSource.
         * @return {Grape.JSONSceneSource} The created JSONSceneSource
         */
        scene: function (name, url, settings) {
            var scn = new JSONSceneSource(this.prefix + url, settings);
            this.add(name, scn);
            return scn;
        }
    });
});