- 论坛徽章:
- 0
|
转:web freer
利用php实现数据统计图
年前由于工作需要,工作的中心由asp转到了php开发上,通过几周的学习与实践,已基本能熟练设计常用的web功能。b/s架构的web应用程序实现原理是一样的,不同的是脚本语法、解析方式等方面。
php在图片处理方面提供了强劲的支持。通过对php技术手册的翻阅,发现在php内置函数与GD库支持下,可以方便创建、操作各种图片,在asp下则需要如aspjpeg类的第三方组件(本人不会写组件)才能完成。而且感觉php在oo方面也很方便,于是趁热打铁写了个数据统计图类,功能与生成效果还是很简陋的那种,呵呵。下面分享给博客园的朋友,类中的WEBSITE_DIRROOT换成你的网站根目录路径,欢迎路过的大牛拍砖指导^^- 001 <?php
- 002 /*
- 003 * class: 数据统计图
- 004 * author: 51JS.COM-ZMM
- 005 * date: 2011.2.1
- 006 * email: 304924248@qq.com
- 007 * blog: http://www.cnblogs.com/cnzmm/
- 008 */
- 009
- 010 class Draw {
- 011 public $mass=10, $unit=10, $data=array(), $save=false, $dir='/images/count';
- 012 private $width=0, $height=0, $side=0, $bgcor=array(255, 255, 255);
- 013 private $name, $image, $offset=0, $margin=20, $space=3, $font='/fonts/simsun.ttc';
- 014 private $fontW, $fontH, $fontC, $fontA, $osSum, $omSum, $xLen, $yLen, $size=9;
- 015
- 016 function __construct($width=0, $height=0, $data=array()) {
- 017 $this->width = $width;
- 018 $this->height = $height;
- 019 if (!empty($data)) $this->data = $data;
- 020
- 021 $this->fontW = imagefontwidth(2);
- 022 $this->fontH = imagefontheight(2);
- 023 $this->fontA = imagefontheight($this->size);
- 024 $this->fontA = round($this->fontA / 2) + 2;
- 025
- 026 $this->font = WEBSITE_DIRROOT.$this->font;
- 027 if (!is_file($this->font)) {
- 028 exit('字体文件不存在!');
- 029 } else {
- 030 $this->font = realpath($this->font);
- 031 }
- 032 }
- 033
- 034 public function DrawPie($name="") {
- 035 $this->SetImgName($name);
- 036
- 037 $this->side = $this->width;
- 038 if ($this->side > 0 && !empty($this->data)) {
- 039 $pie_core = $this->side / 2;
- 040
- 041 $fts_max = 0;
- 042 foreach (array_keys($this->data) as $item) {
- 043 $chk_itm = $item.' '.max($this->data).' 00.00%';
- 044 $fts_box = imagettfbbox($this->size, 0, $this->font, $chk_itm);
- 045 $chk_len = $fts_box[4] - $fts_box[6];
- 046 if ($chk_len > $fts_max) $fts_max = $chk_len;
- 047 } $pie_cAdd = 48 + $fts_max;
- 048
- 049 $this->image = @imagecreate($this->side + $pie_cAdd, $this->side + 1);
- 050 if ($this->image) {
- 051 $this->SetDftColor();
- 052
- 053 $dat_sum = array_sum($this->data);
- 054 $arc_beg = array(-180, -90, 0, 90, 180);
- 055 $arc_beg = $arc_beg[array_rand($arc_beg)];
- 056
- 057 $fts_add = $this->fontA * 2;
- 058 $ftx_beg = $this->side + 28; $fty_beg = 2;
- 059 $ftx_add = 20; $fty_add = 20;
- 060 $fts_cor = imagecolorallocate($this->image, 0, 0, 0);
- 061 $fty_chk = $fty_add * count($this->data);
- 062 while ($fty_chk > $this->side + 2) {
- 063 $fty_chk = --$fty_add * count($this->data);
- 064 }
- 065
- 066 foreach ($this->data as $item => $data) {
- 067 $rnd_cor = $this->GetRndColor();
- 068 $arc_pct = number_format($data * 100 / $dat_sum, 2);
- 069 $arc_end = $data * 360 / $dat_sum + $arc_beg;
- 070 $item = iconv('gb2312', 'UTF-8', (string)$item);
- 071
- 072 imagefilledarc($this->image, $pie_core, $pie_core, $this->side, $this->side, $arc_beg, $arc_end, $rnd_cor, IMG_ARC_PIE);
- 073 imagefilledrectangle($this->image, $ftx_beg, $fty_beg, $ftx_beg + 12, $fty_beg + 10, $rnd_cor);
- 074 imagettftext($this->image, $this->size, 0, $ftx_beg + $ftx_add, $fty_beg + $this->fontA, $fts_cor, $this->font, $item.' '.$data.' '.$arc_pct.'%');
- 075
- 076 $fty_beg += $fty_add; $arc_beg = $arc_end;
- 077 }
- 078
- 079 $this->Output();
- 080 }
- 081 } else {
- 082 exit('画布边长设置不正确或统计数据为空!');
- 083 }
- 084 }
- 085
- 086 public function DrawColumn($name="") {
- 087 $this->SetImgName($name);
- 088
- 089 if (!empty($this->data)) {
- 090 $this->DrawCdtAxes();
- 091 $this->DrawLattice();
- 092
- 093 $cdx_cut = count($this->data);
- 094 $cdx_add = floor($this->xLen / $cdx_cut);
- 095 $cdy_add = $this->yLen / $this->mass;
- 096 imagesetthickness($this->image, floor($cdx_add / 2));
- 097
- 098 $cdy_end = $this->height - $this->osSum - 1;
- 099 $cdx_beg = floor($cdx_add / 2) + $this->osSum;
- 100 foreach ($this->data as $item => $data) {
- 101 $cdy_beg = $this->yLen - ($data * $cdy_add / $this->unit) + $this->omSum;
- 102 imageline($this->image, $cdx_beg, $cdy_beg, $cdx_beg, $cdy_end, $this->GetRndColor());
- 103
- 104 $fts_txt = (string)$data;
- 105 $ftx_beg = $cdx_beg - $this->fontW * strlen($fts_txt) / 2;
- 106 $fty_beg = $cdy_beg - $this->fontH - $this->space;
- 107 imagestring($this->image, 2, $ftx_beg, $fty_beg, $fts_txt, $this->fontC);
- 108
- 109 $fts_txt = iconv('gb2312', 'UTF-8', (string)$item);
- 110 $fts_box = imagettfbbox($this->size, 0, $this->font, $fts_txt);
- 111 $ftx_beg = $cdx_beg - floor($fts_box[4] - $fts_box[6]) / 2;
- 112 $fty_beg = $this->height - $this->offset + $this->fontA;
- 113 imagettftext($this->image, $this->size, 0, $ftx_beg, $fty_beg, $this->fontC, $this->font, $fts_txt);
- 114
- 115 $cdx_beg += $cdx_add;
- 116 }
- 117
- 118 $this->Output();
- 119 } else {
- 120 exit('统计数据为空!');
- 121 }
- 122 }
- 123
- 124 public function DrawLine($name="") {
- 125 $this->SetImgName($name);
- 126
- 127 if (!empty($this->data)) {
- 128 $this->DrawCdtAxes();
- 129 $this->DrawLattice();
- 130
- 131 $dat_idx = 0;
- 132 $cd_line = imagecolorallocate($this->image, 255, 0, 0);
- 133 $cd_fold = imagecolorallocate($this->image, 0, 0, 255);
- 134
- 135 $cdx_cut = count($this->data) - 1;
- 136 $cdx_add = floor($this->xLen / $cdx_cut);
- 137 $cdy_add = $this->yLen / $this->mass;
- 138
- 139 $cdx_old = 0; $cdx_beg = $this->osSum;
- 140 $cdy_old = 0; $cdy_beg = $this->omSum - 5;
- 141 $cdy_end = $this->height - $this->osSum - 1;
- 142 foreach ($this->data as $item => $data) {
- 143 imagesetthickness($this->image, 1);
- 144 $dat_idx > 0 && imageline($this->image, $cdx_beg, $cdy_beg, $cdx_beg, $cdy_end, IMG_COLOR_STYLED);
- 145 imagesetthickness($this->image, 2);
- 146
- 147 $cdx_dot = $cdx_beg;
- 148 $cdy_dot = $this->yLen - $data * $cdy_add / $this->unit + $this->omSum;
- 149 if ($cdx_old > 0 && $cdy_old > 0) {
- 150 imageline($this->image, $cdx_old, $cdy_old, $cdx_dot, $cdy_dot, $cd_line);
- 151 imagefilledellipse($this->image, $cdx_old, $cdy_old, 6, 6, $cd_fold);
- 152 }
- 153 imagefilledellipse($this->image, $cdx_dot, $cdy_dot, 6, 6, $cd_fold);
- 154
- 155 $fts_txt = '('.(string)$data.')';
- 156 if ($dat_idx == 0) {
- 157 $ftx_beg = $cdx_dot + $this->space + 3;
- 158 $fty_beg = $cdy_dot - $this->fontH / 2;
- 159 } else {
- 160 $ftx_beg = $cdx_dot - $this->fontW * strlen($fts_txt) / 2;
- 161 $fty_beg = $cdy_dot - $this->fontH - $this->space * 2;
- 162 }
- 163 imagestring($this->image, 2, $ftx_beg, $fty_beg, $fts_txt, $this->fontC);
- 164
- 165 $fts_txt = iconv('gb2312', 'UTF-8', (string)$item);
- 166 $fts_box = imagettfbbox($this->size, 0, $this->font, $fts_txt);
- 167 $ftx_beg = $cdx_beg - floor($fts_box[4] - $fts_box[6]) / 2;
- 168 $fty_beg = $this->height - $this->offset + $this->fontA;
- 169 imagettftext($this->image, $this->size, 0, $ftx_beg, $fty_beg, $this->fontC, $this->font, $fts_txt);
- 170
- 171 $dat_idx ++; $cdx_beg += $cdx_add;
- 172 $cdx_old = $cdx_dot; $cdy_old = $cdy_dot;
- 173 }
- 174
- 175 $this->Output();
- 176 } else {
- 177 exit('统计数据为空!');
- 178 }
- 179 }
- 180
- 181 public function GetImgName() {
- 182 return empty($this->name) ? null :
- 183 WEBSITE_DIRROOT.$this->dir.'/'.$this->name;
- 184 }
- 185
- 186 public function SetImgName($name) {
- 187 if (!empty($name)) {
- 188 $this->save = true; $this->name = $name;
- 189 }
- 190 }
- 191
- 192 public function ImportData($data=array()) {
- 193 empty($data) || is_array($data) && $this->data = $data;
- 194 }
- 195
- 196 private function GetMinSize() {
- 197 $fts_len = strlen((string)$this->unit) + 1;
- 198 $this->offset = imagefontwidth(2) * $fts_len;
- 199 $this->osSum = $this->offset + $this->space;
- 200 $this->omSum = $this->offset + $this->margin;
- 201 $this->xLen = $this->width - $this->osSum - $this->omSum;
- 202 $this->yLen = $this->height - $this->osSum - $this->omSum;
- 203
- 204 return $this->osSum + $this->omSum;
- 205 }
- 206
- 207 private function DrawCdtAxes() {
- 208 $min_size = $this->GetMinSize();
- 209 if ($this->width > $min_size && $this->height > $min_size) {
- 210 $this->image = @imagecreate($this->width, $this->height);
- 211 if ($this->image) {
- 212 $this->SetDftColor();
- 213
- 214 $cd_cr = imagecolorallocate($this->image, 0, 0, 0);
- 215 $cd_xs = $this->osSum; $cd_xe = $this->width - $this->offset;
- 216 $cd_ys = $this->offset; $cd_ye = $this->height - $this->osSum;
- 217
- 218 imageline($this->image, $cd_xs, $cd_ye, $cd_xe, $cd_ye, $cd_cr);
- 219 imageline($this->image, $cd_xs, $cd_ys, $cd_xs, $cd_ye, $cd_cr);
- 220 imageline($this->image, $cd_xe, $cd_ye, $cd_xe - 6, $cd_ye - 3, $cd_cr);
- 221 imageline($this->image, $cd_xe, $cd_ye, $cd_xe - 6, $cd_ye + 3, $cd_cr);
- 222 imageline($this->image, $cd_xs, $cd_ys, $cd_xs - 3, $cd_ys + 6, $cd_cr);
- 223 imageline($this->image, $cd_xs, $cd_ys, $cd_xs + 3, $cd_ys + 6, $cd_cr);
- 224 } else {
- 225 exit('画布建立失败!');
- 226 }
- 227 } else {
- 228 exit('画布尺寸设置不正确!');
- 229 }
- 230 }
- 231
- 232 private function DrawLattice() {
- 233 $this->SetDashLine();
- 234
- 235 $cdy_each = $this->unit;
- 236 $cdy_yMax = $this->mass * $cdy_each;
- 237 while ($cdy_yMax < max($this->data)) {
- 238 $cdy_each += $this->unit;
- 239 $cdy_yMax = $cdy_each * $this->mass;
- 240 } $this->unit = $cdy_each;
- 241 $cdx_beg = $this->osSum + 1;
- 242 $cdx_end = $this->width - $this->omSum;
- 243 $cdy_add = $this->yLen / $this->mass;
- 244
- 245 $cdy_beg = $this->omSum;
- 246 for ($i = 0; $i < $this->mass; $i ++) {
- 247 imageline($this->image, $cdx_beg, $cdy_beg, $cdx_end, $cdy_beg, IMG_COLOR_STYLED);
- 248
- 249 $fts_txt = (string)$this->unit * ($this->mass - $i);
- 250 $ftx_beg = $cdx_beg - $this->fontW * strlen($fts_txt) - $this->space;
- 251 $fty_beg = $cdy_beg - $this->fontH / 2;
- 252 imagestring($this->image, 2, $ftx_beg, $fty_beg, $fts_txt, $this->fontC);
- 253
- 254 $cdy_beg += $cdy_add;
- 255 }
- 256 }
- 257
- 258 private function SetDftColor() {
- 259 imagecolorallocate($this->image, $this->bgcor[0], $this->bgcor[1], $this->bgcor[2]);
- 260 }
- 261
- 262 private function GetRndColor() {
- 263 return imagecolorallocate($this->image, mt_rand(0, 255), mt_rand(0, 255), mt_rand(0, 255));
- 264 }
- 265
- 266 private function SetDashLine() {
- 267 $cd_stop = imagecolorallocate($this->image, 255, 255, 255);
- 268 $cd_dash = imagecolorallocate($this->image, 200, 200, 200);
- 269 imagesetstyle($this->image, array($cd_stop, $cd_stop, $cd_stop,
- 270 $cd_dash, $cd_dash, $cd_dash));
- 271 $this->fontC = imagecolorallocate($this->image, 56, 56, 56);
- 272 }
- 273
- 274 private function Output() {
- 275 extract($this->GetImgSupot(), EXTR_OVERWRITE);
- 276
- 277 if ($this->save == false) {
- 278 header('Content-Type: '.$type);
- 279 $func($this->image);
- 280 } else {
- 281 if (empty($this->name)) {
- 282 $this->name = array_keys($this->data);
- 283 $this->name = md5(implode('', $this->name));
- 284 }
- 285 $this->dir = WEBSITE_DIRROOT.$this->dir;
- 286 $this->name = $this->name.'.'.$ext;
- 287 $func($this->image, $this->dir.'/'.$this->name);
- 288 }
- 289 }
- 290
- 291 private function GetImgSupot() {
- 292 $img_supt = imagetypes();
- 293 if (($img_supt & IMG_GIF) && function_exists('imagegif'))
- 294 return array('type'=>'image/gif', 'ext'=>'gif', 'func'=>'imagegif');
- 295 if (($img_supt & IMG_JPG) && function_exists('imagejpeg'))
- 296 return array('type'=>'image/jpeg', 'ext'=>'jpg', 'func'=>'imagejpeg');
- 297 if (($img_supt & IMG_PNG) && function_exists('imagepng'))
- 298 return array('type'=>'image/png', 'ext'=>'png', 'func'=>'imagepng');
- 299 }
- 300
- 301 function __destruct() {
- 302 image_destroy($this->image);
- 303 }
- 304 }
- 305
- 306 // 使用方法
- 307 $w = 640; $h = 480;
- 308 $info = array('春季'=>78, '夏季'=>65, '秋季'=>86, '冬季'=>55);
- 309 $draw_ins = new Draw($w, $h);
- 310 $draw_ins->ImportData($info);
- 311 // 柱状图
- 312 $draw_ins->DrawColumn();
- 313 // 线形图
- 314 // $draw_ins->DrawLine();
- 315 // 饼形图
- 316 // $draw_ins->DrawPie();
- 317 unset($draw_ins);
复制代码 |
|