You’ve probably heard of Adobe Edge, a timeline-based tool for creating interactive and animated HTML content. Edge enables you to easily create interactive experiences that rely only on HTML, CSS, and JavaScript. If you’ve used other Adobe Creative Suite tools, such as Flash Professional, Premiere, or After Effects, then Edge will probably look quite familiar. You have a timeline and controls to edit your content.
Currently, the “normal” use case for Edge is creating interactive experiences that are loaded when the page loads. You can chain animation compositions in sequence, but they have to be in the same wrapper HTML file. This works great for a number of use cases, but one thing I wanted to do is create an Edge animation and use that as a component that is arbitrarily added to the HTML DOM at any point in time. My findings: It can be done, although with a few gotchas.
Using Edge animations as components inside of a larger HTML experience isn’t the primary use case which Edge was designed for. However this use case is being evaluated and may end up in Edge at a later date. If that happens, this process will become much easier.
If you’re wondering “What was I thinking?”, I’ll try to explain… while discussing the process of building HTML-based apps, I had the thought:
Wouldn’t it be cool to have a really elaborate loading animation while loading data from the server? We could use Edge to build the animation!
As a proof of concept, I created a very basic application that loads two separate Edge animations on demand. Before I go into too much detail on what I built, let’s take a look at the running example. This example has two buttons, one shows a car animation, one shows an airplane animation. It’s pretty basic and straightforward:
The first thing that I did was create two simple Edge animations which you can view here:
All images used in these animations were obtained from thenounproject.com.
Once the animations were complete, I started looking at the generated HTML output, and figuring out how I can add it to the HTML DOM of an existing HTML page. I then started putting together the sample application using Mustache.js as a templating engine to abstract HTML views away from application logic. Note: I also have a simple utility that enables me to include Mustache.js templates in separate HTML files, so that I can keep everything separate.
First, I created the basic shell for the application. It is more or less an empty HTML structure, where all content is added at runtime:
[html]
[/html]
Inside of the “contentHost” div, all UI is added to the HTML DOM upon request. Basically, when the user clicks a button, the Edge animation is added to the DOM, and then the animation begins.
In order to get this working, I had to change a few things in the generated Edge output:
- in the *_edge.js file, I changed the DOM Ready event handler to use an arbitrary event that I can control. By default, Edge uses the jQuery $(window).ready() event to start the animation. Since I am adding this to an existing HTML DOM, the $(window).ready() event is not applicable. Instead, I changed this to use a custom “animationReady” event:[js]$(window).bind( "animationReady", function() {
Edge.launchComposition(compId);
});[/js] - In the *_edgePreload.js file, I added a reference to the onDocLoaded function so that I can manually invoke it later, once the Edge animation has been added to the DOM, since again, this won’t rely on the “load” event.[js]//added this so it can be invoked later
window.onDocLoaded = onDocLoaded;[/js]I also changed the aLoader object to reference the appropriate JavaScript files, since I changed their location in the directory structure:
[js]
aLoader = [
{ load: "templates/animation_planes/edge_includes/jquery-1.7.1.min.js"},
{ load: "templates/animation_planes/edge_includes/jquery.easing.1.3.js"},
{ load: "templates/animation_planes/edge_includes/edge.0.1.6.min.js"},
{test: !hasJSON, yep:"templates/animation_planes/edge_includes/json2_min.js"},
{ load: "templates/animation_planes/planes_animation_edge.js"},
{ load: "templates/animation_planes/planes_animation_edgeActions.js"}];[/js] - Finally, I created the Mustache.js template, which will be used to generate the HTML DOM elements that will be appended to the existing DOM. In this there is a wrapper DIV, some HTML content including a button and some text (the animation number is dynamic for the templating), the styles, a “Stage” div, and Edge preload JavaScript files necessary for the animation.
[html]</pre>
<div id="animationContainer">
<button id="removeAnimation">Restore Default View</button>Animation {{animationCount}}
<script charset="utf-8" type="text/javascript" src="templates/animation_planes/planes_animation_edgePreload.js"></script></div>
<pre>
[/html] - Next, let’s look at how this is actually injected into the DOM. I created a setupAnimationView() function to inject the animations into the DOM. This function is used by both animations. The first thing that it does is remove any existing DOM content and dereference the AdobeEdge variables in memory. Since Edge wasn’t originally designed for asynchronously loading animations, I found it to be easiest to just wipe-out Edge and reload it for every animation. The unfortunate side effect is that you can only have one Edge animation on screen at any given point in time. Next, the setupAnimationView() function generates the HTML DOM elements and event listeners and adds them to the DOM. Finally, I created an edgeDetectionFunction, which checks to see if Edge is loaded. If not, it loads the Edge runtime. The edgeDetectionFunction() then checks if the Edge animation is sufficiently loaded. If the animation definition is not loaded, it just waits and tries again. If the animation definition is loaded, it dispatches the “animationReady” event (discussed in step 1) to invoke the actual animation.[js]function setupAnimationView( template ) {
$("#contentHost").empty();
window.AdobeEdge = undefined;
AdobeEdge = undefined;
animationCount++;
var viewModel = {animationCount:animationCount};var html = Mustache.to_html(template, viewModel)
$("#contentHost").append( html );
$("#removeAnimation").click( setupDefaultView );//detect if edge is loaded yet
var edgeDetectionFunction = function() {if ( AdobeEdge && AdobeEdge.compositions != undefined) {
var hasComposition = false;
if ( AdobeEdge.compositions ) {
//loop to see if the composition is actually loaded
for ( var key in AdobeEdge.compositionDefns ) {
hasComposition = true;
break;
}
}if ( hasComposition ) {
setTimeout( function(){ $(window).trigger( "animationReady" ); }, 100 );
return;
}
}
else if ( AdobeEdge ) {
window.onDocLoaded();
}
setTimeout( edgeDetectionFunction, 100 );
}
edgeDetectionFunction();
}
[/js]
Since I am using Edge in a manner for which it was not initially designed, there are a few “gotchas” that I ran into:
- You can’t have multiple instances of the same Edge animation in a single HTML DOM – at least, not easily. Each Edge animation is assigned a unique ID. This ID is referenced in the HTML structure and the *_edge.js, *_edgeActions.js, and *_edgePreload.js files. You would need to assign a unique ID to each instance, and make sure everything is referenced consistently.
- It will be very tricky asynchronously add more than one Edge animation at the same time. The shortcut that I used to get these to render was to wipe away the Edge variables in JS and reload them – this would cause some issues with more than one animation.
If the capability to have Edge animations as components gets built into Edge (which I hope it does!), then you will not have to go through all of these steps, and it will be much easier. I’ll be sure to share more if this feature develops.
This Example
More on Edge
If you haven’t yet seen what Edge can do, you really should take a look at some of these examples built with Adobe Edge:
Enjoy!