如何使用PHP動態生成餅狀圖、柱狀圖和折線圖

所有內容:如何使用PHP動態生成餅狀圖、折線圖和柱狀圖
專題討論區:http://hh.cc163.com/form/
主頁:http://hh.cc163.com/

 

目錄

  1. 餅裝圖
    1. 設計思路
    2. 實現過程
    3. 使用方法
    4. 實現效果
  2. 折線圖
    1. 設計思路
    2. 實現過程
    3. 使用方法
    4. 實現效果
  3. 柱狀圖
    1. 設計思路
    2. 實現過程
    3. 使用方法
    4. 實現效果
  4. 參考文獻
  5. 相關鏈接

 

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方式傳入。
顏色圖例如下,請自行排列:

                   
                   

實現效果

1.gif

 

 

折線圖

設計思路

用折線圖表查看某一數據在單位時段內的變化趨勢是一個好的選擇。我們就用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解決方案,實用也很靈活:
大家只需要根據數據個數的不同,動態生成一個表格放置橫軸座標刻度名稱就行了,像這樣

<table width="550" border="0" cellspacing="0" cellpadding="0">
<tr align="center">
<?
for($i=0;$i<12;$i++) {
  echo "<td width=/"30/">".$i."月</td>";
}
?>
</tr>
</table>

實現效果

2.gif

 

 

柱狀圖

設計思路

  1. 還是要首先確定縱軸的刻度值,確定縱軸的刻度最大值
  2. 然後根據得到的數據個數確定圖像的寬度,這時就可以創建圖像了
  3. 計算每個色柱的高度,用高度可以計算出色柱的填充範圍
  4. 用直線畫出座標軸,標註刻度值
  5. 用矩形填充色柱,並在色柱上方標註數據值
  6. 用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解決方案,解決橫軸刻度名稱的問題:
根據數據個數的不同,動態生成一個表格放置橫軸座標刻度名稱就行了,像這樣

<table width="550" border="0" cellspacing="0" cellpadding="0">
<tr align="center">
<?
for($i=0;$i<12;$i++) {
  echo "<td width=/"50/">".$i."月</td>";
}
?>
</tr>
</table>

實現效果

3.gif

 

 

參考文獻

PHP 手冊 http://www.php.net/docs.php

 

 

相關鏈接

原文完整版
http://hh.cc163.com/php/phpimagehowto/default.htm

所有內容下載:
http://hh.cc163.com/php/phpimagehowto/phpimagehowto.rar

討論區
http://hh.cc163.com/form/

主頁
http://hh.cc163.com/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章