hiziqin 发表于 2011-12-21 08:44

如何使用PHP动态生成饼状图、柱状图和折线图

序 <p>PHP在图像操作方面的表现非常出色,我们只需借助可以免费得到的GD库便可以轻松实现图、表勾画。下面将分别介绍笔者实现
的饼状图、折线图和柱状图以及他们的使用方法,这几段代码的特点就是不需要再把它们复制到你的代码之中,只需要把计算得到的数据作为参数传入,即可得到相
应的图形效果</p><p>开发环境:PHP Version 4.3.6+GD Version bundled (2.0.22
compatible) </p><p>由于作者水平有限,文章中难免存在错误,我将非常感激您的指正</p><p>代码中所有使用的函数的说明,请参见
php开发文档 点<a href="http://www.php.net/docs.php" target="_blank" target="_blank">这里</a>获得最
新版</p><a name="bingzhuangtu"></a>饼状图<br><br><a name="bing_shejisilu"></a>设计思路<p>饼状图表对于查看一个值占总值的百分比是一个好的方法。我们就用PHP来
实现一个饼形图表。<br>它的设计思想是:<br>1 接受参数,得到所有数值的和,得到每一个值占数值总和的比例。<br>2
根据比例计算每一个色块在图中的圆周角度<br>3 要产生立体效果,只需要用深颜色画出阴影就可以了<br></p><br><a name="bing_shixianguocheng"></a>实现过程<p>&lt;?<br>//参数以a为参数名传入,a的文本形态
应该是用“,”分割的若干数字连接的字符串 <br>//这里首先判断a是否存在<br>if($_GET["a"]=="") die("0");<br>//
将得到的数据分解,存入数组$shuju中<br>$shuju=split(",",$_GET["a"]);<br>//再次判断数据的合法性,返回
错误代码<br>if(count($shuju)==0) die("2");<br>//定义整个图形的宽度和高度 <br>//读者可以根据需要修
改这两个变量的值<br>$tukuan=300;<br>$tugao=150;</p><p>//定义一个数组,用来存放每一个色块的角度范围<br>$jiaodu
= array();<br>//定义存贮数据和的变量<br>$total=0;<br>//遍历数组求和<br>for ($i = 0; $i
&lt; count($shuju); $i++) {<br>  if(!is_numeric($shuju[$i])) die("1");<br> 
 $total+=$shuju[$i];<br>}<br>//再次遍历,计算色块角度并存入数组<br>for ($i = 0; $i &lt;
count($shuju); $i++) {<br>  array_push ($jiaodu,
round(360*$shuju[$i]/$total));<br>}</p><p>//创建图像<br>$image =
imagecreate($tukuan, $tugao);<br>//定义一个灰色背景色,这个颜色其实就是大家很熟悉的页面色系16进制数字表示
的#EEEEEE<br>$white = imagecolorallocate($image, 0xEE, 0xEE, 0xEE);</p><p>//
再定义10对深浅对应的彩色,存入二维数组<br>$yanse = array(<br>  array(<br>    
imagecolorallocate($image, 0x97, 0xbd, 0x00),<br>    
imagecolorallocate($image, 0x00, 0x99, 0x00),<br>    
imagecolorallocate($image, 0xcc, 0x33, 0x00),<br>    
imagecolorallocate($image, 0xff, 0xcc, 0x00),<br>    
imagecolorallocate($image, 0x33, 0x66, 0xcc),<br>    
imagecolorallocate($image, 0x33, 0xcc, 0x33),<br>    
imagecolorallocate($image, 0xff, 0x99, 0x33),<br>    
imagecolorallocate($image, 0xcc, 0xcc, 0x99),<br>    
imagecolorallocate($image, 0x99, 0xcc, 0x66),<br>    
imagecolorallocate($image, 0x66, 0xff, 0x99)<br>  ),<br>  array(<br>    
imagecolorallocate($image, 0x4f, 0x66, 0x00),<br>    
imagecolorallocate($image, 0x00, 0x33, 0x00),<br>    
imagecolorallocate($image, 0x48, 0x10, 0x00),<br>    
imagecolorallocate($image, 0x7d, 0x64, 0x00),<br>    
imagecolorallocate($image, 0x17, 0x30, 0x64),<br>    
imagecolorallocate($image, 0x1a, 0x6a, 0x1a),<br>    
imagecolorallocate($image, 0x97, 0x4b, 0x00),<br>    
imagecolorallocate($image, 0x78, 0x79, 0x3c),<br>    
imagecolorallocate($image, 0x55, 0x7e, 0x27),<br>    
imagecolorallocate($image, 0x00, 0x93, 0x37)<br>  )<br>);</p><p>//由下至上画
10个像素高的深色饼图,作为阴影<br>$yuanxin_x=$tukuan/2;<br>for ($h = $tugao/2+5; $h
&gt; $tugao/2-5; $h--) {<br>  $kaishi=0;<br>  $jieshu=0;<br>  for ($i =
0; $i &lt; count($shuju); $i++) {<br>    $kaishi=$kaishi+0;<br>    
$jieshu=$kaishi+$jiaodu[$i];<br>    $yanse_i=fmod($i,10);<br>    
imagefilledarc($image,$yuanxin_x,$h,$tukuan,$tugao-20,$kaishi,$jieshu,$yanse[$yanse_i],IMG_ARC_PIE);<br> 
   $kaishi+=$jiaodu[$i];<br>    $jieshu+=$jiaodu[$i];<br>  }<br>}</p><p>//
在最高处(也就是$h最小时)画一个浅色饼图,这个浅色图跟先画上的深色饼图就能产生立体效果了<br>for ($i = 0; $i &lt;
count($shuju); $i++) {<br>  $kaishi=$kaishi+0;<br>  
$jieshu=$kaishi+$jiaodu[$i];<br>  $yanse_i=fmod($i,10);<br>  
imagefilledarc($image, $yuanxin_x, $h, $tukuan, $tugao-20, $kaishi,
$jieshu, $yanse[$yanse_i], IMG_ARC_PIE);<br>  $kaishi+=$jiaodu[$i];<br> 
 $jieshu+=$jiaodu[$i];<br>}<br>//设定文件头 <br>header('Content-type:
image/png');<br>//输出图像<br>imagepng($image);<br>//释放资源 <br>imagedestroy($image);<br>?&gt;</p><a name="bing_shiyongfangfa"></a>使用方法<p>在需要显示图像的位置插入如下代码<br>&lt;img
src="bing_img.php?a=3,2,3,4"/&gt;<br>a的文本格式是由“,”连接的若干个数据的字符串,get方式传入。<br>颜
色图例如下,请自行排列:</p><table border="0" cellpadding="0" cellspacing="2" width="300"><tbody><tr><td bgcolor="#97bd00">&nbsp;</td><td bgcolor="#009900">&nbsp;</td><td bgcolor="#cc3300">&nbsp;</td><td bgcolor="#ffcc00">&nbsp;</td><td bgcolor="#3366cc">&nbsp;</td><td bgcolor="#33cc33">&nbsp;</td><td bgcolor="#ff9933">&nbsp;</td><td bgcolor="#cccc99">&nbsp;</td><td bgcolor="#99cc66">&nbsp;</td><td bgcolor="#66ff99">&nbsp;</td></tr><tr><td bgcolor="#4f6600">&nbsp;</td><td bgcolor="#003300">&nbsp;</td><td bgcolor="#481000">&nbsp;</td><td bgcolor="#7d6400">&nbsp;</td><td bgcolor="#173064">&nbsp;</td><td bgcolor="#1a6a1a">&nbsp;</td><td bgcolor="#974b00">&nbsp;</td><td bgcolor="#78793c">&nbsp;</td><td bgcolor="#557e27">&nbsp;</td><td bgcolor="#009337">&nbsp;</td></tr></tbody></table><a name="bing_shixianxiaoguo"></a>实现效果<p><img src="http://dev.csdn.net/zsrui/admin/images/1.gif" width="598" height="258"></p><p>&nbsp;</p><p>&nbsp;</p><a id="zhexiantu" name="zhexiantu"></a>折线图<br><br><a id="zhe_shejisilu" name="zhe_shejisilu"></a>设计思路<p>用折线图表查看某一数据在单位时段内的变化趋势是一个好的选择。我们就用PHP来实现一个动态折线图表。<br>它的设计思想是:<br>1
接受参数,得到所有数值的和,得到数据的最大值以确定纵轴的最大刻度值<br>2 根据数据个数确定图像的宽度,并画出横轴和纵轴坐标及刻度<br>3
画直线连接各点,为每个点填充一个2*2的矩形,突出点的位置<br>4 在每个点的右上方标注每个点的数据值</p><a name="zhe_shixianguocheng"></a>实现过程<p>&lt;?<br>$img_gao=170;<br>$img_kuan=0;<br>$jiange=30;
//横坐标点与点之间的间隔,生成的图片宽度会根据传入数据的多少而自动变化<br>$zuo=20;//左侧留空<br>$you=20;//右侧留空<br>$shang=20;
//上留空<br>$xia=20;//下留空<br>$zuidashujuzhi=1;<br>$p_x = array();//点横坐标<br>$p_y
= array();//点纵坐标<br>$y_name=split(",",$_GET["x_name"]);<br>if
($_GET["a"]=="") die("error id:0");<br>$shuju=split(",",$_GET["a"]);<br>//
得到纵轴最大值<br>for($i=0;$i&lt;count($shuju);$i++){<br>  
if(!is_numeric($shuju[$i])) die("error id:1");<br>  
if($shuju[$i]&gt;$zuidashujuzhi) $zuidashujuzhi=$shuju[$i];<br>}<br>//得到
图像宽度 <br>$img_kuan=$zuo+$you+count($shuju)*$jiange;<br>//然后创建图像资源 <br>$image
= imagecreate($img_kuan,$img_gao);<br>//灰色背景<br>$white =
imagecolorallocate($image, 0xEE, 0xEE, 0xEE);<br>//坐标轴用黑色显示<br>$zuobiao_yanse
= imagecolorallocate($image, 0x00, 0x00, 0x00);<br>//折线用蓝色显示<br>$xian_yanse
= imagecolorallocate($image, 0x00, 0x00, 0xFF);<br>//画坐标<br>//横轴<br>imageline
( $image, $zuo, $img_gao-$xia, $img_kuan-$you/2, $img_gao-$xia,
$zuobiao_yanse);<br>//纵轴<br>imageline ( $image, $zuo, $shang/2, $zuo,
$img_gao-$xia, $zuobiao_yanse);</p><p>//得到每个点的坐标<br>for($i=0;$i&lt;count($shuju);$i++){<br> 
 array_push ($p_x, $zuo+$i*$jiange);<br>  array_push ($p_y,
$shang+round(($img_gao-$shang-$xia)*(1-$shuju[$i]/$zuidashujuzhi)));<br>}</p><p>//
纵轴刻度<br>imageline ( $image, $zuo, $shang, $zuo+6, $shang,
$zuobiao_yanse);<br>imagestring ( $image, 1, $zuo/4,
$shang,$zuidashujuzhi, $zuobiao_yanse);<br>imageline ( $image, $zuo,
$shang+($img_gao-$shang-$xia)*1/4, $zuo+6,
$shang+($img_gao-$shang-$xia)*1/4, $zuobiao_yanse);<br>imagestring (
$image, 1, $zuo/4, $shang+($img_gao-$shang-$xia)*1/4,$zuidashujuzhi*3/4,
$zuobiao_yanse);<br>imageline ( $image, $zuo,
$shang+($img_gao-$shang-$xia)*2/4, $zuo+6,
$shang+($img_gao-$shang-$xia)*2/4, $zuobiao_yanse);<br>imagestring (
$image, 1, $zuo/4, $shang+($img_gao-$shang-$xia)*2/4,$zuidashujuzhi*2/4,
$zuobiao_yanse);<br>imageline ( $image, $zuo,
$shang+($img_gao-$shang-$xia)*3/4, $zuo+6,
$shang+($img_gao-$shang-$xia)*3/4, $zuobiao_yanse);<br>imagestring (
$image, 1, $zuo/4, $shang+($img_gao-$shang-$xia)*3/4,$zuidashujuzhi*1/4,
$zuobiao_yanse);</p><p>//横轴刻度<br>for($i=0;$i&lt;count($shuju);$i++){<br> 
 imageline ( $image, $zuo+$i*$jiange, $img_gao-$xia, $zuo+$i*$jiange,
$img_gao-$xia-6, $zuobiao_yanse);<br>  imagestring ( $image, 1,
$zuo+$i*$jiange-$jiange/4, $shang+($img_gao-$shang-$xia)+2,$y_name[$i],
$zuobiao_yanse);<br>}</p><p><br>//折线<br>$shuju_yanse_int=0;<br>for($i=0;$i&lt;count($shuju);$i++){<br> 
 if($i+1&lt;&gt;count($shuju)){<br>    imageline ( $image, $p_x[$i],
$p_y[$i], $p_x[$i+1], $p_y[$i+1], $xian_yanse);<br>    
imagefilledrectangle($image, $p_x[$i]-1, $p_y[$i]-1, $p_x[$i]+1,
$p_y[$i]+1, $xian_yanse);<br>  }<br>}<br>//上一个循环没有画出最后一个点效果,这里还要追加<br>imagefilledrectangle($image,
$p_x-1, $p_y-1,
$p_x+1, $p_y+1, $xian_yanse);<br><br>//
标注数据值<br>for($i=0;$i&lt;count($shuju);$i++){<br>  imagestring ( $image,
3, $p_x[$i]+4, $p_y[$i]-12,$shuju[$i], $zuobiao_yanse);<br>}<br>//设定文件头 <br>header('Content-type:
image/png');<br>//输出图像<br>imagepng($image);<br>//释放资源 <br>imagedestroy($image);<br>?&gt;</p><p><br></p><a name="zhe_shiyongfangfa"></a>使用方法<p>在需要显示图像的位置插入如下代码<br>&lt;img
src="zhexian_img.php?a=5.4,2,30.2,4,0,6,7.7,3.8,2,3,4"/&gt;<br>其中a的值由你自己
计算得出<br>a的文本格式是由“,”连接的若干个数据的字符串,get方式传入。</p><p>由于往图形里写入中文需要更多PHP环境配置,所以这
里给出一个html解决方案,实用也很灵活:<br>大家只需要根据数据个数的不同,动态生成一个表格放置横轴坐标刻度名称就行了,像这样</p>&lt;table
width="550" border="0" cellspacing="0" cellpadding="0"&gt;<br>&lt;tr
align="center"&gt; <br>&lt;?<br>for($i=0;$i&lt;12;$i++) {<br>  echo
"&lt;td width=\"30\"&gt;".$i."月</td>";<br>}<br>?&gt;<br></tr><br></table>
<a name="zhe_shixianxiaoguo"></a>实现效果<p class="hiliteRed"><img src="http://dev.csdn.net/zsrui/admin/images/2.gif" width="389" height="199"></p><p class="hiliteRed">&nbsp;</p><p class="hiliteRed">&nbsp;</p>柱状图<br><br><a name="zhu_shejisilu"></a>设计思路<ol><li>还是要首先确定纵轴的刻度值,确定纵轴的刻度最大值 </li><li>然后根据得到的数据个数确定图像的宽度,这时就
可以创建图像了 </li><li>计算每个色柱的高度,用高度可以计算出色柱的填充范围 </li><li>用直线画出坐标轴,标注刻度值 </li><li>用
矩形填充色柱,并在色柱上方标注数据值 </li><li>用Html方式画出需要的横轴坐标名称</li></ol><a name="zhu_shixianguocheng"></a><br>实现过程<p class="hiliteRed">&lt;?<br>$kuan=30;//色柱宽<br>$jiange=20;//色柱间间隔<br>$zuo=20;
//左侧留空<br>$you=20;//右侧留空<br>$shang=20;//上留空<br>$xia=10;//下留空<br>$zuidashujuzhi=1;
//初始化纵轴最大数据值<br>if ($_GET["a"]=="") die("error id:0");<br>$shuju=split(",",$_GET["a"]);<br>//
得到最大值<br>for($i=0;$i&lt;count($shuju);$i++){<br>  
if(!is_numeric($shuju[$i])) die("error id:1");<br>  
if($shuju[$i]&gt;$zuidashujuzhi) $zuidashujuzhi=$shuju[$i];<br>}<br>//计算
图像宽度 <br>$img_kuan=$zuo+$you+$jiange+count($shuju)*($kuan+$jiange);<br>//
图像高 <br>$img_gao=170;<br>//存储色柱高度的数组<br>$zhugaodu = array();<br>$image =
imagecreate($img_kuan,$img_gao);<br>$white = imagecolorallocate($image,
0xEE, 0xEE, 0xEE);<br>//色柱颜色<br>$shuju_yanse =array(<br>  
imagecolorallocate($image, 0x97, 0xbd, 0x00),<br>  
imagecolorallocate($image, 0x00, 0x99, 0x00),<br>  
imagecolorallocate($image, 0xcc, 0x33, 0x00),<br>  
imagecolorallocate($image, 0xff, 0xcc, 0x00),<br>  
imagecolorallocate($image, 0x33, 0x66, 0xcc),<br>  
imagecolorallocate($image, 0x33, 0xcc, 0x33),<br>  
imagecolorallocate($image, 0xff, 0x99, 0x33),<br>  
imagecolorallocate($image, 0xcc, 0xcc, 0x99),<br>  
imagecolorallocate($image, 0x99, 0xcc, 0x66),<br>  
imagecolorallocate($image, 0x66, 0xff, 0x99)<br>);</p><p>//坐标轴颜色<br>$zuobiao_yanse
= imagecolorallocate($image, 0x00, 0x00, 0x00);<br>//横轴<br>imageline (
$image, $zuo, $img_gao-$xia, $img_kuan-$you/2, $img_gao-$xia,
$zuobiao_yanse);<br>//纵轴<br>imageline ( $image, $zuo, $shang/2, $zuo,
$img_gao-$xia, $zuobiao_yanse);</p><p>//纵轴刻度,纵轴上共标注4个点,所以这里分别计算即可<br>imageline
( $image, $zuo, $shang, $zuo+6, $shang, $zuobiao_yanse);<br>imagestring
( $image, 3, $zuo/4, $shang,round($zuidashujuzhi), $zuobiao_yanse);<br>imageline
( $image, $zuo, $shang+($img_gao-$shang-$xia)*1/4, $zuo+6,
round($shang+($img_gao-$shang-$xia)*1/4), $zuobiao_yanse);<br>imagestring
( $image, 3, $zuo/4,
$shang+($img_gao-$shang-$xia)*1/4,round($zuidashujuzhi*3/4),
$zuobiao_yanse);<br>imageline ( $image, $zuo,
$shang+($img_gao-$shang-$xia)*2/4, $zuo+6,
$shang+($img_gao-$shang-$xia)*2/4, $zuobiao_yanse);<br>imagestring (
$image, 3, $zuo/4,
$shang+($img_gao-$shang-$xia)*2/4,round($zuidashujuzhi*2/4),
$zuobiao_yanse);<br>imageline ( $image, $zuo,
$shang+($img_gao-$shang-$xia)*3/4, $zuo+6,
$shang+($img_gao-$shang-$xia)*3/4, $zuobiao_yanse);<br>imagestring (
$image, 3, $zuo/4,
$shang+($img_gao-$shang-$xia)*3/4,round($zuidashujuzhi*1/4),
$zuobiao_yanse);</p><p>//得到每个柱的高度<br>for($i=0;$i&lt;count($shuju);$i++){<br> 
 array_push ($zhugaodu,
round(($img_gao-$shang-$xia)*$shuju[$i]/$zuidashujuzhi));<br>}<br>//画数据柱<br>$shuju_yanse_int=0;<br>for($i=0;$i&lt;count($shuju);$i++){<br> 
 imagefilledrectangle(
$image,$zuo+$jiange+$i*($kuan+$jiange),$shang+($img_gao-$shang-$xia)-$zhugaodu[$i],$zuo+$jiange+$i*($kuan+$jiange)+$kuan,($img_gao-$xia)-1
,$shuju_yanse[$shuju_yanse_int]);<br>//因为只定义了10种颜色,所以这里做一个循环  <br>  
if($shuju_yanse_int==9){<br>    $shuju_yanse_int=0;<br>  }else{<br>    
$shuju_yanse_int++;<br>  }<br>}<br>//标注数据柱上方数据值<br>for($i=0;$i&lt;count($shuju);$i++){<br> 
 imagestring ( $image, 1,
$zuo+$jiange+$i*($kuan+$jiange)+2,$shang+($img_gao-$shang-$xia)-$zhugaodu[$i]-10,$shuju[$i],
$zuobiao_yanse);<br>}<br>header('Content-type: image/png');<br>imagepng($image);<br>imagedestroy($image);<br>?&gt;</p><a id="zhu_shiyongfangfa" name="zhu_shiyongfangfa"></a>使用方法<p>在需要显示图像
的位置插入如下代码<br>&lt;img
src="zhu_img.php?a=5.4,2,30.2,4,0,6,7.7,3.8,2,3,4"/&gt;<br>其中a的值由你自己计算得出<br>a
的文本格式是由“,”连接的若干个数据的字符串,get方式传入。</p><p>同样使用一个html解决方案,解决横轴刻度名称的问题:<br>根据数
据个数的不同,动态生成一个表格放置横轴坐标刻度名称就行了,像这样</p>&lt;table width="550" border="0"
cellspacing="0" cellpadding="0"&gt;<br>&lt;tr align="center"&gt; <br>&lt;?<br>for($i=0;$i&lt;12;$i++)
{<br>  echo "&lt;td width=\"50\"&gt;".$i."月</td>";<br>}<br>?&gt;<br></tr><br></table><br><br><a name="zhu_shixianxiaoguo"></a>实现效果<p class="hiliteRed"><img src="http://dev.csdn.net/zsrui/admin/images/3.gif" width="622" height="195"></p><p>&nbsp;</p><p>&nbsp;</p><a name="cankaowenxian"></a>参考文献<p>PHP
手册 <a href="http://www.php.net/docs.php" target="_blank" target="_blank">http://www.php.net/docs.php</a></p><p>&nbsp;</p>
页: [1]
查看完整版本: 如何使用PHP动态生成饼状图、柱状图和折线图