Thursday, February 5, 2009

WebPattern & ControlPanel

I've finally finished my first visually impressive AS3 project: the WebPattern class. It takes four arrays as arguments: branches, which represents the number of branches originating from each node; branchAngles, which determines the angle between the two farthest branches of a node; branchLengths, which determines the length of the branches originating at a node; and jointWidths, which governs the width of the branches where they connect at a node. If you don't understand my explanation, you can check out a demo.

Here are a couple of warnings before you start fiddling. First, this program is relatively processor intensive, because each new layer of branches dramatically increases processing time. If you want a pattern with five layers, you had better make sure that none of the nodes has more than five branches. This program will kill your computer if you aren't careful.

Second, all of the arrays you pass in as arguments have to be the same length. Otherwise, you'll get silent failure, unless you have the debug Flash plug-in. Also make sure that all of the nodes have at least two branches and none of the other arrays have a zero in them.

WebPattern may be a unique and incredibly fun-to-play-with class, but ControlPanel is a very useful class for demoing classes and apps. That box in the top-right corner that lets you create patterns is an instance of ControlPanel. Creating that panel took only six lines of code: one for instantiation, one for each input field, and one to add it to the stage. It seals away most of the painful interface construction and data management steps.

For example, for this implementation, I had to do only three things to implement the control panel and hook it up to my web pattern drawer. First, I had to construct it:


fields = ['Branches:', 'Branch Angles', 'Branch Lengths:', 'Joint Widths:'];
defaults = ['2, 5, 3','180, 180, 60','50, 50, 50','6, 6, 2']
controlPanel = new ControlPanel('Arial');
for (var i:uint = 0, j:int = fields.length; i < j; i++) {
 controlPanel.addTextInput(fields[i], defaults[i]);
}
addChild(controlPanel);

I only used the arrays to abstract the naming of the fields; you can call it manually if you would like. Next, I added some event listeners:


controlPanel.addEventListener(ControlPanel.SUBMIT, submitListener, false, 0, true);
controlPanel.addEventListener(ControlPanel.CLOSE, closeListener, false, 0, true);

Finally, I created some listening functions. Notice how the submitListener() function only has to retrieve the data from controlPanel with data and access it through the input field names:


private function submitListener(evt:Event):void {
 destroyWebPattern();
 var arguments:Array = [];
 var rawData:Object = controlPanel.data;
 try {
  for (var i:uint = 0, j:int = fields.length; i < j; i++) {
   var fieldData:String = rawData[fields[i]];
   fieldData.replace(' ', '');
   arguments[i] = fieldData.split(',');
  }
  createWebPattern(arguments[0], arguments[1], arguments[2], arguments[3]);
 } catch (e:Error) {
  trace(e);
 }
}
  
private function closeListener(evt:Event):void {
 removeChild(controlPanel);
}

Even if you don't want to analyze that code, the lack of TextField, embedFonts, and defaultFormat should be apparent. Just remember that the ControlPanel relies on embedded fonts; make sure to embed whatever font you'd like it to use and export it for ActionScript.

Check out the demo and the source. I hope you'll have fun with my new toy and new tool.