blob: fd7e58de68a61cbb0c78d059db9002358d1eef67 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.utils
{
import flash.display.Graphics;
/**
* The Graphics class is an all-static class with utility methods
* related to the Graphics class.
* You do not create instances of GraphicsUtil;
* instead you simply call methods such as the
* <code>GraphicsUtil.drawRoundRectComplex()</code> method.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class GraphicsUtil
{
include "../core/Version.as";
//--------------------------------------------------------------------------
//
// Class methods
//
//--------------------------------------------------------------------------
/**
* Draws a rounded rectangle using the size of a radius to draw the rounded corners.
* You must set the line style, fill, or both
* on the Graphics object before
* you call the <code>drawRoundRectComplex()</code> method
* by calling the <code>linestyle()</code>,
* <code>lineGradientStyle()</code>, <code>beginFill()</code>,
* <code>beginGradientFill()</code>, or
* <code>beginBitmapFill()</code> method.
*
* @param graphics The Graphics object that draws the rounded rectangle.
*
* @param x The horizontal position relative to the
* registration point of the parent display object, in pixels.
*
* @param y The vertical position relative to the
* registration point of the parent display object, in pixels.
*
* @param width The width of the round rectangle, in pixels.
*
* @param height The height of the round rectangle, in pixels.
*
* @param topLeftRadius The radius of the upper-left corner, in pixels.
*
* @param topRightRadius The radius of the upper-right corner, in pixels.
*
* @param bottomLeftRadius The radius of the bottom-left corner, in pixels.
*
* @param bottomRightRadius The radius of the bottom-right corner, in pixels.
*
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public static function drawRoundRectComplex(graphics:Graphics, x:Number, y:Number,
width:Number, height:Number,
topLeftRadius:Number, topRightRadius:Number,
bottomLeftRadius:Number, bottomRightRadius:Number):void
{
var xw:Number = x + width;
var yh:Number = y + height;
// Make sure none of the radius values are greater than w/h.
// These are all inlined to avoid function calling overhead
var minSize:Number = width < height ? width * 2 : height * 2;
topLeftRadius = topLeftRadius < minSize ? topLeftRadius : minSize;
topRightRadius = topRightRadius < minSize ? topRightRadius : minSize;
bottomLeftRadius = bottomLeftRadius < minSize ? bottomLeftRadius : minSize;
bottomRightRadius = bottomRightRadius < minSize ? bottomRightRadius : minSize;
// Math.sin and Math,tan values for optimal performance.
// Math.rad = Math.PI / 180 = 0.0174532925199433
// r * Math.sin(45 * Math.rad) = (r * 0.707106781186547);
// r * Math.tan(22.5 * Math.rad) = (r * 0.414213562373095);
//
// We can save further cycles by precalculating
// 1.0 - 0.707106781186547 = 0.292893218813453 and
// 1.0 - 0.414213562373095 = 0.585786437626905
// bottom-right corner
var a:Number = bottomRightRadius * 0.292893218813453; // radius - anchor pt;
var s:Number = bottomRightRadius * 0.585786437626905; // radius - control pt;
graphics.moveTo(xw, yh - bottomRightRadius);
graphics.curveTo(xw, yh - s, xw - a, yh - a);
graphics.curveTo(xw - s, yh, xw - bottomRightRadius, yh);
// bottom-left corner
a = bottomLeftRadius * 0.292893218813453;
s = bottomLeftRadius * 0.585786437626905;
graphics.lineTo(x + bottomLeftRadius, yh);
graphics.curveTo(x + s, yh, x + a, yh - a);
graphics.curveTo(x, yh - s, x, yh - bottomLeftRadius);
// top-left corner
a = topLeftRadius * 0.292893218813453;
s = topLeftRadius * 0.585786437626905;
graphics.lineTo(x, y + topLeftRadius);
graphics.curveTo(x, y + s, x + a, y + a);
graphics.curveTo(x + s, y, x + topLeftRadius, y);
// top-right corner
a = topRightRadius * 0.292893218813453;
s = topRightRadius * 0.585786437626905;
graphics.lineTo(xw - topRightRadius, y);
graphics.curveTo(xw - s, y, xw - a, y + a);
graphics.curveTo(xw, y + s, xw, y + topRightRadius);
graphics.lineTo(xw, yh - bottomRightRadius);
}
/**
* Draws a rounded rectangle using the size of individual x and y radii to
* draw the rounded corners.
* You must set the line style, fill, or both
* on the Graphics object before
* you call the <code>drawRoundRectComplex2()</code> method
* by calling the <code>linestyle()</code>,
* <code>lineGradientStyle()</code>, <code>beginFill()</code>,
* <code>beginGradientFill()</code>, or
* <code>beginBitmapFill()</code> method.
*
* @param graphics The Graphics object that draws the rounded rectangle.
*
* @param x The horizontal position relative to the
* registration point of the parent display object, in pixels.
*
* @param y The vertical position relative to the
* registration point of the parent display object, in pixels.
*
* @param width The width of the round rectangle, in pixels.
*
* @param height The height of the round rectangle, in pixels.
*
* @param radiusX The default radiusX to use, if corner-specific values are not specified.
* This value must be specified.
*
* @param radiusY The default radiusY to use, if corner-specific values are not specified.
* If 0, the value of radiusX is used.
*
* @param topLeftRadiusX The x radius of the upper-left corner, in pixels. If NaN,
* the value of radiusX is used.
*
* @param topLeftRadiusY The y radius of the upper-left corner, in pixels. If NaN,
* the value of topLeftRadiusX is used.
*
* @param topRightRadiusX The x radius of the upper-right corner, in pixels. If NaN,
* the value of radiusX is used.
*
* @param topRightRadiusY The y radius of the upper-right corner, in pixels. If NaN,
* the value of topRightRadiusX is used.
*
* @param bottomLeftRadiusX The x radius of the bottom-left corner, in pixels. If NaN,
* the value of radiusX is used.
*
* @param bottomLeftRadiusY The y radius of the bottom-left corner, in pixels. If NaN,
* the value of bottomLeftRadiusX is used.
*
* @param bottomRightRadiusX The x radius of the bottom-right corner, in pixels. If NaN,
* the value of radiusX is used.
*
* @param bottomRightRadiusY The y radius of the bottom-right corner, in pixels. If NaN,
* the value of bottomRightRadiusX is used.
*
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public static function drawRoundRectComplex2(graphics:Graphics, x:Number, y:Number,
width:Number, height:Number,
radiusX:Number, radiusY:Number,
topLeftRadiusX:Number, topLeftRadiusY:Number,
topRightRadiusX:Number, topRightRadiusY:Number,
bottomLeftRadiusX:Number, bottomLeftRadiusY:Number,
bottomRightRadiusX:Number, bottomRightRadiusY:Number):void
{
var xw:Number = x + width;
var yh:Number = y + height;
var maxXRadius:Number = width / 2;
var maxYRadius:Number = height / 2;
// Rules for determining radius for each corner:
// - If explicit nnnRadiusX value is set, use it. Otherwise use radiusX.
// - If explicit nnnRadiusY value is set, use it. Otherwise use corresponding nnnRadiusX.
if (radiusY == 0)
radiusY = radiusX;
if (isNaN(topLeftRadiusX))
topLeftRadiusX = radiusX;
if (isNaN(topLeftRadiusY))
topLeftRadiusY = topLeftRadiusX;
if (isNaN(topRightRadiusX))
topRightRadiusX = radiusX;
if (isNaN(topRightRadiusY))
topRightRadiusY = topRightRadiusX;
if (isNaN(bottomLeftRadiusX))
bottomLeftRadiusX = radiusX;
if (isNaN(bottomLeftRadiusY))
bottomLeftRadiusY = bottomLeftRadiusX;
if (isNaN(bottomRightRadiusX))
bottomRightRadiusX = radiusX;
if (isNaN(bottomRightRadiusY))
bottomRightRadiusY = bottomRightRadiusX;
// Pin radius values to half of the width/height
if (topLeftRadiusX > maxXRadius)
topLeftRadiusX = maxXRadius;
if (topLeftRadiusY > maxYRadius)
topLeftRadiusY = maxYRadius;
if (topRightRadiusX > maxXRadius)
topRightRadiusX = maxXRadius;
if (topRightRadiusY > maxYRadius)
topRightRadiusY = maxYRadius;
if (bottomLeftRadiusX > maxXRadius)
bottomLeftRadiusX = maxXRadius;
if (bottomLeftRadiusY > maxYRadius)
bottomLeftRadiusY = maxYRadius;
if (bottomRightRadiusX > maxXRadius)
bottomRightRadiusX = maxXRadius;
if (bottomRightRadiusY > maxYRadius)
bottomRightRadiusY = maxYRadius;
// Math.sin and Math,tan values for optimal performance.
// Math.rad = Math.PI / 180 = 0.0174532925199433
// r * Math.sin(45 * Math.rad) = (r * 0.707106781186547);
// r * Math.tan(22.5 * Math.rad) = (r * 0.414213562373095);
//
// We can save further cycles by precalculating
// 1.0 - 0.707106781186547 = 0.292893218813453 and
// 1.0 - 0.414213562373095 = 0.585786437626905
// bottom-right corner
var aX:Number = bottomRightRadiusX * 0.292893218813453; // radius - anchor pt;
var aY:Number = bottomRightRadiusY * 0.292893218813453; // radius - anchor pt;
var sX:Number = bottomRightRadiusX * 0.585786437626905; // radius - control pt;
var sY:Number = bottomRightRadiusY * 0.585786437626905; // radius - control pt;
graphics.moveTo(xw, yh - bottomRightRadiusY);
graphics.curveTo(xw, yh - sY, xw - aX, yh - aY);
graphics.curveTo(xw - sX, yh, xw - bottomRightRadiusX, yh);
// bottom-left corner
aX = bottomLeftRadiusX * 0.292893218813453;
aY = bottomLeftRadiusY * 0.292893218813453;
sX = bottomLeftRadiusX * 0.585786437626905;
sY = bottomLeftRadiusY * 0.585786437626905;
graphics.lineTo(x + bottomLeftRadiusX, yh);
graphics.curveTo(x + sX, yh, x + aX, yh - aY);
graphics.curveTo(x, yh - sY, x, yh - bottomLeftRadiusY);
// top-left corner
aX = topLeftRadiusX * 0.292893218813453;
aY = topLeftRadiusY * 0.292893218813453;
sX = topLeftRadiusX * 0.585786437626905;
sY = topLeftRadiusY * 0.585786437626905;
graphics.lineTo(x, y + topLeftRadiusY);
graphics.curveTo(x, y + sY, x + aX, y + aY);
graphics.curveTo(x + sX, y, x + topLeftRadiusX, y);
// top-right corner
aX = topRightRadiusX * 0.292893218813453;
aY = topRightRadiusY * 0.292893218813453;
sX = topRightRadiusX * 0.585786437626905;
sY = topRightRadiusY * 0.585786437626905;
graphics.lineTo(xw - topRightRadiusX, y);
graphics.curveTo(xw - sX, y, xw - aX, y + aY);
graphics.curveTo(xw, y + sY, xw, y + topRightRadiusY);
graphics.lineTo(xw, yh - bottomRightRadiusY);
}
}
}