In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Transition Sketcher

author Jesse Freeman aka @theFlashBum | http://jessefreeman.com

This is the Doc Class to run my SketchArea. This class adds keyboard support
to help control features of the SketchArea. Here is a list of all the keys
I have set up.

Keyboard Short Cuts

Space Bar - flips between src a and src b. Source A is always the bottom
layer and Source B is the paint layer.

r - Redraw last animation.

c - Clear SketchArea

s - Quick save. The SketchArea will take the last set of recorded points
along with what mode it is in and save it to a number key. For example if
nothing has been saved and you hit save it will register at key 1. Next
save will be key 2, etc.

1 - 0 Plays back a saved animation.

d - Activates the draw tool. Once in draw mode you will see a representation
of the brush that follows the mouse. When you are done you can hit d to
exit draw mode. Hitting replay automatically exits you from draw mode.

+ - Increases the size of the brush.

- - Decreases the size of the brush.

The
/**
 * Copyright FlashBum ( http://wonderfl.net/user/FlashBum )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gBuu
 */

package {
	import flash.text.TextFieldAutoSize;
	import flash.text.TextField;
	import flash.display.Shape;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;

	/**
	 * author Jesse Freeman aka @theFlashBum | http://jessefreeman.com
	 * 
	 * This is the Doc Class to run my SketchArea. This class adds keyboard support
	 * to help control features of the SketchArea. Here is a list of all the keys
	 * I have set up.
	 * 
	 * Keyboard Short Cuts
	 * 
	 * Space Bar - flips between src a and src b. Source A is always the bottom
	 * layer and Source B is the paint layer.
	 * 
	 * r - Redraw last animation.
	 * 
	 * c - Clear SketchArea
	 * 
	 * s - Quick save. The SketchArea will take the last set of recorded points
	 * along with what mode it is in and save it to a number key. For example if
	 * nothing has been saved and you hit save it will register at key 1. Next
	 * save will be key 2, etc.
	 * 
	 * 1 - 0 Plays back a saved animation.
	 * 
	 * d - Activates the draw tool. Once in draw mode you will see a representation
	 * of the brush that follows the mouse. When you are done you can hit d to
	 * exit draw mode. Hitting replay automatically exits you from draw mode.
	 * 
	 * + - Increases the size of the brush.
	 * 
	 * - - Decreases the size of the brush.
	 * 
	 * The main goal of this demo is to illustrate how custom wipe on/off transitions
	 * can be built dynamically in flash based on user generated array of points.
	 * 
	 * Important - this is a proof of concept, there is still a lot of work and 
	 * optimizations I need to do to get this clas production ready.
	 * 
	 */
	public class FlashTest extends Sprite {

		protected var sketchArea : SketchArea;
		protected var loader : Loader;
		private var label : TextField;

		public function FlashTest() {
			
			configureStage();
			init();
		}

		protected function configureStage() : void {
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
		}

		/**
		 * 
		 * Create a loader to get a background image.
		 * 
		 */
		protected function init() : void {
			loader = new Loader();
			loader.load(new URLRequest("http://demos.flashartofwar.com/RandomImageComposite/images/skin3/photo.jpg"), new LoaderContext(true));
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoad);
		}

		/**
		 * 
		 * Once image is loaded we can create our SketchArea class. Here we are
		 * passing in a bitmap of the image we just loaded (will go into sourceA)
		 * then create a white layer and pass it in to represent sourceB (our 
		 * paint layer/color).
		 * 
		 */
		protected function onImageLoad(event : Event) : void {
			var bmd : BitmapData = Bitmap(loader.content).bitmapData.clone();
			var sourceA : Bitmap = new Bitmap(bmd); // This is the background layer

			var sourceB : Shape = new Shape();
			sourceB.graphics.beginFill(0xffffff);
			sourceB.graphics.drawRect(0, 0, sourceA.width, sourceA.height);
			sourceB.graphics.endFill();
			
			sketchArea = new SketchArea(loader.width + loader.x, loader.height + loader.y, sourceA, sourceB);
			addChild(sketchArea);
			
			loader = null;

			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
			
			label = new TextField();
			label.autoSize = TextFieldAutoSize.LEFT;
			label.multiline = true;
			label.wordWrap = true;
			label.width = 400;
			label.htmlText = "<b>Keyboard Short Cuts</b>: <br><b>Space Bar</b> - flips between src a and src b <br> <b>R</b> - Redraw last animation <br> <b>C</b> - Clear SketchArea <br> <b>S</b> - Quick save | <b>1</b> - <b>0</b> Plays back a saved animation <br> <b>D</b> - Activates the draw tool | <b>+</b>/<b>-</b> - Increases/Decrease brush size";
			label.y = sketchArea.height;
			
			addChild(label);
			
			sketchArea.toggleDrawMode();
		}

		protected function keyDownHandler(event : KeyboardEvent) : void {
			switch(event.keyCode) {
				case(32):
					trace("Spacebar");
					sketchArea.toggleDrawMode();
					break;
				case(82):
					trace("r");
					sketchArea.redraw();
					break;
				case(67):
					trace("c");
					sketchArea.clear();
					break;
				case(83):
					sketchArea.quickSave();
					break;
				case(49): 
				case(50): 
				case(51): 
				case(52): 
				case(53): 
				case(54): 
				case(55): 
				case(56): 
				case(57):
					var saveID : Number = event.keyCode - 49;
					sketchArea.quickPlayBack(saveID);
					break;
				case(68):
					sketchArea.activateDraw();
					break;
				case(187):
					sketchArea.increaseThickness();
					break;
				case(189):
					sketchArea.decreaseThickness();
					break; 
			}
           
			//trace("keyDownHandler: " + event.keyCode);
		}
	}
}

import flash.geom.Rectangle;
import flash.geom.Matrix;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.utils.Dictionary;
import flash.utils.Timer;

/**
 * @author jessefreeman
 */
class SketchArea extends Sprite {

	private static const SOURCE_A : String = "sourceA";
	private static const SOURCE_B : String = "sourceB";
	private static const BORDER : String = "border";
	private static const SKETCH_LAYER : String = "sketchArea";
	private static const BRUSH_PREVIEW : String = "brushPreview";
	protected var _width : Number;
	protected var _height : Number;
	protected var sketchCoords : Array = new Array;
	protected var currentVectorID : Number = 0;
	protected var currentPoint : Object;
	protected var thickness : Number = 150 ;
	protected var photoContainer : Sprite;
	protected var lineColor : uint = 0xffffff;
	protected var redrawSpeed : Number = 10;
	protected var redrawTimer : Timer;
	protected var eraseMode : Boolean = false;
	protected var savedSketches : Array = new Array();
	protected var active : Boolean;
	protected var display : Bitmap;
	protected var layers : Dictionary = new Dictionary(true);
	protected var brushPreviewMatrix : Matrix = new Matrix();
	protected var sampleRect : Rectangle;
	protected var samplePoint : Point;
	protected var sourceBitmapData : BitmapData;
	protected var sketchBitmapData : BitmapData;

	/**
	 * The SketchArea represents a canvass where a use can draw on, play back
	 * the drawing's animation, and save it temporarily.
	 * 
	 * At it's core the SketchArea has 2 layers, sourceA (the background) and
	 * sourceB (the paint fill).
	 * 
	 * My swapping sourceA and sourceB you can easily create reveal and remove
	 * animations for images.
	 * 
	 * @param width - width of the canvas
	 * @param height - height of the canvas
	 * @param sourceA - represents the background image used by the canvas
	 * @param sourceB - represents the fill image for the brush
	 * 
	 */
	public function SketchArea(width : Number = 600, height : Number = 400, sourceA : DisplayObject = null, sourceB : DisplayObject = null) {
		_width = width;
		_height = height;
			
		if(sourceA)
				this.sourceA = sourceA;
			
		if(sourceB)
				this.sourceB = sourceB;	
			
		init();
	}

	public function get sourceA() : DisplayObject {
		return layers[SOURCE_A];
	}

	/**
	 * Sets the background image for the SketchArea
	 * @param source - DisplayObject to be used as sourceA.
	 */
	public function set sourceA(source : DisplayObject) : void {
		layers[SOURCE_A] = source;
	}

	public function get sourceB() : DisplayObject {
		return layers[SOURCE_B];
	}

	/**
	 * Sets the fill for the brush in the SketchArea
	 * @param source - DisplayObject to be used as sourceB.
	 */
	public function set sourceB(source : DisplayObject) : void {
		layers[SOURCE_B] = source;
	}

	/**
	 * This makes the line thickness of the brush smaller. Decreases by 10px
	 * as long as the thickness is greater then 0.
	 */
	public function decreaseThickness() : void {
		thickness -= 10;
		if(thickness < 0 ) thickness = 0;
		drawBrushPreview(thickness);
	}

	/**
	 * This makes the line thickness of the brush larger. Increase by 10px
	 * with a 300 px max.
	 */
	public function increaseThickness() : void {
		thickness += 10;
		if(thickness > 300 ) thickness = 300;			
		drawBrushPreview(thickness);
	}

	/**
	 * Turns on the Drawing listeners so a use can begin recording their 
	 * sketch.
	 */
	public function activateDraw() : void {
		active = !active;
			
		if(active) {
			addMousePressEventListeners();
		} else {
			removeMousePressEventListeners();
		}
			
		toggleBrushPreview();
		compositeImage();
	}

	/**
	 * Drawing mode represents what source is used as the background. This
	 * method simply swaps out the instance of source a with the instance
	 * of source b.
	 * 
	 * This lets gives you the effect of revialing or removing an image.
	 */
	public function toggleDrawMode() : void {
			
		var aSrc : DisplayObject = layers[SOURCE_A];
		var bSrc : DisplayObject = layers[SOURCE_B];
			
		layers[SOURCE_A] = bSrc;
		layers[SOURCE_B] = aSrc;
			
		clear();
			
		eraseMode = !eraseMode;
	}

	/**
	 * Clears the SketchArea by removing any graphics drawn as well as resetting
	 * the sketch coordinates array.
	 */
	public function clear() : void {
		clearGraphics();
		sketchCoords = new Array;
		compositeImage();
	}

	/**
	 * This simply clears the graphics layer of the SketchArea.
	 */
	public function clearGraphics() : void {
		layers[SKETCH_LAYER].graphics.clear();
		compositeImage();
	}

	/**
	 * This will playback the currently active sketch ie what ever the last
	 * sketch that was created.
	 */
	public function redraw() : void {
		if(active)
				activateDraw();
			
		if(redrawTimer && redrawTimer.running)
				redrawTimer.stop();
		clearGraphics();

		var total : Number = sketchCoords.length - 1;
		redrawTimer = new Timer(redrawSpeed, total);
		redrawTimer.addEventListener(TimerEvent.TIMER, onRedrawTick);
                        
		currentVectorID = 0;
		var startPoint : Object = sketchCoords[ currentVectorID ];
		moveLine(startPoint.x, startPoint.y);
		redrawTimer.start();
	}

	/**
	 * This saves out the mode and sketchCoords into an object then pushes
	 * it into a savedSketches array. The id of the newly created object can
	 * be used with qucikPlayBack to view the results.
	 */
	public function quickSave() : void {
		var savedState : Object = new Object();
		savedState.eraseMode = eraseMode;
		savedState.sketchCoords = sketchCoords.concat();
			
		savedSketches.push(savedState);
	}

	/**
	 * Quick playback takes a saved sketch id (corresponds to an index in the
	 * savedSketces array and redraws the sketch.
	 * @param id - id repressing a valid index of the saved coords array.
	 */
	public function quickPlayBack(id : Number) : void {
		if(id < savedSketches.length) {
			var state : Object = savedSketches[id];
			if(state.eraseMode != eraseMode)
					toggleDrawMode();
			sketchCoords = state.sketchCoords.concat();
			redraw();
		}
	}

	protected function toggleBrushPreview() : void {
		if(active) {
			drawBrushPreview(thickness);			
		} else {
			layers[BRUSH_PREVIEW].graphics.clear();
		}
	}

	protected function createBorder() : void {
		var border : Shape = new Shape();
		border.graphics.lineStyle(1, 0x000000, .3);
			
		border.graphics.drawRect(0, 0, _width - 1, _height - 1);
		border.graphics.endFill();
			
		layers[BORDER] = border;
	}

	protected function init() : void {
		display = new Bitmap();
		display.bitmapData = new BitmapData(_width, _height, true, 0xffffff);
		addChild(display);
			
		layers[SKETCH_LAYER] = new Shape();
			
		if(!layers[SOURCE_B]) {
			var matt : Shape = new Shape();
			matt.graphics.beginFill(0xff0000);
			matt.graphics.drawRect(0, 0, _width, _height);
			matt.graphics.endFill();
			layers[SOURCE_B] = matt;
		}

		//			
		layers[BRUSH_PREVIEW] = new Shape();
		createBorder();
		//			
		//createMouseBrush( thickness );
		compositeImage();
		toggleDrawMode();
	}

	private function onEnterFrame(event : Event) : void {
		compositeImage();
	}

	protected function drawBrushPreview(size : Number) : void {
		layers[BRUSH_PREVIEW].graphics.clear();
		layers[BRUSH_PREVIEW].graphics.lineStyle(1, 0x000000, .3);
			
		var d : Number = size * .5;
			
		layers[BRUSH_PREVIEW].graphics.drawCircle(0, 0, d);
		layers[BRUSH_PREVIEW].graphics.endFill();
	}

	protected function addMousePressEventListeners() : void {
		addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
		addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		addEventListener(Event.ENTER_FRAME, onEnterFrame);
	}

	protected function removeMousePressEventListeners() : void {
		removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
		removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
		removeEventListener(Event.ENTER_FRAME, onEnterFrame);
	}

	protected function onMouseUp(event : MouseEvent) : void {
		removeDrawListeners();
		sketchCoords.push({x:-1, y:-1});
		layers[SKETCH_LAYER].graphics.endFill();
	}

	protected function onMouseDown(event : MouseEvent) : void {
		layers[SKETCH_LAYER].graphics.moveTo(mouseX, mouseY);
		layers[SKETCH_LAYER].graphics.lineStyle(thickness, lineColor, 1);
                        
		addDrawListeners();
	}

	protected function addDrawListeners() : void {
		addEventListener(MouseEvent.MOUSE_MOVE, onDraw);
	}

	protected function removeDrawListeners() : void {
		removeEventListener(MouseEvent.MOUSE_MOVE, onDraw);
	}

	protected function onDraw(event : MouseEvent) : void {
		currentPoint = {x: mouseX, y: mouseY, thickness: thickness };
                        
		sketchCoords.push(currentPoint);
		draw(currentPoint);
	}

	protected function draw(point : Object) : void {
		layers[SKETCH_LAYER].graphics.lineTo(point.x, point.y);
	}

	protected function drawArea(width : Number, height : Number, alpha : Number = 1) : void {
		graphics.clear();
		graphics.beginFill(0xffffff, alpha);
		graphics.drawRect(0, 0, width, height);
		graphics.endFill();
	}

	protected function onRedrawTick(event : TimerEvent = null) : void {
		var currentPoint : Object = sketchCoords[ currentVectorID ];
                        
                        
		var nextPoint : Object = (currentVectorID == sketchCoords.length) ? {x:-1, y:-1} : sketchCoords[ currentVectorID + 1 ];
		var ink : Number = 1;
            
		if((currentPoint.x == -1) && (currentPoint.y == -1)) {
			moveLine(nextPoint.x, nextPoint.y);
		} else {
			layers[SKETCH_LAYER].graphics.lineStyle(thickness, lineColor, ink);
			drawLine(currentPoint.x, currentPoint.y);
		}
                        
		if(currentVectorID > sketchCoords.length) {
			redrawTimer.stop();
			layers[SKETCH_LAYER].graphics.endFill();
		} else {
			currentVectorID++;
		}
			
		compositeImage();     
	}

	protected function moveLine(x : Number, y : Number) : void {
		layers[SKETCH_LAYER].graphics.moveTo(x, y);
	}

	protected function drawLine(x : Number, y : Number) : void {
		layers[SKETCH_LAYER].graphics.lineTo(x, y);
	}

	protected function compositeImage() : void {
		// Create Bitmap data for final image
		var bmd : BitmapData = display.bitmapData;
			
		bmd.draw(layers[SOURCE_A]);
			
		brushPreviewMatrix = new Matrix();
		brushPreviewMatrix.translate(mouseX, mouseY);
			
		sampleRect = new Rectangle(0, 0, _width, _height);
		samplePoint = new Point(0, 0);
			
		sourceBitmapData = new BitmapData(_width, _height, true, 0x000000);
		sourceBitmapData.draw(layers[SOURCE_B]);
			
		sketchBitmapData = new BitmapData(_width, _height, true, 0x000000);
		sketchBitmapData.draw(layers[SKETCH_LAYER]);
			
		bmd.copyPixels(sourceBitmapData, sampleRect, samplePoint, sketchBitmapData, null, true);
			
		bmd.draw(layers[BORDER]);
			
		bmd.draw(layers[BRUSH_PREVIEW], brushPreviewMatrix);
	}
}