import extend from "lodash-es/extend" ; import pickBy from "lodash-es/pickBy" ; import Model from "./Model" ; /**
 * Defines a resource pack. Resource Packs
 * can be added to resource manager.
 */ export interface IPack { /**
     * Name of the Resource Pack
     */ name : string ; /**
     * URL prefix for the Resource Pack. Full URL to
     * a file in this pack is obtained by appending the filename
     * to this prefix
     */ prefix : string ; /**
     * Names of the files.
     */ fileNames : string [ ] ; } /**
 * ResourceManager manages async loading and caching of resources.
 *
 * ResourceManager Basically, it maintains a map of fileNames to URI for
 * the resource. When a request for resource fileName is received, the uri is looked up
 * and the file is either async loaded or served from cache. This also manages
 * a ready state with callbacks that tells when one or more resources are being loaded and
 * when all resources are ready.
 */ export default class ResourceManager extends Model { public ready : boolean = true ; private packs : IPack [ ] ; private uris : { [ key ] : string ; } = { } ; private images : { [ key ] : HTMLImageElement ; } = { } ; private waitImages : { [ key ] : HTMLImageElement ; } = { } ; private waitCount : number = 0 ; constructor ( packs ) { super ( ) ; if ( packs ) { if ( ! Array . isArray ( packs ) ) { packs = [ packs ] ; } this . packs = packs ; } else { this . packs = [ ] ; } this . clear ( ) ; } param fileName param uri public registerUri ( fileName , uri ? ) { if ( typeof fileName === "string" && typeof uri === "string" ) { this . uris [ fileName ] = uri ; } else { const inputUris = fileName ; extend ( this . uris , inputUris ) ; } } param key public get ( key ) { if ( key === "uris" ) { return this . uris ; } } /**
     * Returns JSON representation of the resource manager
     */ public toJSON ( ) { return { uris : Object . assign ( { } , this . uris ) } ; } param keys public clear ( keys = null ) { for ( const fileName in this . waitImages ) { if ( ! this . waitImages . hasOwnProperty ( fileName ) ) { continue ; } const image = this . waitImages [ fileName ] ; image . onload = null ; image . onerror = null ; } this . waitImages = { } ; if ( keys ) { const pickPredicate = ( val , key ) => keys . indexOf ( key ) === - 1 ; this . uris = pickBy ( this . uris , pickPredicate ) ; this . images = pickBy ( this . images , pickPredicate ) ; } else { this . uris = { } ; this . images = { } ; } this . waitCount = 0 ; this . ready = true ; } param fileName param success param error public getImage ( fileName , success , error ? ) { let image = this . images [ fileName ] ; if ( image ) { if ( success ) { success ( image ) ; } return ; } const uri = this . _getUri ( fileName ) ; if ( ! uri ) { throw new Error ( "Unknown image file " + fileName ) ; } image = new Image ( ) ; if ( uri . indexOf ( "data:" ) !== 0 ) { image . crossOrigin = "anonymous" ; } image . onload = ( ) => { delete this . waitImages [ fileName ] ; this . images [ fileName ] = image ; if ( success ) { success ( image ) ; } this . _loadEnd ( ) ; } ; if ( error ) { image . onerror = ( ) => { delete this . waitImages [ fileName ] ; if ( error ( ) ) { this . _loadEnd ( ) ; } } ; } this . _loadStart ( ) ; image . src = uri ; this . waitImages [ fileName ] = image ; } protected setAttribute ( key , value , options ) { if ( key === "uris" ) { this . uris = value ; return true ; } return false ; } private _getUri ( fileName ) { const uri = this . uris [ fileName ] ; if ( uri ) { return uri ; } for ( let i = this . packs . length - 1 ; i >= 0 ; i -- ) { const pack = this . packs [ i ] ; if ( pack . fileNames . indexOf ( fileName ) !== - 1 ) { return pack . prefix + fileName ; } } } private _loadStart ( ) { this . waitCount ++ ; if ( this . waitCount === 1 ) { this . ready = false ; this . emit ( "wait" ) ; } } private _loadEnd ( ) { this . waitCount -- ; if ( this . waitCount === 0 ) { this . ready = true ; this . emit ( "ready" ) ; } } }