Another link I found the other day to a blog posting by Vaibhav Choudhary on using the JavaFX 1.2 Charting APIs.
He then followed up with a blog populating a chart from a web service call. The important pieces are the following code blocks. The first here is what generates the Pie Chart data slices after the web service call succeeded:
function generateChartData(tg:TagInformation, done:Boolean):PieChart.Data[] { for (i in [0..<sizeof tg.tag]) { PieChart.Data { action: function() { showShopping = true; } label: tg.tag[i] value: tg.tagCount[i] } } }
This function generateChartData
simply returns a sequence of PieChart.Data instances. “for loop” expressions in JavaFX yield a sequence, one item for each iteration of the loop. So the generated sequence will be one PieChart.Data for each result in the tg.tag sequence.
This next block of code uses the HttpRequest
class to fetch and parse the RSS feed from Del.icio.us. The only thing here that I might have done differently, is to have used the RSS APIs introduced in JavaFX 1.2 rather than hand rolling my own parsing code and using HttpRequest. First the code from the blog doing it the “long” way:
public class TagInformation { public var tag: String[]=[]; public var tagCount: Integer[]=[]; public var username: String = "javafx"; // for this sample it's javafx public-read var done = false; var url = bind "http://feeds.delicious.com/v2/rss/tags/{username}?count=4"; var p: PullParser; var h: HttpRequest; init { h = HttpRequest { location: url onException: function(exception: Exception) { exception.printStackTrace(); } onInput: function(input) { p = PullParser { input: input onEvent: function(event) { if ((event.type == PullParser.END_ELEMENT)) { if (event.qname.name == "title" and event.level == 3) { insert event.text into tag; } if(event.qname.name == "description" and event.level == 3){ insert Integer.parseInt(event.text) into tagCount; } } } }; p.parse(); p.input.close(); } onDone: function() { Main.showtag = false; done = true; } }; h.start(); } }
And now here is how I would have done it using the JavaFX 1.2 APIs. In JavaFX 1.2 we released some ATOM and RSS support. These classes are in the javafx.data.feed package.
public class TagInformation { public var tag: String[]=[]; public var tagCount: Integer[]=[]; public var username: String = "javafx"; // for this sample it's javafx public-read var done = false; var url = bind "http://feeds.delicious.com/v2/rss/tags/{username}?count=4"; init { RssTask { location: "http://feeds.delicious.com/v2/rss/tags/javafx?count=4" interval: 1h onItem: function(item) { insert item.title into tag; insert Integer.parseInt(item.description) into tagCount; } onDone: function() { done = true } }.start(); } }
The only thing here that I found somewhat irritating and will get put on the bug list for the next release is that you must specify an interval for the RssTask, even if you won’t be polling. Expect this to change to some reasonable polling value as the default. Maybe 1 hour (as in this example) isn’t a bad default. 1 minute is a bit more extreme, but for the feed-junkies out there maybe that’s a better default.
As you can see, the code is much simpler using the feed APIs. I guess that’s a good thing ;-). The RSS/ATOM feed APIs use the same basic programming model as HttpRequest — both extend from Task. Task’s have API for monitoring progress, canceling, starting, handling error condition, etc in a unified model. All asynchronous operations in JavaFX should extend from Task either directly or indirectly.