AS3 Drawing Shapes (ARC, BURST, DASHED-LINE, GEAR, POLYGON, STAR, WEDGE, LINE)


/ Published in: ActionScript 3
Save to your folder(s)

Credit for this goes to Adobe, Ric Ewing, Kevin Williams, Aden Forshaw and Sidney de Koning.


Copy this code and paste it in your HTML
  1. package nl.funkymonkey.drawing
  2. {
  3. import flash.display.*;
  4.  
  5. /**
  6. * based on source code found at:
  7. * http://www.macromedia.com/devnet/mx/flash/articles/adv_draw_methods.html
  8. *
  9. * @author Ric Ewing - version 1.4 - 4.7.2002
  10. * @author Kevin Williams - version 2.0 - 4.7.2005
  11. * @author Aden Forshaw - Version AS3 - 19.4.2010
  12. * @author Sidney de Koning - Version AS3 - 20.4.2010 - errors/correct datatypes/optimized math operations
  13. *
  14. * Usage:
  15. * var s : Shape = new Shape( ); // Or Sprite of MovieClip or any other Class that makes use of the Graphics class
  16. *
  17. * // Draw an ARC
  18. * s.graphics.lineStyle( 4, 0xE16606 );
  19. * DrawingShapes.drawArc( s.graphics, 50, 50, 10, 150, 60 );
  20. *
  21. * // Draw an BURST
  22. * s.graphics.lineStyle( 3, 0x000000 );
  23. * DrawingShapes.drawBurst( s.graphics, 80, 60, 3, 15, 6, 27 );
  24. *
  25. * // Draw an DASHED-LINE like so - - - -
  26. * s.graphics.lineStyle( 1, 0x3C3C39 );
  27. * DrawingShapes.drawDash( s.graphics, 120, 60, 150, 80, 2, 2 );
  28. *
  29. * // Draw an GEAR
  30. * s.graphics.lineStyle( 3, 0xE16606 );
  31. * DrawingShapes.drawGear( s.graphics, 200, 60, 13, 31, 26, 0, 7, 13 );
  32. *
  33. * // Draw a POLYGON
  34. * s.graphics.lineStyle( 3, 0x0074B9 );
  35. * DrawingShapes.drawPolygon( s.graphics, 270, 60, 7, 30, 45 );
  36. *
  37. * // Draw a STAR
  38. * s.graphics.lineStyle( 2, 0x000000 );
  39. * DrawingShapes.drawStar( s.graphics, 340, 60, 18, 24, 19, 27 );
  40. *
  41. * // Draw an WEDGE - good for pie charts or pacmans
  42. * s.graphics.lineStyle( 2, 0xFFCC00 );
  43. * DrawingShapes.drawWedge( s.graphics, 400, 60, 30, 309, 209 );
  44. *
  45. * // Draw a LINE
  46. * s.graphics.lineStyle( 2, 0x0074B9 );
  47. * DrawingShapes.drawLine( s.graphics, 440, 85, 30, DrawingShapes.VERTICAL_LINE );
  48. *
  49. * addChild( s );
  50. */
  51. public class DrawingShapes
  52. {
  53.  
  54. public static const HORIZONTAL_LINE:String = "DrawingShapes.horizontal";
  55. public static const VERTICAL_LINE:String = "DrawingShapes.vertical";
  56.  
  57.  
  58. public function DrawingShapes()
  59. {
  60. throw new ArgumentError("The DrawingShapes Class cannot be instanicated.");
  61. }
  62.  
  63. /**
  64. * drawDash
  65. * Draws a dashed line from the point x1,y1 to the point x2,y2
  66. *
  67. * @param target Graphics the Graphics Class on which the dashed line will be drawn.
  68. * @param x1 Number starting position on x axis - <strong>required</strong>
  69. * @param y1 Number starting position on y axis - <strong>required</strong>
  70. * @param x2 Number finishing position on x axis - <strong>required</strong>
  71. * @param y2 Number finishing position on y axis - <strong>required</strong>
  72. * @param dashLength [optional] Number the number of pixels long each dash
  73. * will be. Default = 5
  74. * @param spaceLength [optional] Number the number of pixels between each
  75. * dash. Default = 5
  76. */
  77. public static function drawDash(target:Graphics, x1:Number, y1:Number, x2:Number, y2:Number, dashLength:Number=5, spaceLength:Number=5):void
  78. {
  79.  
  80. var x:Number = x2 - x1;
  81. var y:Number = y2 - y1;
  82. var hyp:Number = Math.sqrt((x) * (x) + (y) * (y));
  83. var units:Number = hyp / (dashLength + spaceLength);
  84. var dashSpaceRatio:Number = dashLength / (dashLength + spaceLength);
  85. var dashX:Number = (x / units) * dashSpaceRatio;
  86. var spaceX:Number = (x / units) - dashX;
  87. var dashY:Number = (y / units) * dashSpaceRatio;
  88. var spaceY:Number = (y / units) - dashY;
  89.  
  90. target.moveTo(x1, y1);
  91. while (hyp > 0)
  92. {
  93. x1 += dashX;
  94. y1 += dashY;
  95. hyp -= dashLength;
  96. if (hyp < 0)
  97. {
  98. x1 = x2;
  99. y1 = y2;
  100. }
  101. target.lineTo(x1, y1);
  102. x1 += spaceX;
  103. y1 += spaceY;
  104. target.moveTo(x1, y1);
  105. hyp -= spaceLength;
  106. }
  107. target.moveTo(x2, y2);
  108. }
  109.  
  110. /**
  111. * Draws an arc from the starting position of x,y.
  112. *
  113. * @param target the Graphics Class that the Arc is drawn on.
  114. * @param x x coordinate of the starting pen position
  115. * @param y y coordinate of the starting pen position
  116. * @param radius radius of Arc.
  117. * @param arc = sweep of the arc. Negative values draw clockwise.
  118. * @param startAngle = [optional] starting offset angle in degrees.
  119. * @param yRadius = [optional] y radius of arc. if different than
  120. * radius, then the arc will draw as the arc of an oval.
  121. * default = radius.
  122. *
  123. * Based on mc.drawArc by Ric Ewing.
  124. * the version by Ric assumes that the pen is at x:y before this
  125. * method is called. I explictily move the pen to x:y to be
  126. * consistent with the behaviour of the other methods.
  127. */
  128. public static function drawArc(target:Graphics, x:Number, y:Number, radius:Number, arc:Number, startAngle:Number=0, yRadius:Number=0):void
  129. {
  130.  
  131. if (arguments.length < 5)
  132. {
  133. throw new ArgumentError("DrawingShapes.drawArc() - too few parameters, need atleast 5.");
  134. return;
  135. }
  136.  
  137. // if startAngle is undefined, startAngle = 0
  138. if (startAngle == 0)
  139. {
  140. startAngle = 0;
  141. }
  142. // if yRadius is undefined, yRadius = radius
  143. if (yRadius == 0)
  144. {
  145. yRadius = radius;
  146. }
  147.  
  148. // Init vars
  149. var segAngle:Number, theta:Number, angle:Number, angleMid:Number, segs:Number, ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number;
  150. // no sense in drawing more than is needed :)
  151. if (DrawingShapes.abs(arc) > 360)
  152. {
  153. arc = 360;
  154. }
  155. // Flash uses 8 segments per circle, to match that, we draw in a maximum
  156. // of 45 degree segments. First we calculate how many segments are needed
  157. // for our arc.
  158. segs = DrawingShapes.ceil(DrawingShapes.abs(arc) / 45);
  159. // Now calculate the sweep of each segment
  160. segAngle = arc / segs;
  161. // The math requires radians rather than degrees. To convert from degrees
  162. // use the formula (degrees/180)*Math.PI to get radians.
  163. theta = -(segAngle / 180) * Math.PI;
  164. // convert angle startAngle to radians
  165. angle = -(startAngle / 180) * Math.PI;
  166. // find our starting points (ax,ay) relative to the secified x,y
  167. ax = x - Math.cos(angle) * radius;
  168. ay = y - Math.sin(angle) * yRadius;
  169. // if our arc is larger than 45 degrees, draw as 45 degree segments
  170. // so that we match Flash's native circle routines.
  171. if (segs > 0)
  172. {
  173. target.moveTo(x, y);
  174. // Loop for drawing arc segments
  175. for (var i:int = 0; i < segs; ++i)
  176. {
  177. // increment our angle
  178. angle += theta;
  179. // find the angle halfway between the last angle and the new
  180. angleMid = angle - (theta / 2);
  181. // calculate our end point
  182. bx = ax + Math.cos(angle) * radius;
  183. by = ay + Math.sin(angle) * yRadius;
  184. // calculate our control point
  185. cx = ax + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
  186. cy = ay + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
  187. // draw the arc segment
  188. target.curveTo(cx, cy, bx, by);
  189. }
  190. }
  191. }
  192.  
  193. /**
  194. * draws pie shaped wedges. Could be employeed to draw pie charts.
  195. *
  196. * @param target the Graphics on which the wedge is to be drawn.
  197. * @param x x coordinate of the center point of the wedge
  198. * @param y y coordinate of the center point of the wedge
  199. * @param radius the radius of the wedge
  200. * @param arc the sweep of the wedge. negative values draw clockwise
  201. * @param startAngle the starting angle in degrees
  202. * @param yRadius [optional] the y axis radius of the wedge.
  203. * If not defined, then yRadius = radius.
  204. *
  205. * based on mc.drawWedge() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
  206. */
  207. public static function drawWedge(target:Graphics, x:Number, y:Number, radius:Number, arc:Number, startAngle:Number=0, yRadius:Number=0):void
  208. {
  209.  
  210. // if yRadius is undefined, yRadius = radius
  211. if (yRadius == 0)
  212. {
  213. yRadius = radius;
  214. }
  215.  
  216. // move to x,y position
  217. target.moveTo(x, y);
  218. // if yRadius is undefined, yRadius = radius
  219. if (yRadius == 0)
  220. {
  221. yRadius = radius;
  222. }
  223. // Init vars
  224. var segAngle:Number, theta:Number, angle:Number, angleMid:Number, segs:Number, ax:Number, ay:Number, bx:Number, by:Number, cx:Number, cy:Number;
  225. // limit sweep to reasonable numbers
  226. if (DrawingShapes.abs(arc) > 360)
  227. {
  228. arc = 360;
  229. }
  230. // Flash uses 8 segments per circle, to match that, we draw in a maximum
  231. // of 45 degree segments. First we calculate how many segments are needed
  232. // for our arc.
  233. segs = DrawingShapes.ceil(DrawingShapes.abs(arc) / 45);
  234. // Now calculate the sweep of each segment.
  235. segAngle = arc / segs;
  236. // The math requires radians rather than degrees. To convert from degrees
  237. // use the formula (degrees/180)*Math.PI to get radians.
  238. theta = -(segAngle / 180) * Math.PI;
  239. // convert angle startAngle to radians
  240. angle = -(startAngle / 180) * Math.PI;
  241. // draw the curve in segments no larger than 45 degrees.
  242. if (segs > 0)
  243. {
  244. // draw a line from the center to the start of the curve
  245. ax = x + Math.cos(startAngle / 180 * Math.PI) * radius;
  246. ay = y + Math.sin(-startAngle / 180 * Math.PI) * yRadius;
  247. target.lineTo(ax, ay);
  248. // Loop for drawing curve segments
  249. for (var i:int = 0; i < segs; ++i)
  250. {
  251. angle += theta;
  252. angleMid = angle - (theta / 2);
  253. bx = x + Math.cos(angle) * radius;
  254. by = y + Math.sin(angle) * yRadius;
  255. cx = x + Math.cos(angleMid) * (radius / Math.cos(theta / 2));
  256. cy = y + Math.sin(angleMid) * (yRadius / Math.cos(theta / 2));
  257. target.curveTo(cx, cy, bx, by);
  258. }
  259. // close the wedge by drawing a line to the center
  260. target.lineTo(x, y);
  261. }
  262. }
  263.  
  264. /**
  265. * start draws a star shaped polygon.
  266. *
  267. * <blockquote>Note that the stars by default 'point' to
  268. * the right. This is because the method starts drawing
  269. * at 0 degrees by default, putting the first point to
  270. * the right of center. Negative values for points
  271. * draws the star in reverse direction, allowing for
  272. * knock-outs when used as part of a mask.</blockquote>
  273. *
  274. * @param target the Graphics that the star is drawn on
  275. * @param x x coordinate of the center of the star
  276. * @param y y coordinate of the center of the star
  277. * @param points the number of points on the star
  278. * @param innerRadius the radius of the inside angles of the star
  279. * @param outerRadius the radius of the outside angles of the star
  280. * @param angle [optional] the offet angle that the start is rotated
  281. *
  282. * based on mc.drawStar() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
  283. */
  284. public static function drawStar(target:Graphics, x:Number, y:Number, points:uint, innerRadius:Number, outerRadius:Number, angle:Number=0):void
  285. {
  286.  
  287. // check that points is sufficient to build polygon
  288. if (points <= 2)
  289. {
  290. throw ArgumentError("DrawingShapes.drawStar() - parameter 'points' needs to be atleast 3");
  291. return;
  292. }
  293. if (points > 2)
  294. {
  295. // init vars
  296. var step:Number, halfStep:Number, start:Number, n:Number, dx:Number, dy:Number;
  297. // calculate distance between points
  298. step = (Math.PI * 2) / points;
  299. halfStep = step / 2;
  300. // calculate starting angle in radians
  301. start = (angle / 180) * Math.PI;
  302. target.moveTo(x + (Math.cos(start) * outerRadius), y - (Math.sin(start) * outerRadius));
  303. // draw lines
  304. for (n = 1; n <= points; ++n)
  305. {
  306. dx = x + Math.cos(start + (step * n) - halfStep) * innerRadius;
  307. dy = y - Math.sin(start + (step * n) - halfStep) * innerRadius;
  308. target.lineTo(dx, dy);
  309. dx = x + Math.cos(start + (step * n)) * outerRadius;
  310. dy = y - Math.sin(start + (step * n)) * outerRadius;
  311. target.lineTo(dx, dy);
  312. }
  313. }
  314. }
  315.  
  316. /**
  317. * a method for creating polygon shapes. Negative values will draw
  318. * the polygon in reverse direction. Negative drawing may be useful
  319. * for creating knock-outs in masks.
  320. *
  321. * @param target the Graphics that the polygon is to be drawn on
  322. * @param x x coordinate of the center of the polygon
  323. * @param y y coordinate of the center of the polygon
  324. * @param sides the number of sides (must be > 2)
  325. * @param radius the radius from the center point to the points
  326. * on the polygon
  327. * @param angle [optional] the starting offset angle (degrees) from
  328. * 0. Default = 0
  329. *
  330. * based on mc.drawPoly() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
  331. */
  332. public static function drawPolygon(target:Graphics, x:Number, y:Number, sides:uint, radius:Number, angle:Number=0):void
  333. {
  334.  
  335. // check that sides is sufficient to build
  336. if (sides <= 2)
  337. {
  338. throw ArgumentError("DrawingShapes.drawPolygon() - parameter 'sides' needs to be atleast 3");
  339. return;
  340. }
  341. if (sides > 2)
  342. {
  343. // init vars
  344. var step:Number, start:Number, n:Number, dx:Number, dy:Number;
  345. // calculate span of sides
  346. step = (Math.PI * 2) / sides;
  347. // calculate starting angle in radians
  348. start = (angle / 180) * Math.PI;
  349. target.moveTo(x + (Math.cos(start) * radius), y - (Math.sin(start) * radius));
  350. // draw the polygon
  351. for (n = 1; n <= sides; ++n)
  352. {
  353. dx = x + Math.cos(start + (step * n)) * radius;
  354. dy = y - Math.sin(start + (step * n)) * radius;
  355. target.lineTo(dx, dy);
  356. }
  357. }
  358. }
  359.  
  360. /**
  361. * Burst is a method for drawing star bursts. If you've ever worked
  362. * with an advertising department, you know what they are ;-)
  363. * Clients tend to want them, Developers tend to hate them...
  364. *
  365. * @param target Graphics where the Burst is to be drawn.
  366. * @param x x coordinate of the center of the burst
  367. * @param y y coordinate of the center of the burst
  368. * @param sides number of sides or points
  369. * @param innerRadius radius of the indent of the curves
  370. * @param outerRadius radius of the outermost points
  371. * @param angle [optional] starting angle in degrees. (defaults to 0)
  372. *
  373. * based on mc.drawBurst() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
  374. */
  375. public static function drawBurst(target:Graphics, x:Number, y:Number, sides:uint, innerRadius:Number, outerRadius:Number, angle:Number=0):void
  376. {
  377.  
  378. // check that sides is sufficient to build
  379. if (sides <= 2)
  380. {
  381. throw ArgumentError("DrawingShapes.drawBurst() - parameter 'sides' needs to be atleast 3");
  382. return;
  383. }
  384. if (sides > 2)
  385. {
  386. // init vars
  387. var step:Number, halfStep:Number, qtrStep:Number, start:Number, n:Number, dx:Number, dy:Number, cx:Number, cy:Number;
  388. // calculate length of sides
  389. step = (Math.PI * 2) / sides;
  390. halfStep = step / 2;
  391. qtrStep = step / 4;
  392. // calculate starting angle in radians
  393. start = (angle / 180) * Math.PI;
  394. target.moveTo(x + (Math.cos(start) * outerRadius), y - (Math.sin(start) * outerRadius));
  395. // draw curves
  396. for (n = 1; n <= sides; ++n)
  397. {
  398. cx = x + Math.cos(start + (step * n) - (qtrStep * 3)) * (innerRadius / Math.cos(qtrStep));
  399. cy = y - Math.sin(start + (step * n) - (qtrStep * 3)) * (innerRadius / Math.cos(qtrStep));
  400. dx = x + Math.cos(start + (step * n) - halfStep) * innerRadius;
  401. dy = y - Math.sin(start + (step * n) - halfStep) * innerRadius;
  402. target.curveTo(cx, cy, dx, dy);
  403. cx = x + Math.cos(start + (step * n) - qtrStep) * (innerRadius / Math.cos(qtrStep));
  404. cy = y - Math.sin(start + (step * n) - qtrStep) * (innerRadius / Math.cos(qtrStep));
  405. dx = x + Math.cos(start + (step * n)) * outerRadius;
  406. dy = y - Math.sin(start + (step * n)) * outerRadius;
  407. target.curveTo(cx, cy, dx, dy);
  408. }
  409. }
  410. }
  411.  
  412. /**
  413. * draws a gear shape on the Graphics target. The gear position
  414. * is indicated by the x and y arguments.
  415. *
  416. * @param target Graphics on which the gear is to be drawn.
  417. * @param x x coordinate of the center of the gear
  418. * @param y y coordinate of the center of the gear
  419. * @param sides number of teeth on gear. (must be > 2)
  420. * @param innerRadius radius of the indent of the teeth.
  421. * @param outerRadius outer radius of the teeth.
  422. * @param angle = [optional] starting angle in degrees. Defaults to 0.
  423. * @param holeSides [optional] draw a polygonal hole with this many sides (must be > 2)
  424. * @param holeRadius [optional] size of hole. Default = innerRadius/3.
  425. *
  426. * based on mc.drawGear() - by Ric Ewing (ric at formequalsfunction.com) - version 1.4 - 4.7.2002
  427. */
  428. public static function drawGear(target:Graphics, x:Number, y:Number, sides:uint, innerRadius:Number=80, outerRadius:Number=4, angle:Number=0, holeSides:Number=2, holeRadius:Number=0):void
  429. {
  430.  
  431. // check that sides is sufficient to build polygon
  432. if (sides <= 2)
  433. {
  434. throw ArgumentError("DrawingShapes.drawGear() - parameter 'sides' needs to be atleast 3");
  435. return;
  436. }
  437. if (sides > 2)
  438. {
  439. // init vars
  440. var step:Number, qtrStep:Number, start:Number, n:Number, dx:Number, dy:Number;
  441. // calculate length of sides
  442. step = (Math.PI * 2) / sides;
  443. qtrStep = step / 4;
  444. // calculate starting angle in radians
  445. start = (angle / 180) * Math.PI;
  446. target.moveTo(x + (Math.cos(start) * outerRadius), y - (Math.sin(start) * outerRadius));
  447. // draw lines
  448. for (n = 1; n <= sides; ++n)
  449. {
  450. dx = x + Math.cos(start + (step * n) - (qtrStep * 3)) * innerRadius;
  451. dy = y - Math.sin(start + (step * n) - (qtrStep * 3)) * innerRadius;
  452. target.lineTo(dx, dy);
  453. dx = x + Math.cos(start + (step * n) - (qtrStep * 2)) * innerRadius;
  454. dy = y - Math.sin(start + (step * n) - (qtrStep * 2)) * innerRadius;
  455. target.lineTo(dx, dy);
  456. dx = x + Math.cos(start + (step * n) - qtrStep) * outerRadius;
  457. dy = y - Math.sin(start + (step * n) - qtrStep) * outerRadius;
  458. target.lineTo(dx, dy);
  459. dx = x + Math.cos(start + (step * n)) * outerRadius;
  460. dy = y - Math.sin(start + (step * n)) * outerRadius;
  461. target.lineTo(dx, dy);
  462. }
  463. // This is complete overkill... but I had it done already. :)
  464. if (holeSides > 2)
  465. {
  466. step = (Math.PI * 2) / holeSides;
  467. target.moveTo(x + (Math.cos(start) * holeRadius), y - (Math.sin(start) * holeRadius));
  468. for (n = 1; n <= holeSides; ++n)
  469. {
  470. dx = x + Math.cos(start + (step * n)) * holeRadius;
  471. dy = y - Math.sin(start + (step * n)) * holeRadius;
  472. target.lineTo(dx, dy);
  473. }
  474. }
  475. }
  476. }
  477.  
  478. /**
  479. * draws a line between two points. Make it horizontal or vertical
  480. *
  481. * @param target Graphics on which the gear is to be drawn.
  482. * @param x x coordinate of the center of the gear
  483. * @param y y coordinate of the center of the gear
  484. * @param sides number of teeth on gear. (must be > 2)
  485. *
  486. *
  487. */
  488. public static function drawLine(target:Graphics, x:Number, y:Number, length:Number, direction:String=DrawingShapes.HORIZONTAL_LINE):void
  489. {
  490. target.moveTo(x, y);
  491. switch (direction)
  492. {
  493. case DrawingShapes.HORIZONTAL_LINE:
  494. target.lineTo(length, y);
  495. break;
  496. case DrawingShapes.VERTICAL_LINE:
  497. target.moveTo(x, y);
  498. target.lineTo(x, length);
  499. break;
  500. }
  501. }
  502.  
  503. /*
  504. * new abs function, about 25x faster than Math.abs
  505. */
  506. private static function abs(value:Number):Number
  507. {
  508. return value < 0 ? -value : value;
  509. }
  510.  
  511. /*
  512. * new ceil function about 75% faster than Math.ceil.
  513. */
  514. private static function ceil(value:Number):Number
  515. {
  516. return (value % 1) ? int(value) + 1 : value;
  517. }
  518. }
  519. }

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.