This post follows on from the comparison of two Silverlight chart libraries produced by my colleague, Colin Eberhardt, by adding an implementation of the simple image processing tool in Flex using the Flex Charting library to the comparison. The results show that the Flex Charts perform easily as well as the Visiblox charts without the need to specifically consider performance.

Since Colin produced his comparison of the Silverlight Toolkit and Visiblox charts there has been some noted interest in how Flash stacks up against them. This seems to be part of a general drive across the development community to gain a better understanding of the relative strengths of Flash/Flex, Silverlight and HTML5. In order to contribute a little to this, I produced a comparable application to those of Colin using the charting library that is part of the free, open-source Flex 4 SDK.

Here are my Flex application and the "winning" application from Colin's investigation side-by-side. Click and drag a line across the image to plot the RGB pixel intensities along the line in the chart above. From these examples, it is clear that there is little to differentiate them performance-wise.

Flex Chart Visiblox Chart


Get Microsoft Silverlight

[Squirrel image used royalty free from stock.xchng; hare image used under CC licence from flickr]

Implementation

For details of the implementation of the Visiblox example above, see the original post. The mark-up for the Flex example above is as follows:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" >
    <s:layout>
        <s:VerticalLayout />
    </s:layout>

    <fx:Declarations>
        <s:SolidColorStroke id="axisStroke" color="#cccccc" weight="1" />
    </fx:Declarations>

    <s:Group width="100%" height="100%">
        <mx:CartesianChart id="chart" width="100%" height="100%" visible="false">
            <mx:horizontalAxis>
                <mx:LinearAxis id="xAxis" />
            </mx:horizontalAxis>
            <mx:horizontalAxisRenderers>
                <mx:AxisRenderer axis="{xAxis}" axisStroke="{axisStroke}"
                                 showLabels="false" tickPlacement="none" />
            </mx:horizontalAxisRenderers>
            <mx:verticalAxis>
                <mx:LinearAxis id="yAxis" />
            </mx:verticalAxis>
            <mx:verticalAxisRenderers>
                <mx:AxisRenderer axis="{yAxis}" axisStroke="{axisStroke}"
                                 tickPlacement="outside" tickStroke="{axisStroke}" />
            </mx:verticalAxisRenderers>
            <mx:series>
                <mx:LineSeries yField="red">
                    <mx:lineStroke>
                        <s:SolidColorStroke color="#aa0000" weight="1" />
                    </mx:lineStroke>
                </mx:LineSeries>
                <mx:LineSeries yField="green">
                    <mx:lineStroke>
                        <s:SolidColorStroke color="#00aa00" weight="1" />
                    </mx:lineStroke>
                </mx:LineSeries>
                <mx:LineSeries yField="blue">
                    <mx:lineStroke>
                        <s:SolidColorStroke color="#0000aa" weight="1" />
                    </mx:lineStroke>
                </mx:LineSeries>
            </mx:series>
        </mx:CartesianChart>

        <s:Label id="instructions" visible="{!chart.visible}"
                 horizontalCenter="0" verticalCenter="0"
                 fontSize="9" color="#cccccc"
                 text="Use the mouse to 'drag' a line across the image below." />
    </s:Group>

    <s:Group>
        <mx:Image id="image"
                  source="@Embed(source='squirrel.jpg')"
                  mouseDown="imageMouseDownHandler(event)"
                  mouseUp="imageMouseUpHandler(event)"
                  mouseMove="imageMouseMoveHandler(event)" />
        <s:Line id="line">
            <s:stroke>
                <s:SolidColorStroke color="#000000" weight="3" />
            </s:stroke>
        </s:Line>
    </s:Group>
</s:Application>

The above mark-up creates two Groups: one containing the CartesianChart and instructions, and the other the Image and Line. This is remarkably similar to the mark-up of Colin's Silverlight examples, if slightly more verbose. The verboseness is the result of both Flex technicalities and my overriding the rather ugly default styles axis styles for aesthetic reasons. Note that the CartesianChart was used rather than LineChart purely because of the LineChart using the ugly ShadowLineRenderer by default for LineSeries (the CartesianChart uses the simple LineRenderer).

Unlike in Silverlight, there is no need to do anything funky with mouse event handling Flex, as the Flex component lifecycle means the UI will always have a chance to render. This means a simple mouse move event handler can be used to construct the chart's data:

private function imageMouseMoveHandler(event:MouseEvent):void
{
	if (!_mouseDown)
		return;

	line.xTo = event.localX;
	line.yTo = event.localY;

	// compute length of line
	var length:int = Math.sqrt(Math.pow(line.xFrom - line.xTo, 2) +
				   Math.pow(line.yFrom - line.yTo, 2));

	// build the chart data
	var bitmapData:BitmapData = Bitmap(image.content).bitmapData;
	var chartData:Array = [];
	var xIndex:int;
	var yIndex:int;
	var pixel:uint;
	var point:Object;
	for (var i:int = 0; i < length; i++)
	{
		point= {};
		xIndex = line.xFrom + (line.xTo - line.xFrom) * i / length;
		yIndex = line.yFrom + (line.yTo - line.yFrom) * i / length;
		pixel = bitmapData.getPixel(xIndex, yIndex);
		point.red = pixel & 0xff;
		pixel >>= 8;
		point.green = pixel & 0xff;
		pixel >>= 8;
		point.blue = pixel & 0xff;
		chartData.push(value);
	}

	chart.dataProvider = chartData;
}

Once again, this code is very similar to that used in the Silverlight examples to construct chart data. However, notice that here we can choose to take advantage of ActionScript 3's dynamic objects to drive our chart for simplicity's sake. Furthermore, there has also been no need to pre-process the image data to obtain pixel information since the Image, Bitmap and BitmapData classes are designed and optimised for exactly this kind of pixel-level manipulation.

Conclusions

From the above examples it is apparent that there is little, if anything, to differentiate their relative performance. Furthermore, it would be fair to say that the outright technology choice of Flash/Flex or Silverlight has not differentiated these examples. Rather, the choice of charting library in either technology is far more significant with respect to performance. Therefore, in this case, the technology choice would have to be driven by some other factor than performance, for example, plug-in penetration, cost or existing developer expertise.

However, at a more technical level there are some interesting points to consider alongside the comparative performance of the two applications. The Silverlight examples were created with specific techniques for improving their performance. The implication is that a naive Silverlight implementation of the application is likely to have noticeable performance issues. In contrast, the Flex example has purposefully been created without any of the known performance improvement techniques, yet is still as responsive.

It is also worthwhile contrasting the respective charting libraries. The Visiblox charting library has specifically been designed for performance over flexibility, where as the Flex charting library is the opposite. The result is that although they are roughly equal in performance, the Flex charting library has many more options for customisation and extension than the Visiblox charting library. However, it should be noted that the Flex charting library is relatively mature (~4 years old) compared to the Visiblox charts (~2 months old).

You can download the full source code for the Flex example given in this blog post here: FlexChartPerformance.zip; and the full source code for the Silverlight examples given in Colin's blog post here: ChartPerformance.zip