Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
ActionScript Graphing Cookbook
ActionScript Graphing Cookbook

ActionScript Graphing Cookbook: Learn how to create appealing and interactive visual presentations of your data in ActionScript with this book and ebook.

Arrow left icon
Profile Icon Peter Backx Profile Icon Dominic Gelineau
Arrow right icon
Can$46.79 Can$51.99
Full star icon Full star icon Full star icon Full star icon Full star icon 5 (1 Ratings)
eBook Nov 2012 288 pages 1st Edition
eBook
Can$46.79 Can$51.99
Paperback
Can$64.99
eBook + Subscription
Free Trial
Arrow left icon
Profile Icon Peter Backx Profile Icon Dominic Gelineau
Arrow right icon
Can$46.79 Can$51.99
Full star icon Full star icon Full star icon Full star icon Full star icon 5 (1 Ratings)
eBook Nov 2012 288 pages 1st Edition
eBook
Can$46.79 Can$51.99
Paperback
Can$64.99
eBook + Subscription
Free Trial
eBook
Can$46.79 Can$51.99
Paperback
Can$64.99
eBook + Subscription
Free Trial

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

ActionScript Graphing Cookbook

Chapter 1. Getting Started with Graph Drawing

In this chapter, we will cover:

  • Drawing in two dimensions

  • Building point charts

  • Creating a line graph based on a function

  • Adding labels and axes

  • Graphing a spreadsheet

  • Area charts

  • Multiple area charts

  • Styling a graph

  • Adding legends

  • Using Flex for charts

Area charts

In the previous recipes we've learned:

  • Transforming the data so that it shows up at the right location on the screen
  • Using the correct data structure so it's easy to display it

In the remaining recipes in this chapter, we will look into ActionScript's drawing methods and show you a few ways to customize the display.

This recipe looks at drawing area charts. They resemble a function chart, but the area between the chart line and the x-axis is filled. They are ideal to represent volumes.

Getting ready

Create a Recipe6 document class and set up the graph as in the previous recipe. We will use the two-dimensional data set because we will need an ordered data set:

package  
{
  import flash.display.Sprite;

  public class Recipe6 extends Sprite
  {
    private var graph:Graph;
    private var data:Array = [[0, 20], [50, 70], [100, 0], [150, 150], [200, 300], [250, 200], [300, 400], [350, 20], [400, 60], [450, 250], [500, 90], [550, 400], [600, 500], [650, 450], [700, 320]];
    public function Recipe6() 
    {
      graph = new Graph( -50, 550, 750, -50);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, 700, 50, ["0", "700"]);
      graph.drawVerticalAxis(0, 0, 500, 50, ["0","250","500"]);
    }

  }
}

How to do it...

  1. Add the following code to the Recipe6 constructor:
    for (var i:Number = 1; i < data.length; i++)
    {
      graph.drawLine(data[i-1][0], data[i-1][1], data[i][0], data[i][1]);
    }

    Running the program at this point will yield the data set from the previous recipe, but now connected with a line.

  2. In the Graph class, we create a copy of the drawLine method and name it drawArea. In the main program, we now replace the drawLine call. The result should still be the same. But now we change the code so that the area is filled:
    public function drawArea(x1:Number, y1:Number, x2:Number, y2:Number):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedOrigin:Point    = matrix.transformPoint(new Point(0, 0));
    
      var area:Shape = new Shape();
      area.graphics.beginFill(0xff9933);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation2.x, transformedOrigin.y);
      area.graphics.lineTo(transformedLocation1.x, transformedOrigin.y);
      area.graphics.endFill();
      addChild(area);
    }

    If you run the program now, you should see an orange area chart. Everything below the line is now nicely filled with the orange color.

How it works...

This recipe is created in two steps: first, display a line chart and next, fill the void beneath the line to obtain an area.

Because drawing a line requires two points, we start counting at 1 instead of 0. In the loop, we draw a line between the previous point and the current one.

There are two other things to note from the code:

  • We calculate the transformed origin. Actually, we only need the 0 y-coordinate, but it's easier to just use the matrix for this calculation.
  • Instead of drawing a line between two points, we create a "fill" between four points: the two that were used for the line and the two on the x-axis (with y = 0).

There's more...

As with previous recipes, there's a lot that can be customized. Most of these will be discussed in some of the next recipes, but there's nothing keeping you from starting to experiment.

Having the color as a parameter

Right now, the fill color is fixed. You can make this a variable by using it as an argument to the drawArea method.

The fill style

If you check out the ActionScript documentation, you'll find that there are two more ways of creating fills: the beginGradientFill and beginBitmapFill methods. They are a bit more complicated, but can be used to obtain dramatic effects.

See also

The ActionScript 3.0 reference has a lot more detail on creating and drawing filled shapes. It can be found at the following URL:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html

Multiple area charts

In this recipe, we're going to visualize multiple sets of data on one chart.

Getting ready

As usual, create a Recipe7 document class. We'll start with the code from the previous recipe. Only now, we've slightly changed the data set to demonstrate some of the items covered better. There's also an added set of data. We've chosen to store it in the same array for simplicity, but there are other ways of course.

The following is the starting class:

package  
{
  import flash.display.Sprite;

  public class Recipe7 extends Sprite
  {
    private var graph:Graph;
    private var data:Array = [[0, 20, 50], [50, 70, 40], [100, 0, 100], 
[150, 150, 150], [200, 300, 200], [250, 200, 170], 
[300, 170, 160], [350, 20, 120], [400, 60, 80], 
[450, 250, 150], [500, 90, 20], [550, 50, 40], 
[600, 110, 90], [650, 150, 150], [700, 320, 200]];

    public function Recipe7() 
    {
      graph = new Graph( -50, 550, 750, -50);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, 700, 50, ["0", "700"]);
      graph.drawVerticalAxis(0, 0, 500, 50, ["0", "250", "500"]);

      for (var i:Number = 1; i < data.length; i++)
      {
        graph.drawArea(data[i-1][0], data[i-1][1], data[i][0], data[i][1]);
      }

    }

  }

}

How to do it...

There are two ways to show multiple area charts. You can stack the charts on top of each other or you can make them transparent and have them overlaid.

We'll cover the transparent overlay first, because it's the easiest.

  1. Rewrite the drawArea method as follows:
    public function drawArea(x1:Number, y1:Number, x2:Number, y2:Number, 
    colour:uint = 0xff9933, alpha:Number = 1):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedOrigin:Point    = matrix.transformPoint(new Point(0, 0));
    
      var area:Shape = new Shape();
      area.graphics.beginFill(colour, alpha);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation2.x, transformedOrigin.y);
      area.graphics.lineTo(transformedLocation1.x, transformedOrigin.y);
      area.graphics.endFill();
      addChild(area);
    }
  2. If we now rewrite the main loop, we can draw multiple area charts with transparency:
    for (var i:Number = 1; i < data.length; i++)
    {
      graph.drawArea(data[i - 1][0], data[i - 1][1], data[i][0], data[i][1], 
    0xff9933, 0.5);
      graph.drawArea(data[i - 1][0], data[i - 1][2], data[i][0], data[i][2],
    0x3399ff, 0.5);
    }

    Creating stacked charts is a little more complicated. Once again, we start by expanding the drawArea method. We add two more parameters that define the bottom y-coordinates of the area. In the previous graphs, they've always been zero, so we leave that in as the default:

    public function drawArea(x1:Number, y1:Number, x2:Number, y2:Number, 
    colour:uint = 0xff9933, alpha:Number = 1, 
    y3:Number = 0, y4:Number = 0):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedLocation3:Point = matrix.transformPoint(new Point(x1, y3));
      var transformedLocation4:Point = matrix.transformPoint(new Point(x2, y4));
    
      var area:Shape = new Shape();
      area.graphics.beginFill(colour, alpha);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation4.x, transformedLocation4.y);
      area.graphics.lineTo(transformedLocation3.x, transformedLocation3.y);
      area.graphics.endFill();
      addChild(area);
    }

    Use the following code:

    for (var i:Number = 1; i < data.length; i++)
    {
      graph.drawArea(data[i - 1][0], data[i - 1][1], data[i][0], data[i][1]);
      graph.drawArea(data[i - 1][0], data[i - 1][1] + data[i - 1][2], 
       data[i][0], data[i][1] + data[i][2], 
       0x3399ff, 1,
               data[i - 1][1], data[i][1]);
    }

How it works...

Areas are drawn by moving from one point to the other, either clockwise or counter-clockwise. We rushed over this important point in the previous recipe, but it is important in this one.

Because the areas are a little more complex, you need to be extra careful to get the order right. Otherwise you'll run into some strange phenomena.

When overlaying multiple charts, we use the alpha property of the fills. The alpha value controls the transparency of the fill. By making the fill translucent, we can see both areas behind each other.

When stacking multiple charts, we need to use the sum of both coordinates to properly place the different data sets. The bottom coordinates of the second data set are given by the first area chart, while the top coordinates are the sum of two data sets.

There's more...

We've seen the basics of drawing multiple data sets on one chart. In later chapters, there will be many more ways of displaying this information. In the meantime, here are a few ways to expand this recipe.

Improving the interface

The drawArea method's parameters can be improved upon. In particular if you want to draw a third or fourth set of data points, this is going to become unwieldy.

One option is to accept arrays of y-coordinates.

Styling the fill

As with the previous recipe, there are many options to style the fill. We'll look into a few in the next recipe.

Styling a graph

Until now, we've used the most basic way of drawing points, lines, and areas. However, ActionScript's Graphic class offers a wealth of different options to make your charts look more attractive.

In this recipe, we will give a short primer of some of the tools at your fingertips. We won't be able to cover them all, but this should help you on your way.

Getting ready

We start by having a graph that shows all three types of charts we've discussed:

package  
{
  import flash.display.Sprite;

  public class Recipe8 extends Sprite
  {
    private var graph:Graph;
    private var data:Array = [[0, 20], [50, 70], [100, 0], [150, 150], [200, 300], [250, 200], [300, 400], [350, 20], [400, 60], [450, 250], [500, 90], [550, 400], [600, 500], [650, 450], [700, 320]];

    public function Recipe8() 
    {
      graph = new Graph( -50, 550, 750, -50);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, 700, 50, ["0", "700"]);
      graph.drawVerticalAxis(0, 0, 500, 50, ["0", "250", "500"]);

      graph.drawPoint(data[0][0], data[0][1] + 50);
      for (var i:Number = 1; i < data.length; i++)
      {
        graph.drawArea(data[i - 1][0], data[i - 1][1], data[i][0], data[i][1]);
        graph.drawLine(data[i - 1][0], data[i - 1][1] + 25, data[i][0], data[i][1] + 25);
        graph.drawPoint(data[i][0], data[i][1] + 50);
      }

    }

  }

}

Notice that we have shifted the y-coordinate of the different charts, so that it's clear which one is which. If you run this program you should see an area chart, 25 pixels higher a line graph, and the another 25 pixels higher a point chart.

How to do it...

  1. Let's look at points first and replace the points with images.

    For this recipe, we will use the freely available SweetiePlus icons, available at http://sublink.ca/icons/sweetieplus/. Copy any one of the icons you would like to the lib folder of your project. For instance, the heart icon: heart-16-ns.png.

    If you open the folder in FlashDevelop, you should see the file appear. Place the cursor in the Recipe8 class file, just above the graph's var definition.

    Now right-click on the image and pick generate embed code. This will embed the image into your program and is the easiest and best way to embed small images like this.

    Note

    If you use some other software, embedding images might be a little different: In Flash Builder you can use the [Embed] metadata tag directly. Refer to: http://www.adobe.com/devnet/flash/articles/embed_metadata.html.

    In Flash Professional, you can also add the resource to the stage and give it an instance name to address it directly without the need for an [Embed] tag.

    Just below the embed code, you now need to connect that embedded image to a class name. It looks like the following code:

    …
    public class Recipe8 extends Sprite
    {
      [Embed(source = "../lib/heart-16-ns.png")]
      private var HeartClass:Class;
    
      private var graph:Graph;

    We can now add a new drawBitmapPoint method to the Graph class:

    public function drawBitmapPoint(x:Number, y:Number, BitmapClass:Class):void
    {
      var transformedLocation:Point = matrix.transformPoint(new Point(x, y));
    
      var bitmapPoint: Bitmap = new BitmapClass();
      bitmapPoint.x = transformedLocation.x - bitmapPoint.width / 2;
      bitmapPoint.y = transformedLocation.y - bitmapPoint.height / 2;
      addChild(bitmapPoint);
    }
  2. Next we will look at gradients. These allow you to fill an area or a line with a gradually changing color. The complete description of how to apply, position, and create gradients is fairly complicated and beyond the scope of this recipe.

    However, we will explain one example, the drawing of a gradient-filled area:

    public function drawGradientArea(x1:Number, y1:Number, x2:Number, y2:Number, 
                    y3:Number = 0, y4:Number = 0):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedLocation3:Point = matrix.transformPoint(new Point(x1, y3));
      var transformedLocation4:Point = matrix.transformPoint(new Point(x2, y4));
    
      var area:Shape = new Shape();
    
      var gradType:String = GradientType.LINEAR;
      var colors:Array    = [0xff9933, 0x9933ff];
      var alphas:Array    = [1, 1];
      var ratios:Array    = [100, 255];
      var matrix:Matrix   = new Matrix();
      matrix.createGradientBox(stage.stageWidth, stage.stageHeight, Math.PI / 2);
    
      area.graphics.beginGradientFill(gradType, colors, alphas, ratios, matrix);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation4.x, transformedLocation4.y);
      area.graphics.lineTo(transformedLocation3.x, transformedLocation3.y);
      area.graphics.endFill();
      addChild(area);
    }
  3. You can also apply gradients to lines, but for the final example, we'll look at applying bitmaps to lines:
    public function drawBitmapLine(x1:Number, y1:Number, x2:Number, y2:Number, 
        BitmapClass:Class):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
    
      var line:Shape = new Shape();
      line.graphics.lineStyle(16, 0x000000);
      var bitmap:Bitmap = new BitmapClass();
      line.graphics.lineBitmapStyle(bitmap.bitmapData);
      line.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      line.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      addChild(line);
    }

How it works...

ActionScript's Graphic class offers a rich set of drawing primitives. This allows you to create virtually any vector graphic you like. Some of the concepts will feel natural, while others can take a while to properly grasp. It's worth learning the ins and outs of the Graphics class because a well-placed gradient or bitmap can really spice up any graph.

As in all other drawing methods we've seen in this chapter, first the coordinates are transformed.

When drawing a bitmap point, the embedded resource class is instantiated into a Bitmap class. This is the class that will display the image.

Next we use some simple math to place the bitmap at the center of the coordinates. In ActionScript, the bitmap's (x , y) coordinates reflect the upper-left corner. So if we want to place the center of the bitmap at our coordinates, we need to subtract half of the width and height.

As usual, the final step is adding the bitmap to the graph sprite.

Drawing gradients requires extra work. To draw an area that is filled with a gradient, we use the beginGradientFill method. It takes the following parameters:

Optionally, you can also add a matrix that transforms the gradient. This will allow you to correctly place the gradient. In the case of this example, we stretch the gradient over the full screen and rotate it by 90 degrees.

When drawing bitmap fills for lines, there are a few points worth noting:

  • Line bitmaps and gradients are applied to the actual drawn line. This means you need both the lineStyle and lineBitmapStyle methods. You can't take out the first one or you would not see anything drawn.
  • The lineBitmapStyle method takes a BitmapData class as an argument. The difference between this and the Bitmap class, is that bitmap is the actual representation on the screen, while BitmapData is just the bits that are needed to draw the bitmap. Hence BitmapData does not have an x or y coordinate.

If you want to change the exact placement of the bitmaps, the lineBitmapStyle method takes an optional Matrix as an argument. This works similar to all the other matrix operations we've seen. Getting this exactly right isn't easy, so you may need to do some experimentation.

There's more...

We've only covered the very tip of the iceberg that is the Graphics class.

Transformation

As with most visual elements in ActionScript, bitmaps and gradients can be translated, rotated, made translucent, and much more. It's worth experimenting a little to get to know what's possible.

Gradient lines and points, bitmap areas

We've only shown three examples. However you can combine any style with any type of graph. Feel free to extend the existing Graph class with whatever you need for your graphs.

See also

Most ActionScript books have good coverage of the Graphics class. But there are also a few that go into much more detail.

Although it can be a bit hard to get into, the live docs also provide a fairly in-depth overview of the features. This is available at: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html .

Adding legends

Without a little explanation, any graph will quickly become incomprehensible. Especially when showing multiple sets of data, it is important to properly distinguish between the two. A legend can do just that.

Getting ready

For the Recipe9 class, we start from the overlapping multiple area charts class. So copy that class and rename it to Recipe9 to follow along.

How to do it...

  1. The legend related display methods will receive their own class. We start by creating a new Legend class that extends Sprite. Optionally, you can add a title:
    package  
    {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
    
        public class Legend extends Sprite
        {
          private var lineHeight:Number = 20;
          private var lines:int = 0;
          
          public function Legend(title:String = null) 
          {
             if (title != null) {
                    var titleField:TextField = new TextField();
                    titleField.text = title;
                    titleField.autoSize = TextFieldAutoSize.LEFT;
                    addChild(titleField);
                    lines++;
                }
            }
            public function addKey(key:String, color:uint, alpha:Number):void
            {
                // see further
            }
      }
    }
  2. In the main program (Recipe9), you can add the legend to the display with the following code:
    var legend:Legend = new Legend("Legend title");
    legend.x = 600;
    legend.y = 20;
    legend.addKey("First series", 0xff9933, 0.5);
    legend.addKey("More data points", 0x3399ff, 0.5);
    addChild(legend);
  3. As you can see, we've already added methods to add the display of actual keys. In typical graph fashion, we want to show a small square containing the color of that data set with some text next to it to name the data set.

    The code isn't overly complicated and uses the drawRect method from the Graphics class and the plain TextField class we've seen before:

    public function addKey(key:String, color:uint, alpha:Number):void
    {
      var keySample:Shape = new Shape();
      keySample.graphics.lineStyle(1);
      keySample.graphics.beginFill(color, alpha);
      keySample.graphics.drawRect(0, lines * lineHeight, 15, 15);
      keySample.graphics.endFill();
      addChild(keySample);
    
      var keyField:TextField = new TextField();
      keyField.text = key;
      keyField.x = 20;
      keyField.y = lines * lineHeight;
      keyField.autoSize = TextFieldAutoSize.LEFT;
      addChild(keyField);
    
      lines++;
    }

    If you run the program now, you'll notice one thing still missing: a nice box around our legend to distinguish it from the actual graph.

  4. The only tricky thing is that it needs to be updated dynamically when a key is added. So we store it in an instance variable:
        private var box:Shape;
  5. Next we create the method to update the box:
         private function updateBox():void 
        {
          if (box != null) {
            removeChild(box);
          }
          box = new Shape();
          box.graphics.lineStyle(1);
          box.graphics.drawRect(-5, -5, width+6, height+6);
          addChild(box);
        }
  6. Now we should execute the updateBox method every time the legend changes. So the final step is to add it to the end of the constructor and the addKey methods.

How it works...

Just like with the Graph class, we use the Legend class to hold all of the separate graphical elements of the legend. That way we can just work from the (0,0) origin and not worry about the exact location where the legend will be placed.

Since this would require its own chapter, we won't be going into the details of styling and customizing the textField class. The only option that we use the autoSize property. It will make sure that the size of the text field fits the text and isn't just left at the default 100x100. This guarantees that the sprite's size will be exactly the size of the text and allows us to easily draw a nice fitting box around the entire legend display.

The line counter is responsible for making sure we can place each individual legend key at the right distance.

You may have noticed that we draw the legend in screen coordinates, not graph coordinates. In many cases, it's easier to place it in the correct location that way. Although if you want to fix the legend in relation to the graph (for instance, always in the bottom, at the center) you may want to think about putting it inside the Graph class and use the transformed coordinates. In that case, the Legend class would probably be a child of the Graph class.

The legend is a sprite, which means you can use the legend like any other one. You can resize it, move it, and even rotate it if you want (you may need to use embedded fonts on the text fields to perform some of those operations).

There's more...

With this recipe, we've only scratched the surface of what you can do with legends.

TextField customization

In this recipe, we've used the very basics of the textField class. However, the textField class is one of the most versatile ActionScript classes available. It offers so many options that ActionScript reference books need an entire chapter or two to cover it.

So if you want to change the text display, start with the live docs for textField and textFormat and go from there.

A background

In this recipe, we've kept the legend transparent. It is perfectly possible to add a background color to it. To obtain this, extends the updateBox method so it also draws a fill (see the previous recipe). One thing to keep in mind: you need to make sure that the box is drawn behind the keys and title and not on top.

Research the addChildAt method to find the solution for this issue: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html#addChildAt%28%29.

See also

More information on customizing textField can be found in the Adobe live docs:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html.

The textFormat class is the main way to change fonts, sizes, and many more options:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextFormat.html.

Using Flex for charts

No book on ActionScript graphing would be complete without at least mentioning Flex. The Flex software development kit also contains an extensive API for drawing different types of graphs.

The techniques we've discussed in the previous recipes are much more powerful, but depending on the case, a small Flex component might be enough.

Getting ready

Since we need access to the Flex library, we'll need to set up our FlashDevelop workspace differently. The easiest way is to create a new project. When asked for the type of project, pick Flex 3 project (instead of AS3 Project, which we use throughout the other parts of this book).

If you browse through the files in the src directory of your project, you will now find a Main.mxml file instead of the previous Main.as file. This is the file that describes your user interface. Instead of programmatically adding all the sprites and shapes to your interface, you will add them to this file.

How to do it...

  1. Open Main.mxml. All the code presented here should be added inside the mx:Application tags.
  2. First let's start with the data set definition:
      <mx:Script><![CDATA[
        import mx.collections.ArrayCollection;
        [Bindable]
        public var dataSet:ArrayCollection = new ArrayCollection([
          {x:0,   y1:20,  y2:50},
          {x:50,  y1:70,  y2:40},
          {x:100, y1:0,   y2:100},
          {x:150, y1:150, y2:150},
          {x:200, y1:300, y2:200},
          {x:250, y1:200, y2:170},
          {x:300, y1:170, y2:160},
          {x:350, y1:20,  y2:120},
          {x:400, y1:60,  y2:80},
          {x:450, y1:250, y2:150},
          {x:500, y1:90, y2:20},
          {x:550, y1:50, y2:40},
          {x:600, y1:110, y2:90},
          {x:650, y1:150, y2:150},
          {x:700, y1:320, y2:200}
        ]);
        ]]></mx:Script>
  3. This is the same set we used in previous recipes. Now we add the actual chart and legend:
      <mx:Panel title="Our first Flex chart">
        <mx:AreaChart id="areaChart" showDataTips="true" dataProvider="{dataSet}">
          <mx:horizontalAxis>
            <mx:CategoryAxis
              dataProvider="{dataSet}"
              categoryField="x"
            />
          </mx:horizontalAxis>
          <mx:series>
            <mx:AreaSeries 
              yField="y1" 
              displayName="First series">
              <mx:areaFill>
                <mx:SolidColor color="0xff9933" alpha="0.5" />
              </mx:areaFill>
            </mx:AreaSeries>
            <mx:AreaSeries 
              yField="y2" 
              displayName="More data points">
              <mx:areaFill>
                <mx:SolidColor color="0x3399ff" alpha="0.5" />
              </mx:areaFill>
            </mx:AreaSeries>
          </mx:series>
        </mx:AreaChart>
        <mx:Legend dataProvider="{areaChart}"/>
      </mx:Panel>

How it works...

Flex has a few new data structures; in this recipe we use the ArrayCollection data structure. This is a specially defined data structure that makes it easy to manage chart data. In fact, if you wanted to include the Flex library in your project, you could use the class for your own graph drawing.

Now let's look at the structure as a display list: the root element is a Panel class. This is a simple wrapper class to which you can add a title.

Inside this panel, there are two visual elements: an area chart and a legend. The legend is the easiest of the two explain; we use the default settings and let it read its data from the chart. It's all automatically added and filled.

The area chart is a little more involved:

  • The dataProvider attribute links this chart to the data we previously defined.
  • The showDataTips attribute is enabled to show you how quickly you can get some pretty fancy charts with Flex. If this is enabled, you can hover over the data points with your mouse, and you'll see a pop up with more details.
  • The horizontal axis is mapped to the x element inside the data set. Note that scaling of the axes happens automatically (but it can be overridden if required).
  • Finally we add two data series, both of which we map to the data set we defined previously. We also apply the same fill that was used in the previous recipes.

If you run the program, you will see a graph similar to the one presented in the multiple area charts recipe.

The difference is the way we defined the chart. With Flex you describe how the chart will look and let Flex do the work for you. In plain ActionScript, you have full control, but you have to do all the hard work.

The choice will depend on the application and most likely also on personal preferences.

There's more...

The Flex charting API is immense and with the recipe above, and we haven't even scratched the surface. If you think this style of development is for you, here are a few more things you can do.

Flex without MXML

If you like Flex, but don't like MXML, there's a way to program Flex with virtually no XML. Since Flex wasn't built for this purpose, you'll find fairly little documentation explaining this.

If this is something you want to try out, start with this StackOverflow question:

http://stackoverflow.com/questions/141288/possible-to-use-flex-framework-components-without-using-mxml.

ActionScript in Flex

Everything inside the mx:Script tags is pure ActionScript code. If you don't like the ArrayCollection data structure, you can always write your own bit of ActionScript that maps from any data structure to the one Flex expects.

See also

If you like to get into Flex, there are numerous books. Also, the online documentation is very complete. For charting, your best starting point is available here:

http://livedocs.adobe.com/flex/3/html/help.html?content=charts_intro_7.html.

Graphing a spreadsheet


Graphing functions is nice, but visualizing a spreadsheet is probably the most popular use case for graphs. Having a visual representation of tabular data can result into insights previously hidden behind the numbers.

In this recipe, we will structure the code to use data from a fixed array in the ActionScript program. In the next chapter, we'll go into all kinds of ways to get the data into that array.

Getting ready

Create a new document class called Recipe5 and have it extend Sprite. Also make sure to copy the updated Graph class from the provided source package. It has enhanced and more flexible axes methods (if you implemented any of the items mentioned in the There's more... section of the Adding labels and axes recipe in this chapter, you may have already created a very similar one).

This time we'll focus on only positive numeric data, so we'll put the origin (0,0) of the graph in the bottom-left corner:

package  
{
  import flash.display.Sprite;

    private const MAX_X:int  = 700;
    private const MAX_Y:int  = 500;
    private const BORDER:int = 50;
    private const TICK:int   = 50;

  public class Recipe5 extends Sprite 
  {
    private var graph:Graph;

    public function Recipe5() 
    {
      graph = new Graph( -BORDER, MAX_Y + BORDER, MAX_X + BORDER, -BORDER);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, MAX_X, TICK, ["0", MAX_X]);
      graph.drawVerticalAxis(0, 0, MAX_Y, TICK, ["0", MAX_Y/2, MAX_Y]);
    }
  }
}

If you run this program, you should see both axes run from the bottom-left corner and there should be two labels on the horizontal axis and three on the vertical axis.

How to do it...

For now, we'll just show point charts. Feel free to convert this into a line chart (as shown in the Creating a line graph based on a function recipe in this chapter) and in later recipes you'll learn how to draw many different types of charts.

If we have the following table:

We want to draw two points: (10,40) and (20,60).

Storing data is easiest in a two dimensional array. In the next chapter, we'll go over many different ways of storing data (such as in files and on the Internet). The array mimics how you represent this data in a program such as MS Excel:

private var graph2d:Array = [[0,20],[50,70],[100,0],[150,150],[200,300],[250,200],
[300,400],[350,20],[400,60],[450,250],[500,90],[550,400],
[600,500],[650,450],[700,320]];

All the points are grouped together. Each entry in the array is one (x , y) coordinate on the graph.

The code to draw this dataset is just a simple loop:

for (i = 0; i < graph2d.length; i++)
{
  graph.drawPoint(graph2d[i][0], graph2d[i][1], 0x3399ff);
}

This structure does have one problem: it's not easy to manipulate the data. You may want to change the data, for instance, if this was connected to live web statistics that are updated every minute (we'll see more on that in the next chapter). Say you want to change the point (150,150) to (150,200). How would you do that? You need to loop over the array and find the correct entry and change it.

However, searching this way in a large array can become slow quite quickly. If the array is always sorted, like in the preceding example, you could implement your own version of a search algorithm to make it quicker. But then you'd need to create your own insertion algorithm to make sure the data remains in order.

No matter how you solve this, if you need to manipulate the data a lot, this is not a good data structure.

See the There's more... section of this recipe for other solutions to these problems.

How it works...

The data we want to display is a simple data mapping from one value to the another. Imagine an Excel spreadsheet with two columns. One column holds the x-axis values while the other holds the y-axis value. Two numbers on the same row present one (x , y) point.

That is why a two-dimensional array is one of the best ways to represent data: it's an easy structure to program and it's easy to read. However, it is hard to manipulate. If you have a fixed data set, this is the structure you want.

There's more...

There are an endless number of possible ways to represent data. Depending on your data source or your specific data set, you may want to look into other options. In the following section, we present the two most popular ones, each with its own advantages and disadvantages. Ultimately, it is possible to combine most advantages into one structure, but it will require additional development.

Two arrays

The easiest solution to store data is in two arrays, one for each column in the spreadsheet:

private var graph1x:Array = 
[0, 50, 100, 150, 200, 250, 300, 350, 400, 
450, 500, 550, 600, 650, 700];
private var graph1y:Array = 
[20, 70, 0, 150, 300, 200, 400, 20, 60, 250, 90, 400, 500, 450, 320];

And you can draw the graph with a simple loop:

for (var i:int = 0; i < graph1x.length; i++)
{
  graph.drawPoint(graph1x[i], graph1y[i], 0xff9933);
}

This works effectively and is completely understandable. There is a major drawback to this approach that is already clear in this simple example.

There's no easy way to quickly verify that you have the same number of elements in both arrays. You can write a test in your code, but if you want to edit the data, it's hard to see which value belongs to which.

For instance, the 400 x-value maps to 60 on the y-axis. That isn't readily apparent from the code. If you forget to add a y-value, you run the risk of breaking your entire program.

Associative array

If inserting and updating data is important, you may want to look into a third solution: the object or associative array.

private var graphObject:Object = { 0:20,50:70,100:0,150:150,200:300,250:200,
300:400,350:20,400:60,450:250,500:90,550:400,
600:500,650:450,700:320 };

Although the notation looks similar to the previous one, the data structure that is created internally is quite different. Drawing it is a little more complicated and requires the usage of the for-in loop (again we shift the points to demonstrate the difference):

for (var s:String in graphObject)
{
  graph.drawPoint(Number(s) + 8, graphObject[s], 0xff3399);
}

Because the x coordinate is stored as an object property, it is stored as a string. Before we can draw it, we need to convert it back to a number.

This data structure is perfect for manipulation. Instead of having to search through it to find the item we want to change, we just write the following:

graphObject[150] = 200;

However, there is one very major disadvantage of the associate array and the for-in loop: you should not rely, in any way, on the order in which elements are looped over. So there's no guarantee that the loop will first draw (0,20) and then (50,70), and so on.

Order will become important if you want to draw more complicated charts than the point chart shown. In that case, you need to first convert the object to an array and then sort the array.

Vectors

If you like to work in a more object-oriented manner, and to avoid some of the pitfalls of arrays and increase performance, you may want to look into vectors.

Although the code that you need to write tends to be much more verbose than arrays and objects, they offer a very high level of type safety and have many convenience functions.

For instance, you can store points in the Point objects:

var point:Point = new Point(0,20);

And store these points in a point vector:

var graphVector:Vector.<Point> = new Vector.<Point>();
graphVector.push(point);

Associative array to two-dimensional array conversion

If you intend to manipulate your data inside your ActionScript program you will probably want to write at least a conversion function from the associate array to the ordered two-dimensional arrays. Potentially, you'll also need to do this the other way around.

What you need to do is:

  • Use a for-in loop to construct a two-dimensional array

  • Use the Array.sort method and the custom order function to sort the array

See also

If you're not confident with manipulating (associative) arrays, it's best to look at one of the ActionScript fundamentals books. Both data structures are vital to understanding most of the recipes in this book.

Area charts


In the previous recipes we've learned:

  • Transforming the data so that it shows up at the right location on the screen

  • Using the correct data structure so it's easy to display it

In the remaining recipes in this chapter, we will look into ActionScript's drawing methods and show you a few ways to customize the display.

This recipe looks at drawing area charts. They resemble a function chart, but the area between the chart line and the x-axis is filled. They are ideal to represent volumes.

Getting ready

Create a Recipe6 document class and set up the graph as in the previous recipe. We will use the two-dimensional data set because we will need an ordered data set:

package  
{
  import flash.display.Sprite;

  public class Recipe6 extends Sprite
  {
    private var graph:Graph;
    private var data:Array = [[0, 20], [50, 70], [100, 0], [150, 150], [200, 300], [250, 200], [300, 400], [350, 20], [400, 60], [450, 250], [500, 90], [550, 400], [600, 500], [650, 450], [700, 320]];
    public function Recipe6() 
    {
      graph = new Graph( -50, 550, 750, -50);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, 700, 50, ["0", "700"]);
      graph.drawVerticalAxis(0, 0, 500, 50, ["0","250","500"]);
    }

  }
}

How to do it...

  1. Add the following code to the Recipe6 constructor:

    for (var i:Number = 1; i < data.length; i++)
    {
      graph.drawLine(data[i-1][0], data[i-1][1], data[i][0], data[i][1]);
    }

    Running the program at this point will yield the data set from the previous recipe, but now connected with a line.

  2. In the Graph class, we create a copy of the drawLine method and name it drawArea. In the main program, we now replace the drawLine call. The result should still be the same. But now we change the code so that the area is filled:

    public function drawArea(x1:Number, y1:Number, x2:Number, y2:Number):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedOrigin:Point    = matrix.transformPoint(new Point(0, 0));
    
      var area:Shape = new Shape();
      area.graphics.beginFill(0xff9933);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation2.x, transformedOrigin.y);
      area.graphics.lineTo(transformedLocation1.x, transformedOrigin.y);
      area.graphics.endFill();
      addChild(area);
    }

    If you run the program now, you should see an orange area chart. Everything below the line is now nicely filled with the orange color.

How it works...

This recipe is created in two steps: first, display a line chart and next, fill the void beneath the line to obtain an area.

Because drawing a line requires two points, we start counting at 1 instead of 0. In the loop, we draw a line between the previous point and the current one.

There are two other things to note from the code:

  • We calculate the transformed origin. Actually, we only need the 0 y-coordinate, but it's easier to just use the matrix for this calculation.

  • Instead of drawing a line between two points, we create a "fill" between four points: the two that were used for the line and the two on the x-axis (with y = 0).

There's more...

As with previous recipes, there's a lot that can be customized. Most of these will be discussed in some of the next recipes, but there's nothing keeping you from starting to experiment.

Having the color as a parameter

Right now, the fill color is fixed. You can make this a variable by using it as an argument to the drawArea method.

The fill style

If you check out the ActionScript documentation, you'll find that there are two more ways of creating fills: the beginGradientFill and beginBitmapFill methods. They are a bit more complicated, but can be used to obtain dramatic effects.

See also

The ActionScript 3.0 reference has a lot more detail on creating and drawing filled shapes. It can be found at the following URL:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html

Multiple area charts


In this recipe, we're going to visualize multiple sets of data on one chart.

Getting ready

As usual, create a Recipe7 document class. We'll start with the code from the previous recipe. Only now, we've slightly changed the data set to demonstrate some of the items covered better. There's also an added set of data. We've chosen to store it in the same array for simplicity, but there are other ways of course.

The following is the starting class:

package  
{
  import flash.display.Sprite;

  public class Recipe7 extends Sprite
  {
    private var graph:Graph;
    private var data:Array = [[0, 20, 50], [50, 70, 40], [100, 0, 100], 
[150, 150, 150], [200, 300, 200], [250, 200, 170], 
[300, 170, 160], [350, 20, 120], [400, 60, 80], 
[450, 250, 150], [500, 90, 20], [550, 50, 40], 
[600, 110, 90], [650, 150, 150], [700, 320, 200]];

    public function Recipe7() 
    {
      graph = new Graph( -50, 550, 750, -50);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, 700, 50, ["0", "700"]);
      graph.drawVerticalAxis(0, 0, 500, 50, ["0", "250", "500"]);

      for (var i:Number = 1; i < data.length; i++)
      {
        graph.drawArea(data[i-1][0], data[i-1][1], data[i][0], data[i][1]);
      }

    }

  }

}

How to do it...

There are two ways to show multiple area charts. You can stack the charts on top of each other or you can make them transparent and have them overlaid.

We'll cover the transparent overlay first, because it's the easiest.

  1. Rewrite the drawArea method as follows:

    public function drawArea(x1:Number, y1:Number, x2:Number, y2:Number, 
    colour:uint = 0xff9933, alpha:Number = 1):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedOrigin:Point    = matrix.transformPoint(new Point(0, 0));
    
      var area:Shape = new Shape();
      area.graphics.beginFill(colour, alpha);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation2.x, transformedOrigin.y);
      area.graphics.lineTo(transformedLocation1.x, transformedOrigin.y);
      area.graphics.endFill();
      addChild(area);
    }
  2. If we now rewrite the main loop, we can draw multiple area charts with transparency:

    for (var i:Number = 1; i < data.length; i++)
    {
      graph.drawArea(data[i - 1][0], data[i - 1][1], data[i][0], data[i][1], 
    0xff9933, 0.5);
      graph.drawArea(data[i - 1][0], data[i - 1][2], data[i][0], data[i][2],
    0x3399ff, 0.5);
    }

    Creating stacked charts is a little more complicated. Once again, we start by expanding the drawArea method. We add two more parameters that define the bottom y-coordinates of the area. In the previous graphs, they've always been zero, so we leave that in as the default:

    public function drawArea(x1:Number, y1:Number, x2:Number, y2:Number, 
    colour:uint = 0xff9933, alpha:Number = 1, 
    y3:Number = 0, y4:Number = 0):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedLocation3:Point = matrix.transformPoint(new Point(x1, y3));
      var transformedLocation4:Point = matrix.transformPoint(new Point(x2, y4));
    
      var area:Shape = new Shape();
      area.graphics.beginFill(colour, alpha);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation4.x, transformedLocation4.y);
      area.graphics.lineTo(transformedLocation3.x, transformedLocation3.y);
      area.graphics.endFill();
      addChild(area);
    }

    Use the following code:

    for (var i:Number = 1; i < data.length; i++)
    {
      graph.drawArea(data[i - 1][0], data[i - 1][1], data[i][0], data[i][1]);
      graph.drawArea(data[i - 1][0], data[i - 1][1] + data[i - 1][2], 
       data[i][0], data[i][1] + data[i][2], 
       0x3399ff, 1,
               data[i - 1][1], data[i][1]);
    }

How it works...

Areas are drawn by moving from one point to the other, either clockwise or counter-clockwise. We rushed over this important point in the previous recipe, but it is important in this one.

Because the areas are a little more complex, you need to be extra careful to get the order right. Otherwise you'll run into some strange phenomena.

When overlaying multiple charts, we use the alpha property of the fills. The alpha value controls the transparency of the fill. By making the fill translucent, we can see both areas behind each other.

When stacking multiple charts, we need to use the sum of both coordinates to properly place the different data sets. The bottom coordinates of the second data set are given by the first area chart, while the top coordinates are the sum of two data sets.

There's more...

We've seen the basics of drawing multiple data sets on one chart. In later chapters, there will be many more ways of displaying this information. In the meantime, here are a few ways to expand this recipe.

Improving the interface

The drawArea method's parameters can be improved upon. In particular if you want to draw a third or fourth set of data points, this is going to become unwieldy.

One option is to accept arrays of y-coordinates.

Styling the fill

As with the previous recipe, there are many options to style the fill. We'll look into a few in the next recipe.

Styling a graph


Until now, we've used the most basic way of drawing points, lines, and areas. However, ActionScript's Graphic class offers a wealth of different options to make your charts look more attractive.

In this recipe, we will give a short primer of some of the tools at your fingertips. We won't be able to cover them all, but this should help you on your way.

Getting ready

We start by having a graph that shows all three types of charts we've discussed:

package  
{
  import flash.display.Sprite;

  public class Recipe8 extends Sprite
  {
    private var graph:Graph;
    private var data:Array = [[0, 20], [50, 70], [100, 0], [150, 150], [200, 300], [250, 200], [300, 400], [350, 20], [400, 60], [450, 250], [500, 90], [550, 400], [600, 500], [650, 450], [700, 320]];

    public function Recipe8() 
    {
      graph = new Graph( -50, 550, 750, -50);
      addChild(graph);
      graph.drawHorizontalAxis(0, 0, 700, 50, ["0", "700"]);
      graph.drawVerticalAxis(0, 0, 500, 50, ["0", "250", "500"]);

      graph.drawPoint(data[0][0], data[0][1] + 50);
      for (var i:Number = 1; i < data.length; i++)
      {
        graph.drawArea(data[i - 1][0], data[i - 1][1], data[i][0], data[i][1]);
        graph.drawLine(data[i - 1][0], data[i - 1][1] + 25, data[i][0], data[i][1] + 25);
        graph.drawPoint(data[i][0], data[i][1] + 50);
      }

    }

  }

}

Notice that we have shifted the y-coordinate of the different charts, so that it's clear which one is which. If you run this program you should see an area chart, 25 pixels higher a line graph, and the another 25 pixels higher a point chart.

How to do it...

  1. Let's look at points first and replace the points with images.

    For this recipe, we will use the freely available SweetiePlus icons, available at http://sublink.ca/icons/sweetieplus/. Copy any one of the icons you would like to the lib folder of your project. For instance, the heart icon: heart-16-ns.png.

    If you open the folder in FlashDevelop, you should see the file appear. Place the cursor in the Recipe8 class file, just above the graph's var definition.

    Now right-click on the image and pick generate embed code. This will embed the image into your program and is the easiest and best way to embed small images like this.

    Note

    If you use some other software, embedding images might be a little different: In Flash Builder you can use the [Embed] metadata tag directly. Refer to: http://www.adobe.com/devnet/flash/articles/embed_metadata.html.

    In Flash Professional, you can also add the resource to the stage and give it an instance name to address it directly without the need for an [Embed] tag.

    Just below the embed code, you now need to connect that embedded image to a class name. It looks like the following code:

    …
    public class Recipe8 extends Sprite
    {
      [Embed(source = "../lib/heart-16-ns.png")]
      private var HeartClass:Class;
    
      private var graph:Graph;

    We can now add a new drawBitmapPoint method to the Graph class:

    public function drawBitmapPoint(x:Number, y:Number, BitmapClass:Class):void
    {
      var transformedLocation:Point = matrix.transformPoint(new Point(x, y));
    
      var bitmapPoint: Bitmap = new BitmapClass();
      bitmapPoint.x = transformedLocation.x - bitmapPoint.width / 2;
      bitmapPoint.y = transformedLocation.y - bitmapPoint.height / 2;
      addChild(bitmapPoint);
    }
  2. Next we will look at gradients. These allow you to fill an area or a line with a gradually changing color. The complete description of how to apply, position, and create gradients is fairly complicated and beyond the scope of this recipe.

    However, we will explain one example, the drawing of a gradient-filled area:

    public function drawGradientArea(x1:Number, y1:Number, x2:Number, y2:Number, 
                    y3:Number = 0, y4:Number = 0):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
      var transformedLocation3:Point = matrix.transformPoint(new Point(x1, y3));
      var transformedLocation4:Point = matrix.transformPoint(new Point(x2, y4));
    
      var area:Shape = new Shape();
    
      var gradType:String = GradientType.LINEAR;
      var colors:Array    = [0xff9933, 0x9933ff];
      var alphas:Array    = [1, 1];
      var ratios:Array    = [100, 255];
      var matrix:Matrix   = new Matrix();
      matrix.createGradientBox(stage.stageWidth, stage.stageHeight, Math.PI / 2);
    
      area.graphics.beginGradientFill(gradType, colors, alphas, ratios, matrix);
      area.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      area.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      area.graphics.lineTo(transformedLocation4.x, transformedLocation4.y);
      area.graphics.lineTo(transformedLocation3.x, transformedLocation3.y);
      area.graphics.endFill();
      addChild(area);
    }
  3. You can also apply gradients to lines, but for the final example, we'll look at applying bitmaps to lines:

    public function drawBitmapLine(x1:Number, y1:Number, x2:Number, y2:Number, 
        BitmapClass:Class):void
    {
      var transformedLocation1:Point = matrix.transformPoint(new Point(x1, y1));
      var transformedLocation2:Point = matrix.transformPoint(new Point(x2, y2));
    
      var line:Shape = new Shape();
      line.graphics.lineStyle(16, 0x000000);
      var bitmap:Bitmap = new BitmapClass();
      line.graphics.lineBitmapStyle(bitmap.bitmapData);
      line.graphics.moveTo(transformedLocation1.x, transformedLocation1.y);
      line.graphics.lineTo(transformedLocation2.x, transformedLocation2.y);
      addChild(line);
    }

How it works...

ActionScript's Graphic class offers a rich set of drawing primitives. This allows you to create virtually any vector graphic you like. Some of the concepts will feel natural, while others can take a while to properly grasp. It's worth learning the ins and outs of the Graphics class because a well-placed gradient or bitmap can really spice up any graph.

As in all other drawing methods we've seen in this chapter, first the coordinates are transformed.

When drawing a bitmap point, the embedded resource class is instantiated into a Bitmap class. This is the class that will display the image.

Next we use some simple math to place the bitmap at the center of the coordinates. In ActionScript, the bitmap's (x , y) coordinates reflect the upper-left corner. So if we want to place the center of the bitmap at our coordinates, we need to subtract half of the width and height.

As usual, the final step is adding the bitmap to the graph sprite.

Drawing gradients requires extra work. To draw an area that is filled with a gradient, we use the beginGradientFill method. It takes the following parameters:

Optionally, you can also add a matrix that transforms the gradient. This will allow you to correctly place the gradient. In the case of this example, we stretch the gradient over the full screen and rotate it by 90 degrees.

When drawing bitmap fills for lines, there are a few points worth noting:

  • Line bitmaps and gradients are applied to the actual drawn line. This means you need both the lineStyle and lineBitmapStyle methods. You can't take out the first one or you would not see anything drawn.

  • The lineBitmapStyle method takes a BitmapData class as an argument. The difference between this and the Bitmap class, is that bitmap is the actual representation on the screen, while BitmapData is just the bits that are needed to draw the bitmap. Hence BitmapData does not have an x or y coordinate.

If you want to change the exact placement of the bitmaps, the lineBitmapStyle method takes an optional Matrix as an argument. This works similar to all the other matrix operations we've seen. Getting this exactly right isn't easy, so you may need to do some experimentation.

There's more...

We've only covered the very tip of the iceberg that is the Graphics class.

Transformation

As with most visual elements in ActionScript, bitmaps and gradients can be translated, rotated, made translucent, and much more. It's worth experimenting a little to get to know what's possible.

Gradient lines and points, bitmap areas

We've only shown three examples. However you can combine any style with any type of graph. Feel free to extend the existing Graph class with whatever you need for your graphs.

See also

Most ActionScript books have good coverage of the Graphics class. But there are also a few that go into much more detail.

Although it can be a bit hard to get into, the live docs also provide a fairly in-depth overview of the features. This is available at: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html .

Adding legends


Without a little explanation, any graph will quickly become incomprehensible. Especially when showing multiple sets of data, it is important to properly distinguish between the two. A legend can do just that.

Getting ready

For the Recipe9 class, we start from the overlapping multiple area charts class. So copy that class and rename it to Recipe9 to follow along.

How to do it...

  1. The legend related display methods will receive their own class. We start by creating a new Legend class that extends Sprite. Optionally, you can add a title:

    package  
    {
        import flash.display.Sprite;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
    
        public class Legend extends Sprite
        {
          private var lineHeight:Number = 20;
          private var lines:int = 0;
          
          public function Legend(title:String = null) 
          {
             if (title != null) {
                    var titleField:TextField = new TextField();
                    titleField.text = title;
                    titleField.autoSize = TextFieldAutoSize.LEFT;
                    addChild(titleField);
                    lines++;
                }
            }
            public function addKey(key:String, color:uint, alpha:Number):void
            {
                // see further
            }
      }
    }
  2. In the main program (Recipe9), you can add the legend to the display with the following code:

    var legend:Legend = new Legend("Legend title");
    legend.x = 600;
    legend.y = 20;
    legend.addKey("First series", 0xff9933, 0.5);
    legend.addKey("More data points", 0x3399ff, 0.5);
    addChild(legend);
  3. As you can see, we've already added methods to add the display of actual keys. In typical graph fashion, we want to show a small square containing the color of that data set with some text next to it to name the data set.

    The code isn't overly complicated and uses the drawRect method from the Graphics class and the plain TextField class we've seen before:

    public function addKey(key:String, color:uint, alpha:Number):void
    {
      var keySample:Shape = new Shape();
      keySample.graphics.lineStyle(1);
      keySample.graphics.beginFill(color, alpha);
      keySample.graphics.drawRect(0, lines * lineHeight, 15, 15);
      keySample.graphics.endFill();
      addChild(keySample);
    
      var keyField:TextField = new TextField();
      keyField.text = key;
      keyField.x = 20;
      keyField.y = lines * lineHeight;
      keyField.autoSize = TextFieldAutoSize.LEFT;
      addChild(keyField);
    
      lines++;
    }

    If you run the program now, you'll notice one thing still missing: a nice box around our legend to distinguish it from the actual graph.

  4. The only tricky thing is that it needs to be updated dynamically when a key is added. So we store it in an instance variable:

        private var box:Shape;
  5. Next we create the method to update the box:

         private function updateBox():void 
        {
          if (box != null) {
            removeChild(box);
          }
          box = new Shape();
          box.graphics.lineStyle(1);
          box.graphics.drawRect(-5, -5, width+6, height+6);
          addChild(box);
        }
  6. Now we should execute the updateBox method every time the legend changes. So the final step is to add it to the end of the constructor and the addKey methods.

How it works...

Just like with the Graph class, we use the Legend class to hold all of the separate graphical elements of the legend. That way we can just work from the (0,0) origin and not worry about the exact location where the legend will be placed.

Since this would require its own chapter, we won't be going into the details of styling and customizing the textField class. The only option that we use the autoSize property. It will make sure that the size of the text field fits the text and isn't just left at the default 100x100. This guarantees that the sprite's size will be exactly the size of the text and allows us to easily draw a nice fitting box around the entire legend display.

The line counter is responsible for making sure we can place each individual legend key at the right distance.

You may have noticed that we draw the legend in screen coordinates, not graph coordinates. In many cases, it's easier to place it in the correct location that way. Although if you want to fix the legend in relation to the graph (for instance, always in the bottom, at the center) you may want to think about putting it inside the Graph class and use the transformed coordinates. In that case, the Legend class would probably be a child of the Graph class.

The legend is a sprite, which means you can use the legend like any other one. You can resize it, move it, and even rotate it if you want (you may need to use embedded fonts on the text fields to perform some of those operations).

There's more...

With this recipe, we've only scratched the surface of what you can do with legends.

TextField customization

In this recipe, we've used the very basics of the textField class. However, the textField class is one of the most versatile ActionScript classes available. It offers so many options that ActionScript reference books need an entire chapter or two to cover it.

So if you want to change the text display, start with the live docs for textField and textFormat and go from there.

A background

In this recipe, we've kept the legend transparent. It is perfectly possible to add a background color to it. To obtain this, extends the updateBox method so it also draws a fill (see the previous recipe). One thing to keep in mind: you need to make sure that the box is drawn behind the keys and title and not on top.

Research the addChildAt method to find the solution for this issue: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html#addChildAt%28%29.

See also

More information on customizing textField can be found in the Adobe live docs:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextField.html.

The textFormat class is the main way to change fonts, sizes, and many more options:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/text/TextFormat.html.

Using Flex for charts


No book on ActionScript graphing would be complete without at least mentioning Flex. The Flex software development kit also contains an extensive API for drawing different types of graphs.

The techniques we've discussed in the previous recipes are much more powerful, but depending on the case, a small Flex component might be enough.

Getting ready

Since we need access to the Flex library, we'll need to set up our FlashDevelop workspace differently. The easiest way is to create a new project. When asked for the type of project, pick Flex 3 project (instead of AS3 Project, which we use throughout the other parts of this book).

If you browse through the files in the src directory of your project, you will now find a Main.mxml file instead of the previous Main.as file. This is the file that describes your user interface. Instead of programmatically adding all the sprites and shapes to your interface, you will add them to this file.

How to do it...

  1. Open Main.mxml. All the code presented here should be added inside the mx:Application tags.

  2. First let's start with the data set definition:

      <mx:Script><![CDATA[
        import mx.collections.ArrayCollection;
        [Bindable]
        public var dataSet:ArrayCollection = new ArrayCollection([
          {x:0,   y1:20,  y2:50},
          {x:50,  y1:70,  y2:40},
          {x:100, y1:0,   y2:100},
          {x:150, y1:150, y2:150},
          {x:200, y1:300, y2:200},
          {x:250, y1:200, y2:170},
          {x:300, y1:170, y2:160},
          {x:350, y1:20,  y2:120},
          {x:400, y1:60,  y2:80},
          {x:450, y1:250, y2:150},
          {x:500, y1:90, y2:20},
          {x:550, y1:50, y2:40},
          {x:600, y1:110, y2:90},
          {x:650, y1:150, y2:150},
          {x:700, y1:320, y2:200}
        ]);
        ]]></mx:Script>
  3. This is the same set we used in previous recipes. Now we add the actual chart and legend:

      <mx:Panel title="Our first Flex chart">
        <mx:AreaChart id="areaChart" showDataTips="true" dataProvider="{dataSet}">
          <mx:horizontalAxis>
            <mx:CategoryAxis
              dataProvider="{dataSet}"
              categoryField="x"
            />
          </mx:horizontalAxis>
          <mx:series>
            <mx:AreaSeries 
              yField="y1" 
              displayName="First series">
              <mx:areaFill>
                <mx:SolidColor color="0xff9933" alpha="0.5" />
              </mx:areaFill>
            </mx:AreaSeries>
            <mx:AreaSeries 
              yField="y2" 
              displayName="More data points">
              <mx:areaFill>
                <mx:SolidColor color="0x3399ff" alpha="0.5" />
              </mx:areaFill>
            </mx:AreaSeries>
          </mx:series>
        </mx:AreaChart>
        <mx:Legend dataProvider="{areaChart}"/>
      </mx:Panel>

How it works...

Flex has a few new data structures; in this recipe we use the ArrayCollection data structure. This is a specially defined data structure that makes it easy to manage chart data. In fact, if you wanted to include the Flex library in your project, you could use the class for your own graph drawing.

Now let's look at the structure as a display list: the root element is a Panel class. This is a simple wrapper class to which you can add a title.

Inside this panel, there are two visual elements: an area chart and a legend. The legend is the easiest of the two explain; we use the default settings and let it read its data from the chart. It's all automatically added and filled.

The area chart is a little more involved:

  • The dataProvider attribute links this chart to the data we previously defined.

  • The showDataTips attribute is enabled to show you how quickly you can get some pretty fancy charts with Flex. If this is enabled, you can hover over the data points with your mouse, and you'll see a pop up with more details.

  • The horizontal axis is mapped to the x element inside the data set. Note that scaling of the axes happens automatically (but it can be overridden if required).

  • Finally we add two data series, both of which we map to the data set we defined previously. We also apply the same fill that was used in the previous recipes.

If you run the program, you will see a graph similar to the one presented in the multiple area charts recipe.

The difference is the way we defined the chart. With Flex you describe how the chart will look and let Flex do the work for you. In plain ActionScript, you have full control, but you have to do all the hard work.

The choice will depend on the application and most likely also on personal preferences.

There's more...

The Flex charting API is immense and with the recipe above, and we haven't even scratched the surface. If you think this style of development is for you, here are a few more things you can do.

Flex without MXML

If you like Flex, but don't like MXML, there's a way to program Flex with virtually no XML. Since Flex wasn't built for this purpose, you'll find fairly little documentation explaining this.

If this is something you want to try out, start with this StackOverflow question:

http://stackoverflow.com/questions/141288/possible-to-use-flex-framework-components-without-using-mxml.

ActionScript in Flex

Everything inside the mx:Script tags is pure ActionScript code. If you don't like the ArrayCollection data structure, you can always write your own bit of ActionScript that maps from any data structure to the one Flex expects.

See also

If you like to get into Flex, there are numerous books. Also, the online documentation is very complete. For charting, your best starting point is available here:

http://livedocs.adobe.com/flex/3/html/help.html?content=charts_intro_7.html.

Left arrow icon Right arrow icon

Key benefits

  • Learn how to create various visually dynamic graphs and charts
  • Import data from different sources, such as web services
  • Learn how to map geographical data, visualize in 3D

Description

"A picture is worth a thousand words" has never been more true than when representing large sets of data. Bar charts, heat maps, cartograms, and many more have become important tools in applications and presentations to quickly give insight into complicated issues.The "ActionScript Graphing Cookbook" shows you how to add your own charts to any ActionScript program. The recipes give step-by-step instructions on how to process the input data, how to create various types of charts and how to make them interactive for even more user engagement.Starting with basic ActionScript knowledge, you will learn how to develop many different types of charts.First learn how to import your data, from Excel, web services and more. Next process the data and make it ready for graphical display. Pick one of the many graph options available as the book guides you through ActionScript's drawing functions. And when you're ready for it, branch out into 3D display.The recipes in the "ActionScript Graphing Cookbook" will gradually introduce you into the world of visualization.

Who is this book for?

The "ActionScript Graphing Cookbook" is aimed at any ActionScript developer who wants to add data visualization to their skill set. The reader should be familiar with ActionScript basics, but no deep knowledge of any graphical functions is required.

What you will learn

  • Import data from various sources
  • Organize the various visual elements of a graph
  • Draw many types of charts, such as bar, line and pie charts, meters and many more
  • Make graphs interactive with hover and zoom effects
  • Work with geographical data and maps
  • Animate graphs with real time data
  • Show and interact with network displays
  • Discover three dimensional drawing and graphing

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Nov 21, 2012
Length: 288 pages
Edition : 1st
Language : English
ISBN-13 : 9781849693219
Category :
Languages :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Nov 21, 2012
Length: 288 pages
Edition : 1st
Language : English
ISBN-13 : 9781849693219
Category :
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Can$6 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just Can$6 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total Can$ 204.97
C++ Game Development By Example
Can$65.99
ActionScript Graphing Cookbook
Can$64.99
HTML5 Graphing and Data Visualization Cookbook
Can$73.99
Total Can$ 204.97 Stars icon

Table of Contents

10 Chapters
Getting Started with Graph Drawing Chevron down icon Chevron up icon
Working with Data Chevron down icon Chevron up icon
Creating Bar Charts Chevron down icon Chevron up icon
Drawing Different Types of Graphs Chevron down icon Chevron up icon
Adding Interaction Chevron down icon Chevron up icon
Mapping Geographical and Spatial Data Chevron down icon Chevron up icon
Animating a Graph Chevron down icon Chevron up icon
Creating a Relational Network Chevron down icon Chevron up icon
Creating Three-Dimensional Graphs Chevron down icon Chevron up icon
Working with Various 3D Graph Types Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Full star icon 5
(1 Ratings)
5 star 100%
4 star 0%
3 star 0%
2 star 0%
1 star 0%
Igor Jan 29, 2013
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book has all that you need for creating math graphs. The concept of the book is learning by exampleif you learn this way than this is book for you. Every problem is firstly explained and then the solutionfor the problem is presented with code. There are some more useful information's after that.This book does not concentrate on explaining how sprites, movieclips and animation can bedrawn with ActionScript it is mainly for graphs that are used in different fields statistics,mathematics and other similar fields. So if you need that than this is book for you.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.

Modal Close icon
Modal Close icon