/frameworks/projects/spark/src/spark/primitives/Ellipse.as
ActionScript | 347 lines | 189 code | 50 blank | 108 comment | 36 complexity | 6b4cc9381a945d76771a9d614725b3b1 MD5 | raw file
- ////////////////////////////////////////////////////////////////////////////////
- //
- // ADOBE SYSTEMS INCORPORATED
- // Copyright 2008 Adobe Systems Incorporated
- // All Rights Reserved.
- //
- // NOTICE: Adobe permits you to use, modify, and distribute this file
- // in accordance with the terms of the license agreement accompanying it.
- //
- ////////////////////////////////////////////////////////////////////////////////
-
- package spark.primitives
- {
-
- import flash.display.Graphics;
- import flash.geom.Matrix;
- import flash.geom.Point;
- import flash.geom.Rectangle;
-
- import mx.core.mx_internal;
- import mx.utils.MatrixUtil;
-
- import spark.primitives.supportClasses.FilledElement;
-
- use namespace mx_internal;
-
- /**
- * The Ellipse class is a filled graphic element that draws an ellipse.
- * To draw the ellipse, this class calls the <code>Graphics.drawEllipse()</code>
- * method.
- *
- * @see flash.display.Graphics
- *
- * @includeExample examples/EllipseExample.mxml
- *
- * @langversion 3.0
- * @playerversion Flash 10
- * @playerversion AIR 1.5
- * @productversion Flex 4
- */
- public class Ellipse extends FilledElement
- {
- include "../core/Version.as";
-
- //--------------------------------------------------------------------------
- //
- // Constructor
- //
- //--------------------------------------------------------------------------
-
- /**
- * Constructor.
- *
- * @langversion 3.0
- * @playerversion Flash 10
- * @playerversion AIR 1.5
- * @productversion Flex 4
- */
- public function Ellipse()
- {
- super();
- }
-
- //--------------------------------------------------------------------------
- //
- // Properties
- //
- //--------------------------------------------------------------------------
-
- //--------------------------------------------------------------------------
- //
- // Overridden methods
- //
- //--------------------------------------------------------------------------
-
- /**
- * @inheritDoc
- *
- * @langversion 3.0
- * @playerversion Flash 10
- * @playerversion AIR 1.5
- * @productversion Flex 4
- */
- override protected function draw(g:Graphics):void
- {
- g.drawEllipse(drawX, drawY, width, height);
- }
-
- /**
- * @private
- */
- override protected function transformWidthForLayout(width:Number,
- height:Number,
- postLayoutTransform:Boolean = true):Number
- {
- if (postLayoutTransform && hasComplexLayoutMatrix)
- width = MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
- layoutFeatures.layoutMatrix).width;
-
- // Take stroke into account
- return width + getStrokeExtents(postLayoutTransform).width;
- }
-
- /**
- * @private
- */
- override protected function transformHeightForLayout(width:Number,
- height:Number,
- postLayoutTransform:Boolean = true):Number
- {
- if (postLayoutTransform && hasComplexLayoutMatrix)
- height = MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
- layoutFeatures.layoutMatrix).height;
-
- // Take stroke into account
- return height + getStrokeExtents(postLayoutTransform).height;
- }
-
- /**
- * @inheritDoc
- *
- * @langversion 3.0
- * @playerversion Flash 10
- * @playerversion AIR 1.5
- * @productversion Flex 4
- */
- override public function getBoundsXAtSize(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
- {
- var strokeExtents:Rectangle = getStrokeExtents(postLayoutTransform);
- var m:Matrix = getComplexMatrix(postLayoutTransform);
- if (!m)
- return strokeExtents.left + this.x;
-
- if (!isNaN(width))
- width -= strokeExtents.width;
- if (!isNaN(height))
- height -= strokeExtents.height;
-
- // Calculate the width and height pre-transform:
- var newSize:Point = MatrixUtil.fitBounds(width, height, m,
- explicitWidth, explicitHeight,
- preferredWidthPreTransform(),
- preferredHeightPreTransform(),
- minWidth, minHeight,
- maxWidth, maxHeight);
- if (!newSize)
- newSize = new Point(minWidth, minHeight);
-
- return strokeExtents.left +
- MatrixUtil.getEllipseBoundingBox(newSize.x / 2, newSize.y / 2, newSize.x / 2, newSize.y / 2, m).x;
- }
-
- /**
- * @inheritDoc
- *
- * @langversion 3.0
- * @playerversion Flash 10
- * @playerversion AIR 1.5
- * @productversion Flex 4
- */
- override public function getBoundsYAtSize(width:Number, height:Number, postLayoutTransform:Boolean = true):Number
- {
- var strokeExtents:Rectangle = getStrokeExtents(postLayoutTransform);
- var m:Matrix = getComplexMatrix(postLayoutTransform);
- if (!m)
- return strokeExtents.top + this.y;
-
- if (!isNaN(width))
- width -= strokeExtents.width;
- if (!isNaN(height))
- height -= strokeExtents.height;
-
- // Calculate the width and height pre-transform:
- var newSize:Point = MatrixUtil.fitBounds(width, height, m,
- explicitWidth, explicitHeight,
- preferredWidthPreTransform(),
- preferredHeightPreTransform(),
- minWidth, minHeight,
- maxWidth, maxHeight);
- if (!newSize)
- newSize = new Point(minWidth, minHeight);
-
- return strokeExtents.top +
- MatrixUtil.getEllipseBoundingBox(newSize.x / 2, newSize.y / 2, newSize.x / 2, newSize.y / 2, m).y;
- }
-
- /**
- * @private
- */
- override public function getLayoutBoundsX(postLayoutTransform:Boolean = true):Number
- {
- var stroke:Number = getStrokeExtents(postLayoutTransform).left;
-
- if (postLayoutTransform && hasComplexLayoutMatrix)
- return stroke + MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
- layoutFeatures.layoutMatrix).x;
-
- return stroke + this.x;
- }
-
- /**
- * @private
- */
- override public function getLayoutBoundsY(postLayoutTransform:Boolean = true):Number
- {
- var stroke:Number = getStrokeExtents(postLayoutTransform).top;
-
- if (postLayoutTransform && hasComplexLayoutMatrix)
- return stroke + MatrixUtil.getEllipseBoundingBox(width / 2, height / 2, width / 2, height / 2,
- layoutFeatures.layoutMatrix).y;
-
- return stroke + this.y;
- }
-
- /**
- * @private
- * Returns the bounding box of the transformed ellipse(width, height) with matrix m.
- */
- private function getBoundingBox(width:Number, height:Number, m:Matrix):Rectangle
- {
- return MatrixUtil.getEllipseBoundingBox(0, 0, width / 2, height / 2, m);
- }
-
- /**
- * @private
- */
- override public function setLayoutBoundsSize(width:Number,
- height:Number,
- postLayoutTransform:Boolean = true):void
- {
- var m:Matrix = getComplexMatrix(postLayoutTransform);
- if (!m)
- {
- super.setLayoutBoundsSize(width, height, postLayoutTransform);
- return;
- }
-
- setLayoutBoundsTransformed(width, height, m);
- }
-
- /**
- * @private
- */
- private function setLayoutBoundsTransformed(width:Number, height:Number, m:Matrix):void
- {
- var strokeExtents:Rectangle = getStrokeExtents(true);
- width -= strokeExtents.width;
- height -= strokeExtents.height;
-
- var size:Point = fitLayoutBoundsIterative(width, height, m);
-
- // We couldn't find a solution, try to relax the constraints
- if (!size && !isNaN(width) && !isNaN(height))
- {
- // Try without width constraint
- var size1:Point = fitLayoutBoundsIterative(NaN, height, m);
-
- // Try without height constraint
- var size2:Point = fitLayoutBoundsIterative(width, NaN, m);
-
- // Ignore solutions that will exceed the requested size
- if (size1 && getBoundingBox(size1.x, size1.y, m).width > width)
- size1 = null;
- if (size2 && getBoundingBox(size2.x, size2.y, m).height > height)
- size2 = null;
-
- // Which size was better?
- if (size1 && size2)
- {
- var pickSize1:Boolean = size1.x * size1.y > size2.x * size2.y;
-
- if (pickSize1)
- size = size1;
- else
- size = size2;
- }
- else if (size1)
- {
- size = size1;
- }
- else
- {
- size = size2;
- }
- }
-
- if (size)
- setActualSize(size.x, size.y);
- else
- setActualSize(minWidth, minHeight);
- }
-
- /**
- * Iteratively approach a solution. Returns 0 if no exact solution exists.
- * NaN values for width/height mean "not constrained" in that dimesion.
- *
- * @private
- */
- private function fitLayoutBoundsIterative(width:Number, height:Number, m:Matrix):Point
- {
- var newWidth:Number = this.preferredWidthPreTransform();
- var newHeight:Number = this.preferredHeightPreTransform();
- var fitWidth:Number = MatrixUtil.transformBounds(newWidth, newHeight, m).x;
- var fitHeight:Number = MatrixUtil.transformBounds(newWidth, newHeight, m).y;
-
- if (isNaN(width))
- fitWidth = NaN;
- if (isNaN(height))
- fitHeight = NaN;
-
- var i:int = 0;
- while (i++ < 150)
- {
- var postTransformBounds:Rectangle = getBoundingBox(newWidth, newHeight, m);
-
- var widthDifference:Number = isNaN(width) ? 0 : width - postTransformBounds.width;
- var heightDifference:Number = isNaN(height) ? 0 : height - postTransformBounds.height;
-
- if (Math.abs(widthDifference) < 0.1 && Math.abs(heightDifference) < 0.1)
- {
- return new Point(newWidth, newHeight);
- }
-
- fitWidth += widthDifference * 0.5;
- fitHeight += heightDifference * 0.5;
-
- var newSize:Point = MatrixUtil.fitBounds(fitWidth,
- fitHeight,
- m,
- explicitWidth,
- explicitHeight,
- preferredWidthPreTransform(),
- preferredHeightPreTransform(),
- minWidth, minHeight,
- maxWidth, maxHeight);
-
- if (!newSize)
- break;
-
- newWidth = newSize.x;
- newHeight = newSize.y;
- }
-
- return null;
- }
- }
- }