Moving around Flash

Categories:Working with Flash

Overview

Traditionally, moving around in Flash has been done one of two main ways:

  1. fl.getDocumentDOM().getTimeline().etc.etc to locate specific elements
  2. i, j, k loops to iterate into layers, frames and elements

xJSFL abstracts both the idea and code behind these concepts into two specific classes that allow you to navigate around Flash in a snap; Context and Iterators.

Context

Working with elements on the Flash stage can be simple if you're just running a few commands on the current selection, but can get complicated when you begin to consider the elements within the context of their Document, Timeline, Layer and Frame -- especially if any of these properties has to change as you run JSFL, perhaps from a Flash panel.

For example, in a timeline that has 200 frames and 10 layers, with various carefully-placed keyframes, how do you easily reference where you are in terms of code?

I'm in game level 06.fla, editing library item Green spaceship, on layer jet exhaust, keyframe 4 (at 23 frames in), with the flame_3 instance selected

To get round this problem, xJSFL has a class called Context, which stores all these variables, and allows you to and navigate the IDE focus between contexts as you see fit.

Creating a context is easy; you simply call a static method on the actual class, that returns a Context instance set to the current IDE settings:

var context = Context.create();

Or if you like, pass an existing reference in to start from somewhere specific:

var context = Context.from(frame);

You can then use the context object's properties as a shortcut to Flash timeline properties like so:

context.layer;        // access the actual Flash layer object
context.frame;        // access the context's frame object
context.keyframes;    // access the keyframes from within the current context's layer
context.elements;     // access the elements within the context's frame

This is much easier and infinitely more flexible that writing (and rewriting) verbose JSFL such as:

fl.getDocumentDOM().getTimeline().layers[3].frames[25].elements;

Context also has various methods such as:

context.setLayer(3);  // update the context layer
context.update();     // update the context to the current IDE context
context.goto();       // force Flash to change the window and timeline to the supplied context

Context instances can be also be passed around, stored in Arrays, and serialized to and from XML (WIP) if contexts need to persist longer than the execution of a simple script.

For full details on how to create, update and use contexts in other ways, see the API section on Context.

Iterators

One of the more common workflows in Flash is to test every single element, on every single frame, in every single layer, and do something like rename them, or set their tint to red, or such like. It's not uncommon to see 3-level nested i, j, k loops in order to accomplish this, but the problem with that is it makes for rather hard-to-read and difficult to edit code:

// grab layers
var layers = item.timeline.layers;

// layer loop
for ( var i = 0; i < layers.length; i++ ) {
	var layer = layers[i];

	// frame loop
	for ( var j = 0; j < layer.frames.length; j++ ) {
		var frame = layer.frames[j];

		// element loop
		for ( var k = 0; k < frame.elements.length; k++ ) {
			var element = frame.elements[k];
			element.name = 'item_' + index;
		}
	}
}

Enter the Iterators class, designed to take the tedious legwork out of iterating over layers, frames and elements, as well as adding Documents and Items into the mix.

Instead of writing 3-level (or for documents & items, 5-level) loops, the Iterators class offers you a very simple API to iterate over any Documents, Items, Layers, Frames or Elements, going as deep as you like, and cancelling any level, or the full iteration, any time you like.

For example, the above example would be easily accomplished with the following code:

// set up the callback function
    function callback(element, index) {
        element.name = 'item_' + index;
    }

// iterate!
    Iterators.layers(item, null, null, callback);

Not only that, but if you decided you also wanted to process layers and frames -- such as renaming, or checking a layer is actually valid -- you could simply add in extra callbacks for layers and frames (that's what the previous null arguments are):

// set up the callback functions
    function layerCallback(element) { ... }
    function frameCallback(element) { ... }
    function elementCallback(element) { ... }

// iterate!
    Iterators.layers(item, layerCallback, frameCallback, elementCallback);

Not only that but the Iterators.frames() method automatically skips non-keyframe frames, making it much more efficient than a traditional i, j, k loop.

There are 5 main Iterators methods, for Documents, Timelines, Layers, Frames, and Elements, and each method can iterate as deep or as shallow as you like, simply by supplying (or not supplying) valid callbacks.

Next Steps

Introduction to Collections

Comments are closed.