Table of Contents
searchhistogram
query from the Topsy API. The exact query is http://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.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! FusionChartsXTiOSDemo.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:@"
"]; [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:
// 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.
Have you ever spent hours buried in documentation, hunting for a specific piece of code?…
Do you feel like your data is a cryptic puzzle, locked away from revealing its…
In web development, mastering JavaScript charting libraries is crucial for keeping up with the fast-paced…
Ever spend an afternoon neck-deep in documentation, searching for that one elusive code snippet? Or…
In the dynamic world of data visualization, the need for precision and innovation has never…
Are you drowning in data but struggling to find the insights that drive real business…
View Comments
Do you have one for Android?
Hi Rowena,
You will have to use the WebView component provided in the Android SDK.
In the WebView, you can create charts using a similar methodology illustrated in this post.
Let us know when you try it in Android..
[self.htmlContent appendFormat:@"var chart_object = new FusionCharts('Column3D.swf', 'twitter_data_chart', '%f', '%f', '0', '1');", self.chartWidth, self.chartHeight];
What is the significance of '0', '1' in the HTML code?
Hi Saikat,
The FusionCharts constructor takes in parameters as follows:
- Chart's SWF name: This is automatically mapped to the JavaScript alias when rendering in JavaScript mode.
- Unique ID for chart: All charts should have unique IDs
- Width and Height: Dimensions can be specified in pixels or in percentages. When specified in percentages, the chart will relate to the container element.
- Enable Debug Mode: This is a Boolean which controls the Debug Window when rendered in Flash. For debugging in JavaScript, please refer to the JavaScript Debugging Documentation.
- Register with JavaScript: This parameter allow the FusionCharts JavaScript Object to interact with the chart. This is always set to '1' internally.
Hi, great tutorial. This is the one that finally helped me run FC inside an iOS app. Great work!
Now that I have the example working I'd like to go a bit further and refactor the code a bit. I'd like to run it by you if it's ok to be sure I'm understanding it all.
Besides connection checks and methods, the main events happen in createChartData:interfaceOrientation. As I see it this method does the following:
1- Check for valid data
2- Setup chart size
3- Setup chart XML and HTML
4- Draw chart
I want to refactor this code using MVC and I believe the separation should something like this:
(1) and (2) belong to the controller
(3) belongs to the model
(4) belongs to the view
Is that correct or am I missing something?
I'd like to be able to put everything in its place because when I start adding different data sources and reports this will get messy.
Thanks in advanced for this great post and for your help.
Best regards,
Hi Juan,
We're glad that you liked our tutorial.
The points you illustrate about refactoring the code to follow MVC are correct.
We believe you can further refine your code in this way:
Model:
(1) Retrieve the data
(2) Check for its validity
Controller:
(1) Setup chart size
(2) Setup the required XML and HTML
(3) Call the View from the Controller to draw the chart
View:
(1) Display the chart
Essentially we're are calling the View from the Controller itself. The code required to draw the chart should be in the Controller, while the View should simply interpret this code and render the chart.
Let us know if this works for you..
Hi, thanks!
I'm trying to make it work but I'm having troubles passing some info between classes.
Do you have by any chance an example (code) of some MVC scenario that I can look at and extrapolate to this one? Maybe some other tutorial that I can check and figure it out?
I'll keep on trying. Thanks again for the help.
Regards,
Hi,
Latest version fusionchart support in android 4.0 .Is it possible lower version android.Is there any solution?
Hi Ragav,
FusionCharts XT should work in all versions of the Android OS.
Are you facing any issues? Please let us know at support@fusioncharts.com and we'll help you out.
Hi Hrishikesh,
1.Yes, FusionCharts XT should work in above 3.0+ for me in android.Then how to figure out chart orientation in various android mobile screen?
2.Then can i write click event on fusion charts.Right now i can write click event on HTML div.But my requierment is click event on charts.
Hi,
Can you give me some tutorial for android with fusioncharts.
Hi Ragav,
We don't have a sample project which uses the Android WebView with FusionCharts XT. However, we are pretty sure the general idea behind the implementation would be the same.
If you would want to figure out the device orientation using the Android SDK, I suggest you look at - http://developer.android.com/reference/android/content/res/Configuration.html
Hi,
Can you give me some tutorial for android with fusioncharts.
Hi,
Thanks for the great tutorial.
I tried this example, b ut am not able to get this chart. I am getting the "Chart will render here" message on the view.
Please help me to solve this issue.
Thanks,
Nandha
Hi Nandha,
Please check the path for the JavaScript files. The div text is displayed when the FusionCharts JavaScript files are inaccessible.
You could also check if the HTML & XML strings are proper by writing them to the Xcode console.
Hi, this tutorial is awesome and you can understand it pretty good... but I am trying to put the graph as a extra view in a view controller... like a small chart in the bottom of the view linked to the variables given by some labels in the view controller, is there anyway you know a tutorial about this? or can you explain this please? I really need your help...
1... resizing the chart to look smaller and in a corner
2... link the bars (in the graph) with some label, so the user can type the numbers
Thanks I really appreciate
Hi Manuel,
Glad you liked the tutorial!
When you want to configure the chart according to some variables, you would need to follow the same technique as we did to create chart data using Twitter API. Simply pick the variables and include them while constructing the XML string.
You could reduce the size of the chart by (a) reducing the dimensions of the UIWebView, or (b) by setting the chart dimensions in pixels. In this tutorial, we've specified the chart dimensions in percentages.
Can you please explain what you mean by "link the bars ... so the user can type"?
I want two bars in the UIWebView... and the user will type a variable in a textfield, then the graph will shows the results... can you please give me a code example of how to do this? how to link the bars with some textfields or labels from a different view controller... I am new with Xcode and can't find a way to connect this together with the graph...
Hi Manuel,
You need to use the values of the text fields when constructing the chart XML.
Look for this line:
[self.chartData appendFormat:@"<set label='%@' value='%@' />", [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow:-(i+1)*86400]], [histogramData objectAtIndex:i]];
In this tutorial, we're providing Twitter data when constructing the XML.
Instead, you will need to pass your variables:
[self.chartData appendFormat:@"<set label='%@' value='%@' />", variable_from_text_field, variable_from_text_field];
This change should get you what you want.
Hi,
Thanks for the great tutorial.
I had tried the sample approcah and able to present the graphs on my ipad app.
But one area where I am confused about drill down charts. In the Web sample , I had seen when user clicks a chart it is getting redirected to particular page and the appropriate graphs are getting displayed.
So how to do the same using ios? I mean how to detect the click on a particular bar and render apprpriate graph in ios?
Hi,
The functionality that you are asking for is provided by LinkedCharts. Please have a look at the documentation for LinkedCharts.
Thanks.