Wordpress Flash Navigation

This page created March 19th 2009

Consider this beta, and not heavily tested. Just wanted to get it out there while I’m still working on it.

For a recent project a client wanted more control over the display of their Wordpress navigation. They wanted to be able to use any font. They also wanted a dynamic fold-able navigation that enables access to all categories without re-loading the page. This was a perfect project for me since I use Wordpress all over the mofo place. For example, you can see the navigation in use over there to the right. Also, as I’ve stated previously, I’m a big fan of leveraging the many publishing outlets I already use. So, I buit the nav in Flash connecting to Wordpress via XMLRPC using some classes from http://mattism.com/. This essentially allows me to use Wordpress as a content management system for Flash. You could obviously see how this could be applied to entire sites, like I have with my homepage. I’ve thought about building this a Wordpress plugin, and maybe down the road I will, but I doubt it as I’ll probably jump ship and start another project per usual. Besides, everyone knows you can’t make money writing Wordpress plugins.

How It Works:
Flash calls _rpc.call(”wp.getCategories”) to xmlrpc.php which returns an array of categories. I use this array to create a bunch of MovieClip()s. These clips add TextFields as children, are sorted and have events applied to them that enable the interactions. Two fonts reside in the library. One for the top node and one for the child and grandchildren nodes.

Features [the current goods]:

  • Dynamic – Works dynamically with Wordpress categories. You update your categories in Wordpress, they show properly in Flash
  • Sorting – Dynamically sorts top nodes. Controlled by Wordpress plugin my category order. For this to work I had to make a small addition to the Wordpress xmlrpc.php, located in your Wordpress root folder, to return the category term order. Added line 2776 – $struct['order'] = $cat->term_order;
  • Page recognition – Recognizes the page you’re on and dynamically opens navigation to the parent node of said page onload. I could have used XMLRPC tomake this call, I’m sure. However, I opted to pass in the page url via Flashvars and run a check to find a match. When a match is found the nav opens to it’s parent node.
  • Folding – Uses Grant Skinner GTween for interactions.
  • Multiple – Allows posts to live under multiple category nodes.

Wish List [the future goods]:

  • Multiline – Currently only supports single line category titles, so you’re limited in char length
  • Scrolling – Currently the length of your category list is limited to the length of the swf. I plan to add functions to enable scrolling of the list based on mouseY. This will free up the nav to be as long as you desire.
  • Post count – Do people really use this though? Probably not as its annoying.
  • Levels – Currently the nav only supports 3 levels. It would be nice to be infinite.
  • Build in the rest of Wordpress feature support for tag cloud, recent comments etc.

Total devel time: 2 days, or about 12 hours.

I’d love to see where other people take the code and what people build with it.

Source Code:
wpNavMain.as

/**
* wpNavMain by Chris Teso. Mar 19, 2009
* Visit www.christeso.com/blog for documentation, updates and more free code.
*
*
* Copyright (c) 2009 Chris Teso
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
**/
package
{
	import flash.display.*;

	public class wpNavMain extends Sprite
	{

		/*
		========================================================
		| Constructor
		========================================================
		*/

		public function wpNavMain ()
		{
			stage.align = StageAlign.TOP_LEFT;

			// add nav
			var wp:Wp = new Wp()
			addChild( wp )
		}
	}
}

Wp.as

/**
* Wp by Chris Teso. Mar 19, 2009
* Visit www.christeso.com/blog for documentation, updates and more free code.
*
*
* Copyright (c) 2009 Chris Teso
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
**/

package
{
	import com.gskinner.motion.*
	import com.mattism.http.xmlrpc.*;
	import com.mattism.http.xmlrpc.util.*;
	import flash.filters.*;
	import flash.media.*;
	import flash.ui.*;
	import flash.display.*;
	import flash.events.*;
	import flash.net.*;
	import flash.utils.*;
	import flash.geom.*;
	import flash.text.*;
	import fl.transitions.*;
	import fl.transitions.easing.*;
	import flash.system.SecurityPanel;
	import flash.system.Security;

	public class Wp extends Sprite
	{

		/*
		========================================================
		| Private Variables                         | Data Type
		========================================================
		*/
		private var _navArray:Array = new Array();
		private var _rpc:Connection;
		private var _topFont:Font = new topFont();
		private var _roadSign:Font = new roadSign();
		private var _topFmt:TextFormat = new TextFormat()
		private var _currUrl:String = ""
		private var _hideTimer:Timer

		private var _textYPad:int = 16
		private var _navSpeed:Number = .2
		/*
		========================================================
		| Constructor
		========================================================
		*/

		public function Wp ()
		{
			loadRpc()
		}

		private function checkPage()
		{
			// load in title
			var paramList:Object = this.root.loaderInfo.parameters;

			// set var to hold text
			var _currUrl:String = paramList["url"]

			//_currUrl = "http://www.christeso.com/index.php/category/portfolio/truth/truth-found/"

			// scan through array and open nav to that one
			for( var i=0;i<_navArray.length;i++ )
			{
				//trace( "_currUrl = "+_currUrl+" - "+_navArray[i].link )

				if( _navArray[i].link == _currUrl )
				{
					//trace( "found match!" )

					// open it
					if( _navArray[i].childMc != null )
					{
						showGrandChildren( MovieClip( _navArray[i].childMc ) )
					}
					if( _navArray[i].grandChildMc != null )
					{
						showGrandChildren( MovieClip( _navArray[i].grandChildMc.parent ) )
					}

				}
			}
		}

		private function showGrandChildren( mc:MovieClip )
		{

			//trace( "opening grandchildren" )

			// amount to go down
			var yLeap:Number;

			// total that will be open as long as the node is not already open
			var _totOpen:int = mc.numChildren-1

			//trace( "_totOpen = "+_totOpen )

			// ok we can prob do this in one big loop
			for( var i=0;i<_navArray.length;i++ )
			{
				// push down top nodes as long as they are below the top node you're on
				if( _navArray[i].mc != null )
				{
					if( _navArray[i].mc.origY > MovieClip(mc.parent).origY )
					{
						yLeap = _navArray[i].mc.origY + ( _totOpen*_textYPad )
						new GTween( _navArray[i].mc, _navSpeed, {y:yLeap} )
					}
					else
					{
						yLeap = _navArray[i].mc.origY
						new GTween( _navArray[i].mc, _navSpeed, {y:yLeap} )
					}
				}

				// push down child nodes as long as they are below the node you're on and are a child of the node you're on
				if( _navArray[i].childMc != null )
				{
					if( _navArray[i].childMc.parent == mc.parent )
					{
						if( _navArray[i].childMc.origY > mc.origY )
						{
							yLeap = _navArray[i].childMc.origY + ( _totOpen*_textYPad )
							new GTween( _navArray[i].childMc, _navSpeed, {y:yLeap} )
						}
						else
						{
							yLeap = _navArray[i].childMc.origY
							new GTween( _navArray[i].childMc, _navSpeed, {y:yLeap} )
						}
					}
				}

				// make grandchildren visible
				if( _navArray[i].grandChildMc != null )
				{
					if( _navArray[i].grandChildMc.parent == mc )
					{
						_navArray[i].grandChildMc.visible = true
						new GTween( _navArray[i].grandChildMc, _navSpeed, {alpha:1} )
					}
					else
					{
						new GTween( _navArray[i].grandChildMc, _navSpeed/2, {alpha:0, autoHide:true} )
					}
				}
			}
		}

		private function hideGrandChildren( e:Event )
		{
			// amount to go down
			var yLeap:Number;			

			// ok we can prob do this in one big loop
			for( var i=0;i<_navArray.length;i++ )
			{
				// push up top nodes
				if( _navArray[i].mc != null )
				{
					yLeap = _navArray[i].mc.origY
					new GTween( _navArray[i].mc, _navSpeed, {y:yLeap} )
				}

				// push up child nodes
				if( _navArray[i].childMc != null )
				{
					yLeap = _navArray[i].childMc.origY
					new GTween( _navArray[i].childMc, _navSpeed, {y:yLeap} )
				}

				// make grandchildren visible
				if( _navArray[i].grandChildMc != null )
				{
					new GTween( _navArray[i].grandChildMc, _navSpeed/2, {alpha:0, autoHide:true} )
				}				

			}
		}

		private function childClick( e:Event )
		{
			var i:int = e.currentTarget.indexNum
			var srcRequest:URLRequest = new URLRequest( _navArray[i].link );
			navigateToURL( srcRequest, "" );
		}

		private function childOver( e:Event )
		{
			trace( "mouse over "+MovieClip( e.currentTarget ).name )

			// remove parent events
			MovieClip( e.currentTarget ).parent.removeEventListener( MouseEvent.CLICK, childClick )

			// stop close timer
			_hideTimer.stop()

			// show grandkids
			showGrandChildren( MovieClip( e.currentTarget ) )

		}

		private function childOut( e:Event )
		{
			trace( "mouse out "+MovieClip( e.currentTarget ).name )

			// add parent events
			MovieClip( e.currentTarget ).parent.addEventListener( MouseEvent.CLICK, childClick )

			// start timer for close
			_hideTimer.start();
		}

		private function grandChildOver( e:Event )
		{

			trace( "mouse over "+MovieClip( e.currentTarget ).name )

			// remove parent events
			MovieClip( e.currentTarget ).parent.removeEventListener( MouseEvent.CLICK, childClick )

			// handle its events
			MovieClip( e.currentTarget ).addEventListener( MouseEvent.CLICK, childClick )			

		}

		private function grandChildOut( e:Event )
		{

			trace( "mouse out "+MovieClip( e.currentTarget ).name )

			// remove parent events
			MovieClip( e.currentTarget ).parent.addEventListener( MouseEvent.CLICK, childClick )

			// handle its events
			MovieClip( e.currentTarget ).removeEventListener( MouseEvent.CLICK, childClick )			

		}

		private function orderTop()
		{
			var yPos:int = 0;
			var topCount:int = 0

			// first we need to find all unique parents
			for( var i=0;i<_navArray.length;i++ )
			{
				//
				if( _navArray[i].mc != null )
				{
					// place the top
					_navArray[i].mc.y = yPos
					_navArray[i].mc.origY = yPos
					// calculate the next Y pos
					yPos = _navArray[i].mc.y + ( _navArray[i].mc.numChildren*_textYPad )+_textYPad

				}
			}
		}

		private function makeTopNode( i:int )
		{
			trace( "making top node "+_navArray[i].title+" id = "+_navArray[i].id+" parent id = "+_navArray[i].parentId )

			// create an mc holder
			var mc:MovieClip = new MovieClip()
			mc.name = _navArray[i].title
			// create a text field
			var t:TextField = new TextField()
			t.mouseEnabled = false
			t.name = "text"
			t.autoSize = TextFieldAutoSize.LEFT
			t.selectable = false
			t.embedFonts = true
			t.antiAliasType = flash.text.AntiAliasType.ADVANCED
			t.htmlText = _navArray[i].title.toUpperCase()
			_topFmt.size = 13;
			_topFmt.font = _roadSign.fontName;
			_topFmt.color = 0x666666
			//_topFmt.letterSpacing = .5
			_topFmt.kerning = true;
			t.setTextFormat( _topFmt )

			mc.addChild( t )
			addChild( mc )

			_navArray[i].mc = mc

			// events
			mc.indexNum = i
			mc.origY = mc.y
			mc.buttonMode = true
			mc.addEventListener( MouseEvent.CLICK, childClick )

			// now loop through this level and populate kids
			findChildren( _navArray[i].id, mc )
		}

		private function makeChild( i:int, par:MovieClip )
		{
			trace( "   making child "+_navArray[i].title+" id = "+_navArray[i].id+" parent id = "+_navArray[i].parentId )

			// create an mc holder
			var mc:MovieClip = new MovieClip()
			mc.name = _navArray[i].title
			// create a text field
			var t:TextField = new TextField()
			t.mouseEnabled = false
			t.name = "text"
			t.autoSize = TextFieldAutoSize.LEFT
			t.selectable = false
			t.embedFonts = true
			t.antiAliasType = flash.text.AntiAliasType.ADVANCED
			t.htmlText = _navArray[i].title.toUpperCase()
			_topFmt.size = 10;
			_topFmt.font = _topFont.fontName;
			_topFmt.color = 0xffffff
			_topFmt.letterSpacing = .5
			_topFmt.kerning = true;
			t.setTextFormat( _topFmt )

			_navArray[i].childMc = mc

			mc.y = par.numChildren*_textYPad

			mc.addChild( t )
			par.addChild( mc )

			// now loop through this level and populate kids
			findGrandChildren( _navArray[i].id, mc )

			// events
			mc.indexNum = i
			mc.origY = mc.y
			mc.buttonMode = true
			mc.addEventListener( MouseEvent.CLICK, childClick )
			mc.addEventListener( MouseEvent.MOUSE_OVER, childOver )
			mc.addEventListener( MouseEvent.MOUSE_OUT, childOut )

		}

		private function makeGrandChild( i:int, par:MovieClip )
		{
			trace( "   making grandchild "+_navArray[i].title+" id = "+_navArray[i].id+" parent id = "+_navArray[i].parentId )

			// create an mc holder
			var mc:MovieClip = new MovieClip()
			mc.name = _navArray[i].title
			// create a text field
			var t:TextField = new TextField()
			t.mouseEnabled = false
			t.name = "text"
			t.autoSize = TextFieldAutoSize.LEFT
			t.selectable = false
			t.embedFonts = true
			t.antiAliasType = flash.text.AntiAliasType.ADVANCED
			t.htmlText = _navArray[i].title.toUpperCase()
			_topFmt.size = 10;
			_topFmt.font = _topFont.fontName;
			_topFmt.color = 0x999999
			_topFmt.letterSpacing = 0
			_topFmt.kerning = true;
			t.setTextFormat( _topFmt )

			_navArray[i].grandChildMc = mc

			mc.alpha = 0
			mc.visible = false;

			mc.x = 5
			mc.y = par.numChildren*_textYPad

			mc.addChild( t )
			par.addChild( mc )

			// events
			mc.indexNum = i
			mc.buttonMode = true
			//mc.mouseChildren = false
			//mc.addEventListener( MouseEvent.CLICK, childClick )
			mc.addEventListener( MouseEvent.MOUSE_OVER, grandChildOver )
			mc.addEventListener( MouseEvent.MOUSE_OUT, grandChildOut )

		}

		private function findGrandChildren( id:int, par:MovieClip )
		{
			for( var i=0;i<_navArray.length;i++ )
			{
				// hunt for children of the parent
				if( _navArray[i].parentId == id )
				{
					//trace( "-- found child "+_navArray[i].title+" | id = "+_navArray[i].id+" | parent = "+_navArray[i].parentId )
					// found one, now make a grandchild
					makeGrandChild( i, par )
				}
			}

		}

		private function findChildren( id:int, par:MovieClip )
		{
			for( var i=0;i<_navArray.length;i++ )
			{
				// hunt for children of the parent
				if( _navArray[i].parentId == id )
				{
					//trace( "-- found child "+_navArray[i].title+" | id = "+_navArray[i].id+" | parent = "+_navArray[i].parentId )
					// found one, now make a child
					makeChild( i, par )
				}
			}

		}

		private function findParents()
		{

			// first we need to find all unique parents
			for( var i=0;i<_navArray.length;i++ )
			{
				// analyze the node... is it a top node?
				if( _navArray[i].parentId == 0 && _navArray[i].title != "Uncategorized" )
				{
					//trace( "-- found parent "+_navArray[i].title )
					// create a top node container
					makeTopNode( i )
				}

			}
		}

		private function loadRpc()
		{
			_rpc = new ConnectionImpl('blogaddress/xmlrpc.php');
			_rpc.addEventListener(Event.COMPLETE, rpcCompleteHandler);
			_rpc.addEventListener(ErrorEvent.ERROR, rpcErrorHandler);
			_rpc.addParam(0, XMLRPCDataTypes.INT);  // Blog Id
			_rpc.addParam("blogusername", XMLRPCDataTypes.STRING); // Username
			_rpc.addParam("blogpassword", XMLRPCDataTypes.STRING); // Password

			getCategories()
		}

		private function getCategories():void
		{
			_rpc.call("wp.getCategories")
		}

		private function rpcCompleteHandler(evt:Event):void
		{
			var response:Object = _rpc.getResponse();
			for(var i:String in response)
			{
				// need to first grab all the top nav categories
				trace( response[i].categoryName )
				trace( response[i].htmlUrl )
				trace( response[i].parentId )
				trace( response[i].categoryId )
				trace( response[i].order )
				trace( "------------------" )
				_navArray.push( { title:response[i].categoryName, link:response[i].htmlUrl, id:response[i].categoryId, parentId:response[i].parentId, order:response[i].order } )
			}

			// Sort the array according to your category order setting in WP
			_navArray.sortOn( "order", Array.NUMERIC )

			// setup close timer
			_hideTimer = new Timer( 500, 1 );
			_hideTimer.addEventListener( TimerEvent.TIMER, hideGrandChildren );

			findParents()
			orderTop()
			checkPage()
		}

		private function rpcErrorHandler(evt:ErrorEvent):void
		{
			var fault:MethodFault = _rpc.getFault();
		}

	}
}

Download CS4 AS3 FLA and Classes

Enjoy.

Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Print

BIT-101 Particle class in AS3

This page created January 12th 2009

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

When I lived in AS2land I was extremely fond of Keith Peter’s Particle class. It was so easy to implement and get things moving. It helped me build sweet node movement in Call and Response and mock up various other interfaces requiring physics engines. His class was simple but performed many cool particle animations with minimal effort and thus low cpu intensity. Moving to AS3 I’ve tried various other particle classes such as Flint . I really dig Flint but it’s a tad bulky for rapid prototyping or those situations where you don’t need a heavy class. Therefore, I’ve rewritten Keiths partcle class ported from AS2 to AS3. I saw that Eric had tried to rewrite it but had some errors. Enjoy, and thanks Keith.

Source: particleBIT101.zip

Permalink: http://www.christeso.com/index.php/lab/bit-101-particle-class-in-as3

Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Print

AS3 Polar Coordinates and Radians

This page created January 9th 2009

Many times I’ve set up interfaces where I need to place different objects equidistant around a central object. The solution to this problem is to first calculate the angle of each object by converting Radians to Degrees. This can be expressed by the following formula

1 \mbox{ rad} = 1 \cdot \frac {180^\circ} {\pi} \approx 57.2958^\circ

So, you simply need to loop through your collection of objects and assign each a different angle. After that you plug that angle into a new Polar Point.

for(var i=0;i<array.length;i++)
{
	var angle:Number = i*( 180/Math.PI )
	var coord:Point = Point.polar( circumference, angle )
}

Here’s the complete source: radians.zip

package
{
	import flash.ui.*;
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;

	public class Main extends Sprite
	{

		/*
		========================================================
		| Private Variables                         | Data Type
		========================================================
		*/

		private var array:Array = new Array()
		private var circumference:int;

		/*
		========================================================
		| Constructor
		========================================================
		*/

		public function Main ()
		{
			stage.align = StageAlign.TOP_LEFT;

			// make some balls
			addParticle( 100 )

			menu.txtParticles.text = 'Particles: 100';

			stage.addEventListener( Event.ENTER_FRAME, runParticle )

			menu.slideCircumference.addEventListener( Event.CHANGE, changeCircumference );
			menu.particles.addEventListener( Event.CHANGE, changeParticles );

		}

		private function addParticle( num )
		{
			stage.removeEventListener( Event.ENTER_FRAME, runParticle )

			var tot:Number = array.length

			// kill mc's
			for( var t=0;t<tot;t++ )
			{
				removeChild( array[t].mc );
			}

			// kill array
			for( var r=0;r<tot;r++ )
			{
				array.shift();
			}

			trace( 'removed particles '+array.length )

			for( var d=0;d<num;d++ )
			{
				var c:MovieClip = new MovieClip()
				c.name = "particle"
				c.graphics.beginFill( 0xffffff, 1 )
				c.graphics.drawCircle( 0, 0, 1 )
				c.graphics.endFill()
				addChild( c )

				array.push( { mc:c } )
			}

			trace( 'added particles '+array.length )

			changeCirc( circumference )

			stage.addEventListener( Event.ENTER_FRAME, runParticle )
		}

		private function runParticle( e:Event )
		{
			//trace( 'running' )
			graphics.clear()
			graphics.lineStyle( 1, 0xffffff, .1 )

			for(var i=0;i<array.length;i++)
			{
				graphics.moveTo( stage.stageWidth/2, stage.stageHeight/2 )
				graphics.lineTo( array[i].mc.x, array[i].mc.y )
			}

		}

		private function changeCirc( c:int )
		{
			for(var i=0;i<array.length;i++)
			{
				var angle:Number = i*( 180/Math.PI )
				var coord:Point = Point.polar( c, angle )

				array[i].mc.x = ( stage.stageWidth/2 ) + coord.x
				array[i].mc.y = ( stage.stageHeight/2 ) + coord.y
			}

			circumference = c
		}

		private function changeCircumference( e:Event ):void
		{
			menu.txtCircumference.text = 'Circumference: ' + e.target.value;
			changeCirc( e.target.value )
		}

		private function changeParticles( e:Event ):void
		{
			menu.txtParticles.text = 'Particles: ' + e.target.value;
			addParticle( e.target.value )
		}
	}
}

Permalink: http://www.christeso.com/index.php/lab/as3-polar-coordinates-and-radians

Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Print

AS3 Drop Down Menu Class

This page created November 28th 2008

I briefly Googled for a drop down class to no avail. I say briefly as I only went one page deep. I’m sure there are others out there, but I instead got impatient as usual and just wrote my own. I thought I’d share it for other impatient people’s benefit. Without further ado here’s the AS3 Drop Down Class code. It’s a work in progress and most likely will be updated when I give it any more thought.

You can see the drop down in use on my homepage.

Edit [ 12.16.08 ] : added directional code.


//usage
// array for drop
var dropOtherArray:Array = new Array()
dropOtherArray.push( {title:"iWork", name:"folio"} )
dropOtherArray.push( {title:"iExperiment", name:"lab"} )
dropOtherArray.push( {title:"iWrite", name:"blog"} )
dropOtherArray.push( {title:"iPhotograph", name:"photo"} )
dropOtherArray.push( {title:"iFlickr", name:"flickr"} )
dropOtherArray.push( {title:"iRecord", name:"vimeo"} )
dropOtherArray.push( {title:"contactMe", name:"contact"} )

fmat.color = 0xffffff
fmat.font = font.fontName
fmat.size = 11

addChild( _dropOther = new DropDown( 180, 25, "iLiveElsewhere:", fmat, 0x000033, dropOtherArray, "down", other ) )

package com.teso.ui
{
	import com.gskinner.motion.*
	import flash.display.*;
	import flash.events.*;
	import flash.net.*;
	import flash.utils.*;
	import flash.text.*;
	import fl.transitions.*;
	import fl.transitions.easing.*;

	public class DropDown extends Sprite
	{
		private var _items:Array = new Array()
		private var _overC:uint;
		private var _backC:uint;
		private var _w:Number;
		private var _h:Number;
		private var _timer:Timer;
		private var _open:Boolean = false;
		private var _defaultText:TextField;
		private var _title:String;
		private var _direction:String;
		private var _fmt:TextFormat;

		public function DropDown( w:Number, h:Number, title:String, fmt:TextFormat, colorBack:uint, itemArray:Array, direction:String, callback )
		{
			// timer
			_timer = new Timer( 300 );
			_timer.addEventListener( TimerEvent.TIMER, closeDrop )

			// vars
			_w = w
			_h = h
			_backC = colorBack
			_items = itemArray
			_title = title
			_direction = direction
			_fmt = fmt

			// create a back for the holder
			var holder:MovieClip = new MovieClip();
			holder.name = "holder"
			holder.graphics.beginFill( _backC, 1 );
			holder.graphics.drawRoundRect( 0, 0, _w, _h, 2, 2 )
			holder.graphics.endFill()

			// add the drop
			addChild( holder )

			// set listeners
			holder.buttonMode = true;
			holder.addEventListener( MouseEvent.MOUSE_OVER, openDrop )
			holder.addEventListener( MouseEvent.MOUSE_OVER, cancelClose )
			holder.addEventListener( MouseEvent.MOUSE_OUT, startClose )

			// create a text field
			var t:TextField = new TextField()
			t.name = "holderText"
			t.selectable = false;
			t.autoSize = TextFieldAutoSize.LEFT;
			t.htmlText = title
			t.setTextFormat( fmt )
			t.y = ( holder.height/2 ) - ( t.height/2 )

			_defaultText = t

			// add the text
			holder.addChild( t )

			// create children
			for( var i=0; i<_items.length; i++ )
			{
				// create a back
				var back:MovieClip = new MovieClip()
				back.name = _items[i].name;
				back.graphics.beginFill( _backC, 1 )
				back.graphics.drawRoundRect( 0, 0, _w, _h, 10, 10 )
				back.graphics.endFill()

				// create a text field
				t = new TextField();
				t.name = "t"
				t.x = 5
				t.selectable = false;
				t.autoSize = TextFieldAutoSize.LEFT;
				t.htmlText = _items[i].title;
				t.setTextFormat( fmt )
				t.y = ( back.height/2 ) - ( t.height/2 )

				if( _items[i].d )
				{
					_defaultText.htmlText = _title+" "+_items[i].title
					_defaultText.setTextFormat( _fmt )
				}

				// make them invisible for now
				back.visible = false;

				// set a listener
				back.buttonMode = true;
				back.addEventListener( MouseEvent.CLICK, closeDrop )
				back.addEventListener( MouseEvent.CLICK, setDefaultText )
				back.addEventListener( MouseEvent.CLICK, callback )
				back.addEventListener( MouseEvent.MOUSE_OUT, startClose )
				back.addEventListener( MouseEvent.MOUSE_OVER, cancelClose )

				// add the text
				back.addChild( t )

				// add it to the holder
				addChildAt( back, 0 )

				_items[i].mc = back
			}
		}

		private function openDrop( e:Event )
		{
			if( !_open )
			{

				for( var i=0; i<_items.length; i++ )
				{
					// set a var
					var item:DisplayObject = _items[i].mc

					// set the items alpha to zero
					item.alpha = 0;

					// make the item visible
					item.visible = true

					// fade it in
					var tweenIn:GTween;

					if( _direction == "down" )
					{
						tweenIn = new GTween( item, .3, {y:_h + ( _h * i ),  alpha:1} )
					}
					else
					{
						tweenIn = new GTween( item, .3, {y:-_h - ( _h * i ),  alpha:1} )
					}
					tweenIn.ease = Regular.easeOut
				}
			}
			_open = true;

		}
		private function cancelClose( e:Event )
		{
			if( e.currentTarget.name != "holder" )
			{
				e.currentTarget.alpha = .8
			}
			_timer.stop()
		}
		private function startClose( e:Event )
		{
			e.currentTarget.alpha = 1
			_timer.start()
		}
		private function setDefaultText( e:Event )
		{
			_defaultText.htmlText = _title+" "+e.currentTarget.getChildByName( "t" ).text
			_defaultText.setTextFormat( _fmt )
		}
		private function closeDrop( e:Event )
		{
			closeIt()
		}
		private function closeIt()
		{
			if( _open )
			{
				for( var i=0; i<_items.length; i++ )
				{
					// set a var
					var item:DisplayObject = _items[i].mc

					// make the item visible
					item.visible = true

					// fade it in
					var tweenOut:GTween = new GTween( item, .3, {y:0, alpha:0}, {completeListener:done, data:item} )
					tweenOut.ease = Regular.easeOut
				}
			}

			_timer.stop()

			_open = false;
		}
		private function done( e:Event )
		{
			e.currentTarget.data.visible = false

		}

	}
}
Permalink:
http://www.christeso.com/index.php/lab/as3-drop-down-menu-classas3-drop-down-menu-class/
Share and Enjoy:
  • Twitter
  • Facebook
  • Digg
  • del.icio.us
  • Google Bookmarks
  • Print