When one branches beyond the simple shapes built into the ActionScript language, one has to face the issue of creating and filling some odd-looking shapes. The main example in Chapter 3 of our book on "Flash and Math Applets" consists of filling a circular segment -- that is, we want to draw and fill a partial circle. This how-to will show the trick used in this example and will apply the same trick to produce a small improvement over this simple application.

Download

Download the well-commented fla file for this tutorial from the link below.

The code for FilledCircle.fla

The secret here is to draw a filled shape that gives the illusion of filling the circular sector. In reality, at each step we are drawing part of a filled 360-sided polygon — the speed in which this can be cleared and redrawn gives the perfect effect of interactive motion. The reader should know that the textboxes txtCoords, txtArea, and txtDegrees are created at authoring time, as are the buttons btnMore and btnLess. Open the accompanying fla file to see how these are positioned and initialized.

The script starts with several numerical settings that a programmer might want to adjust, placed for convenience at the beginning of the code.

var degree:Number = 0; **// Initial angle**

var degChange:Number = 1; **// Amount angle will change on each click**

var circleR:Number = 100; **// Circle radius (in pixels)**

var circleX:Number = 180; **// Screen coordinates of center of circle**

var circleY:Number = 180;

var angleR:Number = circleR/4; **// Radius of circular arc that illustrates the angle**

We make a Sprite called spBoard on which to place the other elements. This way, changing the x and y properties of spBoard will reposition it along with all of its children.

var spBoard:Sprite = new Sprite();

spBoard.x = circleX;

spBoard.y = circleY;

addChild(spBoard);

We create all of the Shapes that we will use, we draw in them, and then we add them as children to spBoard in the order we want them layered. The shCircle Shape is self-explanatory (the perimeter of a circle), the Shape shFill will eventually be our circular sector, and shAngle will be the circular arc that sweeps out the angle. Like spBoard, the Shape object shArrow (the little cursor that looks like an arrowhead) is only drawn once. By drawing the arrow relative to the (0,0) point on spBoard, we will be able to accomplish the desired rotation effect via simple change of the shArrow.rotation property.

var shCircle:Shape = new Shape();

shCircle.graphics.lineStyle(2,0x000000);

shCircle.graphics.drawCircle(0,0,circleR);

shCircle.x = 0;

shCircle.y = 0;

var shFill:Shape = new Shape();

shFill.graphics.lineStyle(1,0x000000);

shFill.graphics.moveTo(0,0);

shFill.graphics.lineTo(circleR,0);

shFill.x = 0;

shFill.y = 0;

var shAngle:Shape = new Shape();

var shArrow:Shape = new Shape();

shArrow.graphics.lineStyle();

shArrow.graphics.beginFill(0x000000);

shArrow.graphics.moveTo(angleR,1);

shArrow.graphics.lineTo(angleR-5,8);

shArrow.graphics.lineTo(angleR+5,8);

shArrow.graphics.lineTo(angleR,1);

shArrow.graphics.endFill();

spBoard.addChild(shFill);

spBoard.addChild(shAngle);

spBoard.addChild(shArrow);

spBoard.addChild(shCircle);

The heart of the program is the function updatePicture to do more than just rotate the radial line. At each step we clear all the graphics from shFill and then redraw an entirely new picture composed of an appropriate number of sides of a 360-sided polygon inscribed in our circle. This will give the appearance of filling the circular region. Similarly, we draw the "circular" arc shAngle as part of a smaller 360-sided polygon.

function updatePicture(t:Number):void {

var radianAngle:Number = t*Math.PI/180.0;

var i:int;

shFill.graphics.clear();

shAngle.graphics.clear();

shFill.graphics.lineStyle(1,0x000000);

shAngle.graphics.lineStyle(1,0x000000);

shFill.graphics.moveTo(0,0);

shAngle.graphics.moveTo(angleR,0);

shFill.graphics.beginFill(0xFF00FF,0.7);

**// The loop draws tiny lines between points on the circle one**

**// separated from each other by one degree.**

for (i=0; i<=t; i++) {

shFill.graphics.lineTo(circleR*Math.cos(i*Math.PI/180), -circleR*Math.sin(i*Math.PI/180) );

shAngle.graphics.lineTo(angleR*Math.cos(i*Math.PI/180), -angleR*Math.sin(i*Math.PI/180));

}

**//The final lineTo outside of the loop takes the "pen" back to its starting point.**

shFill.graphics.lineTo(0,0);

**//Since the drawing is between beginFill and endFill, we get the filled shape.**

shFill.graphics.endFill();

**//We rotate the arrow head appropriately -- this is much easier than doing**

**//the trig to figure out how to redraw it dynamically.**

shArrow.rotation = -t;

**//The remaining lines position the txtCoords textbox, create a string**

**//showing the coordinates to two decimal places to put this**

**//into this textbox, and put the current radian value of t and**

**//the area of the shaded region into the appropriate textboxes.**

txtCoords.x = circleX + (40+circleR)*Math.cos(radianAngle)-40;

txtCoords.y = circleY - (20+circleR)*Math.sin(radianAngle)-10;

txtCoords.text = "(" + Math.cos(radianAngle).toFixed(2) + ", " + Math.sin(radianAngle).toFixed(2) + ")";

txtDegrees.text = radianAngle.toFixed(2);

txtArea.text = (radianAngle/2).toFixed(4);

}

When the left or right arrow keyboard keys are pressed on the keyboard, the value of degree is adjusted up or down appropriately by the value of degChange. In each case, we use an if statement to keep the angle within the range 0 to 360.

stage.addEventListener(KeyboardEvent.KEY_DOWN,keyPressed);

function keyPressed(evt:KeyboardEvent):void {

if (evt.keyCode == Keyboard.LEFT) {

degree = (degree - degChange);

if (degree < 0) {

degree = degree + 360;

}

updatePicture(degree);

}

if (evt.keyCode == Keyboard.RIGHT) {

degree = (degree + degChange);

if (degree > 360) {

degree = degree - 360;

}

updatePicture(degree);

}

}

When the btnLess button is clicked, the decreaseAngle handler function is called upon to reduce that value of t by the preset amount. Similarly, when the btnMore button is clicked, we increase the value of t by the preset amount. Just as above, the value of t is kept in the range 0 to 360 degrees.

btnLess.addEventListener(MouseEvent.CLICK, decreaseAngle);

function decreaseAngle(evt:MouseEvent):void {

degree = (degree - degChange);

if (degree < 0) {

degree = 360 + degree;

}

updatePicture(degree);

}

btnMore.addEventListener(MouseEvent.CLICK, increaseAngle);

function increaseAngle(evt:MouseEvent):void {

degree = (degree + degChange);

if (degree > 360) {

degree = degree - 360;

}

updatePicture(degree);

}

We call the updatePicture function initially by placing the following line at the end of our script. This will ensure that all graphics objects are drawn, the txtCoords textbox is placed in the correct position, and other textboxes initially contain correct information.

updatePicture(degree);