Holly has posted 3 posts at DZone. View Full User Profile

Real-time data visualization using Flex and publish/subscribe messaging

02.01.2010
| 47723 views |
  • submit to reddit

When you hear the term “data visualization”, you probably immediately think of pie charts, bar charts, and line charts showing sales data, population data, or other historical data.   These charts and graphs help us to visualize the data, detect key trends, and make decisions moving forward.

While charts are great for understanding historical data, real-time data can benefit from visualization also. For example, financial transaction data can contain immediately useful trending information that is undetectable without some visualization.  The same goes for credit card transactions, website traffic, etc.

Although Flex is fantastic for traditional data visualization, it is uniquely qualified for visualizing real-time data.  This article describes some common techniques for collecting data in real-time, visualizing it using traditional charting controls, and applying some more advanced location/mapping controls to further improve the user experience. 

Each of the exercises covered in this article includes complete source code. There is also an extensive list of resources at the end of the article to help with server-side configuration and provide additional background.

  Editor's Note: This article was co-authored by Greg Wilson, Enterprise Platform Evangelist at Adobe Systems.

Collecting the data

The first step in being able to visualize real-time data is collecting it.  Whether it’s financial transactions or GPS coordinates of a moving vehicle, you’ll need to collect the data as it is generated.  One popular (yet inefficient) way of doing this is to poll a data source repeatedly.  Although it may work for some scenarios, it is not at all scalable.  Imagine 100,000 customers refreshing a webpage every minute to get a current snapshot of their stock portfolio!  A much more efficient approach is to implement publish/subscribe messaging.  Your real-time data source “publishes” the data as a series of messages and individual “subscribers” consume the data.  Whether there is one subscriber or a million subscribers, the publishing side simply broadcasts the data.

Flex offers two main components for this model:  Producer and Consumer.   These components need a server-side message broker to work.  This is where BlazeDS and LiveCycle Data Services come in. 

 

A simple chat application

Before you get into the visualization fun, building a simple chat app will help you understand the underlying communication mechanism on which real-time visualization in Flex depends. This obligatory “hello world” application will illustrate the publish/subscribe paradigm that enables efficient real-time data collection.

Note: Exercise 1 requires access to a working BlazeDS or LiveCycle Data Services deployment; the remaining exercises do not. If you’re not running BlazeDS or LiveCycle Data Services and don’t want to install one of them at this time, you can simply review the code in Exercise 1, and get hands-on with the data visualization exercises.

In this exercise you will learn how to build a simple chat application. You’ll code Flex Producer and Consumer objects that will communicate via a ChannelSet object. The ChannelSet object defines at runtime which type of channel will be used in communicating with the BlazeDS or LiveCycle Data Services server. The channels are defined in the order in which they should be used in the case of a failure. Your Consumer and Producer objects will contain a destination property pointing to a destination defined on your BlazeDS or LiveCycle Data Services server along with the message and fault handlers shown in the code sample below. The subscribe() method is called on the Consumer object to start listening to any incoming messages across the channel that the Producer may be sending. Consumed messages are shown in a TextArea when they’re received. The send() method on the Producer object is called to write messages out to the destination where those messages are then broadcast to any Consumers  currently subscribed.  

Note: You must add the destination to your messaging-config.xml file (see Appendix) on the BlazeDS/LiveCycle Data Services instance and restart your server for this to work correctly.

 

Complete Source Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" applicationComplete="init()">

<!--How to send a message to a topic as a producer of the message. Should see message sent on big screen.
Need to have a destination setup in messaging config called helloWorld under lcds-samples/WEB-INF/flex. -->

<mx:Script>
<![CDATA[
import mx.messaging.events.MessageEvent;
import mx.messaging.messages.AsyncMessage;
import mx.controls.Alert;

private function init():void
{
// Start listening for messages published in the "helloWorld" destination
consumer.subscribe();
}
private function messageHandler(event:MessageEvent):void
{
log.text += event.message.body.chatMessage + "\n";
}
// Add a send method to send the message as the producer
private function send():void
{
var message:AsyncMessage = new AsyncMessage();
// Set the term chatMessage for the body
message.body.chatMessage = msg.text;
producer.send(message);
msg.text = "";
}
]]>
</mx:Script>

<mx:ChannelSet id="channelSet">
<mx:AMFChannel url="http://your-lcds-blazeds-host:your-port/lcds-samples/messagebroker/amflongpolling"/>
</mx:ChannelSet>

<mx:Consumer id="consumer"
channelSet="{channelSet}"
destination="helloWorld"
message="messageHandler(event)"
fault="Alert.show(event.faultString)"/>

<!-- Add a producer to send messages -->
<mx:Producer id="producer"
channelSet="{channelSet}"
destination="helloWorld"/>

<mx:Panel title="Data Feed" width="100%" height="100%">
<mx:TextArea id="log" width="100%" height="100%" editable="false"/>
<mx:ControlBar>
<mx:TextInput id="msg" width="100%" enter="send()"/>
<mx:Button label="Send" click="send()"/>
</mx:ControlBar>
</mx:Panel>

</mx:Application>

 

See the Results:

 

You can now share this application with anyone that has access to the same server and chat with them.  

 

Consuming real-time data without visualization

If you are already a Flex developer, you are probably familiar with Tour de Flex, a tool developed by the Adobe evangelist team for exploring coding samples.  Tour de Flex includes more than 360 samples, which illustrate every Flex component as well as Adobe AIR and tons of third-party components.  You can download Tour de Flex from http://flex.org/tour.

More than a million samples are viewed every month in Tour de Flex and we track every single view.  Not only do we record each view, we publish this data to a message destination that you can connect to!

In this example you’ll learn how to consume the Tour de Flex real-time data feed. As in the previous sample, you will define your Producer, Consumer and ChannelSet objects but this time you will point to the Tour de Flex data feed destination (tdf.sampleviewingfeed).  Since there are other types of data feeds currently collected on the server you need to specify a subtopic of “Flex” to point to the Tour de Flex live data. When the data is received it is simply added to an ArrayCollection and shown as a new entry in the DataGrid.

 

Note: The destination can be accessed using four different channels: RTMP, AMF Streaming, AMF Long Polling, and AMF Polling. You can choose which channel(s) to use to access the destination. For example, if you don't want a dependency on fds.swc, do not use the RTMP channel definition. The order of the channels defined in the ChannelSet tag is important. The system will try to connect using the first one. If that connection fails, it will fall back to the next one, and so on. In production applications, these URLs shouldn't be hardcoded in the application. One alternative is to use a configuration file as described here:

http://coenraets.org/blog/2009/03/externalizing-service-configuration-using-blazeds-and-lcds/

For more information on defining and using channels, see the following link:

http://devgirl.wordpress.com/2009/07/14/livecycle-data-services-channels-and-endpoints-explained/        

 

Complete Source Code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init()">

<mx:Script>
<![CDATA[
import mx.messaging.events.MessageEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;

[Bindable]
private var feedItems:ArrayCollection = new ArrayCollection();

private function init():void
{
this.consumer.subscribe();
}
private function messageHandler(event:MessageEvent):void
{
feedItems.addItem(event.message.body);
}

]]>
</mx:Script>

<!-- The destination can be accessed using four different channels: RTMP, AMF Streaming, AMF Long Polling, AMF Polling.
You can choose which channel(s) to use to access the destination: just comment out the channels you don't want to use.
For example, if you don't want a dependency on fds.swc, uncomment the RTMP channel definition. The order of the channels
defined in the ChannelSet tag is important: The system will try to connect using the first one. If that connection fails,
it will fall back to the next one, etc. In real life, these URLs shouldn't be hardcoded in the application... One option
is to use a configuration file as described here:
http://coenraets.org/blog/2009/03/externalizing-service-configuration-using-blazeds-and-lcds/-->
<mx:ChannelSet id="channelSet">
<!-- RTMP channel -->
<!--<mx:RTMPChannel id="rtmp" url="rtmp://tourdeflex.adobe.com:2037"/>-->
<!-- Long Polling Channel -->
<mx:AMFChannel url="http://tourdeflex.adobe.com:8080/lcds-samples/messagebroker/amflongpolling"/>
<!-- Regular polling channel -->
<mx:AMFChannel url="http://tourdeflex.adobe.com:8080/lcds-samples/messagebroker/amfpolling"/>
</mx:ChannelSet>

<mx:Consumer id="consumer"
channelSet="{channelSet}"
destination="tdf.sampleviewingfeed"
subtopic="flex"
message="messageHandler(event)"
fault="Alert.show(event.faultString)"/>

<mx:Panel title="Data Feed" width="100%" height="100%">
<mx:DataGrid id="dg" dataProvider="{feedItems}" width="100%" height="100%"/>
</mx:Panel>

</mx:Application>

 

See the results:

 The end result should look something like the following, where each time a user accesses a Tour de Flex sample, you see it displayed in the DataGrid:

It’s not really pretty, but it’s cool to see real-time data appearing!

 

AttachmentSize
screenshot1.png90.65 KB
screenshot2.png300.22 KB
screenshot3.png52.59 KB
screenshot4.png514.05 KB
screenshot5.png256.45 KB
tourdeflex-screenshot.png144.08 KB
gregsq.jpg69.13 KB
Published at DZone with permission of its author, Holly Schinsky.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)