Source: loader.js

loader.js

import * as PIXI from 'pixi.js';
import request from 'superagent';
import * as element from './element';
import Asset from './asset';

/**
 * Create assets and layers, also load all images includes AfterEffects animation.
 *
 * @class AEDataLoader
 * @memberof PIXI
 * @prop {function} imagePathProxy - Callback with image path before load image. If modify image path before load image, override this member and return newly path
 * @prop {function} createImageLoader - Create PIXI.loader.Loader for loading image. If create PIXI.loader.Loader for you want, override this member and can return another loader
 */
export default class AEDataLoader {
  constructor() {
    this.imagePathProxy = path => path;
    this.createImageLoader = imageAssets => new PIXI.loaders.Loader('', imageAssets.length);
  }

  /**
   * Load JSON data by url
   *
   * @memberof PIXI.AEDataLoader#
   * @param {string} - The JSON url
   * @return {Promise}
   */
  loadJSON(jsonPath) {
    return new Promise((resolve, reject) => {
      request.get(jsonPath).end((err, res) => {
        if (err) return reject(err);
        return this.load(res.body, jsonPath, null).then(() => {
          resolve(res.body);
        }).catch((e) => {
          reject(e);
        });
      });
    });
  }

  /**
   * Load JSON data by url with PIXI.AEDataInterceptor
   *
   * @memberof PIXI.AEDataLoader#
   * @param {string} - The JSON url
   * @param {PIXI.AEDataInterceptor} - The AEDataInterceptor instance
   * @return {Promise}
   */
  loadJSONWithInterceptor(jsonPath, interceptor) {
    return new Promise((resolve, reject) => {
      if (!interceptor) {
        return reject(new Error('required interceptor parameter'));
      }
      return request.get(jsonPath).end((err, res) => {
        if (err) return reject(err);
        const data = res.body;
        return this.load(data, jsonPath, interceptor).then(() => {
          resolve(data);
        }).catch((e) => {
          reject(e);
        });
      });
    });
  }

  static loadLayers(data, interceptor) {
    return data.layers.map((layer) => {
      if (interceptor) interceptor.intercept(layer);
      return element.ElementFactory.create(layer);
    }).filter(layer => layer !== null);
  }

  loadAssets(data, jsonPath, interceptor) {
    const baseName = jsonPath.split('/').slice(0, -1).join('/');
    const assets = data.assets.map((asset) => {
      if (interceptor) interceptor.intercept(asset);
      return new Asset(this, asset, baseName);
    });
    const imageAssets = assets.filter((asset) => {
      return !!asset.imagePath;
    });
    if (imageAssets.length === 0) {
      return new Promise(resolve => resolve(assets));
    }
    return this.loadImages(imageAssets).then(() => assets);
  }

  loadImages(imageAssets) {
    return new Promise((resolve, reject) => {
      const loader = this.createImageLoader(imageAssets);

      // if override createImageLoader and use shared PIXI.Loaders,
      // possibly loader.resources has already loaded resource
      const requiredLoadAssets = imageAssets.filter(asset => !loader.resources[asset.imagePath]);
      if (requiredLoadAssets.length === 0) {
        imageAssets.forEach((asset) => {
          asset.texture = loader.resources[asset.imagePath].texture;
        });
        return resolve();
      }
      requiredLoadAssets.forEach((asset) => {
        loader.add(asset.imagePath, asset.imagePath);
      });
      loader.onError.add((error, _, resource) => {
        reject(error, resource);
      });
      return loader.load((_, resources) => {
        imageAssets.forEach(asset => asset.texture = resources[asset.imagePath].texture);
        resolve();
      });
    });
  }

  static resolveReference(layers, assets) {
    const assetMap = {};
    assets.forEach((asset) => {
      assetMap[asset.id] = asset;
    });
    layers.forEach((layer) => {
      if (layer.isCompType()) {
        layer.setupReference(assetMap);
      } else if (layer.isImageType()) {
        layer.setupImage(assetMap);
      }
    });
  }

  load(data, jsonPath, interceptor) {
    return this.loadAssets(data, jsonPath, interceptor)
      .then((assets) => {
        const layers = AEDataLoader.loadLayers(data, interceptor);
        AEDataLoader.resolveReference(layers, assets);
        data.assets  = assets;
        data.layers  = layers;
      });
  }
}