【IT168 技术】在分析数据时,使用图表的方式是很直接形象的,而假如图表是可以有交互能力的,那么其效果会更加好。在本文中,将探讨如何使用php搭配开源报表库FusionCharts(项目地址:www.fusioncharts.com/),去创建交互式的钻取报表。所谓的钻取报表,指的是可以当用户点取报表中的数据轴的时候,可以再新打开一个新的报表,这样方便在不同的报表之间导航,十分方便。
介绍链接式图表
一般而言,普通图表的数据都是独立的,如何才能将这些数据聚合在一起,并且让我们可以在这些数据图之间来回地导航查看呢?这正是LinkedCharts能实现的。它是在FusionCharts 3.2中新增加的钻取新特性,它允许只需要一个数据源就可以创建无限制级的钻取图表,所有的的链接都是来自父图表和其数据。
在本文中,我们将学习如何将图表跟web应用结合起来。其中Mysql数据库会包含所需要的数据,而PHP程序则会将数据从数据库中取出,而FusionCharts则会负责处理和显示数据,它们的关系如下图:
想要更多的了解关于LinkedCharts的情况,可以看以下这篇文章介绍(http://kb.fusioncharts.com/questions/459/What+is+a+Drill-down+chart?),这篇文章的要点归纳如下:
1 钻取报表用父图表默认的设置去显示数据;
2 每一层的钻取层都是可以进行额外的设置的,当然你可以去改变每一个钻取层的设置和图表类型;
3 可以在新的窗口中打开链接图表,其中支持象jQuery 对话框,lightbox,extJS窗口和更多;
4 支持使用Javascript去扩展事件。
我们要做什么
我们要经常去监视我们的网站应用有多少来访客人,看下其是否增长了,在本文中,我们就来做一个小应用,可以显示一段时间来我们网站有多少注册的用户。
预备:支持php的web服务器,这里我们用apache,mysql数据库,下载FusionCharts。
步骤1 初始设置
创建一个空的数据库fctutorial,创建一个fcdemo的子目录用来存放php文件。
步骤2 初始化数据库数据
这里我们创建一个users表,这里只是简单有两个字段,一个是ID,一个是用户注册时间:
(
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`ID`),
KEY `Time` (`Time`)
)
步骤3 连接数据库
接下来,我们用很简单的代码去连接数据库,代码如下:
$db_host = 'localhost';
$db_database = 'fctutorial';
$db_username = 'root';
$db_password = '';
if ( ! mysql_connect($db_host, $db_username, $db_password))
die ("Could not connect to the database server.");
if ( ! mysql_select_db($db_database))
die ("Could not select the database.");
?>
并把这个文件保存为connect-to-database.php,接下来,我们插入一些样例数据,当然我们的例子中只能是少量的数据而已,代码如下:
//连接数据库
require 'connect-to-database.php';
//设置时间
$MinTime = strtotime('2010-01-01');
$MaxTime = strtotime('2010-12-12');
$RecordsToInsert = 10000;
//插入10000条数据
for($i = 0; $i < $RecordsToInsert; $i++)
{
$RandomTime = rand($MinTime, $MaxTime);
mysql_query("INSERT INTO `users` (Time) VALUES (FROM_UNIXTIME({$RandomTime}))") or die(mysql_error());
}
echo "Inserted {$RecordsToInsert} records.";
?>
这里我们往用户表的时间字段,随机插入了2010年内的任意一个时间,最后把这个文件保存为generate-random-data.php。
步骤4 准备应用的HTML页框架
首先,我们使用HTML设计一个用于呈现报表的区域,代码如下:
<head>
<title>FusionCharts v3.2 - LinkedCharts with PHP Demo</title
<script type="text/javascript" src="Charts/FusionCharts.js"></script>
</head>
<body>
<div id="chartContainer">FusionCharts will load here</div>
<script type="text/javascript"><!--
var myChart = new FusionCharts( "Charts/Column3D.swf", "myChartId", "800", "400");
myChart.setXMLUrl( "get-data.php?year=2010" );
myChart.render( "chartContainer" );
// -->
</script>
</body>
</html>
把这个文件保存为demo.html,下面解析下这个文件:
首先,在head部分,要引入FusionCharts.js库,在body部分,在中将会是图表放置的地方。接下来是一段很短的javascript,其中:
a) Charts/Column3D.swf,指出了这里使用的是Column3D这个Flash类型的图表;
b) myChartId指定了图表的id,这是很有用的,特别是当有多个图表时,图表之间互相引用;
c) 而800和400则是指定了图片的宽度和高度;
而myChart.setXMLUrl("get-data.php?year=2010" )则指定了数据来源,这里我们告诉图表的数据将会以XML的形式加载,而get-data.php?year=2010这个脚本则会负责读取后端的数据。
步骤5 编写后端程序
FusionCharts需要XML或者JSON格式的数据源,本文使用XML。而我们编写后端程序的目的是能够从数据库中读取数据,并且产生XML格式的文件,生成的数据格式应该是如下样子的:
<set value="486" name="1"/>
<set value="443" name="2"/>
<set value="553" name="3"/>
<set value="550" name="4"/>
<set value="634" name="5"/>
<set value="622" name="6"/>
<set value="710" name="7"/>
<set value="772" name="8"/>
<set value="850" name="9"/>
<set value="1044" name="10"/>
<set value="1175" name="11"/>
<set value="761" name="12"/>
</chart>
我们解析上这个文件。首先,使用了chart标签指定了图表的一些显示属性,指定了SWF文件是如何显示数据的,这里我们指定了X轴和Y轴的文字说明,背景颜色和其他的一些属性,如透明度和字体大小等。而用<set value>
接下来我们编写get_data.php程序,从数据库中取出数据并将其解析成XML格式,程序如下:
//获得年份
$Year = intval($_GET['year']);
//获得指定月份的用户访客数
$Query = "SELECT MONTH(Time) AS Value, COUNT(*) AS Total FROM `users` WHERE YEAR(Time)={$Year} GROUP BY Value";
// 初始化每个月份的数据为0
$ResultArray = array_fill(1, 12, 0);
// 设置图表的标题和X轴标题
$ChartHeading = 'Monthly New Users for the Year: '.$Year;
$XaxisName = 'Months';
//连接数据库
require 'connect-to-database.php';
//查询数据库
$QueryResult = mysql_query($Query);
while($Row = mysql_fetch_assoc($QueryResult))
$ResultArray[$Row['Value']]=$Row['Total'];
//构造XML输出
$Output = '<chart caption="'.$ChartHeading.'" xAxisName="'.$XaxisName.'" yAxisName="Users" showNames="1" bgColor="E6E6E6,F0F0F0" bgAlpha="100,50" bgRatio="50,100" bgAngle="270" showBorder="1" borderColor="AAAAAA" baseFontSize="12">';
foreach($ResultArray as $key => $val)
$Output .= '<set value="'.$val.'" name="'.$key.'"/>';
//完成XML输出
$Output .= '</chart>';
//向浏览器输出XML
header('Content-type: text/xml');
//Send output
echo $Output;
?>
上文都有比较详细的注释了,这里稍微解析下:首先我们获得要查看的年份,保存在year年份中,接着获得指定月份的用户访客数,这里使用了函数year,只获取当年年份的数目,接着是连接数据库进行了查询,并将查询的每个月份的访问数组合成XML,最后向浏览器输出XML。最后访问http://localhost/fcdemo/get-data.php?year=2010.就可以看到XML格式输出的文件。
接下来我们测试下运行的效果,输入http://localhost/fcdemo/demo.html,运行后如下图所示:
步骤6 使用LinedCharts转换为钻取报表
有两个方法去将子图表嵌入到父图表中去。我们或者可以通过把新的数据字符串增加到父图表的数据源,也可以仅仅把子图表的数据链接地址加到父图表中去。假如直接在父图表中嵌入子图表的数据,对于我们的例子不大合适,因为有12个月,每个月有30天,每天有24小时,这样显示起来的话会有点混乱。这里我们采用的是数据URL链接的方式,只需要在父图表中要点击的区域设置链接即可。
下面修改代码,让能够产生三种不同类型的子图表:月、日、时,代码如下:
//处理输入,分别获得年、月,日
$Type = $_GET['type'];
$Year = intval($_GET['year']);
$Month = intval($_GET['month']);
$Day = intval($_GET['day']);
//月份名称
$MonthsNames = array(null, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
switch($Type)
{
default:
case 'monthly':
$Query = "SELECT MONTH(Time) AS Value, COUNT(*) AS Total FROM `users` WHERE YEAR(Time)={$Year} GROUP BY Value";
$ResultArray = array_fill(1, 12, 0);
$ChartHeading = 'Monthly New Users for the Year: '.$Year;
$XaxisName = 'Months';
break;
case 'daily':
$Query = "SELECT DAY(Time) AS Value, count(*) AS Total FROM `users` WHERE YEAR(Time)={$Year} AND MONTH(Time)={$Month} GROUP BY Value";
$ResultArray = array_fill(1, 31, 0);
$ChartHeading = 'Daily New Users for the Month: '.$MonthsNames[$Month].'/'.$Year;
$XaxisName = 'Days';
break;
case 'hourly':
$Query = "select HOUR(Time) AS Value, count(*) AS Total FROM `users` WHERE YEAR(Time)={$Year} AND MONTH(Time)={$Month} AND DAY(Time)={$Day} GROUP BY Value";
$ResultArray = array_fill(0, 24, 0);
$ChartHeading = 'Hourly New Users for the Date: '.$Day.'/'.$MonthsNames[$Month].'/'.$Year;
$XaxisName = 'Hours';
break;
}
//连接数据库
require 'connect-to-database.php';
//查询数据库
$QueryResult = mysql_query($Query);
while($Row = mysql_fetch_assoc($QueryResult))
$ResultArray[$Row['Value']]=$Row['Total'];
//生成XML数据
$Output = '<chart caption="'.$ChartHeading.'" xAxisName="'.$XaxisName.'" yAxisName="Users" showNames="1" bgColor="E6E6E6,F0F0F0" bgAlpha="100,50" bgRatio="50,100" bgAngle="270" showBorder="1" borderColor="AAAAAA" baseFontSize="12">';
//根据月、日和时间,生成XML的主体数据
switch($Type)
{
default:
case 'monthly':
foreach($ResultArray as $MonthNumber => $value) // MonthNumber is month number (1-12)
$Output .= '<set value="'.$value.'" name="'.$MonthsNames[$MonthNumber].'" link="newchart-xmlurl-get-data.php?type=daily&year='.$Year.'&month='.$MonthNumber.'"/>';
break;
case 'daily':
foreach($ResultArray as $DayNumber => $value) // DayNumber is day (1-31)
$Output .= '<set value="'.$value.'" name="'.$DayNumber.'" link="newchart-xmlurl-get-data.php?type=hourly&year='.$Year.'&month='.$Month.'&day='.$DayNumber.'"/>';
break;
case 'hourly':
foreach($ResultArray as $HourNumber => $value) // HourNumber is hour (0-23)
$Output .= '<set value="'.$value.'" name="'.$HourNumber.'"/>';
break;
}
$Output .= '</chart>';
header('Content-type: text/xml');
//输出
echo $Output;
?>
下面我们简单解析下上面修改了的部分。
首先,设置了type这个变量来存放图表类型,这里可以是月,日或者是小时。
接着,我们建立了一个$MonthNames数组,这是用来存放每个月的用户访问数据的,注意这里设置了第0个元素是null,因为第1个元素位置代表的是1月份。
根据图表的类型,变量$Query, $ResultArray, $ChartHeading和$XAsixName都会设置为不同的值。如果$Type没有值的话,则默认选择的是月份的图表。
接下来连接数据库,执行查询语句,把结果集存放到$ResultArray中,并且生成XML文件中的头部。
XML文件的主体部分(即生成符合FusionCharts格式的XML)是根据图表的类型而有一点不同,具体为:
月份:基本都是相同的,除了link属性。Link中设定了如下的值:newchart-xmlurl-get-data.php。这里newchart指明了这里是要创建新的一个图表,xmlurl表明数据是通过url的形式去获得的,比如获得1月份的数据,则链接为newchart-xmlurl-get-data.php?type=hourly&Year=2010&Month=1。
日:跟月份也差不多,只不过链接中有day日期这个属性而已。
小时:由于查看图表的最小单位是小时,小时是最后一层的图表了,所以这里对link不做任何的设置。
重新将该文件改名保存为get-data.php,然后运行http://localhost/fcdemo/get-data.php?year=2010,即可看到如下的XML文件:
<set value="486" name="Jan" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=1"/>
<set value="443" name="Feb" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=2"/>
<set value="553" name="Mar" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=3"/>
<set value="550" name="Apr" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=4"/>
<set value="634" name="May" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=5"/>
<set value="622" name="Jun" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=6"/>
<set value="710" name="Jul" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=7"/>
<set value="772" name="Aug" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=8"/>
<set value="850" name="Sep" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=9"/>
<set value="1044" name="Oct" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=10"/>
<set value="1175" name="Nov" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=11"/>
<set value="761" name="Dec" link="newchart-xmlurl-get-data.php?type=daily&year=2010&month=12"/>
</chart>
最后,运行http://localhost/fcdemo/demo.html,即可看到如下效果图:
首先这个是显示了1-12月份的数据,而当点每个月份的柱型图时,将会显示一个新的图,即显示每个月31天的数据,如下图:
而当每天的柱型图时,又会显示一个新图表,显示一天内每个小时的用户访问数,如下图: