Recently in Charts Category

Date range selection for Flex charts

| 3 Comments

Charting applications that have user interaction are great. They can take advantage of the built-in charting effects, and also take advantage of users' needs to look at data differently, and drill down into data. One of the most interesting ways to experience time-based data is by using a date range selector.

There are some examples of date range selectors out there, such as the fantastic one used by Google finance. I wanted to do something simpler so I wrote this example, which is loosely based on Ely's Custom Annotation example in his Chart Sampler.

Try it out. Just click and drag a range for the chart:

This app consists of a main application file (DateSelectionExample.mxml) and a single ActionScript class file, RangeSelector.as.

The RangeSelector extends the ChartElement class. As a result, you add it to your chart as an annotationElement:

    <mx:annotationElements>
        <custom:RangeSelector/>                 
    </mx:annotationElements>

The meat of the RangeSelector class is in the updateDisplayList() method. Here, it does several things:

  1. Draws a transparent rectangle over the entire chart. This rectangle allows the mouse events to be handled in the RangeSelector rather than be passed to the chart.
  2. Draws the selected region if the mouse is being held down and dragged over the chart.
  3. Transforms the screen coordinates of the selected region into data coordinates that the chart "understands".
  4. Positions the region's labels as it expands and contracts due to mouse movement.
  5. Resets the selection region and hide the labels when the mouse is not drawing a new area.

In the constructor, the RangeSelector added labels that show the current date as you drag a selection out and in:

    _labelLeft = new Label();
    _labelRight = new Label();
    addChild(_labelLeft);
    addChild(_labelRight);

The startTracking() and endTracking() methods keep track of the mouse when it is clicked and dragged. This rectangular region is what defines the new dates to show on the chart.

I used the parentApplication property to access objects and properties on the main application. It's not the cleanest or most portable code, but it works, and you could easily write a class that handles the access methods.

The width of the selection area is determined by where the user drags the mouse. But to get the height, I wanted to use the entire height of the chart. To do this, I use the parentApplication property to reach up to the parent app and get the height of the chart itself:

    g.drawRect(c[0].x,0,rectWidth, parentApplication.myChart.height);

Later, in the commitProperties() method, the RangeSelector extracts the date information (day, date, and year) to build the label's text:

    leftDate = new Date(dLeft);
    rightDate = new Date(dRight);
    _labelLeft.text = (leftDate.getMonth()+1) + "/" + leftDate.getDate() + "/" + leftDate.getFullYear();
    _labelRight.text = (rightDate.getMonth()+1) + "/" + rightDate.getDate() + "/" + rightDate.getFullYear(); 

Note that the Date class's month property is zero-based, so I added 1 to make sure I had the right month in the label.

Finally, when you finish dragging, the RangeSelector modifies the chart's data in the parent application:

    parentApplication.minDate = new Date(dLeft);
    parentApplication.maxDate = new Date(dRight);

The minDate and maxDate properties in the parent application are bound to the chart's DateTimeAxis. By changing these values, the chart's axis changes. As a result, the data shown on the chart changes.

    <mx:horizontalAxis>
        <mx:DateTimeAxis id="hAxis"
            dataUnits="days"
            minimum="{minDate}"
            maximum="{maxDate}"/>
    </mx:horizontalAxis>

When the chart data changes, the RangeSelector also adjusts the size of the plot points. In this case, I adjust the size of the plot points at the same ratio as the size of the selection is to the chart area. For example, if you drew a selection area half the size of the chart, the plot points increase 50% in size. The smaller the selection, the greater the increase in size of the plot points.

    var plotPointRatio:Number = rectWidth/parentApplication.myChart.width;
    var curRadius:int = parentApplication.series1.getStyle("radius");
    parentApplication.series1.setStyle("radius", curRadius *(1 - plotPointRatio + 1));
    parentApplication.series2.setStyle("radius", curRadius *(1 - plotPointRatio + 1));
    parentApplication.series3.setStyle("radius", curRadius *(1 - plotPointRatio + 1));

In the main app, when you hit reset, the radii of the plot points are reset to their defaults, and the minDate and maxDate properties are reset. The chart's axis returns to its original range:

    minDate = null;
    maxDate = null;
    ...                
    series1.setStyle("radius", 5);          
    series2.setStyle("radius", 5);          
    series3.setStyle("radius", 5);          

You can download the source here:

DateSelectionExample.mxml
RangeSelector.as

Changing chart series color at run time with a ColorPicker

| 1 Comment

A recent thread in the Flex support forums resulted in a couple of new charting examples. Specifically, a user was trying to use a ColorPicker component to change the color of a series in a chart at run time. Turns out, it was a little tricky, so I figured I should share the examples.

The first example shows a LineChart. You can click on an item in the chart, which brings up a ColorPicker. You select a color and Flex applies that color to the selected series.

The meat of the example is in the itemClick handler. This is where you get a reference to the LineSeries by accessing the LineSeriesItem's element property. Here's the code:

  private function selectItemHandler(e:ChartItemEvent):void {
    var hitData:HitData = e.hitData;
    csi = LineSeriesItem(hitData.chartItem);
    el = ChartElement(csi.element);
        
    cp = new ColorPicker();
    myChart.addChild(cp);
    cp.addEventListener(ColorPickerEvent.CHANGE, changeItemColor);
    cp.x = e.localX;
    cp.y = e.localY;
    cp.open();
  }

The changeItemColor() method is pretty straightforward. For a LineChart's series, you define a new Stroke and then apply that Stroke to the series' lineStroke style. You then remove the ColorPicker from the display list so it doesn't pollute the chart's appearance. Here's the code for that:

  private function changeItemColor(e:ColorPickerEvent):void {
    var s1:Stroke = new Stroke(cp.selectedColor, 4, 1);
    el.setStyle("lineStroke", s1);		
    myChart.removeChild(cp);
  }

Here's a running example:

To change the color of a series like a ColumnSeries or a BarSeries, you have to apply the style a little bit differently. In this case, you define a SolidColor and then apply that to the series' fill property.

    var c:SolidColor = new SolidColor(cp.selectedColor);		
    el.setStyle("fill", c);

Here's the running example:

The final example is a little different in that it applies the color to a single item in the series and not the entire series. I thought it was interesting, so I figure I'd share it.

Instead of applying a style to the series, you set the fill property on the ColumnSeriesItem:

    var c:SolidColor = new SolidColor(cp.selectedColor);				
    csi.fill = c;

In addition, to get it to work requires a little workaround: You have to trigger a call to the series' updateDisplayList(). To do that, you just set a property on the itemRenderer, like this:

    csi.itemRenderer.height = csi.itemRenderer.height;           

Here's the running example:

Here is a ZIP file of the 3 running examples and the source code:
Download file (985KB)

You might notice that these examples also use the live data that I blogged about recently.

"Live" data for charting examples

| 1 Comment

This is not a major announcement, but it's got a touch of cool factor and represents an improvement to about 200 doc examples. The charting examples in Flex documentation have been updated to use real-time data served up from a MySQL database. They connect to the database via an HTTPService tag, and then use the results as the data provider for the charts.

The server that hosts the data is located at:
aspexamples.adobe.com

The following list provides links to the new example data. The link in parentheses provides the XML output of the request. The best way to view the source data as it is used by Flex is to click the XML link, and then select View > Source in your browser:

To use these URLs as data sources in your apps, you can do something like the following:


<mx:HTTPService
id="srv"
url="http://aspexamples.adobe.com/chart_examples/expenses-xml.aspx"
/>

Be sure to call the service's send() method when your app is finished loading (in the creationComplete event handler):


creationComplete="srv.send()"

And then set the value of the chart's dataProvider property to something like this:


dataProvider="{srv.lastResult.data.result}"

The updated examples won't appear in the Flex documentation until the next time it is generated for the public. This will likely be for the Flex 4 ("Gumbo") beta. But the data is available now for your testing.

Customizing the layout of legend items

| 3 Comments

This question came up in a recent forum posting:

You can make the LegendItems in a Legend display horizontally in a long line or vertically in a long list, but how do I customize the layout of these LegendItems?

The answer took me a little while to figure out, so I'll post it here so others can benefit from it... Yes, the answer is also posted as a response in the forums, but I can put running examples here so you can see what I mean.

First, an app that shows the problem. The ColumnChart control in the following app has 7 separate series, each with a separate entry in the legend. If you lay out the LegendItems vertically, you get a lot of extra white space to the right of the legend, below the chart, as the following example shows:

If you lay the LegendItems out horizontally, you get scroll bars at the bottom of the application, as the following example shows:

There's no way (that I could figure out) to eliminate those scroll bars without clipping the LegendItems.

One solution, which can be adapted to any number of layout techniques, is to build the list of LegendItems in ActionScript and add them to a dynamic grid layout. I did this in a single loop that takes into account the preferred number of items per row:

for (var j:int = 0; j < numRows; j++) {
var gr:GridRow = new GridRow();
myGrid.addChild(gr);
for (var k:int = 0; k < rowSize; k++) {
  if (z < myChart.series.length) {
    var gi:GridItem = new GridItem();
    gr.addChild(gi);		
    var li:LegendItem = new LegendItem();		
    // Apply the current series' displayName to the LegendItem's label.
    ...
    // Get the current series' fill.
    ...		
    // Apply the current series' fill to the corresponding LegendItem.
    ...		
    // Add the LegendItem to the GridItem.
    gi.addChild(li);
    // Increment any time a LegendItem is added.
    z++;
    }
  }							

Before you do any of this, you have to remove all the existing GridRows and GridItems. You do this with a call to the removeAllChildren() method, like this:

myGrid.removeAllChildren();

There are a couple of gotchas in this approach: you have to be sure to grab the right labels so that your dynamic LegendItems match the series' display names that show up in the chart. You do this by accessing the chart's series array's displayName property, as the following example shows:

li.label = myChart.series[z].displayName;

You also have to get the color (actually, it's the "fill" property) from the series, and apply it to the corresponding LegendItem's fill, as the following example shows:

var sc:SolidColor = myChart.series[z].getStyle("fill");
li.setStyle("fill", sc);

Here's a running example that lays out the LegendItems in the selected number of rows. I also took the opportunity to apply some styles to make the LegendItems a little more attractive. They are of uniform width and their background colors are the same as the marker color, as the following example shows:

  li.setStyle("textIndent", 5);
  li.setStyle("labelPlacement", "left");
  li.setStyle("fontSize", 9);
  gi.setStyle("backgroundAlpha", "1");
  gi.setStyle("backgroundColor", sc.color);
  gi.width = 80;

Here's the running example:

Here's the source code:
Download ZIP (9K)

Extracting data visualization source code

| 7 Comments

All users have access to the Flex 3 SDK source code. You can view the ActionScript source files for classes like Button and DataGrid. The source code is in the frameworks\projects\framework\src directory of your Flex installation. The source code for the data visualization projects does not come pre-installed, however. If you have a Flex Builder Professional license key, you can extract the data visualization source code, which include the charting controls, the AdvancedDataGrid classes, the OLAP classes, and the automation classes. To view your Flex Builder license key, select Manage Flex Licenses from the Help menu.

To extract the data visualization source code, you use the DMV-source.jar file. This file is located in the SDK's lib directory. If you are using Flex Builder, the lib directory is located at {Flex Builder 3}\sdks\3.0.0\lib.

The syntax to extract the data visualization source code is as follows:

> java -jar DMV-source.jar {license-file-location} {output-location}

The first argument is the location of the license.properties file. This file must contain a valid Flex Builder 3 Professional license key. The second parameter is the location that you want the data visualization source code to be extracted to.

If you installed Flex Builder 3 Professional, then the license.properties file is located at the following locations, depending on your operating system:

  • Windows: C:\Documents and Settings\All Users\Application Data\Adobe\Flex\
  • Mac OS: /Library/Application Support/Adobe/Flex/
  • Linux: ~/.adobe/Flex/

The following example extracts the data visualization source code to the c:\temp\dataviz_source directory on Windows:

java -jar c:\Flex Builder 3\sdks\3.0.0\lib\DMV-source.jar 
     "C:\Documents and Settings\All Users\Application Data\Adobe\Flex\" 
     c:\temp\dataviz_source

If you have a valid Flex Builder 3 Professional license key but did not install Flex Builder, then you can create a license.properties file anywhere, and point to it when you use the DMV-source.jar file. The syntax of the license.properties file is as follows:

flexbuilder3={license_key}

Community Help

Contribute to Community Help

About this Archive

This page is an archive of recent entries in the Charts category.

BlazeDS is the previous category.

Command line tools is the next category.

Find recent content on the main index or look in the archives to find all content.