//////////////////////////////////////////////////////////////////////////////// // // 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 * GraphicsUtil.drawRoundRectComplex() 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 drawRoundRectComplex() method * by calling the linestyle(), * lineGradientStyle(), beginFill(), * beginGradientFill(), or * beginBitmapFill() 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 drawRoundRectComplex2() method * by calling the linestyle(), * lineGradientStyle(), beginFill(), * beginGradientFill(), or * beginBitmapFill() 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); } } }