1package com.yahoo.astra.utils 2{ 3 import flash.display.Graphics; 4 import flash.geom.Point; 5 6 /** 7 * Utility functions for drawing to <code>Graphics</code> objects. 8 * 9 * @author Josh Tynjala 10 * @see flash.display.Graphics 11 */ 12 public class GraphicsUtil 13 { 14 /** 15 * @private 16 * Draws a wedge. 17 * 18 * @param x x component of the wedge's center point 19 * @param y y component of the wedge's center point 20 * @param startAngle starting angle in degrees 21 * @param arc sweep of the wedge. Negative values draw clockwise. 22 * @param radius radius of wedge. If [optional] yRadius is defined, then radius is the x radius. 23 * @param yRadius [optional] y radius for wedge. 24 */ 25 public static function drawWedge(target:Graphics, x:Number, y:Number, startAngle:Number, arc:Number, radius:Number, yRadius:Number = NaN):void 26 { 27 // move to x,y position 28 target.moveTo(x, y); 29 30 // if yRadius is undefined, yRadius = radius 31 if(isNaN(yRadius)) 32 { 33 yRadius = radius; 34 } 35 36 // limit sweep to reasonable numbers 37 if(Math.abs(arc) > 360) 38 { 39 arc = 360; 40 } 41 42 // Flash uses 8 segments per circle, to match that, we draw in a maximum 43 // of 45 degree segments. First we calculate how many segments are needed 44 // for our arc. 45 var segs:int = Math.ceil(Math.abs(arc) / 45); 46 47 // Now calculate the sweep of each segment. 48 var segAngle:Number = arc / segs; 49 50 // The math requires radians rather than degrees. To convert from degrees 51 // use the formula (degrees/180)*Math.PI to get radians. 52 var theta:Number = -(segAngle / 180) * Math.PI; 53 54 // convert angle startAngle to radians 55 var angle:Number = -(startAngle / 180) * Math.PI; 56 57 // draw the curve in segments no larger than 45 degrees. 58 if(segs > 0) 59 { 60 // draw a line from the center to the start of the curve 61 var ax:Number = x + Math.cos(startAngle / 180 * Math.PI) * radius; 62 var ay:Number = y + Math.sin(-startAngle / 180 * Math.PI) * yRadius; 63 target.lineTo(ax, ay); 64 65 // Loop for drawing curve segments 66 for(var i:int = 0; i < segs; i++) 67 { 68 angle += theta; 69 var angleMid:Number = angle - (theta / 2); 70 var bx:Number = x + Math.cos(angle) * radius; 71 var by:Number = y + Math.sin(angle) * yRadius; 72 var cx:Number = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2)); 73 var cy:Number = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2)); 74 target.curveTo(cx, cy, bx, by); 75 } 76 // close the wedge by drawing a line to the center 77 target.lineTo(x, y); 78 } 79 } 80 81 /** 82 * Draws a dashed line between two points. 83 * 84 * @param xStart The x position of the start of the line 85 * @param yStart The y position of the start of the line 86 * @param xEnd The x position of the end of the line 87 * @param yEnd The y position of the end of the line 88 * @param dashSize the size of dashes, in pixels 89 * @param gapSize the size of gaps between dashes, in pixels 90 */ 91 public static function drawDashedLine(target:Graphics, xStart:Number, yStart:Number, xEnd:Number, yEnd:Number, dashSize:Number = 10, gapSize:Number = 10):void 92 { 93 // calculate the length of a segment 94 var segmentLength:Number = dashSize + gapSize; 95 96 // calculate the length of the dashed line 97 var xDelta:Number = xEnd - xStart; 98 var yDelta:Number = yEnd - yStart; 99 var delta:Number = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2)); 100 101 // calculate the number of segments needed 102 var segmentCount:int = Math.floor(Math.abs(delta / segmentLength)); 103 104 // get the angle of the line in radians 105 var radians:Number = Math.atan2(yDelta, xDelta); 106 107 // start the line here 108 var xCurrent:Number = xStart; 109 var yCurrent:Number = yStart; 110 111 // add these to cx, cy to get next seg start 112 xDelta = Math.cos(radians) * segmentLength; 113 yDelta = Math.sin(radians) * segmentLength; 114 115 // loop through each segment 116 for(var i:int = 0; i < segmentCount; i++) 117 { 118 target.moveTo(xCurrent, yCurrent); 119 target.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize); 120 xCurrent += xDelta; 121 yCurrent += yDelta; 122 } 123 124 // handle last segment as it is likely to be partial 125 target.moveTo(xCurrent, yCurrent); 126 delta = Math.sqrt((xEnd - xCurrent) * (xEnd - xCurrent) + (yEnd - yCurrent) * (yEnd - yCurrent)); 127 128 if(delta > dashSize) 129 { 130 // segment ends in the gap, so draw a full dash 131 target.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize); 132 } 133 else if(delta > 0) 134 { 135 // segment is shorter than dash so only draw what is needed 136 target.lineTo(xCurrent + Math.cos(radians) * delta, yCurrent + Math.sin(radians) * delta); 137 } 138 139 // move the pen to the end position 140 target.moveTo(xEnd, yEnd); 141 } 142 143 } 144}