Articles

AS3 Drawing Utility Class

Trying to work as much in pure AS3 as I can on projects, I’m often dynamically drawing simple shapes like squares, rectangles and circles. Rather than re-writing the drawing methods each time I have a few stored in a DrawingUtil class, which I just include in my Libraries folder – along with a bunch of other utilities I reuse over and over (I’ll post more of these utils in time). Anyhow I thought I’d share this DrawingUtil class with the world in the hope it may make some of your lives easier. If you want to just scroll straight down to the script (download link is at the bottom) go for it. Else I’ll explain a little some of it first…

There’s 3 main methods in the class drawRectSprite which will return a square/rectangle shaped Sprite (with optional rounded corners via the ellipse parameter), drawCircSprite which will return a circle shaped Sprite and drawTriSprite which will return a simple triangle shaped Sprite. With all 3 methods there are optional parameters for stroke and fill properties as Objects.

For the fill Object (null by default), you can create a gradient fill by setting fill.colour as an Array of two hex values (I’ve only written it to be a simple gradient between 2 colours). If the fill.colour value is an Array with only one item or fill.colour itself is a hex value the shape will be filled with that one solid colour. Note that if fill or fill.colour is null the default fill colour of 0x00FFFF will be used. All the options that are accepted for the fill Object are:

  • colour - A single hex value (eg 0xFFFFFF) or an Array containing one hex value item for a solid fill. Or an Array containing 2 hex values for a gradient fill.
  • alpha – For solid fills this can be a Number value, or an Array value where alpha[0] is a Number. For gradient fills, an Array of two Number items will match alpha[0] to colour[0] and alpha[1] to colour[1]. If the fill is a gradient and only one alpha is set, either as a Number of Array item that single value will be used for both gradient colours. Default value is 1.

The following additional properties are available in the fill Object for gradients:

  • gradientType - A String value of “linear” or “radial” (See GradientType). Default value is GradientType.LINEAR
  • spreadMethod - A String value of “pad”, “repeat” or “reflect” (See SpreadMethod). Default value is SpreadMethod.PAD
  • ratios – An Array with 2 Number items containing the gradient fill ratios. Default is [0, 255]
  • rotation – A Number value of the gradient fill rotation. Default value is 0

For the stroke Object (null by default), you can leave it as null to not draw a stroke or you can set stroke.weight and stroke.colour (hex value). Note that if the stroke Object is not null and stroke.colour is not set, a black stroke will be drawn. The default values noted below are set if the stroke paramater is not null.

  • weight – A Number value of the stroke weight. Default is 1
  • colour - A single hex (uint) value for the colour of the stroke. Default is black (ox000000)
  • pixelHinting - A Boolean value for whether to use pixel hinting or not. Default is true
  • scaleMode – A String value for the stroke scale mode (See LineScaleMode). Default is LineScaleMode.NONE
  • alpha - A Number value for the stroke alpha. Default is 1
/**
 *
 * DrawingUtil class
 *
 * Copyright (c) 2009 Ben Kanizay
 * This software is released under the MIT License
 *
 */

 package beekay.core.utils {
	import flash.display.LineScaleMode;
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.display.SpreadMethod;
	import flash.display.Sprite;
	import flash.geom.Matrix;

	/**
	 * @author ben.kanizay
	 */
	public class DrawingUtil {

		/*
		 * Returns a rectangular sprite.
		 *
		 * @param width:Number  the width of the rectangle
		 * @param height:Number  the height of the rectangle
		 * @param fill:Object (optional) - An object containing fill properties - default is a solid 0x00FFFF fill and alpha of 1
		 * @param stroke:Object (optional) - An object containing stroke properties - default is no stroke
		 * @param ellipse:int (optional) the size of the rounded corners - default is 0
		 *
		 * @return Sprite
		 *
		 */

		public static function drawRectSprite(width:Number, height:Number, fill:Object=null, stroke:Object=null, ellipse:int=0):Sprite {

			var sprite:Sprite = new Sprite();
			var graphics:Graphics = sprite.graphics;

			// check if we're drawing a stroke
			if (stroke != null) {
				var strokeObj:Object = getStroke(stroke);
				graphics.lineStyle(strokeObj.weight, strokeObj.colour, strokeObj.alpha, strokeObj.pixelHinting, strokeObj.scaleMode);
			}

			// determine the fill type and properties
			if (fill != null && fill.colour != null && fill.colour is Array && fill.colour.length > 1) {
				// gradient
				var gradProps:Object = getGradient(fill);
				var gradMatrix:Matrix = new Matrix();
				gradMatrix.createGradientBox(width, height, gradProps.rotation, 0, 0);
				graphics.beginGradientFill(gradProps.type, gradProps.colours, gradProps.alphas, gradProps.ratios, gradMatrix, gradProps.Spread);
			}
			else {
				// solid
				var fillProps:Object = getSolid(fill);
				graphics.beginFill(fillProps.colour, fillProps.alpha);
			}

			// rounded corners or not?
			if (ellipse > 0) {
				graphics.drawRoundRect(0, 0, width, height, ellipse);
			}
			else {
				graphics.drawRect(0, 0, width, height);
			}

			graphics.endFill();
			return sprite;
		}

		/*
		 * Returns a circular sprite.
		 *
		 * @param radius:int  the radius of the circle
		 * @param fill:Object (optional) - An object containing fill properties
		 * @param stroke:Object (optional) - An object containing stroke properties
		 *
		 * @return Sprite
		 *
		 */

		public static function drawCircSprite(radius:int, fill:Object=null, stroke:Object=null):Sprite {
			var sprite:Sprite = new Sprite();
			var graphics:Graphics = sprite.graphics;

			// check if we're drawing a stroke
			if (stroke != null) {
				var strokeObj:Object = getStroke(stroke);
				graphics.lineStyle(strokeObj.weight, strokeObj.colour, strokeObj.alpha, strokeObj.pixelHinting, strokeObj.scaleMode);
			}

			// determine the fill type and properties
			if (fill != null && fill.colour != null && fill.colour is Array && fill.colour.length > 1) {
				// gradient
				var gradProps:Object = getGradient(fill);
				var gradMatrix:Matrix = new Matrix();
				gradMatrix.createGradientBox(radius, radius, gradProps.rotation, 0, 0);
				graphics.beginGradientFill(gradProps.type, gradProps.colours, gradProps.alphas, gradProps.ratios, gradMatrix, gradProps.Spread);
			}
			else {
				// solid
				var fillProps:Object = getSolid(fill);
				graphics.beginFill(fillProps.colour, fillProps.alpha);
			}

			graphics.drawCircle(0, 0, radius);
			graphics.endFill();
			return sprite;
		}

		/*
		 * Returns a simple triangle shaped Sprite with equal sides.
		 *
		 * @param base:int  the length of the triangle base (the other sides will be the same)
		 * @param fill:Object (optional) - An object containing fill properties
		 * @param stroke:Object (optional) - An object containing stroke properties
		 *
		 * @return Sprite
		 *
		 */

		public static function drawTriSprite(base:int, fill:Object=null, stroke:Object=null) : Sprite {
			var height:Number = Math.sqrt((base*base)-((base/2)*(base/2)));
			var sprite:Sprite = new Sprite();
			var graphics:Graphics = sprite.graphics;

			// check if we're drawing a stroke
			if (stroke != null) {
				var strokeObj:Object = getStroke(stroke);
				graphics.lineStyle(strokeObj.weight, strokeObj.colour, strokeObj.alpha, strokeObj.pixelHinting, strokeObj.scaleMode);
			}

			// determine the fill type and properties
			if (fill != null && fill.colour != null && fill.colour is Array && fill.colour.length > 1) {
				// gradient
				var gradProps:Object = getGradient(fill);
				var gradMatrix:Matrix = new Matrix();
				gradMatrix.createGradientBox(base, height, gradProps.rotation, 0, 0);
				graphics.beginGradientFill(gradProps.type, gradProps.colours, gradProps.alphas, gradProps.ratios, gradMatrix, gradProps.Spread);
			}
			else {
				// solid
				var fillProps:Object = getSolid(fill);
				graphics.beginFill(fillProps.colour, fillProps.alpha);
			}

			graphics.moveTo(0, height);
			graphics.lineTo(base/2, 0);
			graphics.lineTo(base, height);
			graphics.lineTo(0, height);
			graphics.endFill();

			return sprite;
		}

////////////////////////////////////////////////////////////////
//		HELPER METHODS
////////////////////////////////////////////////////////////////		

		/*
		 * Creates the stroke properties, using defaults for any null values
		 */
		private static function getStroke(props:Object) : Object {
			var stroke:Object = {};

			var strokeWeight:Number = (props.weight != null) ? props.weight : 1;
			var strokeColour:uint = (props.colour != null) ? props.colour : 0x000000;
			var pixelHinting:Boolean = (props.pixelHinting != null) ? props.pixelHinting : true;
			var scaleMode:String = (props.scaleMode != null) ? props.scaleMode : LineScaleMode.NONE;
			var strokeAlpha:Number = (props.alpha != null) ? props.alpha : 1;

			stroke.weight = strokeWeight;
			stroke.colour = strokeColour;
			stroke.pixelHinting = pixelHinting;
			stroke.scaleMode = scaleMode;
			stroke.alpha = strokeAlpha;

			return stroke;
		}

		/*
		 * Creates the gradient fill properties, using defaults for any null values
		 */
		private static function getGradient(fill:Object) : Object {
			var gradient:Object = {};

			var gradColours:Array = [parseInt(fill.colour[0]), parseInt(fill.colour[1])];
			var gradAlphas:Array = (fill.alpha is Array) ? (fill.alpha.length > 1) ? [fill.alpha[0], fill.alpha[1]] : [fill.alpha[0], fill.alpha[0]] : (fill.alpha != null) ? [fill.alpha, fill.alpha] : [1, 1];
			var gradType:String = (fill.gradientType != null) ? fill.gradientType : GradientType.LINEAR;
			var gradSpread:String = (fill.spreadMethod != null) ? fill.spreadMethod : SpreadMethod.PAD;
			var gradRatios:Array = (fill.ratios is Array && fill.ratios.length > 1) ? [fill.ratios[0], fill.ratios[1]] : [0, 255];
			var gradRotation:Number = (fill.rotation != null) ? fill.rotation : 0;

			gradient.colours = gradColours;
			gradient.alphas = gradAlphas;
			gradient.type = gradType;
			gradient.spread = gradSpread;
			gradient.ratios = gradRatios;
			gradient.rotation = gradRotation;

			return gradient;
		}

		/*
		 * Creates the solid fill properties, using defaults for any null values
		 */
		private static function getSolid(fill:Object) : Object {
			var solid:Object = {};

			var fillAlpha:Number = (fill.alpha == null) ? 1 : (fill.alpha is Array) ? fill.alpha[0] : fill.alpha;
			var fillColour:uint = (fill.colour != null) ? (fill.colour is Array) ? parseInt(fill.colour[0]) : parseInt(fill.colour) : 0x00FFFF;

			solid.alpha = fillAlpha;
			solid.colour = fillColour;

			return solid;
		}

	}
}

Some basic usage examples

// a 200x200 black square:
var box1:Sprite = DrawingUtil.drawRectSprite(200, 200, {colour:0x000000});

// a 200x200 square with a linear gradient from grey to black:
var box2:Sprite = DrawingUtil.drawRectSprite(200, 200, {colour:[0xCCCCCC, 0x000000]});

// and 200x200 black square with a grey 2px grey stroke
var box3:Sprite = DrawingUtil.drawRectSprite(200, 200, {colour:0x000000}, {weight:2, colour:0xCCCCCC});

// the same as above but with rounded corners set to 20
var box4:Sprite = DrawingUtil.drawRectSprite(200, 200, {colour:0x000000}, {weight:2, colour:0xCCCCCC}, 20);

// and the black square with rounded corners but no stroke
var box5:Sprite = DrawingUtil.drawRectSprite(200, 200, {colour:0x000000}, null, 20);

And similarly on it goes with drawTriSprite and drawCircSprite. Best way I find is to have a play, so download the DrawingUtil class and go nuts.
As always I appreciate your feedback am happy to improve if you have any suggestions.

13
Nov 2009
POSTED BY
POSTED IN

Articles

DISCUSSION 4 Comments