Current File : /home/caballoscriollos/public_html/espanol/encuesta/graphs/contents/ruby_js_xml.html
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>FusionCharts v3 Documentation</title>
<link rel="stylesheet" href="Style.css" type="text/css" />
</head>
<body>
<table width="98%" border="0" cellspacing="0" cellpadding="3" align="center">
<tr>
<td><h2 class="pageHeader">Combining FusionCharts, RoR - JavaScript (dataXML) method </h2></td>
</tr>
<tr>
<td valign="top" class="text"><p>In our previous example, we had combined FusionCharts, Ruby and JavaScript to create client side dynamic charts. We were updating the chart by asking it to fetch new data from server and update itself, without incurring any page refreshes. </p>
<p>In this example, we will see how to <strong> provide updated XML data to chart using JavaScript </strong> functions. The chart will simply accept that XML data and then render. </p>
<p class="highlightBlock">This method can effectively be used in your AJAX applications, where your JavaScript code gets the updated XML from server and then provides it to charts locally. You can process the data received from AJAX Calls, build XML from it and finally provide it to the chart. </p>
<p><strong>Before you proceed with the contents in this page, we strictly recommend you to please go through the sections "How FusionCharts works?" and
"<a href="PHP_DB.html">Plotting from Database Example</a>", as we'll directly use a lot of concepts defined in those sections.</strong></p>
<p class="highlightBlock">All code discussed here is present in <br>
<span class="codeInline">Controller : Download Package > Code > RoR > SampleApp > app > controllers > fusioncharts > db_js_controller.rb</span>. <br>
<span class="codeInline">View : Download Package > Code > RoR > SampleApp > app > views > fusioncharts > db_js</span> folder. </p>
<p class="header">Defining the applicaton </p>
<p>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. </p>
<p>In this example we will put both the charts together on a single page where clicking on a pie slice of the Production Summary chart will open the detailed chart on the same page without page refresh.</p>
<p>Effectively, we will do the following:</p>
<ol>
<li>Contain both the pie chart (summary) and column chart (detailed) in one page (<span class="codeInline">default</span>).</li>
<li>When the page loads, the pie chart would use <span class="codeInline">dataXML</span> method to show summary of all factories. This data will be built in <span class="codeInline">factories_quantity</span> builder. </li>
<li>There will be a JavaScript array named <span class="codeInline">data</span> in this page. This array will contain detailed data for the factories. The array will be dynamically built by the controller and then outputted as JavaScript code. </li>
<li>Apart from the data in JavaScript, we'll also have a local JavaScript function <span class="codeInline">updateChart()</span>, which would process the data in this array and convert it to XML data document, for direct usage by the column chart. </li>
<li>The column chart would initialize with no data, as there is no factory selected initially. We'll customize the "<span class="codeInline">No data to display</span>" message of the chart to show a friendly message.</li>
<li>The pie chart would have JavaScript links defined for each pie slice. This JavaScript links refer to <span class="codeInline">updateChart()</span> JavaScript function present on the same page. We'll later see how to hand code this function. When a pie is clicked, the <span class="codeInline">factoryID </span>and factoryName are passed to this function. </li>
<li>The <span class="codeInline"> updateChart()</span> function is responsible for updating the column chart. It generates the XML data from data stored in JavaScript <span class="codeInline">data</span> array and conveys it to the column chart using the <span class="codeInline">updateChartXML</span> method.</li>
<li>The column chart would now accept this XML data, parse it and finally render.</li>
</ol>
<p>We will first take a look at the controller action <span class="codeInline">default</span>.</p>
<p><span class="header">Creating the page containing the charts</span></p>
<p class="codeBlock"><b>Controller: Fusioncharts::DbJsController<br>
Action: default<br>
</b><span class="codeComment">#In this action, the total quantity produced and name of each factory <br>
#is obtained from the database and plotted.<br>
#On clicking on a pie-section, it links to another chart giving detailed information <br>
#of each output produced and the date of production. For this dataURL method is used from the js.<br>
#of that factory. An array is created to store the index, factory name and total output. This <br>
#array is accessible to the view. Also, a js_var_string variable is constructed.<br>
#This variable contains javascript code to create an array, to contain the date of production<br>
#and the factory output quantity.</span><br>
def default<br>
headers["content-type"]="text/html";<br>
@factory_data = [] <br>
@js_var_string =""<br>
index_count = -1<br>
<span class="codeComment"> #Get data from factory masters table</span><br>
factory_masters = FactoryMaster.find(:all)<br>
factory_masters.each do |factory_master| <br>
total=0.0<br>
<strong>index_count = index_count + 1</strong><br>
factory_id = factory_master.id<br>
factory_name = factory_master.name<br>
<span class="codeComment"> # Construct the javascript variable to hold an array.</span><br>
<strong> @js_var_string =@js_var_string+ "data[" + index_count.to_s + "] = new Array();\n" ; </strong> factory_master.factory_output_quantities.each do |factory_output|<br>
date_of_production = factory_output.date_pro<br>
<span class="codeComment"># Formats the date to dd/mm without leading zeroes</span><br>
formatted_date = format_date_remove_zeroes(date_of_production)<br>
quantity_number = factory_output.quantity<br>
<span class="codeComment"> # Calculate the total quantity for this factory</span><br>
total = total + factory_output.quantity<br>
<span class="codeComment"> # Append values to the javascript array</span><br>
<strong>@js_var_string =@js_var_string+ "\t\t\t\tdata[" + index_count.to_s + "].push(new Array('" + formatted_date + "','" +quantity_number.to_s+"'));\n"</strong> <br>
end<br>
<span class="codeComment"> #Formatting the output html</span><br>
<strong> @js_var_string =@js_var_string+"\t\t\t";</strong><br>
<span class="codeComment"> #Push hash of values into the array </span><br>
@factory_data<<{:factory_index=>index_count,:factory_name=>factory_name,:factory_output=>total}<br>
end<br>
end</p>
<p class="text">Most of the code in the controller is the same. The changed portions have been highlighted above. <b> </b></p>
<ol>
<li>Perform a find on the Model FactoryMaster to select all the columns.</li>
<li>Iterate through the recordset obtained above and obtain the factory id and name. Also a variable index_count which starts with 0 is incremented in the beginning of this loop. This number is used as an index for this factory in the javascript array which we will create. </li>
<li>For each factory, iterate through the factory_output_quantities and calculates the total quantity for this factory. Also, create a variable @js_var_string to which <strong><br>
"data[" + index_count.to_s + "].push(new Array('" + formatted_date + "','"+quantity_number.to_s+"'));"<br>
</strong>is appended. This js_var_string when output to html, creates a code to construct the 2-dimensional javascript array data. data[0], say,will contain an array with date of production and quantity values for a particular factory. So on, for all other factories. </li>
<li>Constructs a hash containing <span class="codeInline">index_count</span>, factory name and total output.</li>
<li>Appends the hash to the array <span class="codeInline">@factory_data</span>. </li>
</ol>
<p>This array @factory_data is used by the view to generate the first chart. The <span class="codeInline">@js_var_string</span> is used in the view to create the javascript array. This is shown below: </p>
<p class="codeBlock"><strong>View: default.html.erb<br>
</strong><HTML><br>
<HEAD><br>
<TITLE>FusionCharts Free - Client Side Dynamic Chart (using Database) Example</TITLE><br>
<%<br>
<span class="codeComment">#In this example, we show a combination of database + JavaScript rendering using FusionCharts.<br>
#The entire example (page) can be summarized as under. This app shows the break-down<br>
#of factory wise output generated. In a pie chart, we first show the sum of quantity<br>
#generated by each factory. These pie slices, when clicked would show detailed date-wise<br>
#output of that factory.<br>
<br>
#The XML data for the pie chart is fully created in the controller at run-time. The controller interacts<br>
#with the database and creates the XML for this.<br>
#Now, for the column chart (date-wise output report), we do not submit request to the server.<br>
#Instead we store the data for the factories in JavaScript arrays. These JavaScript<br>
#arrays are rendered by our ruby Code (at run-time). We also have a few defined JavaScript<br>
#functions which react to the click event of pie slice.</span><br>
<br>
<br>
<span class="codeComment">#Before the page is rendered, we need to connect to the database and get the<br>
#data, as we'll need to convert this data into JavaScript variables.<br>
<br>
#The js_var_string will contain the JS Data and variables.<br>
#This string will be built in the controller and rendered at run-time as JavaScript.</span><br>
%><br>
<%= javascript_include_tag "FusionCharts" %><br>
<% <span class="codeComment">#You need to include the above JS file, if you intend to embed the chart using JavaScript.<br>
#Embedding using JavaScripts avoids the "Click to Activate..." issue in Internet Explorer<br>
#When you make your own charts, make sure that the path to this JS file is correct. <br>
#Else, you would get JavaScript errors.</span><br>
%><br>
<br>
<SCRIPT LANGUAGE="JavaScript"><br>
<%<br>
<span class="codeComment"> #Here, we use a mix of server side code (ruby) and JavaScript to<br>
#render our data for factory chart in JavaScript variables. We'll later<br>
#utilize this data to dynamically plot charts.<br>
<br>
#All our data is stored in the data array. In the controller, we iterate through<br>
#each resultset of data and then store it as nested arrays in this data array.</span><br>
%><br>
var data = new Array();<br>
<br>
<%<br>
<span class="codeComment">#Write the data as JavaScript variables here<br>
#The data is now present as arrays in JavaScript. Local JavaScript functions<br>
#can access it and make use of it. We'll see how to make use of it.<br>
</span><br>
%><br>
<%= @js_var_string %><br>
<% <span class="codeComment">#The data is now present as arrays in JavaScript. Local JavaScript functions<br>
#can access it and make use of it. We'll see how to make use of it. </span><br>
%><br>
<br>
<span class="codeComment">/** <br>
* updateChart method is invoked when the user clicks on a pie slice.<br>
* In this method, we get the index of the factory, build the XML data<br>
* for that that factory, using data stored in data array, and finally<br>
* update the Column Chart.<br>
* @param factoryIndex Sequential Index of the factory.<br>
* @param factoryName Name of the factory.<br>
*/</span> <br>
function updateChart(factoryIndex,factoryName){<br>
<span class="codeComment">//defining array of colors<br>
//We also initiate a counter variable to help us cyclically rotate through<br>
//the array of colors.</span><br>
var FC_ColorCounter=0;<br>
var arr_FCColors= new Array("1941A5" , "AFD8F8", "F6BD0F", "8BBA00", "A66EDD", "F984A1", "CCCC00", "999999", "0099CC", "FF0000", "006F00",<br>
"0099FF", "FF66CC", "669966", "7C7CB4", "FF9933", "9900FF", "99FFCC", "CCCCFF", "669900");<br>
<br>
<br>
<span class="codeComment">//Storage for XML data document</span><br>
var strXML = "<graph caption='" + factoryName + " Output ' subcaption='(In Units)' xAxisName='Date' decimalPrecision='0'>";<br>
<br>
<span class="codeComment">//Add <set> elements</span><br>
var i=0;<br>
for (i=0; i<data[factoryIndex].length; i++){<br>
strXML = strXML + "<set name='" + data[factoryIndex][i][0] + "' value='" + data[factoryIndex][i][1] + "' color='"+ arr_FCColors[++FC_ColorCounter % arr_FCColors.length] +"' />";<br>
}<br>
<br>
<span class="codeComment">//Closing graph Element</span><br>
strXML = strXML + "</graph>";<br>
<span class="codeComment">//Update it's XML</span><br>
updateChartXML("FactoryDetailed",strXML);<br>
} <br>
</SCRIPT><br>
<style type="text/css"><br>
<!--<br>
body {<br>
font-family: Arial, Helvetica, sans-serif;<br>
font-size: 12px;<br>
}<br>
.text{<br>
font-family: Arial, Helvetica, sans-serif;<br>
font-size: 12px;<br>
}<br>
--><br>
</style><br>
</HEAD><br>
<BODY><br>
<CENTER><br>
<h3><a href="http://www.fusioncharts.com" target="_blank">FusionCharts Free</a> Database + JavaScript Example</h2><br>
<h5>Inter-connected charts - Click on any pie slice to see detailed<br>
chart below.</h4><br>
<p>The charts in this page have been dynamically generated using<br>
data contained in a database. We've NOT hard-coded the data in<br>
JavaScript.</p><br>
<% <br>
<span class="codeComment"># The xml is obtained as a string from builder template.</span><br>
str_xml = render "fusioncharts/db_js/factories_quantity", {:factory_data=>@factory_data}<br>
<span class="codeComment">#Create the chart - Pie 3D Chart with data from strXML</span><br>
render_chart '/FusionCharts/FCF_Pie3D.swf', '', str_xml, 'FactorySum', 650, 300, false, false do-%><br>
<% end-%><br>
<BR><br>
<%<br>
<span class="codeComment"> #Column 2D Chart with changed "No data to display" message<br>
#We initialize the chart with <graph></graph></span><br>
render_chart '/FusionCharts/FCF_Column2D.swf?ChartNoDataText=Please click on a pie slice above to view detailed data.', '',<br>
'<graph></graph>','FactoryDetailed', 600, 300, false, false do-%><br>
<% end-%><br>
<BR><br>
<BR><br>
<a href='/NoChart.html' target="_blank">Unable to see the charts above?</a><br>
<BR><h5><%= link_to '&laquo; Back to list of examples', :controller=>'fusioncharts/index'%></h5><br>
</CENTER><br>
</BODY><br>
</HTML><br>
</p>
<p>In this page, we first render all the data in database as JavaScript array. To do so, output the variable that is present in the controller <span class="codeInline">@jsVarString</span> in the <span class="codeInline"><SCRIPT></span> section of <span class="codeInline"><HEAD> tag </span>as shown.</p>
<p class="codeBlock"> var data = new Array();<br />
<%= @jsVarString %><br />
</p>
<p>If you run this page and view the source JavaScript code, you'll see the following: </p> <p class="codeBlock">var data = new Array();<br />
<br />
data[0] = new Array();<br>
data[0].push(new Array('01/01','21'));<br>
data[0].push(new Array('02/01','23'));<br>
data[0].push(new Array('03/01','22'));<br>
data[0].push(new Array('04/01','24'));<br>
data[0].push(new Array('05/01','32'));<br>
data[0].push(new Array('06/01','21'));<br>
data[0].push(new Array('07/01','34'));<br>
data[0].push(new Array('08/01','32'));<br>
data[0].push(new Array('09/01','32'));<br>
data[0].push(new Array('10/01','23'));<br>
data[0].push(new Array('11/01','23'));<br>
data[0].push(new Array('12/01','32'));<br>
data[0].push(new Array('13/01','53'));<br>
data[0].push(new Array('14/01','23'));<br>
data[0].push(new Array('15/01','26'));<br>
data[0].push(new Array('16/01','43'));<br>
data[0].push(new Array('17/01','16'));<br>
data[0].push(new Array('18/01','45'));<br>
data[0].push(new Array('19/01','65'));<br>
data[0].push(new Array('20/01','54'));<br>
data[1] = new Array();<br>
data[1].push(new Array('01/01','121'));<br>
data[1].push(new Array('02/01','123'));<br>
data[1].push(new Array('03/01','122'));<br>
data[1].push(new Array('04/01','124'));<br>
data[1].push(new Array('05/01','132'));<br>
data[1].push(new Array('06/01','121'));<br>
data[1].push(new Array('07/01','134'));<br>
data[1].push(new Array('08/01','132'));<br>
data[1].push(new Array('09/01','132'));<br>
data[1].push(new Array('10/01','123'));<br>
data[1].push(new Array('11/01','123'));<br>
data[1].push(new Array('12/01','132'));<br>
data[1].push(new Array('13/01','153'));<br>
data[1].push(new Array('14/01','123'));<br>
data[1].push(new Array('15/01','126'));<br>
data[1].push(new Array('16/01','143'));<br>
data[1].push(new Array('17/01','116'));<br>
data[1].push(new Array('18/01','145'));<br>
data[1].push(new Array('19/01','165'));<br>
data[1].push(new Array('20/01','154'));<br>
data[2] = new Array();<br>
data[2].push(new Array('01/01','54'));<br>
data[2].push(new Array('02/01','56'));<br>
data[2].push(new Array('03/01','89'));<br>
data[2].push(new Array('04/01','56'));<br>
data[2].push(new Array('05/01','98'));<br>
data[2].push(new Array('06/01','76'));<br>
data[2].push(new Array('07/01','65'));<br>
data[2].push(new Array('08/01','45'));<br>
data[2].push(new Array('09/01','75'));<br>
data[2].push(new Array('10/01','54'));<br>
data[2].push(new Array('11/01','75'));<br>
data[2].push(new Array('12/01','76'));<br>
data[2].push(new Array('13/01','34'));<br>
data[2].push(new Array('14/01','97'));<br>
data[2].push(new Array('15/01','55'));<br>
data[2].push(new Array('16/01','43'));<br>
data[2].push(new Array('17/01','16'));<br>
data[2].push(new Array('18/01','35'));<br>
data[2].push(new Array('19/01','78'));<br>
data[2].push(new Array('20/01','75'));</p>
<p>Now, before we get to the JavaScript functions, let's first see what we're doing in our RoR code. In the body of the html, we have rendered two charts. The first chart uses the builder template <span class="codeInline">factory_quantities.builder</span>, passes the <span class="codeInline">@factory_data</span> array constructed in the controller to it. The resulting xml is passed to <span class="codeInline">render_chart</span> function to show a Pie3D chart. </p>
<p>The second chart is initialized with a customized message "Please select a factory from pie chart above to view detailed data.".</p>
<p>Let us take a look at the builder which actually does the work of creating a link to the detailed chart for each factory.</p>
<p class="codeBlock"><span class="codeComment">#Creates xml with values for factory output along with their names. It also creates<br>
#a link to javascript function updateChart<br>
#The values required for building the xml is obtained as parameter factory_data<br>
#It expects an array in which each element as <br>
#a hash with values for "factory_name","factory_output" and "factory_index"</span><br>
xml = Builder::XmlMarkup.new<br>
xml.graph(:caption=>'Factory Output report', :subCaption=>'By Quantity',:decimalPrecision=>'0' ,:showNames=>'1' ,:numberSuffix=>' Units' ,:pieSliceDepth=>'20' ,:formatNumberScale=>'0' ) do<br>
for item in factory_data<br>
xml.set(:name=>item[:factory_name],:value=>item[:factory_output],:link=>'javaScript:updateChart('+item[:factory_index].to_s+ <br>
',"'+item[:factory_name]+'");' )<br>
end<br>
end</p>
<p>For each <span class="codeInline"><set></span>, we provide a JavaScript link to the <span class="codeInline">updateChart()</span> function and pass the factory index and factory name to it.</p>
<p>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 <span class="codeInline">updateChart()</span> JavaScript function is called and the index<span class="codeInline"> of the </span>factory in the array and the factory name of the pie is passed to it. This function is responsible for updating the column chart and contains the following code: </p>
<p class="codeBlock"> <span class="codeComment">/** <br>
* updateChart method is invoked when the user clicks on a pie slice.<br>
* In this method, we get the index of the factory, build the XML data<br>
* for that that factory, using data stored in data array, and finally<br>
* update the Column Chart.<br>
* @param factoryIndex Sequential Index of the factory.<br>
* @param factoryName Name of the factory.<br>
*/ </span><br>
function updateChart(factoryIndex,factoryName){<br>
<span class="codeComment"> //defining array of colors<br>
//We also initiate a counter variable to help us cyclically rotate through<br>
//the array of colors.</span><br>
var FC_ColorCounter=0;<br>
var arr_FCColors= new Array("1941A5" , "AFD8F8", "F6BD0F", "8BBA00", "A66EDD", "F984A1", "CCCC00", "999999", "0099CC", "FF0000", "006F00",<br>
"0099FF", "FF66CC", "669966", "7C7CB4", "FF9933", "9900FF", "99FFCC", "CCCCFF", "669900");<br>
<br>
<br>
<span class="codeComment"> //Storage for XML data document</span><br>
var strXML = "<graph caption='" + factoryName + " Output ' subcaption='(In Units)' xAxisName='Date' decimalPrecision='0'>";<br>
<br>
<span class="codeComment"> //Add <set> elements</span><br>
var i=0;<br>
for (i=0; i<data[factoryIndex].length; i++){<br>
strXML = strXML + "<set name='" + data[factoryIndex][i][0] + "' value='" + data[factoryIndex][i][1] + "' color='"+ arr_FCColors[++FC_ColorCounter % arr_FCColors.length] +"' />";<br>
}<br>
<br>
<span class="codeComment"> //Closing graph Element</span><br>
strXML = strXML + "</graph>";<br>
<span class="codeComment"> //Update it's XML</span><br>
updateChartXML("FactoryDetailed",strXML);<br>
}</p>
<p>Here, </p>
<ol>
<li>We first create the XML data document for the column chart by iterating through data contained in our JavaScript <span class="codeInline">data</span> array, by using the index of the factory provided as parameter. </li>
<li>Thereafter, we pass this XML data to the column chart. To do so, we first get a reference to the column chart using it's DOM Id <span class="codeInline">FactoryDetailed</span>. We use the <span class="codeInline">getChartFromId</span>() function defined in <span class="codeInline">FusionCharts.js</span> to do so. </li>
<li>Once we've the reference to the chart, we simply call the <span class="codeInline">updateChartXML</span> method of the chart and pass the chart id and XML data document as parameters. </li>
<li>This updates the chart with new data. </li>
</ol>
<p>When you now see the application, the initial state would look as under: </p> <p class="text"><img src="Images/Code_JS_XML_Ini.jpg" class="imageBorder" /></p>
<p class="text">And when you click on a pie slice, the following would appear on the same page (without involving any browser refreshes): </p>
<p class="text"><img src="Images/Code_JS_XML_Fin.jpg" width="575" height="516" /> </p>
<p class="text">This example demonstrated a very basic sample of the integration capabilities possible with FusionCharts Free. For advanced demos, you can see and download our FusionCharts Blueprint/Demo Applications. </p></td>
</tr>
</table>
</body>
</html>
Mr. DellatioNx196 GaLers xh3LL Backd00r 1.0, Coded By Mr. DellatioNx196 - Bogor BlackHat