Index: lams_common/src/flash/com/polymercode/Draw.as =================================================================== diff -u --- lams_common/src/flash/com/polymercode/Draw.as (revision 0) +++ lams_common/src/flash/com/polymercode/Draw.as (revision f21f23f651433de36707cac2e3962e0567626d81) @@ -0,0 +1,639 @@ +/** + * Draw is a static toolbox class that provides a number of functions + * to draw shapes that are not part of the standard ActionScript Drawing + * API. + * + * To call this code from the timeline you must include this class in the + * classpath in the publish settings menu. + * + * File -> Publish Settings (Ctrl+Shift+F12 on windows) + * - Click "Flash" tab + * - Set ActionScript Version to "ActionScript 2.0" or higher... + * - Click "Settings" + * - click the target icon and select the directory you've extracted + * - this code into. You should select the directory that has + * - the com directory in it. NOT the directory + * - that has the Draw.as file. + * + * based on source code found at: + * http://www.macromedia.com/devnet/mx/flash/articles/adv_draw_methods.html + * + * @author Ric Ewing - version 1.4 - 4.7.2002 + * @author Kevin Williams - version 2.0 - 4.7.2005 + */ +class com.polymercode.Draw +{ + /** + * + * This class has all static functions. To call them simply call + * com.polymercode.Draw.functionName(parameters); + * + * You should never have to call new Draw(); + * + */ + private function Draw(){} + + /** + * dashTo + * Draws a dashed line from the point x1,y1 to the point x2,y2 + * The line may is drawn on the movie clips specified by the + * target parameter (default is _root). The line may + * be any color or transparency and width, length of dashes, + * and space between dashes may all be specified. + * + * @param target MovieClip the movie clip on which the dashed + * line will be drawn. + * @param x1 Number starting position on x axis - required + * @param y1 Number starting position on y axis - required + * @param x2 Number finishing position on x axis - required + * @param y2 Number finishing position on y axis - required + * @param dashLength [optional] Number the number of pixels long each dash + * will be. Default = 5 + * @param spaceLength [optional] Number the number of pixels between each + * dash. Default = 5 + * @param strokWidth [optional] Number the width of each dash. + * Default = 1 + * @param rgbHex [optional] the Hex color value of the dashed line. + * Default = 0x000000 + * @param alpha [optional] Number the alpha transparancy that the dashed + * line will have. Default = 100; + */ + public static function dashTo(target:MovieClip, x1:Number, + y1:Number,x2:Number, y2:Number, dashLength:Number, + spaceLength:Number,strokeWidth:Number,rgbHex:Number ):Void + { + trace("com.polymercode.Draw.dashTo - arguments:"+arguments.toString()); + if ( arguments < 5 ){ + trace("com.polymercode.Draw.dashTo - too few parameters."); + return; + } + if ( spaceLength == undefined ) + spaceLength = 5; + if ( dashLength == undefined ) + dashLength = 5; + + //added to this + target.lineStyle(strokeWidth,rgbHex); + + var x = x2 - x1; + var y = y2 - y1; + var hyp = Math.sqrt((x)*(x) + (y)*(y)); + var units = hyp/(dashLength+spaceLength); + var dashSpaceRatio = dashLength/(dashLength+spaceLength); + var dashX = (x/units)*dashSpaceRatio; + var spaceX = (x/units)-dashX; + var dashY = (y/units)*dashSpaceRatio; + var spaceY = (y/units)-dashY; + target.moveTo(x1, y1); + while (hyp > 0) { + x1 += dashX; + y1 += dashY; + hyp -= dashLength; + if (hyp < 0) { + x1 = x2; + y1 = y2; + } + target.lineTo(x1, y1); + x1 += spaceX; + y1 += spaceY; + target.moveTo(x1, y1); + hyp -= spaceLength; + } + target.moveTo(x2, y2); + } + + + /** + * Draws an arc from the starting position of x,y. + * + * @param target the movie clip that the Arc is drawn on. + * @param x x coordinate of the starting pen position + * @param y y coordinate of the starting pen position + * @param radius radius of Arc. + * @param arc = sweep of the arc. Negative values draw clockwise. + * @param startAngle = [optional] starting offset angle in degrees. + * @param yRadius = [optional] y radius of arc. if different than + * radius, then the arc will draw as the arc of an oval. + * default = radius. + * + * Based on mc.drawArc by Ric Ewing. + * the version by Ric assumes that the pen is at x:y before this + * method is called. I explictily move the pen to x:y to be + * consistent with the behaviour of the other methods. + */ + public static function arcTo(target:MovieClip, x:Number, + y:Number, radius:Number, arc:Number, startAngle:Number, + yRadius:Number):Void + { + if (arguments.length<5) { + trace("com.polymercode.Draw.arcTo - too few parameters."); + return; + } + + // if startAngle is undefined, startAngle = 0 + if( startAngle == undefined ){ + startAngle = 0; + } + // if yRadius is undefined, yRadius = radius + if (yRadius == undefined) { + yRadius = radius; + } + + // Init vars + var segAngle, theta, angle, angleMid, segs, ax, ay, bx, by, cx, cy; + // no sense in drawing more than is needed :) + if (Math.abs(arc)>360) { + arc = 360; + } + // Flash uses 8 segments per circle, to match that, we draw in a maximum + // of 45 degree segments. First we calculate how many segments are needed + // for our arc. + segs = Math.ceil(Math.abs(arc)/45); + // Now calculate the sweep of each segment + segAngle = arc/segs; + // The math requires radians rather than degrees. To convert from degrees + // use the formula (degrees/180)*Math.PI to get radians. + theta = -(segAngle/180)*Math.PI; + // convert angle startAngle to radians + angle = -(startAngle/180)*Math.PI; + // find our starting points (ax,ay) relative to the secified x,y + ax = x-Math.cos(angle)*radius; + ay = y-Math.sin(angle)*yRadius; + // if our arc is larger than 45 degrees, draw as 45 degree segments + // so that we match Flash's native circle routines. + if (segs>0) { + target.moveTo(x,y); + // Loop for drawing arc segments + for (var i = 0; i2) { + // init vars + var step, halfStep, qtrStep, start, n, dx, dy, cx, cy; + // calculate length of sides + step = (Math.PI*2)/sides; + halfStep = step/2; + qtrStep = step/4; + // calculate starting angle in radians + start = (angle/180)*Math.PI; + target.moveTo(x+(Math.cos(start)*outerRadius), y-(Math.sin(start)*outerRadius)); + // draw curves + for (n=1; n<=sides; n++) { + cx = x+Math.cos(start+(step*n)-(qtrStep*3))*(innerRadius/Math.cos(qtrStep)); + cy = y-Math.sin(start+(step*n)-(qtrStep*3))*(innerRadius/Math.cos(qtrStep)); + dx = x+Math.cos(start+(step*n)-halfStep)*innerRadius; + dy = y-Math.sin(start+(step*n)-halfStep)*innerRadius; + target.curveTo(cx, cy, dx, dy); + cx = x+Math.cos(start+(step*n)-qtrStep)*(innerRadius/Math.cos(qtrStep)); + cy = y-Math.sin(start+(step*n)-qtrStep)*(innerRadius/Math.cos(qtrStep)); + dx = x+Math.cos(start+(step*n))*outerRadius; + dy = y-Math.sin(start+(step*n))*outerRadius; + target.curveTo(cx, cy, dx, dy); + } + } + } + + /** + * draws a gear shape on the MovieClip target. The gear position + * is indicated by the x and y arguments. + * + * @param target MovieClip on which the gear is to be drawn. + * @param x x coordinate of the center of the gear + * @param y y coordinate of the center of the gear + * @param sides number of teeth on gear. (must be > 2) + * @param innerRadius radius of the indent of the teeth. + * @param outerRadius outer radius of the teeth. + * @param angle = [optional] starting angle in degrees. Defaults to 0. + * @param holeSides [optional] draw a polygonal hole with this many sides (must be > 2) + * @param holeRadius [optional] size of hole. Default = innerRadius/3. + * + * based on mc.drawGear() - by Ric Ewing (ric@formequalsfunction.com) - version 1.4 - 4.7.2002 + */ + public static function gear(target:MovieClip, x:Number, y:Number, + sides:Number, innerRadius:Number, outerRadius:Number, + angle:Number, holeSides:Number, holeRadius:Number ):Void + { + if(arguments<6){ + trace("com.polymercode.Draw.gear - too few parameters"); + return; + } + if ( angle == undefined ) + angle = 0; + if ( holeSides == undefined ) + holeSides = 0; + + if (sides>2) { + // init vars + var step, qtrStep, start, n, dx, dy; + // calculate length of sides + step = (Math.PI*2)/sides; + qtrStep = step/4; + // calculate starting angle in radians + start = (angle/180)*Math.PI; + target.moveTo(x+(Math.cos(start)*outerRadius), y-(Math.sin(start)*outerRadius)); + // draw lines + for (n=1; n<=sides; n++) { + dx = x+Math.cos(start+(step*n)-(qtrStep*3))*innerRadius; + dy = y-Math.sin(start+(step*n)-(qtrStep*3))*innerRadius; + target.lineTo(dx, dy); + dx = x+Math.cos(start+(step*n)-(qtrStep*2))*innerRadius; + dy = y-Math.sin(start+(step*n)-(qtrStep*2))*innerRadius; + target.lineTo(dx, dy); + dx = x+Math.cos(start+(step*n)-qtrStep)*outerRadius; + dy = y-Math.sin(start+(step*n)-qtrStep)*outerRadius; + target.lineTo(dx, dy); + dx = x+Math.cos(start+(step*n))*outerRadius; + dy = y-Math.sin(start+(step*n))*outerRadius; + target.lineTo(dx, dy); + } + // This is complete overkill... but I had it done already. :) + if (holeSides>2) { + if(holeRadius == undefined) { + holeRadius = innerRadius/3; + } + step = (Math.PI*2)/holeSides; + target.moveTo(x+(Math.cos(start)*holeRadius), y-(Math.sin(start)*holeRadius)); + for (n=1; n<=holeSides; n++) { + dx = x+Math.cos(start+(step*n))*holeRadius; + dy = y-Math.sin(start+(step*n))*holeRadius; + target.lineTo(dx, dy); + } + } + } + } + + /** + * oval draws used to draw circles or ovals. + * According to Ric Ewing -
This method, like most of + * the others, is not as optimized as it could be. This was a + * conscious decision to keep the code as accessible as + * possible for those either new to AS or to the math + * involved in plotting points on a curve.
+ * + * @param target the MovieClip that the oval/circle is drawn on. + * @param x x coordinate of the center of the oval/circle + * @param y y coordinate of the center of the oval/circle + * @param radius the radius of the oval/circle + * @param yRadius [optional] y radius of the oval. if not defined + * then yRadius = radius and therefore, it draws a circle. + * + * based on mc.drawOval() - by Ric Ewing (ric@formequalsfunction.com) - version 1.4 - 4.7.2002 + */ + public static function oval(target:MovieClip, x:Number, y:Number, + radius:Number, yRadius:Number):Void + { + if (arguments.length<4) + { + trace("com.polymercode.Draw.oval - too few parameters"); + return; + } + // if only yRadius is undefined, yRadius = radius + if (yRadius == undefined) { + yRadius = radius; + } + + // init variables + var theta, xrCtrl, yrCtrl, angle, angleMid, px, py, cx, cy; + // covert 45 degrees to radians for our calculations + theta = Math.PI/4; + // calculate the distance for the control point + xrCtrl = radius/Math.cos(theta/2); + yrCtrl = yRadius/Math.cos(theta/2); + // start on the right side of the circle + angle = 0; + target.moveTo(x+radius, y); + // this loop draws the circle in 8 segments + for (var i = 0; i<8; i++) { + // increment our angles + angle += theta; + angleMid = angle-(theta/2); + // calculate our control point + cx = x+Math.cos(angleMid)*xrCtrl; + cy = y+Math.sin(angleMid)*yrCtrl; + // calculate our end point + px = x+Math.cos(angle)*radius; + py = y+Math.sin(angle)*yRadius; + // draw the circle segment + target.curveTo(cx, cy, px, py); + } + } + + /** + * a method for creating polygon shapes. Negative values will draw + * the polygon in reverse direction. Negative drawing may be useful + * for creating knock-outs in masks. + * + * @param target the MovieClip that the polygon is to be drawn on + * @param x x coordinate of the center of the polygon + * @param y y coordinate of the center of the polygon + * @param sides the number of sides (must be > 2) + * @param radius the radius from the center point to the points + * on the polygon + * @param angle [optional] the starting offset angle (degrees) from + * 0. Default = 0 + * + * based on mc.drawPoly() - by Ric Ewing (ric@formequalsfunction.com) - version 1.4 - 4.7.2002 + */ + public static function polygon(target:MovieClip, x:Number, + y:Number, sides:Number, radius:Number, angle:Number):Void + { + if (arguments.length<5) + { + trace("com.polymercode.Draw.polygon - too few parameters"); + return; + } + if ( angle == undefined ) + angle = 0; + + // convert sides to positive value + var count = Math.abs(sides); + // check that count is sufficient to build polygon + if (count>2) { + // init vars + var step, start, n, dx, dy; + // calculate span of sides + step = (Math.PI*2)/sides; + // calculate starting angle in radians + start = (angle/180)*Math.PI; + target.moveTo(x+(Math.cos(start)*radius), y-(Math.sin(start)*radius)); + // draw the polygon + for (n=1; n<=count; n++) { + dx = x+Math.cos(start+(step*n))*radius; + dy = y-Math.sin(start+(step*n))*radius; + target.lineTo(dx, dy); + } + } + } + + /** + * roundedRectangle draws rectangles with rounded corners. + * This is similar to the Flash rectangle tool. If the + * rectangle is smaller in either dimension than the + * rounding permits then rounding is scaled down to fit + * + * @param target the MovieClip that the rouded rectangle is to be + * drawn on. + * @param x x coordinate of the top left corner of the rectangle + * @param y y coordinate of the top right corner of the rectangle + * @param width width of the rectangle + * @param height height of the rectangle + * @param cornerRadius the radius of the rounding of the corners of + * the rectangle. [optional] + * + * based on mc.drawRect() - by Ric Ewing (ric@formequalsfunction.com) - version 1.4 - 4.7.2002 + */ + public static function roundedRectangle(target:MovieClip, + x:Number, y:Number, width:Number, height:Number, + cornerRadius:Number ):Void + { + if ( arguments.length<5 ) + { + trace("com.polymercode.Draw.roundedRectangle - too few parameters"); + return; + } + if ( cornerRadius == undefined ) + cornerRadius = 0; + + // if the user has defined cornerRadius our task is a bit more complex. :) + if (cornerRadius>0) { + // init vars + var theta, angle, cx, cy, px, py; + // make sure that w + h are larger than 2*cornerRadius + if (cornerRadius>Math.min(width, height)/2) { + cornerRadius = Math.min(width, height)/2; + } + // theta = 45 degrees in radians + theta = Math.PI/4; + // draw top line + target.moveTo(x+cornerRadius, y); + target.lineTo(x+width-cornerRadius, y); + //angle is currently 90 degrees + angle = -Math.PI/2; + // draw tr corner in two parts + cx = x+width-cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+width-cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+cornerRadius+(Math.sin(angle+theta)*cornerRadius); + + target.curveTo(cx, cy, px, py); + angle += theta; + cx = x+width-cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+width-cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+cornerRadius+(Math.sin(angle+theta)*cornerRadius); + target.curveTo(cx, cy, px, py); + // draw right line + target.lineTo(x+width, y+height-cornerRadius); + // draw br corner + angle += theta; + cx = x+width-cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+height-cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+width-cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+height-cornerRadius+(Math.sin(angle+theta)*cornerRadius); + target.curveTo(cx, cy, px, py); + angle += theta; + cx = x+width-cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+height-cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+width-cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+height-cornerRadius+(Math.sin(angle+theta)*cornerRadius); + target.curveTo(cx, cy, px, py); + // draw bottom line + target.lineTo(x+cornerRadius, y+height); + // draw bl corner + angle += theta; + cx = x+cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+height-cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+height-cornerRadius+(Math.sin(angle+theta)*cornerRadius); + target.curveTo(cx, cy, px, py); + angle += theta; + cx = x+cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+height-cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+height-cornerRadius+(Math.sin(angle+theta)*cornerRadius); + target.curveTo(cx, cy, px, py); + // draw left line + target.lineTo(x, y+cornerRadius); + // draw tl corner + angle += theta; + cx = x+cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+cornerRadius+(Math.sin(angle+theta)*cornerRadius); + target.curveTo(cx, cy, px, py); + angle += theta; + cx = x+cornerRadius+(Math.cos(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + cy = y+cornerRadius+(Math.sin(angle+(theta/2))*cornerRadius/Math.cos(theta/2)); + px = x+cornerRadius+(Math.cos(angle+theta)*cornerRadius); + py = y+cornerRadius+(Math.sin(angle+theta)*cornerRadius); + target.curveTo(cx, cy, px, py); + } else { + // cornerRadius was not defined or = 0. This makes it easy. + target.moveTo(x, y); + target.lineTo(x+width, y); + target.lineTo(x+width, y+height); + target.lineTo(x, y+height); + target.lineTo(x, y); + } + } + + /** + * start draws a star shaped polygon. + * + *
Note that the stars by default 'point' to + * the right. This is because the method starts drawing + * at 0 degrees by default, putting the first point to + * the right of center. Negative values for points + * draws the star in reverse direction, allowing for + * knock-outs when used as part of a mask.
+ * + * @param x x coordinate of the center of the star + * @param y y coordinate of the center of the star + * @param points the number of points on the star + * @param innerRadius the radius of the inside angles of the star + * @param outerRadius the radius of the outside angles of the star + * @param angle [optional] the offet angle that the start is rotated + * @param target the MovieClip that the star is drawn on + * + * based on mc.drawStar() - by Ric Ewing (ric@formequalsfunction.com) - version 1.4 - 4.7.2002 + */ + public static function star(target:MovieClip, x:Number, y:Number, + points:Number, innerRadius:Number, outerRadius:Number, + angle:Number ):Void + { + if( arguments.length < 6) + { + trace("com.polymercode.Draw.star - too few parameters"); + return; + } + if( angle == undefined ) + angle = 0; + + var count = Math.abs(points); + if (count>2) { + // init vars + var step, halfStep, start, n, dx, dy; + // calculate distance between points + step = (Math.PI*2)/points; + halfStep = step/2; + // calculate starting angle in radians + start = (angle/180)*Math.PI; + target.moveTo(x+(Math.cos(start)*outerRadius), y-(Math.sin(start)*outerRadius)); + // draw lines + for (n=1; n<=count; n++) { + dx = x+Math.cos(start+(step*n)-halfStep)*innerRadius; + dy = y-Math.sin(start+(step*n)-halfStep)*innerRadius; + target.lineTo(dx, dy); + dx = x+Math.cos(start+(step*n))*outerRadius; + dy = y-Math.sin(start+(step*n))*outerRadius; + target.lineTo(dx, dy); + } + } + } + + /** + * draws pie shaped wedges. Could be employeed to draw pie charts. + * + * @param target the MovieClip on which the wedge is to be drawn. + * @param x x coordinate of the center point of the wedge + * @param y y coordinate of the center point of the wedge + * @param startAngle the starting angle in degrees + * @param arc the sweep of the wedge. negative values draw clockwise + * @param radius the radius of the wedge + * @param yRadius [optional] the y axis radius of the wedge. + * If not defined, then yRadius = radius. + * + * based on mc.drawWedge() - by Ric Ewing (ric@formequalsfunction.com) - version 1.4 - 4.7.2002 + */ + public static function wedge(target:MovieClip, x:Number, y:Number, + startAngle:Number, arc:Number, radius:Number, + yRadius:Number):Void + { + if (arguments.length<5) { + trace("com.polymercode.Draw.wedge - too few parameters"); + return; + } + // move to x,y position + target.moveTo(x, y); + // if yRadius is undefined, yRadius = radius + if (yRadius == undefined) { + yRadius = radius; + } + // Init vars + var segAngle, theta, angle, angleMid, segs, ax, ay, bx, by, cx, cy; + // limit sweep to reasonable numbers + if (Math.abs(arc)>360) { + arc = 360; + } + // Flash uses 8 segments per circle, to match that, we draw in a maximum + // of 45 degree segments. First we calculate how many segments are needed + // for our arc. + segs = Math.ceil(Math.abs(arc)/45); + // Now calculate the sweep of each segment. + segAngle = arc/segs; + // The math requires radians rather than degrees. To convert from degrees + // use the formula (degrees/180)*Math.PI to get radians. + theta = -(segAngle/180)*Math.PI; + // convert angle startAngle to radians + angle = -(startAngle/180)*Math.PI; + // draw the curve in segments no larger than 45 degrees. + if (segs>0) { + // draw a line from the center to the start of the curve + ax = x+Math.cos(startAngle/180*Math.PI)*radius; + ay = y+Math.sin(-startAngle/180*Math.PI)*yRadius; + target.lineTo(ax, ay); + // Loop for drawing curve segments + for (var i = 0; i