creative-connections/aurelia-bodylight-plugin

View on GitHub
src/elements/animate-adobe-ss.js

Summary

Maintainability
D
3 days
Test Coverage
import {bindable} from 'aurelia-framework';
import 'latest-createjs';

export class AnimateAdobeSs {
  @bindable src;
  @bindable width=800;
  @bindable height=600;
  @bindable name;//="ZelezoCelek"
  //@bindable cid;//="3CC81150E735AE4485D4B0DF526EB8B4";

  constructor(){}
  bind(){}

  attached(){
    //let that = this;
    let continueAfter = () => {
      if (typeof createjs === 'undefined') console.log('WARN: createjs not present,loading script manually not supported yet.');

      //if (!window.createjs) window.createjs = createjs;
      //make this component global - due to further calls
      //this.bindings = [];
      //window.ani = that;
      //detects and if not present - adds script with JS into DOM - so browser will load it, after that, initAdobe() will be called
      this.getScript(this.src, this.init.bind(this));
      //this.ratio = this.width / this.height;
      //window.addEventListener('resize', this.handleResize);
      //this.init();
    };

    //check global instance of createjs - if not present wait 500 ms
    if (typeof createjs === 'undefined') {
      console.log('INFO: waiting 1000ms for createjs ');
      setTimeout(() => continueAfter.bind(this), 1000);
    } else continueAfter();
  }

  //handleResize(); // First draw
  detached() {
    console.log('adobeobj detached()');
    //stop animation
    //this.disableAnimation();
    //remove script
    this.removeScript(this.src);
    //destroy bindings
    this.bindings = [];
    //remove listeners
    /*let fromel = document.getElementById(this.fromid);
    if (fromel) {
      fromel.removeEventListener('animatestart', this.startAllAnimation);
      fromel.removeEventListener('animatestop', this.stopAllAnimation);
      fromel.removeEventListener('fmidata', this.handleValueChange);
      fromel.removeEventListener('fmistart', this.enableAnimation);
      fromel.removeEventListener('fmistop', this.disableAnimation);
    }*/
    this.destroyAdobe();
    //document.removeEventListener('fmiattached',this.handleFMIAttached);
  }

  destroyAdobe() {
    console.log('animate adobe ss destroy()');
    if (this.stage) {
      this.stage.enableMouseOver(-1);
      this.stage.enableDOMEvents(false);
      this.stage.removeAllEventListeners();
      this.stage.removeAllChildren();
      this.stage.canvas = null;
      this.stage = null;
    }
    if (this.exportRoot) this.exportRoot = null;
    if (this.ss) this.ss = null;
    if (this.lib) this.lib = null;
    if (this.comp) this.comp = null;
    if (this.cid) this.cid = null;
    if (this.objs) this.objs = null;
    if (this.animobjs) this.animobjs = null;
    if (this.textobjs) this.textobjs = null;
    if (this.playobjs) this.playobjs = null;
    if (this.AdobeAn) this.AdobeAn = null;
  }


  init(){
    //canvas = document.getElementById("canvas");
    //anim_container = document.getElementById("animation_container");
    //dom_overlay_container = document.getElementById("dom_overlay_container");
    //find the right composition
    this.lib = null; this.comp = null;
    for (let cid of Object.keys(AdobeAn.compositions)) {
      let comp = AdobeAn.getComposition(cid);
      let lib = comp.getLibrary();
      if (lib[this.name] || lib['_'+this.name]) {
        this.lib = lib;
        this.comp = comp;
        break;
      }
    }
    /*let cid = Object.keys(AdobeAn.compositions).at(-1); //TODO last composition is the one needed??
    let comp=AdobeAn.getComposition(cid);
    this.lib=comp.getLibrary();*/
    let loader = new createjs.LoadQueue(false);
    loader.installPlugin(createjs.Sound);
    loader.addEventListener("fileload", function(evt){this.handleFileLoad(evt,this.comp)}.bind(this));
    loader.addEventListener("complete", function(evt){this.handleComplete(evt,this.comp)}.bind(this));
    //var lib=comp.getLibrary();
    loader.loadManifest(this.lib.properties.manifest);
  }

  handleFileLoad(evt, comp) {
    var images=comp.getImages();
    if (evt && (evt.item.type == "image")) { images[evt.item.id] = evt.result; }
  }
  handleComplete(evt,comp) {
    //This function is always called, irrespective of the content. You can use the variable "stage" after it is created in token create_stage.
    //var lib=comp.getLibrary();
    let ss=comp.getSpriteSheet();
    let queue = evt.target;
    let ssMetadata = this.lib.ssMetadata;
    for(let i=0; i<ssMetadata.length; i++) {
      ss[ssMetadata[i].name] = new createjs.SpriteSheet( {"images": [queue.getResult(ssMetadata[i].name)], "frames": ssMetadata[i].frames} )
    }
    let keys = Object.keys(this.lib);
    console.log('animate adobe ss lib keys:',keys);
    console.log('animate adobe ss name to be initialized:',this.name);
    //fix '_' before object name
    if (typeof this.lib[this.name] == 'function') this.exportRoot = new this.lib[this.name]
    else if (typeof this.lib['_'+this.name] == 'function') this.exportRoot = new this.lib['_'+this.name]();//new lib._04_Fe_výskyt_HTML5Canvas();
    else { console.warn('cannot instantiate animation',this.name); return;}
    this.stage = new this.lib.Stage(this.canvas);
    //Registers the "tick" event listener.
    //Code to support hidpi screens and responsive scaling.
    //AdobeAn.makeResponsive(false,'both',false,1,[this.canvas,this.anim_container,this.dom_overlay_container]);
    this.makeResponsive(true, 'both', true, 1, [this.canvas, this.anim_container, this.dom_overlay_container]);

    AdobeAn.compositionLoaded(this.lib.properties.id);
    this.fnStartAnimation();
  }

  fnStartAnimation() {
    this.stage.addChild(this.exportRoot);
    createjs.Ticker.setFPS(this.lib.properties.fps);
    createjs.Ticker.addEventListener("tick", this.stage);
  }


  playSound(id, loop) {
    return createjs.Sound.play(id, createjs.Sound.INTERRUPT_EARLY, 0, 0, loop);
  }

  //get script element and registers 'onload' callback to be called when the script is loaded
  getScript(source, callback) {
    //check whether the script is not already there
    if (Array.from(document.getElementsByTagName('script')).filter(x=> x.getAttribute('src') === source).length > 0) {
      console.warn('AnimateAdobe.getScript() WARNING, script is already added into DOM:', source);
      //do callback?
      if (callback) setTimeout(callback, 0);
      return;
    }
    //console.log('animateadobe getscript()');
    let script = document.createElement('script');
    let prior = document.getElementsByTagName('script')[0];
    script.async = 1;
    //set that after onload a callback will be executed
    script.onerror = function() {
      if (!script.readyState || /loaded|complete/.test(script.readyState) ) {
        script.onerror = script.onload = script.onreadystatechange = null;
        script = undefined;
        // try to insert script by other app for previewing - scripts might be inserted into DOM
        if (window.editorapi && (typeof window.editorapi.insertScriptById === 'function')) {
          //disable previoues definition
          this.destroyAdobe();
          //enable current def
          //console.log('inserting script by thirdparty api');
          window.editorapi.insertScriptById(source, 'adobeobj')
            .then(innerscript => {
              //console.log('third party script node', innerscript);
              try {
                // eslint-disable-next-line no-eval
                eval(innerscript.innerHTML);
              } catch (e) {
                console.warn('Error during evaluation of adobe script. Probably OK to ignore', e.message);
              }
              if (callback) setTimeout(callback, 1000);
            });
        }
        // do callback after 2s
        //if (callback) setTimeout(callback, 1000);
      }
    };
    script.onload = script.onreadystatechange = function( _, isAbort ) {
      if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
        script.onerror = script.onload = script.onreadystatechange = null;
        script = undefined;

        if (!isAbort && callback) setTimeout(callback, 0);
      }
    };
    //set script source - if base url is defined then base is prefixed
    script.src = window.bdlBaseHref ? window.bdlBaseHref + source : source;
    //add custom animate script into DOM - the onload will be called then
    prior.parentNode.insertBefore(script, prior);
  }

  makeResponsive(isResp, respDim, isScale, scaleType, domContainers) {
    //let lastW; let lastH; let lastS = 1;
    window.addEventListener('resize', this.handleResize.bind(this));
    this.isResp = isResp;
    this.respDim = respDim;
    this.isScale = isScale;
    this.scaleType = scaleType;
    this.domContainers = domContainers;
    this.handleResize();
  }

  handleResize() {
    console.log('animateadobe handleResize()');
    //do not run if ani.lib is not defined - no adobe component is available
    if (!this.lib) return;
    let w = this.lib.properties.width; let h = this.lib.properties.height;
    let iw = window.innerWidth;
    let ih = window.innerHeight;
    if (this.canvas && this.canvas.parentElement && this.canvas.parentElement.parentElement && this.canvas.parentElement.parentElement.parentElement) {
      iw = this.canvas.parentElement.parentElement.parentElement.offsetWidth;
      ih = this.canvas.parentElement.parentElement.parentElement.offsetHeight;
    }
    ih = iw / ( w / h );
    //let iw = window.innerWidth; let ih = window.innerHeight;
    let pRatio = window.devicePixelRatio || 1; let xRatio = iw / w; let yRatio = ih / h; let sRatio = 1;
    if (this.isResp) {
      if ((this.respDim === 'width' && this.lastW === iw) || (this.respDim === 'height' && this.lastH === ih)) {
        sRatio = this.lastS;
      } else if (!this.isScale) {
        if (iw < w || ih < h) {sRatio = Math.min(xRatio, yRatio);}
      } else if (this.scaleType === 1) {
        sRatio = Math.min(xRatio, yRatio);
      } else if (this.scaleType === 2) {
        sRatio = Math.max(xRatio, yRatio);
      }
    }
    this.domContainers[0].width = w * pRatio * sRatio;
    this.domContainers[0].height = h * pRatio * sRatio;
    this.domContainers.forEach(function(container) {
      container.style.width = w * sRatio + 'px';
      container.style.height = h * sRatio + 'px';
    });
    this.stage.scaleX = pRatio * sRatio;
    this.stage.scaleY = pRatio * sRatio;
    this.lastW = iw; this.lastH = ih; this.lastS = sRatio;
    this.stage.tickOnUpdate = false;
    this.stage.update();
    this.stage.tickOnUpdate = true;
  }

  removeScript(source) {
    let src = window.bdlBaseHref ? window.bdlBaseHref + source : source;
    let tags = document.getElementsByTagName('script');
    for (let i = tags.length; i >= 0; i--) { //search backwards within nodelist for matching elements to remove
      if (tags[i] && tags[i].getAttribute('src') !== null && tags[i].getAttribute('src').indexOf(src) !== -1) {tags[i].parentNode.removeChild(tags[i]);} //remove element by calling parentNode.removeChild()
    }
  }


}