OBO_FlashBox – LightBox in Flash (with added 3d)

Just in for the holidays – a new LightBox JS implementation for Flash (with a Flash 10 3d Twist).

Here’s a quickie example made with Flex┬ájust to see what I’m on about. The main drawback seems to be the new Flash Player 10 3d features tend to blur the edges of the picture’s frame. Not entirely sure why that is, but If anyone can explain, please let me know and I’ll do what I can to fix it up.

If interested, the script is below. It requires TweenLite and the Tweener equations for the animation (I like to mix and match), though you’re welcome to rewrite it for another tweening engine.

The main FlashBox class:

package com.onebyonedesign.extras {
	
	import caurina.transitions.Equations;
	import com.onebyonedesign.extras.OBO_PreloadAni;
	import flash.display.DisplayObjectContainer;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.net.URLRequest;
	import flash.text.AntiAliasType;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import gs.OverwriteManager;
	import gs.TweenLite;
	
	/**
	 * LightBox for Flash flash. Requires TweenLite for animation.
	 * @author Devon O.
	 */
	public class OBO_FlashBox extends Sprite {
		
		private var _instructions:TextField;
		private static const INSTRUCTIONS_FORMAT:TextFormat = new TextFormat("_sans", 12, 0x000000);
		
		private var _cover:Sprite;
		private var _frame:Sprite;
		private var _frameHolder:Sprite;
		
		private var _parent:DisplayObjectContainer;
		private var _path:String;
		
		private var _preloader:OBO_PreloadAni;
		
		private var _loader:Loader;
		
		private var _imageWidth:int;
		private var _imageHeight:int;
		
		private static const COVER_COLOR:uint = 0x000000;
		private static const FRAME_COLOR:uint = 0xFFFFFF;
		
		/**
		 * 
		 * @param	attachTo		DisplayObjectContainer that will "hold" the flashbox. Must be in the display list.
		 * @param	pathToImage		String that describes the path to the image to load.
		 */
		public function OBO_FlashBox(attachTo:DisplayObjectContainer, pathToImage:String):void {
			trace (pathToImage);
			_parent = attachTo;
			_path = pathToImage;
			mouseChildren = false;
			buttonMode = true;
			
			init();
		}
		
		private function init():void {
			OverwriteManager.init();
			initTextfield();
			initDisplay();
		}
		
		private function initTextfield():void {
			_instructions = new TextField();
			_instructions.defaultTextFormat = INSTRUCTIONS_FORMAT;
			_instructions.mouseEnabled = false;
			_instructions.selectable = false;
			_instructions.autoSize = TextFieldAutoSize.LEFT;
			_instructions.antiAliasType = AntiAliasType.ADVANCED;
			_instructions.text = "Click to close.";
		}
		
		private function initDisplay():void {
			_cover = drawCover(COVER_COLOR, .75, _parent.stage.stageWidth, _parent.stage.stageHeight);
			
			addChild(_cover);
			
			_frame = drawFrame(FRAME_COLOR, 1, 100, 100);
			
			_frameHolder = new Sprite();
			_frameHolder.x = _cover.width * .5;
			_frameHolder.y = _cover.height * .5;
			_frameHolder.addChild(_frame);
			_frameHolder.buttonMode = true;
			
			_preloader = new OBO_PreloadAni(10, 10, "Loading image...");
			_frame.addChild(_preloader);
			
			addEventListener(MouseEvent.CLICK, remove);
			_frameHolder.addEventListener(MouseEvent.CLICK, remove);
			
			_parent.addChild(this);
			_parent.addChild(_frameHolder);
			loadImage();
		}
		
		private function loadImage():void {
			_loader = new Loader();
			_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoad);
			_loader.load(new URLRequest(_path));
		}
		
		private function onImageLoad(event:Event):void {
			_frame.removeChild(_preloader);
			_imageHeight = Math.round(_loader.height + 40);
			_imageWidth = Math.round(_loader.width + 20);
			TweenLite.to(_frame, .3, { height:_imageHeight, ease:Equations.easeOutQuad } );
			TweenLite.to(_frame, .3, { width:_imageWidth, ease:Equations.easeOutQuad, delay:.3, onComplete:displayImage } );
		}
		
		private function displayImage():void {
			_loader.x = _loader.width * .5;
			_loader.y = -(_loader.height * .5 + 10);
			_loader.scaleX = -1;
			_loader.visible = false;
			_frameHolder.addChild(_loader);
			_instructions.x = 10 - _imageWidth * .5 + _instructions.textWidth;
			_instructions.y = _imageHeight * .5 - 20;
			_instructions.rotationY = 180;
			_instructions.visible = false;
			_frameHolder.addChild(_instructions);
			TweenLite.to(_frameHolder, .5, { rotationY:-180, onUpdate:checkRotation } );
		}
		
		private function checkRotation():void {
			if (_frameHolder.rotationY <= -90) {
				_loader.visible = true;
				_instructions.visible = true;
			}
		}
		
		private function drawCover(colour:uint, alpha:Number, w:Number, h:Number):Sprite {
			var s:Sprite = new Sprite();
			s.graphics.beginFill(colour, alpha);
			s.graphics.drawRect(0, 0, w, h);
			s.graphics.endFill();
			return s;
		}
		
		private function drawFrame(colour:uint, alpha:Number, w:Number, h:Number):Sprite {
			var s:Sprite = new Sprite();
			s.graphics.beginFill(colour, alpha);
			s.graphics.drawRect(-(w * .5), -(h * .5), w, h);
			s.graphics.endFill();
			return s;
		}
		
		private function remove(event:MouseEvent):void {
			_parent.removeChild(this);
			_parent.removeChild(_frameHolder);
		}
	}
}

And, while you can use any little graphic preloader you'd like, I used the one below:

package com.onebyonedesign.extras {
	
	import flash.display.Sprite;
	import flash.geom.ColorTransform;
	import flash.geom.Transform;
	import flash.text.AntiAliasType;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.events.Event;

	public class OBO_PreloadAni extends Sprite {
		
		private var _r:Number;
		private var _numItems:uint;

		private var _p:Sprite;
		private var _items:Array;
		
		private var _timer:Timer;
		private var _ct:ColorTransform;
		private var _currItem:int;
		
		private var _words:String;
		
		public function OBO_PreloadAni(radius:Number, numItems:uint, message:String = "") {
			
			_r = radius;
			_numItems = numItems;
			_p = new Sprite();
			_words = message;
			
			_items = new Array();
			_currItem = 0;
			
			init();
		}
		
		private function init():void {
			addChild(_p);
			createItems();
			addText();
			startAnimation();
			addEventListener(Event.REMOVED_FROM_STAGE, kill);
		}
		
		private function createItems():void {
			var angleIncrement:Number = 360 / _numItems;
			for (var i:int=0; i <= _numItems; i++) {
				var item:Sprite = createItem(i);
				var degrees:Number  = (i * angleIncrement);
				var rads:Number = (degrees * Math.PI) / 180;	
				
				//end X and Y values for the card
				var tx:Number = Math.cos(rads) * _r;
				var ty:Number = Math.sin(rads) * _r;
				
				// get distance clip is from center
				var dx:Number = tx;
				var dy:Number = ty;
				// Computing the arctangent to find angle
				// atan2 is used to find the direction from one point to another in 2-dimension
				// Steradians (square radians) can be converted to square degrees by multiplying 
				// by the square of the number of degrees in a radian = 57.2957795... degrees. 
				// It is used to describe two-dimensional angular spans in three-dimensional space,
				item.rotation = Math.atan2(dy, dx) * 57.2957795;
				item.x = tx;
				item.y = ty;
				_items.push(item);
				
				_p.addChild(item);
			}
		}
		
		private function addText():void {
			if (_words) {
				var tf:TextField = new TextField();
				tf.selectable = false;
				tf.autoSize = TextFieldAutoSize.LEFT;
				tf.mouseEnabled = false;
				tf.defaultTextFormat = new TextFormat("_sans", 11);
				tf.antiAliasType = AntiAliasType.ADVANCED;
				tf.text = _words;
				tf.y = Math.round(_p.height / 2 + 5);
				tf.x = Math.round(- tf.textWidth / 2);
				addChild(tf);
			}
		}
		
		private function startAnimation():void {
			_timer = new Timer(40);
			_timer.addEventListener(TimerEvent.TIMER, updateColor);
			_timer.start();
		}
		
		private function updateColor(te:TimerEvent):void {
			// change old to black
			var t:Sprite = _items[_currItem];
			_ct = new ColorTransform();
			t.transform.colorTransform = _ct;
			
			if (++_currItem > _items.length - 1) _currItem = 1;
			
			// change new to reddish
			t = _items[_currItem];
			_ct = new ColorTransform();
			_ct.redMultiplier = 1;
			_ct.redOffset = 0x88;
			_ct.greenMultiplier = 0;
			_ct.blueMultiplier = 0;
			t.transform.colorTransform = _ct;
			
		}
		
		private function createItem(id:Number):Sprite {
			var r:Sprite = new Sprite();
			r.graphics.beginFill(0x000000);
			r.graphics.drawRect(0, 0, 8, 3);
			r.graphics.endFill();
			return r;
		}
		
		
		public function destroy():void {
			_timer.stop();
			_timer.removeEventListener(TimerEvent.TIMER, updateColor);
			_ct = new ColorTransform();
			_items.forEach(setBlack);
			_currItem = _items.length - 1;
			_timer = new Timer (20, _items.length);
			_timer.addEventListener(TimerEvent.TIMER, removeItem);
			_timer.addEventListener(TimerEvent.TIMER_COMPLETE, onDone);
			_timer.start();
		}
		
		private function setBlack(e:Sprite, i:uint, a:Array):void {
			e.transform.colorTransform = _ct;
		}
		

		private function removeItem(te:TimerEvent):void {
			_p.removeChild(_items[_currItem--]);
		}
		
		private function onDone(te:TimerEvent):void {
			_timer.removeEventListener(TimerEvent.TIMER, removeItem);
			_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, onDone) 
			dispatchEvent(new Event("onPlaDone"));
		}
		
		private function kill(event:Event):void {
			removeEventListener(Event.REMOVED_FROM_STAGE, kill);
			_timer.stop();
			_timer.removeEventListener(TimerEvent.TIMER, updateColor);
			
			_p = null;
			_items = null;
			_timer = null;
			_ct = null;
		}
	}
}

Unfortunately, to get the OBO_FlashBox class to play nicely with Flex, you need to create a little Flex "bridge" that extends UIComponent like so:

package  {
	
	import flash.events.Event;
	import mx.core.UIComponent;
	import com.onebyonedesign.extras.OBO_FlashBox;
	
	/**
	 * little class to use OBO_FlashBox in Flex
	 * @author Devon O.
	 */
	public class FlexBox extends UIComponent {
		
		private var _pathToImage:String;
		
		public function FlexBox(pathToImage:String) {
			_pathToImage = pathToImage;
			if (stage) {
				init(null);
			} else {
				addEventListener(Event.ADDED_TO_STAGE, init)
			}
		}
		
		private function init(event:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, init)
			var _fb:OBO_FlashBox = new OBO_FlashBox(this, _pathToImage);
		}
	}
}

And finally, the mxml for the example shown:



	
		
	
		
			
				
					
					
					
					
					
					
					
					
					
					
					
					
				
			
		
	

Hope it may be useful. Enjoy...

Date: