PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/frameworks/projects/spark/src/spark/primitives/Ellipse.as

https://github.com/bigbangtechnology/flex
ActionScript | 347 lines | 189 code | 50 blank | 108 comment | 36 complexity | 6b4cc9381a945d76771a9d614725b3b1 MD5 | raw file
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // ADOBE SYSTEMS INCORPORATED
  4. // Copyright 2008 Adobe Systems Incorporated
  5. // All Rights Reserved.
  6. //
  7. // NOTICE: Adobe permits you to use, modify, and distribute this file
  8. // in accordance with the terms of the license agreement accompanying it.
  9. //
  10. ////////////////////////////////////////////////////////////////////////////////
  11. package spark.primitives
  12. {
  13. import flash.display.Graphics;
  14. import flash.geom.Matrix;
  15. import flash.geom.Point;
  16. import flash.geom.Rectangle;
  17. import mx.core.mx_internal;
  18. import mx.utils.MatrixUtil;
  19. import spark.primitives.supportClasses.FilledElement;
  20. use namespace mx_internal;
  21. /**
  22. * The Ellipse class is a filled graphic element that draws an ellipse.
  23. * To draw the ellipse, this class calls the <code>Graphics.drawEllipse()</code>
  24. * method.
  25. *
  26. * @see flash.display.Graphics
  27. *
  28. * @includeExample examples/EllipseExample.mxml
  29. *
  30. * @langversion 3.0
  31. * @playerversion Flash 10
  32. * @playerversion AIR 1.5
  33. * @productversion Flex 4
  34. */
  35. public class Ellipse extends FilledElement
  36. {
  37. include "../core/Version.as";
  38. //--------------------------------------------------------------------------
  39. //
  40. // Constructor
  41. //
  42. //--------------------------------------------------------------------------
  43. /**
  44. * Constructor.
  45. *
  46. * @langversion 3.0
  47. * @playerversion Flash 10
  48. * @playerversion AIR 1.5
  49. * @productversion Flex 4
  50. */
  51. public function Ellipse()
  52. {
  53. super();
  54. }
  55. //--------------------------------------------------------------------------
  56. //
  57. // Properties
  58. //
  59. //--------------------------------------------------------------------------
  60. //--------------------------------------------------------------------------
  61. //
  62. // Overridden methods
  63. //
  64. //--------------------------------------------------------------------------
  65. /**
  66. * @inheritDoc
  67. *
  68. * @langversion 3.0
  69. * @playerversion Flash 10
  70. * @playerversion AIR 1.5
  71. * @productversion Flex 4
  72. */
  73. override protected function draw(g:Graphics):void
  74. {
  75. g.drawEllipse(drawX, drawY, width, height);
  76. }
  77. /**
  78. * @private
  79. */
  80. override protected function transformWidthForLayout(width:Number,
  81. height:Number,
  82. postLayoutTransform:Boolean = true):Number
  83. {
  84. if (postLayoutTransform && hasComplexLayoutMatrix)
  85. width = MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
  86. layoutFeatures.layoutMatrix).width;
  87. // Take stroke into account
  88. return width + getStrokeExtents(postLayoutTransform).width;
  89. }
  90. /**
  91. * @private
  92. */
  93. override protected function transformHeightForLayout(width:Number,
  94. height:Number,
  95. postLayoutTransform:Boolean = true):Number
  96. {
  97. if (postLayoutTransform && hasComplexLayoutMatrix)
  98. height = MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
  99. layoutFeatures.layoutMatrix).height;
  100. // Take stroke into account
  101. return height + getStrokeExtents(postLayoutTransform).height;
  102. }
  103. /**
  104. * @inheritDoc
  105. *
  106. * @langversion 3.0
  107. * @playerversion Flash 10
  108. * @playerversion AIR 1.5
  109. * @productversion Flex 4
  110. */
  111. override public function getBoundsXAtSize(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
  112. {
  113. var strokeExtents:Rectangle = getStrokeExtents(postLayoutTransform);
  114. var m:Matrix = getComplexMatrix(postLayoutTransform);
  115. if (!m)
  116. return strokeExtents.left + this.x;
  117. if (!isNaN(width))
  118. width -= strokeExtents.width;
  119. if (!isNaN(height))
  120. height -= strokeExtents.height;
  121. // Calculate the width and height pre-transform:
  122. var newSize:Point = MatrixUtil.fitBounds(width, height, m,
  123. explicitWidth, explicitHeight,
  124. preferredWidthPreTransform(),
  125. preferredHeightPreTransform(),
  126. minWidth, minHeight,
  127. maxWidth, maxHeight);
  128. if (!newSize)
  129. newSize = new Point(minWidth, minHeight);
  130. return strokeExtents.left +
  131. MatrixUtil.getEllipseBoundingBox(newSize.x / 2, newSize.y / 2, newSize.x / 2, newSize.y / 2, m).x;
  132. }
  133. /**
  134. * @inheritDoc
  135. *
  136. * @langversion 3.0
  137. * @playerversion Flash 10
  138. * @playerversion AIR 1.5
  139. * @productversion Flex 4
  140. */
  141. override public function getBoundsYAtSize(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
  142. {
  143. var strokeExtents:Rectangle = getStrokeExtents(postLayoutTransform);
  144. var m:Matrix = getComplexMatrix(postLayoutTransform);
  145. if (!m)
  146. return strokeExtents.top + this.y;
  147. if (!isNaN(width))
  148. width -= strokeExtents.width;
  149. if (!isNaN(height))
  150. height -= strokeExtents.height;
  151. // Calculate the width and height pre-transform:
  152. var newSize:Point = MatrixUtil.fitBounds(width, height, m,
  153. explicitWidth, explicitHeight,
  154. preferredWidthPreTransform(),
  155. preferredHeightPreTransform(),
  156. minWidth, minHeight,
  157. maxWidth, maxHeight);
  158. if (!newSize)
  159. newSize = new Point(minWidth, minHeight);
  160. return strokeExtents.top +
  161. MatrixUtil.getEllipseBoundingBox(newSize.x / 2, newSize.y / 2, newSize.x / 2, newSize.y / 2, m).y;
  162. }
  163. /**
  164. * @private
  165. */
  166. override public function getLayoutBoundsX(postLayoutTransform:Boolean = true):Number
  167. {
  168. var stroke:Number = getStrokeExtents(postLayoutTransform).left;
  169. if (postLayoutTransform && hasComplexLayoutMatrix)
  170. return stroke + MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
  171. layoutFeatures.layoutMatrix).x;
  172. return stroke + this.x;
  173. }
  174. /**
  175. * @private
  176. */
  177. override public function getLayoutBoundsY(postLayoutTransform:Boolean = true):Number
  178. {
  179. var stroke:Number = getStrokeExtents(postLayoutTransform).top;
  180. if (postLayoutTransform && hasComplexLayoutMatrix)
  181. return stroke + MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
  182. layoutFeatures.layoutMatrix).y;
  183. return stroke + this.y;
  184. }
  185. /**
  186. * @private
  187. * Returns the bounding box of the transformed ellipse(width, height) with matrix m.
  188. */
  189. private function getBoundingBox(width:Number, height:Number, m:Matrix):Rectangle
  190. {
  191. return MatrixUtil.getEllipseBoundingBox(0, 0, width / 2, height / 2, m);
  192. }
  193. /**
  194. * @private
  195. */
  196. override public function setLayoutBoundsSize(width:Number,
  197. height:Number,
  198. postLayoutTransform:Boolean = true):void
  199. {
  200. var m:Matrix = getComplexMatrix(postLayoutTransform);
  201. if (!m)
  202. {
  203. super.setLayoutBoundsSize(width, height, postLayoutTransform);
  204. return;
  205. }
  206. setLayoutBoundsTransformed(width, height, m);
  207. }
  208. /**
  209. * @private
  210. */
  211. private function setLayoutBoundsTransformed(width:Number, height:Number, m:Matrix):void
  212. {
  213. var strokeExtents:Rectangle = getStrokeExtents(true);
  214. width -= strokeExtents.width;
  215. height -= strokeExtents.height;
  216. var size:Point = fitLayoutBoundsIterative(width, height, m);
  217. // We couldn't find a solution, try to relax the constraints
  218. if (!size && !isNaN(width) && !isNaN(height))
  219. {
  220. // Try without width constraint
  221. var size1:Point = fitLayoutBoundsIterative(NaN, height, m);
  222. // Try without height constraint
  223. var size2:Point = fitLayoutBoundsIterative(width, NaN, m);
  224. // Ignore solutions that will exceed the requested size
  225. if (size1 && getBoundingBox(size1.x, size1.y, m).width > width)
  226. size1 = null;
  227. if (size2 && getBoundingBox(size2.x, size2.y, m).height > height)
  228. size2 = null;
  229. // Which size was better?
  230. if (size1 && size2)
  231. {
  232. var pickSize1:Boolean = size1.x * size1.y > size2.x * size2.y;
  233. if (pickSize1)
  234. size = size1;
  235. else
  236. size = size2;
  237. }
  238. else if (size1)
  239. {
  240. size = size1;
  241. }
  242. else
  243. {
  244. size = size2;
  245. }
  246. }
  247. if (size)
  248. setActualSize(size.x, size.y);
  249. else
  250. setActualSize(minWidth, minHeight);
  251. }
  252. /**
  253. * Iteratively approach a solution. Returns 0 if no exact solution exists.
  254. * NaN values for width/height mean "not constrained" in that dimesion.
  255. *
  256. * @private
  257. */
  258. private function fitLayoutBoundsIterative(width:Number, height:Number, m:Matrix):Point
  259. {
  260. var newWidth:Number = this.preferredWidthPreTransform();
  261. var newHeight:Number = this.preferredHeightPreTransform();
  262. var fitWidth:Number = MatrixUtil.transformBounds(newWidth, newHeight, m).x;
  263. var fitHeight:Number = MatrixUtil.transformBounds(newWidth, newHeight, m).y;
  264. if (isNaN(width))
  265. fitWidth = NaN;
  266. if (isNaN(height))
  267. fitHeight = NaN;
  268. var i:int = 0;
  269. while (i++ < 150)
  270. {
  271. var postTransformBounds:Rectangle = getBoundingBox(newWidth, newHeight, m);
  272. var widthDifference:Number = isNaN(width) ? 0 : width - postTransformBounds.width;
  273. var heightDifference:Number = isNaN(height) ? 0 : height - postTransformBounds.height;
  274. if (Math.abs(widthDifference) < 0.1 && Math.abs(heightDifference) < 0.1)
  275. {
  276. return new Point(newWidth, newHeight);
  277. }
  278. fitWidth += widthDifference * 0.5;
  279. fitHeight += heightDifference * 0.5;
  280. var newSize:Point = MatrixUtil.fitBounds(fitWidth,
  281. fitHeight,
  282. m,
  283. explicitWidth,
  284. explicitHeight,
  285. preferredWidthPreTransform(),
  286. preferredHeightPreTransform(),
  287. minWidth, minHeight,
  288. maxWidth, maxHeight);
  289. if (!newSize)
  290. break;
  291. newWidth = newSize.x;
  292. newHeight = newSize.y;
  293. }
  294. return null;
  295. }
  296. }
  297. }