Table of Contents
Example – An iOS App to Plot Twitter Data Using FusionCharts XT
We will be plotting the count of mentions of ‘HTML5’ for each of the last seven days in a UIWebView control using FusionCharts XT. This is how your chart will finally look like in an iPhone:Requirements
- Xcode 3.2 and above
- The latest version of FusionCharts XT
- JSONKit library
- You would need to have internet access too. We will be using the
searchhistogram
query from the Topsy API. The exact query ishttp://otter.topsy.com/searchhistogram.json?q=html5&slice=86400&period=7
. You may run this query and see the JSON response, which returns the number of times ‘HTML5’ was mentioned every day for the last seven days.
How We Will Create the Chart
To create the chart, we will go through the following steps:- Create a View-based project in Xcode
- Use Topsy’s Otter API to get the count of mentions of ‘HTML5’ over the last seven days
- Use JSONKit to parse through the received JSON response
- Create the XML data for the chart
- Create the HTML required to show the chart
- Enable rotation of the chart according to the device’s orientation so that the chart will fit the screen whether the device is in landscape or portrait mode
Creating the Xcode Project
Let us open Xcode and create a View-based project, and save it as FusionChartsXTiOSDemo.Download Package > Charts
to the Xcode Resources project group. Make sure you select the Copy items into destination group’s folder (if needed)
checkbox on the top. Doing so would ensure that you have a copy of all the JavaScript files local to your application. Click Add
to add your files to your project.
We need to modify Xcode’s compilation step a little bit. Xcode considers JavaScript files as code (rightfully so) and tries to compile them. However, we want these files to render charts inside our UIWebView and not compiled. Expand the Targets
group and your project target. Our target is called FusionChartsXTiOSDemo
. Also, expand the Copy Bundle Resources
and Compile Sources
build phases. Next, select the JavaScript files and drag them from the compile stage to the copy bundle build phase.
JSONKit.h
and JSONKit.m
to your project too. We have now prepared Xcode with all the files necessary. Let us begin designing and coding!
Designing and Coding
InFusionChartsXTiOSDemo.h
, add an IBOutlet
for the WebView.
@property (nonatomic, retain) IBOutlet UIWebView *webView;
Also, @synthesize
and release
this accordingly.
Open your project’s main view controller Interface Builder file (inside the Resources group). For our project this file is called FusionChartsXTiOSDemoViewController.xib
. To add a WebView control to your app, drag a UIWebView from Interface Builder’s library to our view.
File’s Owner
to the UIWebView
. You should get a popup bubble, click webView
. Save your work and close Interface Builder.
Next, we will add the required properties needed to create the chart data and its configuration. We will write the following code in FusionChartsXTiOSDemo.h
:
// Chart properties. @property (nonatomic, retain) NSMutableString *htmlContent; @property (nonatomic, retain) NSMutableString *javascriptPath; @property (nonatomic, retain) NSMutableString *chartData; @property (nonatomic, retain) NSMutableString *chartType; @property (nonatomic, assign) UIInterfaceOrientation currentOrientation; @property (nonatomic, assign) CGFloat chartWidth; @property (nonatomic, assign) CGFloat chartHeight; @property (nonatomic, retain) NSMutableString *debugMode; @property (nonatomic, retain) NSMutableString *registerWithJavaScript;Let us also add the properties we require to perform the HTTP request and to handle the response data:
// Twitter data. @property (nonatomic, retain) NSMutableString *twitterQuery; @property (nonatomic, retain) NSMutableData *twitterData; @property (nonatomic, retain) NSDictionary *twitterDataDictionary; @property (nonatomic, assign) BOOL twitterDataError;Remember to
@synthesize
and release
the above properties correctly.
Declare the following 4 methods here; we will define them later.
- (void)displayDataError; - (void)createChartData:(UIInterfaceOrientation)interfaceOrientation; - (void)plotChart; - (void)removeChart;As a best practice, let us keep our first task to handle any error that might crop up because of connectivity issues. For this, we need to define the
displayDataError
method. We need to create the HTML that displays the error in plain English to the user in his WebView.
- (void)displayDataError { NSMutableString *displayErrorHTML = [NSMutableString stringWithString:@""]; [displayErrorHTML appendString:@""]; [displayErrorHTML appendString:@""]; [displayErrorHTML appendString:@"Unable to plot chart. Error receiving data from Twitter. "]; [displayErrorHTML appendString:@""]; [self.webView loadHTMLString:displayErrorHTML baseURL:nil]; }We have created the HTML content to show in the WebView in case of a network error or in case the Topsy API is unable to respond. Also, we could simulate a network error for testing this method either by unplugging the LAN cable or turning off the WiFi. When you’ve done either of these, run the project, and this is the error that you should see:
viewDidLoad
method, and create and execute the query to Topsy’s API:
// Setting up the Twitter query. self.twitterQuery = [NSMutableString stringWithFormat:@"%@", @"http://otter.topsy.com/searchhistogram.json?q=html5&slice=86400&period=7"]; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.twitterQuery]]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; // Check whether we have a valid connection. if (connection) { // Create the NSMutableData to hold the received data. self.twitterData = [NSMutableData data]; } else { // Error in receiving data. self.twitterDataError = YES; } // Done using the connection. [connection release];Now that we have made the connection, we need to prepare the four delegates of
NSURLConnection
.
We should reset all previous data each time we receive a message at connection:didReceiveResponse
.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { // This method is called when the server has determined that it // has enough information to create the NSURLResponse. // It can be called multiple times, for example, in the case of a // redirect, so each time we reset the data. // (Re)Initialize the Twitter data store. [self.twitterData setLength:0]; }Let us implement the delegate that stores the newly sent data.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // Store received data. [self.twitterData appendData:data]; }If NSURLConnection returns an error while loading the data, let us explain it in plain English to the user using our own method
displayDataError
.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { // Display an error on connection failure. [self displayDataError]; }Finally, using JSONKit, let us convert the data stored in
self.twitterData
to a dictionary. Once the data has been converted, we call the createChartData::(UIInterfaceOrientation)interfaceOrientation
method.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { // Convert received JSON data to an Objective-C dictionary. self.twitterDataDictionary = [self.twitterData objectFromJSONData]; // Create chart as per current orientation. self.currentOrientation = self.interfaceOrientation; [self createChartData:self.currentOrientation]; }In the
createChartData::(UIInterfaceOrientation)interfaceOrientation
method, we need to parse through the dictionary and form our XML. Note that the dictionary has two keys named request
and response
. Within response
, there is an array named histogram
, which holds the count of mentions of ‘HTML5’ for the last seven days. We need to get hold of this array in NSArray
.
- (void)createChartData:(UIInterfaceOrientation)interfaceOrientation { // Check whether we have valid data. if (self.twitterDataError) { [self displayDataError]; } else { // Valid data. self.chartWidth = 300; self.chartHeight = 440; // Setup chart XML. NSDictionary *responseData = [self.twitterDataDictionary objectForKey:@"response"]; NSArray *histogramData = [responseData objectForKey:@"histogram"];We continue the same code block to iterate through
histogramData
and form the chart data in XML. Since the numbers in the array are for the previous seven days, starting from yesterday, we need to calculate and format the date accordingly.
self.chartData = [NSMutableString string]; [self.chartData appendFormat:@""]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateStyle:NSDateFormatterShortStyle]; for (int i = 0; i < [histogramData count]; i++) { [self.chartData appendFormat:@"", [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow:-(i+1)*86400]], [histogramData objectAtIndex:i]]; } [self.chartData appendFormat:@""]; [dateFormatter release];In the same code block, we create the HTML required to show the chart. Note the path of
FusionCharts.js
in the tag. We will provide the base URL when we actually load the HTML in the WebView.
// Setup chart HTML. self.htmlContent = [NSMutableString stringWithFormat:@"%@", @""]; [self.htmlContent appendString:@""]; [self.htmlContent appendString:@"
Chart will render here.
"]; [self.htmlContent appendString:@""];Finally, we send the
plotChart
message to self
.
// Draw the actual chart. [self plotChart]; } }Thereafter, we will define the
plotChart
method. In this method we will provide the baseURL
, and load the HTML string we created.
- (void)plotChart { NSURL *baseURL = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@", [[NSBundle mainBundle] bundlePath]]]; [self.webView loadHTMLString:self.htmlContent baseURL:baseURL]; }Run this project in the iPhone Simulator, you would get the following chart:
Making FusionCharts Aware of the Orientation
However, our work here is not done yet. We still need to add orientation support to this project. Let us override the default value to allow autorotation according to the orientation.// Override to allow orientations other than the default portrait orientation. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES since we support all orientations. return YES; }We need to dispose of the chart before we render it again according to the new orientation. To do this, we can can empty
chart_container
of all the HTML. Let us write the removeChart
method to do this.
- (void)removeChart { NSString *emptyChartContainer = [NSString stringWithString:@""]; [self.webView stringByEvaluatingJavaScriptFromString:emptyChartContainer]; }Next, we need to know exactly when the device begins to rotate. For this, we have the
)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
class method. In this method, we will first check if the data is valid; so that an error message will be displayed even upon rotation. Next, we store the orientation to which the device is rotating to. Then we remove the chart and render it again according to the new orientation.
// Handle interface rotation. - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { // Check whether we have valid data. if (self.twitterDataError) { [self displayDataError]; } else { // Valid data. // Store new orientation. self.currentOrientation = toInterfaceOrientation; // Remove existing chart and recreating it // as per the new orientation. [self removeChart]; [self createChartData:self.currentOrientation]; } }In the
createChart
method, we need to supply the new chart dimensions to the FusionCharts object according to the orientation. So let us add the following code just before the block where we create the chart XML:
// Set chart width and height depending on the screen's orientation. if (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) { self.chartWidth = 300; self.chartHeight = 440; } else if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight) { self.chartWidth = 440; self.chartHeight = 280; }Let us now run this project. Rotate your iPhone Simulator by ⌘+Left Arrow or ⌘+Right Arrow.
Download Sample Project
The sample project that we created is available for download. We used Xcode 3.2 and the target was iOS 4.2.Taking It Further
You can expand on this project by using the other chart types provided by FusionCharts. Also, you can interface with a database on the backend, and provide a UI to create the SQL queries in the WebView itself. You could make use of the Spark Line charts provided in FusionWidgets XT and create a html5 dashboard for your iPhone and iPad users. Drill-down JavaScript charts are also super easy to create. The field is open for experimentation. Do share your implementations with us.FusionCharts Suite XT
Tom
2012-04-11 4.2/5 stars
Charts for iPhone & iPads