Ok, so displaying data from your database in a table is rather boring don't you think? I'm working with time series data in this project, and so I'm really interested in being able to quickly display a trend. This will be particularly useful since data becomes updated once every quarter, so fairly frequently. I don't have a professional license of Flex Builder which opens up the very simple to use charting features (played around with a demo a while back), so I've had to look for alternatives. There are two that I came across: Flare, and Axiis. The first problem I ran into with both is that my data didn't come in a 'web' format, but as an array from the SQLite question. The lack of tutorials for both project made it difficult to find out an answer to this question, so I had to play around with both. The short answer is - yes you can take the SQLResult.Data and apply it directly to both projects. I ended up using Flare which was actually much much easier to use (for me) compared to Axiis. I don't find Axiis very intuitive to use. Which I was really disapointed by, not just because I couldn't figure it out, but because it is based on the excellent Degrafa project. Which is how it gets such nice looking charts. It was easy enough, but it took some playing around with, to get the data array to be used by Axiis. Instead of playing with the dataset class, just set the DataProvider to the array directly. Here is a tutorial that was useful. And I was even able to get it to display some bar graphs, which all the tutorials seem to teach. When I started to try and work with the LineSeriesGroup, I couldn't ever get a series of lines to display. I found this one really difficult to understand, because I think of data statistically where there is a x and y axis and couldn't grasp how to set this up. If anyone wants to explain it to me, I would still like to give Axiis a go.
Like I said, I ended up using Flare which I found much easier to work with. Instead of the mxml base, Flare uses sprites, which is more Flash less Flex, but still useable in Flex. So after querying and getting my data array, mentioned in a previous post, this is where I start:
A bunch of Imports:
import flare.vis.data.Data;
import flare.vis.data.EdgeSprite;
import flare.vis.data.NodeSprite;
import flare.vis.operator.encoder.ColorEncoder;
import flare.vis.operator.encoder.PropertyEncoder;
import flare.vis.operator.label.Labeler;
import flare.vis.operator.layout.AxisLayout;
import flare.vis.Visualization;
import flare.scale.ScaleType;
import flare.vis.controls.AnchorControl;
import flare.vis.controls.HoverControl;
import flare.vis.controls.SelectionControl;
import flare.vis.data.DataSprite;
import flare.vis.events.SelectionEvent;
import flare.vis.controls.TooltipControl;
import flare.vis.events.TooltipEvent;
import flare.display.TextSprite;
import flare.util.Strings;
import flash.filters.GlowFilter;
import flash.display.Sprite;
import flash.geom.Rectangle;
A class that extends Sprite:
public class LineChartExperiment extends Sprite
{
Global variables and the constructor are commented. The loaddata() function is the key step that takes our data array and puts it in the data format that is used by Flare. Flare uses a graph data model. This means everything is stored as a node and an edge. You see graphs all the time, not line graphs, but real graphs. Search wikipedia if you want a more in-depth explanation of graph theory. This makes a lot of sense given what the library is capable of. If you look at the Flare Demo Page, and select the layout and then force option, this is a visual representation of a graph that is being organized by a force directed method. In other words it uses physics to place the circles. The circles are the nodes, and the lines connecting the nodes are the edges.
When you look at the loaddata function, we are actually taking each object in the array and creating a node from this. Once we exit the loop we can use Flare's createEdges function to generate the edges for us. It does this based on two inputs, a sort by input and group by input. So in this example I sort by time, and group by the name. Another way to think of this is sort is your x axis and group is the series.
//this is the string that will be used for a tooltip that pops up when hovering
private static const _tipText:String =
"Venue: {0}<br/>" +
"Value: {1}<br/>" +
"Date: {2}";
//visualization is the component that handles everyting
private var vis:Visualization;
//this holds our data
private var dataArray:Array;
//this is passed in when the sprite is created. I add the sprite to a canvas
private var _width:Number;
private var _height:Number;
public function LineChartExperiment(da:Array, width:Number, height:Number)
{
super();
this.dataArray = da;
this._width = width;
this._height = height;
//call the load data function
loadData();
}
private function loadData():void
{
var data:Data = new Data();
for each (var o:Object in dataArray) {
data.addNode(o);
//this also works but uses more lines of code
//data.addNode({
//Value: o.Value,
//Date: o.Date,
//Name: o.Name
//});
}
//Important Step do not miss this one
data.createEdges("data.Date", "data.Name");
createVisualization(data);
}
Once the data is loaded we pass it to the createVisualization function. A lot of this was pulled from the source code of the examples that download with the swc file.
private function createVisualization(data:Data):void
{
//This sets up the location and size of the Visualization
vis = new Visualization(data);
vis.bounds = new Rectangle(0, 0, _width - 25, _height - 25);
vis.x = 50;
vis.y = 0;
//and is added to the sprite as a child
addChild(vis);
//I need to look ino these in more depth, but basically they are used to set up the chart, and the colors
//Date is the xAxis and Value is the y Axis Note how you are creating symbols for the nodes, and edges.
//This allows the edges to show as a line in the chart. You could skip the nodes and just show the lines
vis.operators.add(new AxisLayout("data.Date", "data.Value"));
vis.operators.add(new ColorEncoder("data.Name", Data.EDGES, "lineColor", ScaleType.CATEGORIES));
vis.operators.add(new ColorEncoder("data.Name", Data.NODES, "fillColor", ScaleType.CATEGORIES));
vis.operators.add(new PropertyEncoder( { lineAlpha: 0, alpha:0.5, buttonMode: false, scaleX: 1, scaleY:1, size:0.5 } ));
vis.operators.add(new PropertyEncoder( { lineWidth:2 }, Data.EDGES));
vis.data.nodes.setProperties( { fillColor:0, lineWidth:2 } );
// add mouse-over highlight
vis.controls.add(new HoverControl(NodeSprite, 0,
// highlight on mouse over
function(e:SelectionEvent):void {
e.item.filters = [new GlowFilter(0xFFFF55, 0.8, 6, 6, 10)];
},
// remove higlight on mouse out
function(e:SelectionEvent):void {
e.item.filters = null
}
));
// add tooltip showing data values
vis.controls.add(new TooltipControl(DataSprite, null,
function(e:TooltipEvent):void {
var data:Object = e.node.data;
TextSprite(e.tooltip).htmlText = Strings.format(
_tipText, data.Name, data.Value, data.Date);
}
));
vis.update();
}
//I added an eventlistener to the canvas to when it was resized, it then called this function
//Which resizes the visualization to the canvas' new size
public function resize(w:Number, h:Number):void
{
var rect:Rectangle = new Rectangle(0, 0, w - 25, h - 25);
_width = w;
_height = h;
vis.bounds = rect.clone();
vis.update();
}
Because we are working with a sprite, when we add this to our Main.mxml, we should first add it to a UIComponent, then add it to the Canvas or else you get an error. Can is a canvas that is created in another portion of the code.
exp = new LineChartExperiment(rev.dataArray, can.width, can.height);
exp.width = can.width;
exp.height = can.height;
var ui:UIComponent = new UIComponent();
can.addChild(ui);
ui.addChild(exp);
Hopefully that is helpful to those who are starting out with flare too.