Bear and Share [my] Knowledge

Bear and Share Knowledge

Generate dynamic chart using amchart and php + ajax drill down

with 2 comments

On our previous tutorial, we’ve made simple dynamic chart using php. Now we will add little feature to make the chart more interactive. We will add drill down feature using jquery’s ajax.

For this purpose, we need to make several changes. We will add another chart as a view of dill down data. Again, we will simulate this data using -fake-data dummy.

We can assume our chart can show the detail of composition of the visitor for ‘clicked’ day, eg. for January 1st, the number of visitor is 68 persons, we -hope- can see the composition of that ’68′ persons divided into male and female.

Enough for introduction. Lets coding.

chart_app/chart.php

<?php
/**
  * File: chart.php
  * author: imamiscool
  * description: generate chart of visitor statistic for certain month
  */
  
/**
 *  Here we will fake the process of FETCH DATA from DATABASE
 *  to simplify the tutorial, the day of every month are equal to 30 days.
 */  
 
$dummy_data = array(
    array(66,95,40,93,48,88,70,63,62,36,24,36,80,74,50,22,25,86,45,81,69,7,55,22,32,20,77,4,87,60),
    array(58,36,57,12,96,79,12,10,36,40,74,38,76,81,16,31,63,9,60,73,94,85,76,98,15,18,88,91,23,67),
    array(67,86,65,42,35,67,39,2,63,70,90,56,74,77,16,63,40,25,64,34,81,96,30,27,72,26,62,52,32,99),
    array(56,68,34,48,60,85,100,60,69,62,2,67,31,8,61,54,43,83,50,56,52,96,91,58,55,6,54,92,97,24),
    array(63,44,77,7,89,49,42,66,53,90,87,60,28,2,60,98,36,69,58,40,49,25,28,95,88,56,66,23,25,95),
    array(20,32,82,27,86,83,31,87,11,84,94,57,92,95,42,74,76,26,99,21,60,35,35,32,91,32,72,92,65,77),
    array(82,36,30,79,88,48,82,97,60,62,68,40,22,62,85,68,44,83,80,91,49,10,50,68,8,76,42,7,44,66),
    array(52,69,27,15,28,63,81,6,65,48,77,75,12,33,37,5,66,79,33,31,72,94,86,37,27,37,69,58,80,19),
    array(3,77,26,98,60,31,13,84,63,2,36,36,82,25,44,64,40,85,33,27,9,15,50,34,11,1,92,45,17,77),
    array(6,69,50,26,88,65,80,84,85,43,31,35,95,62,74,13,64,32,31,2,89,12,73,37,17,12,23,3,44,89),
    array(53,33,19,56,84,12,37,69,88,75,45,39,87,5,41,26,54,38,71,38,9,57,32,35,25,97,71,27,23,42),
    array(84,72,76,27,20,80,6,36,73,11,83,3,93,73,31,14,74,27,21,1,65,81,74,50,62,96,64,94,12,79)
);

 
/**
 *  Get from user request the number of month
 *  that will be displayed 
 */
 
if( isset($_GET['month_number']) ){

	$month_number = (int)$_GET['month_number'];
	
	// fetch data, 
	// you can change this part by mysql_query or anything 
	// that suitable to your case
	if( $month_number > 0 && $month_number < 13 ){
		
		$data = $dummy_data[$month_number-1];
		
		// title of chart 
		$chart_title = 'Number of visitor <br/> Month : '.$month_number;
		
		// path to file of our chart_data.xml, 
		// that store the data of our chart
		$xml_file = 'chart_data.xml';
		
		// format data into xml data 
		$xml_data = '   <?xml version="1.0" encoding="UTF-8"?>'."\n";
		$xml_data.= '	<chart>'."\n";
		
		// generate data series
		$xml_data.= '		<series>'."\n";		
		for($i=1; $i<=30; $i++){
			$xml_data.= '		<value xid="'.$i.'">'.$i.'</value>'."\n";
		}		
		$xml_data.= '		</series>'."\n";
		
		// now, make the data 
		$xml_data.= '		<graphs>'."\n";		
		$xml_data.= '			<graph gid="1">'."\n"; 	
		$xml_data.= '				<type>column</type>'."\n";                             
		$xml_data.= '				<title>Visitor</title> '."\n"; 

		for($i=1; $i<=30; $i++){
			$xml_data.= '				<value color="#FCD202" xid="'.$i.'">'.$data[$i-1].'</value>'."\n";
		}			
		
		$xml_data.= '			</graph>'."\n";		
		$xml_data.= '		</graphs>'."\n";
		
		// putting the title
		$xml_data.= '       <labels>'."\n";
		$xml_data.= '           <label lid="3">'."\n";
		$xml_data.= '                <x>0</x>'."\n";
		$xml_data.= '                <y>0</y>'."\n";
		$xml_data.= '                <align>center</align>'."\n";
		$xml_data.= '                <text><![CDATA[<b>'.$chart_title.'</b>]]></text>'."\n";
		$xml_data.= '           </label>'."\n";
		$xml_data.= '       </labels>'."\n";
		$xml_data.= '	</chart>'."\n";
		
		
		// save it
		file_put_contents($xml_file, $xml_data);
		
		// generate outputs
		?>		
		<script type="text/javascript" src="jquery.js"></script>
		
		<script type="text/javascript" src="amcolumn_1.6.1.2/amcolumn/swfobject.js"></script>
		<div id="flashcontent">
			<strong>You need to upgrade your Flash Player</strong>
		</div>
		<script type="text/javascript">
			// <![CDATA[		
			var myChart = new SWFObject("amcolumn_1.6.1.2/amcolumn/amcolumn.swf", "my_id", "600", "300", "8", "#FFFFFF");
			myChart.addVariable("chart_id", "my_id");
			myChart.addVariable("path", "amcolumn_1.6.1.2/amcolumn/");
			myChart.addVariable("settings_file", encodeURIComponent("chart_setting.xml"));
			myChart.addVariable("data_file", encodeURIComponent("chart_data.xml"));		
			myChart.write("flashcontent");
			// ]]>
		</script>
		<div id="flashcontent2">
			<strong>You need to upgrade your Flash Player</strong>
		</div>
		<script type="text/javascript">
			// <![CDATA[		
			var myChart2 = new SWFObject("amcolumn_1.6.1.2/amcolumn/amcolumn.swf", "my_id2", "450", "300", "8", "#FFFFFF");
			myChart2.addVariable("chart_id", "my_id2");
			myChart2.addVariable("path", "amcolumn_1.6.1.2/amcolumn/");
			myChart2.addVariable("settings_file", encodeURIComponent("chart_drill_setting.xml"));
			myChart2.addVariable("data_file", encodeURIComponent("chart_drill_data.xml"));		
			myChart2.write("flashcontent2");
			// ]]>
		</script>
		
		<script language="javascript">
		// CHART INITED //////////////////////////////////////////////////////////////////////////    
		// amChartInited(chart_id)
		// This function is called when the chart is fully loaded and initialized.
		var flashMovie = new Object();

		function amChartInited(chart_id){
		  // get the flash object into "flashMovie" variable   
		  flashMovie[chart_id] = document.getElementById(chart_id);
		}

		// FIND WHICH COLUMN/BULLET WAS CLICKED //////////////////////////////////////////////////
		// amClickedOnBullet(chart_id, graph_index, value, series, url, description)
		// This function is called when the viewer clicks on a graph bullet. It returns the
		// sequential number of a graph (graph_index), the value of the data point (value),
		// the series value (series), the URL and the description attributes.
		function amClickedOnBullet(chart_id, graph_index, value, series, url, description){
		  // do jquery stuff
		  // make ajax calls
		  if( chart_id == 'my_id' ){
			  $.get("ajax_detail.php", 
					{day_number: series, month_number: <?php echo $_GET['month_number'];?>},
					function(data){
						if( data ){
							flashMovie['my_id2'].reloadAll();
						}
						else{
							alert('Error occured. Drill down aborted.');
						}
					},
				   "json"  // here you specify that the return type is JSON
			  );
		  }
		}
		</script>
		<?php
	}
	else{
		die("Month number invalid.");
	}
}
else{
	/**
	 *  Display form 
	 */
 	
	echo "<form method='GET' action='chart.php'>
			<label for='month_number'>Insert month number (1-12) here : </label>
			<input type='text' name='month_number' id='month_number'/>
			<input type='submit' value='Submit' />
		  </form>";
}

As you can see, starting to line number 107 till 119 we add another chart to view the detail of certain day. Also we have to manage how this drill down processed. We use jquery ajax method as shown on line 141 till 155, the other javascript are used to communicate among amchart and jquery.

We must noticed that our charts now must have different id to access.

Now, the setting for our main chart, this setting remain same with our previous tutorial.
chart_app/chart_setting.xml


<?xml version="1.0" encoding="UTF-8"?>
<settings>
  <type>column</type>
  <data_type>xml</data_type>
  <font>Tahoma</font>
  <colors>#fff000</colors>

  <column>
   <width>85</width>
    <spacing>0</spacing>
    <grow_time>1</grow_time>
    <sequenced_grow>true</sequenced_grow>
    <balloon_text>
     <![CDATA[{value}]]>
    </balloon_text>
    <hover_brightness>30</hover_brightness>
  </column>

  <plot_area>
    <margins>
      <left>70</left>
      <top>60</top>
      <right>50</right>
      <bottom>80</bottom>
    </margins>
  </plot_area>


  <legend>
    <enabled>false</enabled>
  </legend>

  <export_as_image>
    <file>amcolumn_1.6.1.2/amcolumn/export.php</file>
  </export_as_image>

  <labels>
  <label lid="0">
      <x>10</x>
      <y>260</y>
      <rotate>true</rotate>
      <width></width>
      <align>center</align>
      <text>
        <![CDATA[<b>Number of visitor</b>]]>
      </text>
    </label>
    <label lid="1">
      <x>0</x>
      <y>250</y>
      <rotate>false</rotate>
      <width></width>
      <align>center</align>
      <text>
        <![CDATA[<b>Date</b>]]>
      </text>
    </label>
  </labels>
</settings>

Now, the interesting part. We will add ajax response when we click certain column of data displayed by our main chart (ID: my_id) then display the result in our second chart (my_id2).

Lets named it ajax_detail.php which handles ajax request and creates xml data for detailed information.
chart_app/ajax_detail.php

<?php
/**
  * File: ajax_detail.php
  * author: imamiscool
  * description: responses daily detail
  */
  
/**
 *  Here we will fake the process of FETCH DATA from DATABASE
 *  this data consist of male/female composition for specific day..
 */  
 
$dummy_data = array(
	// jan
	array(array(18, 48),array(29, 66),array(10, 30),array(83, 10),array(37, 11),array(57, 31),array(55, 15),array(46, 17),array(38, 24),array(28, 8),array(16, 8),array(24, 12),array(13, 67),array(15, 59),array(49, 1),array(21, 1),array(7, 18),array(75, 11),array(15, 30),array(20, 61),array(19, 50),array(2, 5),array(45, 10),array(18, 4),array(0, 32),array(6, 14),array(2, 75),array(1, 3),array(74, 13),array(33, 27),),
	
	// feb
	array(array(3, 55),array(5, 31),array(35, 22),array(11, 1),array(49, 47),array(65, 14),array(8, 4),array(9, 1),array(16, 20),array(25, 15),array(58, 16),array(13, 25),array(39, 37),array(25, 56),array(6, 10),array(27, 4),array(48, 15),array(0, 9),array(17, 43),array(29, 44),array(74, 20),array(51, 34),array(64, 12),array(38, 60),array(11, 4),array(3, 15),array(78, 10),array(75, 16),array(1, 22),array(30, 37),),
	
	// ...etc
	array(array(51, 16),array(13, 73),array(1, 64),array(29, 13),array(11, 24),array(24, 43),array(5, 34),array(1, 1),array(57, 6),array(64, 6),array(47, 43),array(23, 33),array(24, 50),array(59, 18),array(12, 4),array(52, 11),array(40, 0),array(10, 15),array(58, 6),array(1, 33),array(56, 25),array(76, 20),array(18, 12),array(23, 4),array(57, 15),array(10, 16),array(58, 4),array(20, 32),array(4, 28),array(18, 81),),
	array(array(28, 28),array(28, 40),array(1, 33),array(30, 18),array(22, 38),array(11, 74),array(40, 60),array(42, 18),array(10, 59),array(17, 45),array(1, 1),array(57, 10),array(30, 1),array(0, 8),array(15, 46),array(3, 51),array(15, 28),array(17, 66),array(48, 2),array(46, 10),array(22, 30),array(90, 6),array(41, 50),array(3, 55),array(44, 11),array(6, 0),array(5, 49),array(25, 67),array(54, 43),array(11, 13),),
	array(array(47, 16),array(19, 25),array(22, 55),array(1, 6),array(63, 26),array(48, 1),array(3, 39),array(29, 37),array(46, 7),array(82, 8),array(47, 40),array(50, 10),array(15, 13),array(2, 0),array(46, 14),array(59, 39),array(20, 16),array(17, 52),array(18, 40),array(19, 21),array(14, 35),array(2, 23),array(9, 19),array(65, 30),array(53, 35),array(11, 45),array(25, 41),array(22, 1),array(20, 5),array(3, 92),),
	array(array(11, 9),array(14, 18),array(59, 23),array(15, 12),array(39, 47),array(78, 5),array(23, 8),array(17, 70),array(2, 9),array(53, 31),array(64, 30),array(57, 0),array(28, 64),array(23, 72),array(38, 4),array(27, 47),array(72, 4),array(0, 26),array(23, 76),array(6, 15),array(41, 19),array(22, 13),array(0, 35),array(8, 24),array(55, 36),array(10, 22),array(8, 64),array(21, 71),array(21, 44),array(61, 16),),
	array(array(70, 12),array(24, 12),array(28, 2),array(22, 57),array(7, 81),array(26, 22),array(82, 0),array(50, 47),array(9, 51),array(19, 43),array(43, 25),array(28, 12),array(20, 2),array(59, 3),array(37, 48),array(37, 31),array(29, 15),array(78, 5),array(40, 40),array(26, 65),array(14, 35),array(2, 8),array(20, 30),array(43, 25),array(1, 7),array(23, 53),array(11, 31),array(6, 1),array(0, 44),array(8, 58),),
	array(array(34, 18),array(36, 33),array(8, 19),array(2, 13),array(19, 9),array(0, 63),array(67, 14),array(2, 4),array(60, 5),array(47, 1),array(72, 5),array(21, 54),array(6, 6),array(21, 12),array(17, 20),array(4, 1),array(63, 3),array(57, 22),array(26, 7),array(12, 19),array(31, 41),array(41, 53),array(61, 25),array(1, 36),array(14, 13),array(19, 18),array(41, 28),array(12, 46),array(23, 57),array(3, 16),),
	array(array(1, 2),array(70, 7),array(9, 17),array(12, 86),array(6, 54),array(17, 14),array(11, 2),array(50, 34),array(59, 4),array(0, 2),array(7, 29),array(10, 26),array(7, 75),array(3, 22),array(30, 14),array(28, 36),array(17, 23),array(42, 43),array(28, 5),array(21, 6),array(2, 7),array(11, 4),array(37, 13),array(16, 18),array(6, 5),array(1, 0),array(92, 0),array(13, 32),array(7, 10),array(0, 77),),
	array(array(4, 2),array(29, 40),array(46, 4),array(14, 12),array(37, 51),array(40, 25),array(24, 56),array(68, 16),array(24, 61),array(2, 41),array(13, 18),array(27, 8),array(83, 12),array(31, 31),array(46, 28),array(11, 2),array(17, 47),array(4, 28),array(24, 7),array(0, 2),array(8, 81),array(8, 4),array(11, 62),array(33, 4),array(7, 10),array(4, 8),array(16, 7),array(1, 2),array(37, 7),array(83, 6),),
	array(array(35, 18),array(22, 11),array(9, 10),array(31, 25),array(79, 5),array(0, 12),array(32, 5),array(67, 2),array(77, 11),array(71, 4),array(6, 39),array(16, 23),array(24, 63),array(1, 4),array(38, 3),array(15, 11),array(29, 25),array(17, 21),array(17, 54),array(26, 12),array(4, 5),array(31, 26),array(24, 8),array(17, 18),array(10, 15),array(94, 3),array(34, 37),array(4, 23),array(5, 18),array(29, 13),),
	array(array(6, 78),array(31, 41),array(19, 57),array(5, 22),array(12, 8),array(44, 36),array(2, 4),array(17, 19),array(51, 22),array(2, 9),array(67, 16),array(3, 0),array(37, 56),array(46, 27),array(16, 15),array(9, 5),array(24, 50),array(14, 13),array(18, 3),array(1, 0),array(38, 27),array(10, 71),array(40, 34),array(44, 6),array(46, 16),array(14, 82),array(2, 62),array(85, 9),array(11, 1),array(64, 15),),
);

 
/**
 *  Get from user request the number of day
 *  that will be displayed 
 */
 
if( isset($_GET['day_number']) && isset($_GET['month_number'])){

	$day_number   = (int)$_GET['day_number'];
	$month_number = (int)$_GET['month_number'];
	
	// fetch data, 
	// you can change this part by mysql_query or anything 
	// that suitable to your case
	if( $day_number > 0 && $day_number < 31 && $month_number > 0 && $month_number < 13 ){
		
		$data = $dummy_data[$month_number-1][$day_number-1];
		
		// title of chart 
		$chart_title = 'Composition of visitor <br/> Month: '.$month_number.' Day : '.$day_number;
		
		// path to file of our chart_data.xml, 
		// that store the data of our chart
		$xml_file = 'chart_drill_data.xml';
		
		// format data into xml data 
		$xml_data = '   <?xml version="1.0" encoding="UTF-8"?>'."\n";
		$xml_data.= '	<chart>'."\n";
		
		// generate data series
		$xml_data.= '		<series>'."\n";		
		$xml_data.= '			<value xid="1">Male</value>'."\n";
		$xml_data.= '			<value xid="2">Female</value>'."\n";
		$xml_data.= '		</series>'."\n";
		
		// now, make the data 
		$xml_data.= '		<graphs>'."\n";		
		$xml_data.= '			<graph gid="1">'."\n"; 	
		$xml_data.= '				<type>column</type>'."\n";                             
		$xml_data.= '				<title>Visitor</title> '."\n"; 
		$xml_data.= '				<value color="#FCD202" xid="1">'.$data[0].'</value>'."\n";
		$xml_data.= '				<value color="#FCD202" xid="2">'.$data[1].'</value>'."\n";		
		$xml_data.= '			</graph>'."\n";		
		$xml_data.= '		</graphs>'."\n";
		
		// putting the title
		$xml_data.= '       <labels>'."\n";
		$xml_data.= '           <label lid="3">'."\n";
		$xml_data.= '                <x>0</x>'."\n";
		$xml_data.= '                <y>0</y>'."\n";
		$xml_data.= '                <align>center</align>'."\n";
		$xml_data.= '                <text><![CDATA[<b>'.$chart_title.'</b>]]></text>'."\n";
		$xml_data.= '           </label>'."\n";
		$xml_data.= '       </labels>'."\n";
		$xml_data.= '	</chart>'."\n";
		
		
		// save it
		file_put_contents($xml_file, $xml_data);
		echo "true"; // to inform that ajax calls done perfectly..
	}
	else{
		echo "false";
	}
} 

As you can see, our ajax_detail requires two parameter to run, they are month_number and day_number. These parameter used to generate data from our -fake- database into single xml file named chart_drill_data.xml (which is generated each time ajax calls triggered).

Now the setting for our second chart (drill chart)
chart_app/chart_drill_setting.xml

<?xml version="1.0" encoding="UTF-8"?>
<settings>
  <type>column</type>
  <data_type>xml</data_type>
  <font>Tahoma</font>
  <colors>#fff000</colors>

  <column>
   <width>85</width>
    <spacing>0</spacing>
    <grow_time>1</grow_time>
    <sequenced_grow>true</sequenced_grow>
    <balloon_text>
     <![CDATA[{value}]]>
    </balloon_text>
    <hover_brightness>30</hover_brightness>
  </column>

  <plot_area>
    <margins>
      <left>70</left>
      <top>60</top>
      <right>50</right>
      <bottom>80</bottom>
    </margins>
  </plot_area>


  <legend>
    <enabled>false</enabled>
  </legend>

  <export_as_image>
    <file>amcolumn_1.6.1.2/amcolumn/export.php</file>
  </export_as_image>

  <labels>
  <label lid="0">
      <x>10</x>
      <y>260</y>
      <rotate>true</rotate>
      <width></width>
      <align>center</align>
      <text>
        <![CDATA[<b>Number of visitor</b>]]>
      </text>
    </label>
    <label lid="1">
      <x>0</x>
      <y>250</y>
      <rotate>false</rotate>
      <width></width>
      <align>center</align>
      <text>
        <![CDATA[<b>Gender</b>]]>
      </text>
    </label>
  </labels>
</settings>

The last part is to download jQuery then rename it into jquery.js and put in the same folder as another files above.

Thats all, for today, you also can download the final version of this tutorial.

Written by imamiscool

2009/06/16 at 17:47

Posted in tutorial

Tagged with , , , , ,

2 Responses

Subscribe to comments with RSS.

  1. Great post. Use a tool like Style Chart might make this easier.

    Steve

    2009/07/01 at 05:47

    • yeah sure..
      but I was noticed by its price and personally I prefer make ajax call by myself which I can manage everything and customize the option based on our need. :)

      imamiscool

      2009/07/03 at 18:17


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.