Now that we have built a bar chart using Flex, we are ready to do the same in pure ActionScript. This bar chart version will allow you to expand it in multiple ways and will remove the weight that the Flex framework adds to the file size. Now a bit about bar charts; Bar charts are good when you don't have too much data (more than 20 bars starts to make a big chart), or when you've averaged it. It is a quick way to compare data visually.
All we will need for this is to start a new project in FlashDevelop. Also, it would help to read about preparing data and about axes in the Adding labels and axes recipe in Chapter 1, Getting Started with Graph Drawing.
This section will refer a lot to the code provided with the book; check the Bar Chart folder within code files for Chapter 3. You will notice that we divided all the elements in the charts into their own classes.
Main.as
file, where we create the data that we will use to display in the chart after that we just create the chart and add it to the display list.var data:Vector.<BarData> = new Vector.<BarData>(); data.push(new BarData("January", 60)); data.push(new BarData("February", 100)); data.push(new BarData("March", 30)); var chart:BarChart = new BarChart(data, 400, 410); chart.x = 30; chart.y = 30; addChild(chart);
BarData
class, which it is just two variables, a string and a number that represents the data that we are going to show.Bar
class: This class will only draw a rectangle with the height representing the data for a certain label. The following is its constructor:public function Bar(width:int, height:int) { graphics.beginFill(0xfca25a); graphics.drawRect(-width/2, 0, width, -height); graphics.endFill(); }
public function HorizontalAxis(listOfMark:Vector.<Number>, data:Vector.<BarData>, width:Number) { drawAxisLine(new Point(0, 0), new Point(width, 0)); for (var i:int = 0; i < listOfMark.length; i++) { drawAxisLine(new Point(listOfMark[i], -3), new Point(listOfMark[i], 3)); var textField:TextField = new TextField(); textField.text = data[i].label; textField.width = textField.textWidth + 5; textField.height = textField.textHeight + 3; textField.x = listOfMark[i] - textField.width / 2; textField.y = 5; addChild(textField); } }
for (var i:int = 0; i < _numberOfMarks; i++) { drawAxisLine(new Point( -3, (i + 1) * -heightOfAxis / _numberOfMarks ), new Point(3, (i + 1) * -heightOfAxis / _numberOfMarks)); var textField:TextField = new TextField(); textField.text = String(((i + 1) / (_numberOfMarks)) * maximumValue ); textField.width = textField.textWidth + 5; textField.height = textField.textHeight + 3; textField.x = -textField.width - 3; textField.y = (i + 1) * -heightOfAxis / _numberOfMarks - textField.height / 2; addChild(textField); }
BarChart
class will take the three classes we just created and put it all together. By iterating through all the data, it will find the maximum value, so that we know what range of values to put on the vertical axis.var i:int; var maximumValue:Number = data[0].data; for (i = 1; i < data.length; i++) { if (data[i].data > maximumValue) { maximumValue = data[i].data; } }
var listOfMarks:Vector.<Number> = new Vector.<Number>(); var bar:Bar; for (i = 0; i < data.length; i++) { bar = new Bar(_barWidth, data[i].data * scaleHeight); bar.x = MARGIN + _barSpacing + _barWidth / 2 + i * (_barWidth + _barSpacing); listOfMarks.push(bar.x - MARGIN); bar.y = height - MARGIN; addChild(bar); }
_horizontalAxis = new HorizontalAxis(listOfMarks, data, width - MARGIN); _horizontalAxis.x = MARGIN; _horizontalAxis.y = height - MARGIN; addChild(_horizontalAxis); _verticalAxis = new VerticalAxis(height - MARGIN, maximumValue); _verticalAxis.x = MARGIN; _verticalAxis.y = height -MARGIN; addChild(_verticalAxis);
So we divided all the elements into their own classes because this will permit us to extend and modify them more easily in the future.
So let's begin where it all starts, the data. Well, our BarChart
class accepts a vector of BarData
as an argument. We did this so that you could add as many bars as you want and the chart would still work. Be aware that if you add many bars, you might have to give more width to the chart so that it can accommodate them.
You can see in the code, that the width of the bar of determined by the width of the graph divided by the number bars. We decided that 85 percent of that value would be given to the bars and 15 percent would be given to the space between the bars. Those values are arbitrary and you can play with them to give different styles to the chart.
Also the other important step is to determine what our data range is. We do so by finding what the maximum value is. For simplicity, we assume that the values will start at 0, but the validity of a chart is always relative to the data, so if there are negative values it wouldn't work, but you could always fix this. So when we found our maximum value, we can decide for a scale for the rest of the values. You can use the following formula for it:
var scaleHeight:Number = (height - 10) / maximumValue;
Here, height
is the height of the chart and 10
is just a margin we leave to the graph to place the labels. After that, if we multiply that scale by the value of the data, it will give us the height of each bar and there you have it, a completed bar chart.
We created a very simple version of a bar chart but there are numerous things we could do to improve it. Styling, interactivity, and the possibility of accommodating a wider range of data are just some examples.
This basic chart could use a little bit of styling. By modifying the color of the bars, the font of the labels, and by adding a drop shadow to the bars, it could be greatly enhanced. You could also make all of them dynamic so that you could specify them when you create a new chart.
It would be really good to show the values for the bars when you move the mouse over them. Right now you can kind of get an idea of which one is the biggest bar but that is all. If this feature is implemented, you can get the exact value.
As we explained earlier, we didn't account for all the data range. Values could be very different; some could be negative, some could be very small (between 0 and 1), or you would want to set the minimum and maximum value of the vertical axes. The good thing here is that you can modify the code to better fit your data.
3.133.109.30