Nested Tree Nav

This snippet takes xml and builds a multi-tiered navigation based on how nodes are nested etc…:

So that something like this:

[XML]
var menu:XML=

;
[/XML]

Turns into an expandable and collapsible menu that looks like this:

flash on 2010-3-3 – wonderfl build flash online

Here is the timeline code:

var menu:XML=<nav>
   <element label="one">
       <element label="a" />
   <element label="b" />
   <element label="c" />
</element>
<element label="two">
     <element label="three">
     <element label="aa" > 
	   <element label="zevan" /> 
	 </element>
     <element label="bb" />
     <element label="cc" />
 </element>
 </element>
</nav>;

var elements:Array = new Array();
setupMenu();

function setupMenu():void {
	parse(menu);
	// hide child elements
	for (var i:int = 0; i<elements.length; i++) {
		var mc:MovieClip = elements[i];
		if (mc.parents != 1) {
			removeChild(mc);
		}
	}
	arrangeY();
}

function parse(m:XML):void {
	for each (var d:XML in m.children()) {
		makeBtn(d, numParents(d));
		parse(d);
	}
}

function makeBtn(d:XML, offsetX:int):void {
	var btn:MovieClip = new MovieClip();
	btn.x = offsetX * 20;
	btn.y = numChildren * 20;
	btn.data = d;
	btn.parents = offsetX;
	btn.value = d.@label;

	var txt:TextField = new TextField();
	txt.text = d.@label;
	txt.selectable = false;
	txt.border = true;
	txt.width = 100;
	txt.mouseEnabled = false;
	txt.height = 19;
	btn.addChild(txt);
	btn.buttonMode= true;
	addChild(btn);
	
	// store references to btn
	elements.push(btn);
	elements[d.parent().@label+"_"+d.@label] = btn

	btn.addEventListener(MouseEvent.CLICK, onClick);
}

function onClick(evt:MouseEvent):void {
	showHide(MovieClip(evt.currentTarget));
	arrangeY();
	trace(evt.currentTarget.value);
}

function showHide(btn:MovieClip, forceHide:Boolean=false):void {
	for each (var d:XML in btn.data.children()) {
		var mc:MovieClip = elements[btn.data.@label+"_"+d.@label];
		if (contains(mc)) {
			removeChild(mc);
			showHide(mc, true);
		} else if (forceHide == false) {
			addChild(mc);
		}
	}
}

function arrangeY():void {
	var inc:Number = 0;
	for (var i:int = 0; i<elements.length; i++) {
		if (contains(elements[i])) {
			elements[i].y = inc * 20;
			inc++;
		}
	}
}

function numParents(e:XML):int {
	var num:int = 0;
	while (e.parent()!= null) {
		num++;
		e = e.parent();
	}
	return num;
}

This is one of those snippets I’ve had laying around but never got around to posting. Next time I need to do a multi-tiered nav I’ll wrap it up into a nice class (the wondeful class was done just by using my script that auto-converts timeline code to doc class code).

2 comments

  1. How about adding some animation to it? That’s the icing on the cake! Keep up the awesome snippets!

Leave a Reply

Your email address will not be published. Required fields are marked *