FusionCharts v3 offers tremendous integration capabilities with JavaScript. You can easily use FusionCharts and JavaScript to create client side dynamic charts.
Here, we'll see the JavaScript + URL method - where we ask the chart to fetch new data from server and update itself, without incurring any page refreshes. The entire application resides in a single page which makes it a seamless experience for your end viewers.
Before you proceed with the contents in this page, we strictly recommend you to please go through the sections "How FusionCharts works?" and "Basic Examples", as we'll directly use a lot of concepts defined in those sections.
All code discussed here is present in
Controller : Download Package > Code > RoR > app > controllers > fusioncharts > db_js_data_url_controller.rb.
Rhtml : Download Package > Code > RoR > app > views > fusioncharts > db_js_dataurl folder.
Let us first define what we want to achieve in this example. We'll carry on from our previous drill-down example and convert it into a single page example. In our previous example, we were showing the Production Summary of all the factories in a pie chart. When the user clicked on a pie slice, he was taken to another page, where a detailed date-wise chart was shown for the required factory.
In this example, we'll assimilate both the charts in a single page and make them interact with each other using JavaScript, thereby making the end-user experience smooth. Effectively, we will do the following:
- Contain both the pie chart (summary) and column chart (detailed) in one page (default.html.erb).
- When the page loads, the pie chart would use dataXML method to show summary of all factories.
- The column chart would initialize with no data, as the user has not selected a factory initially. We'll customize the "No data to display" message of the chart to show a friendly message.
- The pie chart would have JavaScript links defined for each pie slice. This JavaScript links refer to updateChart() JavaScript function present on the same page. We'll later see how to hand code this function. When a pie is clicked, the factory ID is passed to this function.
- The updateChart() function is responsible for updating the column chart. It generates a dataURL link by including the factoryId as a part of dataURL. Once the dataURL is built, it conveys this dataURL to the column chart.
- The column chart would now accept this dataURL, the associated action factory_details is invoked to create XML data and finally render.
We have two actions in our Fusioncharts::DbJsDataurlController controller - default and detailed just like in our previous example. Then what is the difference? Let's take a look:
Controller: Fusioncharts::DbJsDataurlController
Action: default
class Fusioncharts::DbJsDataurlController < ApplicationController
def default
headers["content-type"]="text/html";
@animate_chart = params[:animate]
if(@animate_chart=='')
@animate_chart = '1'
end
@factory_data = []
factory_masters = FactoryMaster. find(:all)
factory_masters.each do |factory_master|
factory_id = factory_master.id
factory_name = factory_master.name
total = 0.0
factory_master.factory_output_quantities.each do |factory_output|
total = total + factory_output.quantity
end
@factory_data<<{:factory_id=>factory_id,:factory_name=>factory_name,:factory_output=>total}
end
end
We will see the view in a minute. Let us first assimilate what the controller is doing.
- Gets the request parameter animate and assigns it to the variable @animate_chart
- Performs a find on the Model FactoryMaster to select all the columns.
- Iterates through the recordset obtained above and obtains the factory id and name.
- For each factory, iterates through the factory_output_quantities and calculates the total quantity for this factory.
- Constructs a hash containing factory id, factory name and total output.
- Appends the hash to the array @factory_data.
So, where is the link to the detailed chart created? Let's analyze the view.
View: (default.html.erb)
<HTML>
<HEAD>
<TITLE>FusionCharts - Database + JavaScript Example</TITLE>
<%= javascript_include_tag "FusionCharts" %>
%>
<SCRIPT LANGUAGE="JavaScript">
function updateChart(factoryIndex){
var strURL = "/Fusioncharts/db_js_dataurl/factory_details?factoryId=" + factoryIndex;
strURL = escape(strURL);
//Get reference to chart object using Dom ID "FactoryDetailed"
var chartObj = getChartFromId("FactoryDetailed");
//Send request for XML
chartObj.setDataURL(strURL);
}
function getTimeForURL(){
var dt = new Date();
var strOutput = "";
strOutput = dt.getHours() + "_" + dt.getMinutes() + "_" + dt.getSeconds() + "_" + dt.getMilliseconds();
return strOutput;
}
</SCRIPT>
<style type="text/css">
<!--
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
}
.text{
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
}
-->
</style>
</HEAD>
<BODY>
<CENTER>
<h2>FusionCharts Database + JavaScript (dataURL method) Example</h2>
<h4>Inter-connected charts - Click on any pie slice to see detailed
chart below.</h4>
<p>The charts in this page have been dynamically generated using
data contained in a database.</p>
<%
str_xml = render :file=>"fusioncharts/db_js_dataurl/factories_quantity", :locals=>{:factory_data=>@factory_data}
render_chart '/FusionCharts/Pie3D.swf','',str_xml,'FactorySum', 500, 250, false, false do-%>
<% end -%>
<BR>
<%
render_chart '/FusionCharts/Column2D.swf?ChartNoDataText=Please select a factory from pie chart above to view detailed data.','','<chart></chart>','FactoryDetailed',600, 250, false, true do-%>
<% end -%>
<BR>
<BR>
<a href='/NoChart.html' target="_blank">Unable to see the charts above?</a>
</CENTER>
</BODY>
</HTML>
Note that this view does not use the "common" layout, as this view is quite different and has lot of javascript code too.
Before we get to the JavaScript functions, let's first see what we're doing in our ruby code. This is the piece of code:
<%
str_xml = render :file=>"fusioncharts/db_js_dataurl/factories_quantity", :locals=>{:factory_data=>@factory_data}
render_chart '/FusionCharts/Pie3D.swf','',str_xml,'FactorySum', 500, 250, false, false do-%>
<% end -%>
<BR>
<%
render_chart '/FusionCharts/Column2D.swf?ChartNoDataText=Please select a factory from pie chart above to view detailed data.','','<chart></chart>','FactoryDetailed',600, 250, false, true do-%>
<% end -%>
Here as you can see, we have rendered two charts. For the first chart , we use the builder factories_quantity.builder to obtain the xml. Then call render_chart function to show a Pie3D chart with this xml as data.
For the second chart, we chart Column2D chart with parameter ChartNoDataText and the initial xml <chart></chart>. This will initialize the chart an ddisplay the message on the screen just below the first chart.
The builder does the actual work of creating the link to the second chart. Like this:
xml = Builder::XmlMarkup.new
xml.chart(:caption=>'Factory Output report', :subCaption=>'By Quantity', :pieSliceDepth=>'30', :showBorder=>'1', :formatNumberScale=>'0', :numberSuffix=>' Units', :animation=>@animate_chart) do
for item in @factory_data
xml.set(:label=>item[:factory_name],:value=>item[:factory_output],
:link=>'javaScript:updateChart('+item[:factory_id].to_s + ')')
end
end
Effectively, our page is now set to show two charts. The pie chart shows the summary data provided to it using dataXML method. The column chart shows the above "friendly" error message. Now, when each pie slice is clicked, the updateChart() JavaScript function is called and the factoryID of the pie is passed to it. This function is responsible for updating the column chart and contains the following code:
function updateChart(factoryIndex){
var strURL = "/Fusioncharts/db_js_dataurl/factory_details?factoryId=" + factoryIndex;
strURL = escape(strURL);
var chartObj = getChartFromId("FactoryDetailed");
chartObj.setDataURL(strURL);
}
Here,
- We first create a dataURL string by appending the factoryID to the path to the detailed action factory_details.
- Thereafter, we URL Encode this dataURL.
- Finally, we convert this dataURL to the column chart. To do so, we first get a reference to the column chart using it's DOM Id FactoryDetailed. We use the getChartFromId() function defined in FusionCharts.js to do so.
- Once we've the reference to the chart, we simply call the setDataURL method of the chart and pass it the URL to request data from.
- This updates the chart with new data.
This completes our front-end for the app. We now just need to build factory_details action and builder, responsible to provide detailed data to column chart. It contains the following code:
Controller: Fusioncharts::DbJsDataurlController
Action: factory_details
def factory_details
headers["content-type"]="text/xml";
@factory_id = params[:factoryId]
@factory_data = []
factory_master = FactoryMaster. find(@factory_id)
factory_master.factory_output_quantities.each do |factory_output|
date_of_production = factory_output.date_pro
formatted_date = format_date_remove_zeroes(date_of_production)
quantity_number = factory_output.quantity
@factory_data<<{:date_of_production=>formatted_date,:quantity_number=>quantity_number}
end
end
This action is same as the detailed action seen in the drill-down example. We basically request the factory Id passed to it as querystring, query the database for required data contruct an array of hashes with date of production and quantity values. Note that the content-type of this action is "text/xml". This arrray is used by the builder as shown:
xml = Builder::XmlMarkup.new
xml.chart(:palette=>'2', :caption=>'Factory' + @factory_id.to_s + ' Output ', :subcaption=>'(In Units)', :xAxisName=>'Date', :showValues=>'1', :labelStep=>'2') do
for item in @factory_data
xml.set(:label=>item[:date_of_production],:value=>item[:quantity_number])
end
end
This is a simple xml with <set> tags within <chart> element. Each <set> element has attributes label and value. "label" attribute takes value of date of production and the attribute "value" has value as quantity. The values for the attributes are obtained from the hash present in the @factory_details array of the controller.
When you now see the application, the initial state would look as under:
And when you click on a pie slice, the following would appear on the same page (without involving any browser refreshes):
This example demonstrated a very basic sample of the integration capabilities possible with FusionCharts v3. For advanced demos, you can see and download our FusionCharts Blueprint/Demo Applications. |