Site icon FusionBrew – The FusionCharts Blog

Create Charts for iPhone and iPad Apps Using FusionCharts XT

To provide executives with access to business data on the go, enterprises are adopting iPhones and iPads in droves. Many of these applications need innovative data visualizations but are currently restricted by the limited capabilities of available charting libraries for iOS. Some have limited chart types, whereas others lack visual appeal and interactivity. Open-source libraries are not backed by proper technical support either. So what are your options? Enter FusionCharts XT, which addresses all these concerns. Being a JavaScript charting library, it can quickly render charts and widgets within the UIWebView control of an iOS application. With over 90 chart types that are animated and interactive, it augments the visual appeal and functionality of your iOS applications. In addition, dedicated tech support is there to answer any or all of your queries. You can either obtain the data from a remote web service or access the local data stores on the device. This data needs to be provided in XML or JSON format that the FusionCharts JavaScript graph object understands. This blog post will show you how to use FusionCharts XT in an iOS app and power it using data from a web service. We will create the necessary XML and HTML required for the UIWebView to display our chart.

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

How We Will Create the Chart

To create the chart, we will go through the following steps:

Creating the Xcode Project

Let us open Xcode and create a View-based project, and save it as FusionChartsXTiOSDemo. We now need to add FusionCharts XT’s JavaScript files to our project. Copy the JavaScript files present in 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. Add the JSONKit files, namely 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

In FusionChartsXTiOSDemo.h, add an IBOutlet for the WebView. @property (nonatomic, retain) IBOutlet UIWebView *webView; Also, @synthesizeand 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. We now need to connect the UIWebView outlet to this UIWebView. From the Document Window in Interface Builder, Ctrl+Drag from 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: After this, let us concern ourselves with the HTTP query and handling its JSON response. Uncomment the 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
2012-04-11
4.2/5 stars
Charts for iPhone & iPads
Exit mobile version