所有內容:如何使用PHP動態生成餅狀圖、折線圖和柱狀圖
專題討論區:http://hh.cc163.com/form/
主頁:http://hh.cc163.com/
目錄
序
PHP在圖像操作方面的表現非常出色,我們只需藉助可以免費得到的GD庫便可以輕鬆實現圖、表勾畫。下面將分別介紹筆者實現的餅狀圖、折線圖和柱狀圖以及他們的使用方法,這幾段代碼的特點就是不需要再把它們複製到你的代碼之中,只需要把計算得到的數據作爲參數傳入,即可得到相應的圖形效果
開發環境:PHP Version 4.3.6+GD Version bundled (2.0.22 compatible)
由於作者水平有限,文章中難免存在錯誤,我將非常感激您的指正
代碼中所有使用的函數的說明,請參見php開發文檔 點這裏獲得最新版
餅狀圖
設計思路
餅狀圖表對於查看一個值佔總值的百分比是一個好的方法。我們就用PHP來實現一個餅形圖表。
它的設計思想是:
1 接受參數,得到所有數值的和,得到每一個值佔數值總和的比例。
2 根據比例計算每一個色塊在圖中的圓周角度
3 要產生立體效果,只需要用深顏色畫出陰影就可以了
實現過程
<?
//參數以a爲參數名傳入,a的文本形態應該是用“,”分割的若干數字連接的字符串
//這裏首先判斷a是否存在
if($_GET["a"]=="") die("0");
//將得到的數據分解,存入數組$shuju中
$shuju=split(",",$_GET["a"]);
//再次判斷數據的合法性,返回錯誤代碼
if(count($shuju)==0) die("2");
//定義整個圖形的寬度和高度
//讀者可以根據需要修改這兩個變量的值
$tukuan=300;
$tugao=150;
//定義一個數組,用來存放每一個色塊的角度範圍
$jiaodu = array();
//定義存貯數據和的變量
$total=0;
//遍歷數組求和
for ($i = 0; $i < count($shuju); $i++) {
if(!is_numeric($shuju[$i])) die("1");
$total+=$shuju[$i];
}
//再次遍歷,計算色塊角度並存入數組
for ($i = 0; $i < count($shuju); $i++) {
array_push ($jiaodu, round(360*$shuju[$i]/$total));
}
//創建圖像
$image = imagecreate($tukuan, $tugao);
//定義一個灰色背景色,這個顏色其實就是大家很熟悉的頁面色系16進制數字表示的#EEEEEE
$white = imagecolorallocate($image, 0xEE, 0xEE, 0xEE);
//再定義10對深淺對應的彩色,存入二維數組
$yanse = array(
array(
imagecolorallocate($image, 0x97, 0xbd, 0x00),
imagecolorallocate($image, 0x00, 0x99, 0x00),
imagecolorallocate($image, 0xcc, 0x33, 0x00),
imagecolorallocate($image, 0xff, 0xcc, 0x00),
imagecolorallocate($image, 0x33, 0x66, 0xcc),
imagecolorallocate($image, 0x33, 0xcc, 0x33),
imagecolorallocate($image, 0xff, 0x99, 0x33),
imagecolorallocate($image, 0xcc, 0xcc, 0x99),
imagecolorallocate($image, 0x99, 0xcc, 0x66),
imagecolorallocate($image, 0x66, 0xff, 0x99)
),
array(
imagecolorallocate($image, 0x4f, 0x66, 0x00),
imagecolorallocate($image, 0x00, 0x33, 0x00),
imagecolorallocate($image, 0x48, 0x10, 0x00),
imagecolorallocate($image, 0x7d, 0x64, 0x00),
imagecolorallocate($image, 0x17, 0x30, 0x64),
imagecolorallocate($image, 0x1a, 0x6a, 0x1a),
imagecolorallocate($image, 0x97, 0x4b, 0x00),
imagecolorallocate($image, 0x78, 0x79, 0x3c),
imagecolorallocate($image, 0x55, 0x7e, 0x27),
imagecolorallocate($image, 0x00, 0x93, 0x37)
)
);
//由下至上畫10個像素高的深色餅圖,作爲陰影
$yuanxin_x=$tukuan/2;
for ($h = $tugao/2+5; $h > $tugao/2-5; $h--) {
$kaishi=0;
$jieshu=0;
for ($i = 0; $i < count($shuju); $i++) {
$kaishi=$kaishi+0;
$jieshu=$kaishi+$jiaodu[$i];
$yanse_i=fmod($i,10);
imagefilledarc($image,$yuanxin_x,$h,$tukuan,$tugao-20,$kaishi,$jieshu,$yanse[1][$yanse_i],IMG_ARC_PIE);
$kaishi+=$jiaodu[$i];
$jieshu+=$jiaodu[$i];
}
}
//在最高處(也就是$h最小時)畫一個淺色餅圖,這個淺色圖跟先畫上的深色餅圖就能產生立體效果了
for ($i = 0; $i < count($shuju); $i++) {
$kaishi=$kaishi+0;
$jieshu=$kaishi+$jiaodu[$i];
$yanse_i=fmod($i,10);
imagefilledarc($image, $yuanxin_x, $h, $tukuan, $tugao-20, $kaishi, $jieshu, $yanse[0][$yanse_i], IMG_ARC_PIE);
$kaishi+=$jiaodu[$i];
$jieshu+=$jiaodu[$i];
}
//設定文件頭
header('Content-type: image/png');
//輸出圖像
imagepng($image);
//釋放資源
imagedestroy($image);
?>
使用方法
在需要顯示圖像的位置插入如下代碼
<img src="bing_img.php?a=3,2,3,4"/>
a的文本格式是由“,”連接的若干個數據的字符串,get方式傳入。
顏色圖例如下,請自行排列:
實現效果
折線圖
設計思路
用折線圖表查看某一數據在單位時段內的變化趨勢是一個好的選擇。我們就用PHP來實現一個動態折線圖表。
它的設計思想是:
1 接受參數,得到所有數值的和,得到數據的最大值以確定縱軸的最大刻度值
2 根據數據個數確定圖像的寬度,並畫出橫軸和縱軸座標及刻度
3 畫直線連接各點,爲每個點填充一個2*2的矩形,突出點的位置
4 在每個點的右上方標註每個點的數據值
實現過程
<?
$img_gao=170;
$img_kuan=0;
$jiange=30;//橫座標點與點之間的間隔,生成的圖片寬度會根據傳入數據的多少而自動變化
$zuo=20;//左側留空
$you=20;//右側留空
$shang=20;//上留空
$xia=20;//下留空
$zuidashujuzhi=1;
$p_x = array();//點橫座標
$p_y = array();//點縱座標
$y_name=split(",",$_GET["x_name"]);
if ($_GET["a"]=="") die("error id:0");
$shuju=split(",",$_GET["a"]);
//得到縱軸最大值
for($i=0;$i<count($shuju);$i++){
if(!is_numeric($shuju[$i])) die("error id:1");
if($shuju[$i]>$zuidashujuzhi) $zuidashujuzhi=$shuju[$i];
}
//得到圖像寬度
$img_kuan=$zuo+$you+count($shuju)*$jiange;
//然後創建圖像資源
$image = imagecreate($img_kuan,$img_gao);
//灰色背景
$white = imagecolorallocate($image, 0xEE, 0xEE, 0xEE);
//座標軸用黑色顯示
$zuobiao_yanse = imagecolorallocate($image, 0x00, 0x00, 0x00);
//折線用藍色顯示
$xian_yanse = imagecolorallocate($image, 0x00, 0x00, 0xFF);
//畫座標
//橫軸
imageline ( $image, $zuo, $img_gao-$xia, $img_kuan-$you/2, $img_gao-$xia, $zuobiao_yanse);
//縱軸
imageline ( $image, $zuo, $shang/2, $zuo, $img_gao-$xia, $zuobiao_yanse);
//得到每個點的座標
for($i=0;$i<count($shuju);$i++){
array_push ($p_x, $zuo+$i*$jiange);
array_push ($p_y, $shang+round(($img_gao-$shang-$xia)*(1-$shuju[$i]/$zuidashujuzhi)));
}
//縱軸刻度
imageline ( $image, $zuo, $shang, $zuo+6, $shang, $zuobiao_yanse);
imagestring ( $image, 1, $zuo/4, $shang,$zuidashujuzhi, $zuobiao_yanse);
imageline ( $image, $zuo, $shang+($img_gao-$shang-$xia)*1/4, $zuo+6, $shang+($img_gao-$shang-$xia)*1/4, $zuobiao_yanse);
imagestring ( $image, 1, $zuo/4, $shang+($img_gao-$shang-$xia)*1/4,$zuidashujuzhi*3/4, $zuobiao_yanse);
imageline ( $image, $zuo, $shang+($img_gao-$shang-$xia)*2/4, $zuo+6, $shang+($img_gao-$shang-$xia)*2/4, $zuobiao_yanse);
imagestring ( $image, 1, $zuo/4, $shang+($img_gao-$shang-$xia)*2/4,$zuidashujuzhi*2/4, $zuobiao_yanse);
imageline ( $image, $zuo, $shang+($img_gao-$shang-$xia)*3/4, $zuo+6, $shang+($img_gao-$shang-$xia)*3/4, $zuobiao_yanse);
imagestring ( $image, 1, $zuo/4, $shang+($img_gao-$shang-$xia)*3/4,$zuidashujuzhi*1/4, $zuobiao_yanse);
//橫軸刻度
for($i=0;$i<count($shuju);$i++){
imageline ( $image, $zuo+$i*$jiange, $img_gao-$xia, $zuo+$i*$jiange, $img_gao-$xia-6, $zuobiao_yanse);
imagestring ( $image, 1, $zuo+$i*$jiange-$jiange/4, $shang+($img_gao-$shang-$xia)+2,$y_name[$i], $zuobiao_yanse);
}
//折線
$shuju_yanse_int=0;
for($i=0;$i<count($shuju);$i++){
if($i+1<>count($shuju)){
imageline ( $image, $p_x[$i], $p_y[$i], $p_x[$i+1], $p_y[$i+1], $xian_yanse);
imagefilledrectangle($image, $p_x[$i]-1, $p_y[$i]-1, $p_x[$i]+1, $p_y[$i]+1, $xian_yanse);
}
}
//上一個循環沒有畫出最後一個點效果,這裏還要追加
imagefilledrectangle($image, $p_x[count($shuju)-1]-1, $p_y[count($shuju)-1]-1, $p_x[count($shuju)-1]+1, $p_y[count($shuju)-1]+1, $xian_yanse);
//標註數據值
for($i=0;$i<count($shuju);$i++){
imagestring ( $image, 3, $p_x[$i]+4, $p_y[$i]-12,$shuju[$i], $zuobiao_yanse);
}
//設定文件頭
header('Content-type: image/png');
//輸出圖像
imagepng($image);
//釋放資源
imagedestroy($image);
?>
使用方法
在需要顯示圖像的位置插入如下代碼
<img src="zhexian_img.php?a=5.4,2,30.2,4,0,6,7.7,3.8,2,3,4"/>
其中a的值由你自己計算得出
a的文本格式是由“,”連接的若干個數據的字符串,get方式傳入。
由於往圖形裏寫入中文需要更多PHP環境配置,所以這裏給出一個html解決方案,實用也很靈活:
大家只需要根據數據個數的不同,動態生成一個表格放置橫軸座標刻度名稱就行了,像這樣
<tr align="center">
<?
for($i=0;$i<12;$i++) {
echo "<td width=/"30/">".$i."月</td>";
}
?>
</tr>
</table>
實現效果
柱狀圖
設計思路
- 還是要首先確定縱軸的刻度值,確定縱軸的刻度最大值
- 然後根據得到的數據個數確定圖像的寬度,這時就可以創建圖像了
- 計算每個色柱的高度,用高度可以計算出色柱的填充範圍
- 用直線畫出座標軸,標註刻度值
- 用矩形填充色柱,並在色柱上方標註數據值
- 用Html方式畫出需要的橫軸座標名稱
實現過程
<?
$kuan=30;//色柱寬
$jiange=20;//色柱間間隔
$zuo=20;//左側留空
$you=20;//右側留空
$shang=20;//上留空
$xia=10;//下留空
$zuidashujuzhi=1;//初始化縱軸最大數據值
if ($_GET["a"]=="") die("error id:0");
$shuju=split(",",$_GET["a"]);
//得到最大值
for($i=0;$i<count($shuju);$i++){
if(!is_numeric($shuju[$i])) die("error id:1");
if($shuju[$i]>$zuidashujuzhi) $zuidashujuzhi=$shuju[$i];
}
//計算圖像寬度
$img_kuan=$zuo+$you+$jiange+count($shuju)*($kuan+$jiange);
//圖像高
$img_gao=170;
//存儲色柱高度的數組
$zhugaodu = array();
$image = imagecreate($img_kuan,$img_gao);
$white = imagecolorallocate($image, 0xEE, 0xEE, 0xEE);
//色柱顏色
$shuju_yanse =array(
imagecolorallocate($image, 0x97, 0xbd, 0x00),
imagecolorallocate($image, 0x00, 0x99, 0x00),
imagecolorallocate($image, 0xcc, 0x33, 0x00),
imagecolorallocate($image, 0xff, 0xcc, 0x00),
imagecolorallocate($image, 0x33, 0x66, 0xcc),
imagecolorallocate($image, 0x33, 0xcc, 0x33),
imagecolorallocate($image, 0xff, 0x99, 0x33),
imagecolorallocate($image, 0xcc, 0xcc, 0x99),
imagecolorallocate($image, 0x99, 0xcc, 0x66),
imagecolorallocate($image, 0x66, 0xff, 0x99)
);
//座標軸顏色
$zuobiao_yanse = imagecolorallocate($image, 0x00, 0x00, 0x00);
//橫軸
imageline ( $image, $zuo, $img_gao-$xia, $img_kuan-$you/2, $img_gao-$xia, $zuobiao_yanse);
//縱軸
imageline ( $image, $zuo, $shang/2, $zuo, $img_gao-$xia, $zuobiao_yanse);
//縱軸刻度,縱軸上共標註4個點,所以這裏分別計算即可
imageline ( $image, $zuo, $shang, $zuo+6, $shang, $zuobiao_yanse);
imagestring ( $image, 3, $zuo/4, $shang,round($zuidashujuzhi), $zuobiao_yanse);
imageline ( $image, $zuo, $shang+($img_gao-$shang-$xia)*1/4, $zuo+6, round($shang+($img_gao-$shang-$xia)*1/4), $zuobiao_yanse);
imagestring ( $image, 3, $zuo/4, $shang+($img_gao-$shang-$xia)*1/4,round($zuidashujuzhi*3/4), $zuobiao_yanse);
imageline ( $image, $zuo, $shang+($img_gao-$shang-$xia)*2/4, $zuo+6, $shang+($img_gao-$shang-$xia)*2/4, $zuobiao_yanse);
imagestring ( $image, 3, $zuo/4, $shang+($img_gao-$shang-$xia)*2/4,round($zuidashujuzhi*2/4), $zuobiao_yanse);
imageline ( $image, $zuo, $shang+($img_gao-$shang-$xia)*3/4, $zuo+6, $shang+($img_gao-$shang-$xia)*3/4, $zuobiao_yanse);
imagestring ( $image, 3, $zuo/4, $shang+($img_gao-$shang-$xia)*3/4,round($zuidashujuzhi*1/4), $zuobiao_yanse);
//得到每個柱的高度
for($i=0;$i<count($shuju);$i++){
array_push ($zhugaodu, round(($img_gao-$shang-$xia)*$shuju[$i]/$zuidashujuzhi));
}
//畫數據柱
$shuju_yanse_int=0;
for($i=0;$i<count($shuju);$i++){
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]);
//因爲只定義了10種顏色,所以這裏做一個循環
if($shuju_yanse_int==9){
$shuju_yanse_int=0;
}else{
$shuju_yanse_int++;
}
}
//標註數據柱上方數據值
for($i=0;$i<count($shuju);$i++){
imagestring ( $image, 1, $zuo+$jiange+$i*($kuan+$jiange)+2,$shang+($img_gao-$shang-$xia)-$zhugaodu[$i]-10,$shuju[$i], $zuobiao_yanse);
}
header('Content-type: image/png');
imagepng($image);
imagedestroy($image);
?>
使用方法
在需要顯示圖像的位置插入如下代碼
<img src="zhu_img.php?a=5.4,2,30.2,4,0,6,7.7,3.8,2,3,4"/>
其中a的值由你自己計算得出
a的文本格式是由“,”連接的若干個數據的字符串,get方式傳入。
同樣使用一個html解決方案,解決橫軸刻度名稱的問題:
根據數據個數的不同,動態生成一個表格放置橫軸座標刻度名稱就行了,像這樣
<tr align="center">
<?
for($i=0;$i<12;$i++) {
echo "<td width=/"50/">".$i."月</td>";
}
?>
</tr>
</table>
實現效果
參考文獻
PHP 手冊 http://www.php.net/docs.php
相關鏈接
原文完整版
http://hh.cc163.com/php/phpimagehowto/default.htm
所有內容下載:
http://hh.cc163.com/php/phpimagehowto/phpimagehowto.rar