简体   繁体   中英

Using Adobe Edge Animate with AngularJS and AngularUI Router

I'm working on a project at the moment which will incorporate multiple animations created with Adobe Edge Animate into an single AngularJS application. The idea is that these animations will act as the visuals for a game and I will control the composition based on input from the player. It's taken some experimenting to get to this stage but all of that is working perfectly.

My problems start whenever the player chooses to exit the current view and access it for a second time. For some reason this causes an issue with the Adobe Edge Animate Javascript API and the composition fails to load.

Essentially, I can load a composition once but no more. Whenever I attempt to load the composition for a second time I get the following Javascript errors...

Uncaught TypeError: Cannot read property 'stage' of undefined    edge.5.0.1.js:4872
Uncaught TypeError: Cannot read property 'stage' of undefined    edge.5.0.1.js:4519

I'm currently loading the composition directly from within the controller as follows...

.controller('GameTest', function($scope, $state) {
    AdobeEdge.loadComposition('edge-animate/GameTest', 'GameTest', {
      scaleToFit: "width",
      centerStage: "none",
      minW: "0",
      maxW: "undefined",
      width: "2048px",
      height: "1134px"
    }, {dom: [ ]}, {dom: [ ]});
})

I've also disabled caching for this state...

.state('game-test', {
  cache: false,
  url: "/games/test",
  controller: 'GameTest',
  templateUrl: 'templates/games/test.html'
})

All suggestions welcome and appreciate any help!

Thanks

Update: I've worked out a solution! Hopefully...

The issue seems to be resolved if the browser handles the contents of the relevant *_edge.js again. Since these are injected into the <head> whenever AdobeEdge.loadComposition(...) is called (via yepnope), and there doesn't appear to be any method of asking yepnope to reload injected Javascript, I have written a small service for Angular that I can use to handle this in place of the standard AdobeEdge.loadComposition(...) function. It's essentially a wrapper that will do the relevant checks beforehand.

.service('$AdobeEdge', function() {
  var head = document.getElementsByTagName('head')[0],
    scripts = head.getElementsByTagName('script');

  return { 
    loadComposition: function(projectPrefix, compId, opts, preloaderDOM, downLevelStageDOM) {
      // Determine the filename for our project
      var projectFile = projectPrefix + '_edge.js';
      var newScript = null;

      // Iterate through each script tag in the header to search for our file
      angular.forEach(scripts, function(script, index, scripts) {

        // Does the script src tag end with our project filename?
        if (script.src.substr(script.src.length - projectFile.length) == projectFile) {

          // It's already loaded! Let's go about removing it and injecting a fresh script tag...
          script.remove();
          newScript = document.createElement('script');
          newScript.setAttribute('type', 'text/javascript');
          newScript.setAttribute('src', script.src);
          head.insertBefore(newScript, scripts[0]);

          // Let's also delete the composition within the Adobe Edge API so that events
          // like 'compositionReady' are fired again when we call loadComposition()
          delete AdobeEdge.compositions[compId];
        }
      });

      // Ultimately we always need to call loadComposition() no matter what
      AdobeEdge.loadComposition(projectPrefix, compId, opts, preloaderDOM, downLevelStageDOM);
    }
  }
})

Using this method I can simply invoke this service in the relevant controllers and load a composition in a similar manner to normal. In this particular case...

.controller('GameTest', function($scope, $state, $AdobeEdge) {
  $AdobeEdge.loadComposition('edge-animate/GameTest', 'GameTest', {
    scaleToFit: "width",
    centerStage: "none",
    minW: "0",
    maxW: "undefined",
    width: "2048px",
    height: "1134px"
  }, {dom: [ ]}, {dom: [ ]});
});

So far it's been working great! I'll use it to build out the rest of the games in our project and post any issues I run into.

Hopefully this saves someone else a lot of heartache!

Answer by Rob Sinton :

The issue seems to be resolved if the browser handles the contents of the relevant *_edge.js again. Since these are injected into the <head> whenever AdobeEdge.loadComposition(...) is called (via yepnope), and there doesn't appear to be any method of asking yepnope to reload injected Javascript, I have written a small service for Angular that I can use to handle this in place of the standard AdobeEdge.loadComposition(...) function. It's essentially a wrapper that will do the relevant checks beforehand.

.service('$AdobeEdge', function() {
  var head = document.getElementsByTagName('head')[0],
    scripts = head.getElementsByTagName('script');

  return { 
    loadComposition: function(projectPrefix, compId, opts, preloaderDOM, downLevelStageDOM) {
      // Determine the filename for our project
      var projectFile = projectPrefix + '_edge.js';
      var newScript = null;

      // Iterate through each script tag in the header to search for our file
      angular.forEach(scripts, function(script, index, scripts) {

        // Does the script src tag end with our project filename?
        if (script.src.substr(script.src.length - projectFile.length) == projectFile) {

          // It's already loaded! Let's go about removing it and injecting a fresh script tag...
          script.remove();
          newScript = document.createElement('script');
          newScript.setAttribute('type', 'text/javascript');
          newScript.setAttribute('src', script.src);
          head.insertBefore(newScript, scripts[0]);

          // Let's also delete the composition within the Adobe Edge API so that events
          // like 'compositionReady' are fired again when we call loadComposition()
          delete AdobeEdge.compositions[compId];
        }
      });

      // Ultimately we always need to call loadComposition() no matter what
      AdobeEdge.loadComposition(projectPrefix, compId, opts, preloaderDOM, downLevelStageDOM);
    }
  }
})

Using this method I can simply invoke this service in the relevant controllers and load a composition in a similar manner to normal. In this particular case...

.controller('GameTest', function($scope, $state, $AdobeEdge) {
  $AdobeEdge.loadComposition('edge-animate/GameTest', 'GameTest', {
    scaleToFit: "width",
    centerStage: "none",
    minW: "0",
    maxW: "undefined",
    width: "2048px",
    height: "1134px"
  }, {dom: [ ]}, {dom: [ ]});
});

So far it's been working great! I'll use it to build out the rest of the games in our project and post any issues I run into.

Hopefully this saves someone else a lot of heartache!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM