PHP & Others

GD 동적콤보그래프 그리기-PHP+MySQL

컨텐츠 정보

본문



사용자가 특정 제품명을 클릭시 해당 제품의 최근 12개월 매출 자료와 동 12개월간의 전체 매출 자료를
DB에서 불러와 막대그래프로는 전체 매출을 그리고 꺽은선 그래프로는 해당 제품의 매출 기록을
GD라이브러리를 사용하여 JPEG 또는 PNG 포멧의 이미지로 나타낸다.
그래프 변화를 최대한 표현하기 위하여 y축의 눈금 단위는 0부터 시작하지 않고 변화 폭을 추려서 나타냈다.
한글 출력을 위해서 본인의 컴퓨터에 설치되어있는 트루타입 글꼴을 업로드하여 사용하였다.


/*****************************************************
# Source Name : comboGraph.php
# Information : DB로부터 데이터를 불러와 GD라이브러리를 이용해 바그래프와 꺽은선 그래프를 그린다.
# Program by : Michael Choi
*****************************************************/
require "DB 접속 정보파일";

if(abs(date(His))<25959) {     // DB서버가 동부시간대 지역에 있어 모든 자료가 동부시간으로 기록
        $now_date = date(Ymd,time()-(24*3600));  // 이를 3시간 느린 서부시간에 맞추어 자료를 불러온다.
}else{                         //즉, 동부시간 2006년 1월 1일 새벽 1시는
        $now_date = date(Ymd); // 서부시간으로 2005년 12월 31일 밤 10시다.
}                              // 따라서 서부시간의 어제는 서버가 있는 동부시간으로 기록된 DB 검색시
//$prod_name = "Global talk";  // 어제 03시부터 오늘 새벽 02시 59분 59초이다.

$connect = mysql_connect("$hostname","$user","$password");
mysql_select_db("$database", $connect);

for($i=12; $i>0; $i--) {
        $dstart = date(YmdHsi,mktime(3,0,0,substr($now_date,4,2)-$i,1,substr($now_date,0,4)));             // 검색 조건 시간대 설정
        $dend = date(YmdHsi,mktime(2,59,59,substr($now_date,4,2)-$i+1,1,substr($now_date,0,4)));
        $dmon = date("n월",mktime(3,0,0,substr($now_date,4,2)-$i,1,substr($now_date,0,4)));

        $product_rs = mysql_query("select sum(price) sale from order_info2 where date between '$dstart' and '$dend'", $connect) or die;
        $rs = mysql_fetch_row($product_rs);
        if(!$rs[0]) $rs[0] = 0;
        $gdata[] = array($dmon, $rs[0]);     // 지정된 시간대의 매출 총액을 월단위 합산하여 배열에 넣는다. (막대그래프용 데이터)

        $product_rs = mysql_query("select sum(price) sale from order_info2 where product_name like '$prod_name' and (date between '$dstart' and '$dend') group by product_name", $connect) or die;
        $rs = mysql_fetch_row($product_rs);
        if(!$rs[0]) $rs[0] = 0;
        $hdata[] = array($rs[0]);     // 지정된 시간대에서 사용자가 선택한 제품의 매출 총액을 월별 합산, 배열에 기록. (꺽은선 그래프용 데이터)

        if($i==12) $init_y = date("'y",mktime(3,0,0,substr($now_date,4,2)-$i,1,substr($now_date,0,4)));
        if($i==1) $end_y = date("'y",mktime(3,0,0,substr($now_date,4,2)-$i,1,substr($now_date,0,4)));
}

mysql_close($connect);

$maxmin = getMaxMin($gdata, 1);
$rmax = $maxmin[0];
$rmin = $maxmin[1];

$maxmin = getMaxMin($hdata, 0);
$hmax = $maxmin[0];
$hmin = $maxmin[1];

$margin_top = 30;
$margin_bottom = 45;
$margin_left = 35;
$margin_right = 38;
$ystep = 4;               // y축 눈금 희망 개수
$y_height = 160;          // 그래프 높이(Y축 높이)
$x_div = 30;              // x축 눈금 간격
$bar_w = $x_div - 10;     // 바그래프 개별 너비
$x_line = $margin_top + $y_height;        // x축이 놓일 y좌표값

$img_w = $margin_left + $x_div * 12 + $margin_right;
$img_h = $margin_top + $y_height + $margin_bottom;

$im = imagecreate($img_w, $img_h);

$black = imagecolorallocate($im, 0, 0, 0);
$red = imagecolorallocate($im, 255, 0, 0);
$red1 = imagecolorallocate($im, 201, 98, 102);
$blue = imagecolorallocate($im, 0, 0, 255);
$green = imagecolorallocate($im, 14, 99, 3);
$skyblue = imagecolorallocate($im, 234, 252, 255);
$white = imagecolorallocate($im, 255, 255, 255);
$gray = imagecolorallocate($im, 230, 230, 230);
$gray1 = imagecolorallocate($im, 180, 180, 180);
$pink = imagecolorallocate($im, 255, 237, 219);
$efont = "gd/font/arial.ttf";
$efonti = "gd/font/ariali.ttf";
$hfont = "gd/font/h2bdrm.ttf";

if(!$gdata) {
        $image = imageCreateFromGif("img/rad14.gif");
        imageCopyResized($im, $image, 0, 0, 0, 0, $img_w, $img_h, 200, 200);
        $txtTitle = isIconv("자료가 없습니다.");
        $titleBox = imagettfbbox(24, 0, $hfont, $txtTitle);
        $xcord = $img_w/2 - ($titleBox[2]-$titleBox[0])/2;
        $ycord = $img_h/2 + ($titleBox[5]-$titleBox[3])/2;
        imagettftext($im, 24, 0, $xcord, $ycord, $black, $hfont, $txtTitle);
}else{
        //배경색 그리기
        imagefill($im, 0, 0, $white);
        
        //폰트 설정
        $hfont = "gd/font/h2bdrm.ttf";  //한글폰트
        $efont = "gd/font/arial.ttf";   //영문폰트

        //타이틀 출력
        $txtString = isIconv("월별 총매출 대비 ".$prod_name." 매출 현황");
        $txtBox = imagettfbbox(10, 0, $hfont, $txtString);
        imagettftext($im, 10, 0, ($img_w/2-($txtBox[2]-$txtBox[0])/2)+2, $margin_top-15+2, $gray1, $hfont, $txtString);
        imagettftext($im, 10, 0, $img_w/2-($txtBox[2]-$txtBox[0])/2, $margin_top-15, $black, $hfont, $txtString);

        //Copyright
        $str = "Copyright ".date(Y)." CallKoreaNow.com - Graph by Mike";
        $txtBox = imagettfbbox(7, 0, $efont, $str);
        $xcord = $img_w - $margin_right - ($txtBox[2]-$txtBox[0])+3;
        $ycord = $img_h-2;
        imagettftext($im, 7, 0, $xcord, $ycord, $gray, $efont, $str);

        //X축눈금 그리기
        for($i=0;$i<12;$i++) {
                $value_x = $margin_left + ($i + 1) * $x_div;
                if($i==11) {
                        imageline($im, $value_x, $x_line + 3, $value_x, $margin_top, $black);
                }else{
                        imageline($im, $value_x, $x_line, $value_x, $x_line + 3, $black);
                }
                $txtTip = isIconv($gdata[$i][0]);
                $txtBox = imagettfbbox(8, 0, $hfont, $txtTip);
                imagettftext($im, 8, 0, $value_x-$x_div/2-($txtBox[2]-$txtBox[0])/2, $x_line+19, $black, $hfont, $txtTip);
        }
        $title_x = isIconv("(최근 12개월)");
        $txtBox = imagettfbbox(8, 0, $hfont, $title_x);
        $xcord = ($img_w-$margin_left-$margin_right)/2 - ($txtBox[2]-$txtBox[0])/2 + $margin_left;
        $ycord = $x_line + 32;
        imagettftext($im, 8, 0, $xcord, $ycord, $black, $hfont, $title_x);
        imagestring($im, 1, $margin_left+1, $x_line+1, $init_y, $black);
        imagestring($im, 1, $img_w - $margin_right - 16, $x_line+1, $end_y, $black);

        //Y축 눈금(左) *************  DB자료에 따라 꺽은선그래프 눈금 최소, 최대값의 최적치를 구해 기록한다.
        for($i=0;$i<$ystep+1;$i++) {
                $txt_y = round($hmax-($i*(($hmax-$hmin)/$ystep)));
                if($txt_y >= 500) {
                        $txt_y = ceil($txt_y/100) * 100;
                }
                if(strlen($txt_y)>3) $txt_y = round($txt_y/1000,1)."K";
                $txtWidth = imagettfbbox(7, 0, $efont, $txt_y);
                $txtw = abs($txtWidth[2]-$txtWidth[0]);
                $txt_xcord = $margin_left - $txtw - 4;
                $txth = abs($txtWidth[5] - $txtWidth[3]);
                $txt_ycord = $margin_top + ($i * $y_height / $ystep) + $txth/2;
                $value_y = $margin_top + ($i * $y_height/$ystep);
                imageline($im, $margin_left - 3, $value_y, $margin_left, $value_y, $black);
                imageline($im, $margin_left + 1, $value_y, $img_w - $margin_right, $value_y, $gray);
                imagettftext($im, 7, 0, $txt_xcord, $txt_ycord, $red, $efont, $txt_y);
        }
        $title_y = isIconv("단위매출($)");
        $txtBox = imagettfbbox(9, 90, $hfont, $title_y);
        $xcord = abs($txtBox[2]-$txtBox[4])-2;
        $ycord = $y_height/2 + $margin_top + (abs($txtBox[3])-abs($txtBox[2]))/2;
        imagettftext($im, 9, 90, $xcord, $ycord, $red, $hfont, $title_y);

        //imagestring($im, 3, 0, 0, $hmax, $black);
        //imagestring($im, 3, 0, 15, $hmin, $black);

                //Y축눈금(右) *************  DB자료에 따라 막대그래프 눈금 최소, 최대값의 최적치를 구해 기록한다.
        for($i=0;$i<$ystep+1;$i++) {
                $txt_y = round($rmax-($i*(($rmax-$rmin)/$ystep)));
                if($txt_y >= 500) {
                        $txt_y = ceil($txt_y/100) * 100;
                }
                $txt_y = round($txt_y/1000)."K";
                $txtWidth = imagettfbbox(7, 0, $efont, $txt_y);
                $txtw = abs($txtWidth[2]-$txtWidth[0]);
                $rend = $margin_left + $x_div * 12;
                $txt_xcord =  $rend+7;
                $txth = abs($txtWidth[5] - $txtWidth[3]);
                $txt_ycord = $margin_top + ($i * $y_height / $ystep) + $txth/2;
                $value_y = $margin_top + ($i * $y_height/$ystep);
                imageline($im, $rend, $value_y, $rend + 3, $value_y, $black);
                imagettftext($im, 7, 0, $txt_xcord, $txt_ycord, $green, $efont, $txt_y);
        }
        $title_y = isIconv("총매출($)");
        $txtBox = imagettfbbox(9, 90, $hfont, $title_y);
        $xcord = $img_w-5;
        $ycord = $y_height/2 + $margin_top + (abs($txtBox[3])-abs($txtBox[2]))/2;
        imagettftext($im, 9, 90, $xcord, $ycord, $green, $hfont, $title_y);


        //막대그래프 그리고 그라데이션 넣기
        $div = ($rmax-$rmin)/$y_height;
        for($i=0;$i<12;$i++){
                $xcord = $margin_left + ($x_div-$bar_w)/2 + $i * $x_div;
                $ycord = $margin_top + round(($rmax - $gdata[$i][1])/$div);
                $xxcord = $margin_left + ($x_div-$bar_w)/2 +$bar_w + $i * $x_div;
                $yycord = $x_line;
                $bar_h = $x_line - $ycord + 1;
                //imagefilledrectangle($im, $xcord, $ycord, $xxcord, $yycord, $red1);
                $image = imagecreatefromgif("img/rad12.gif");
                imagecopyresized($im, $image, $xcord, $ycord, 0, 0, $bar_w, $bar_h, 200, 200);

                $sale = round($gdata[$i][1]);
                $txtBox = imagettfbbox(9, 90, $efonti, $sale);
                if(($txtBox[1]-$txtBox[3])>$bar_h) {
                        $ycord = $ycord - 5;
                        $bartxtColor = $green;
                }else{
                        $ycord = $ycord + ($txtBox[1]-$txtBox[3]);
                        $bartxtColor = $white;
                }
                $xcord = $xcord + $bar_w/2 + ($txtBox[0]-$txtBox[6])/2;
                imagettftext($im, 9, 90, $xcord, $ycord, $bartxtColor, $efonti, $sale);
                //imagettftext($im, 10, 0, 280, $margin_top + 15 + ($i *15), $red1, $efont, "y = ".$ycord);        // 임시
                //imagettftext($im, 7, 0, $margin_left + 40, $margin_top+$i*10, $red1, $efont, $bar_h);                // 임시
        }

        
        //꺽은선그래프 그리기
        $div = ($hmax-$hmin)/$y_height;
        for($i=0;$i<12;$i++){
                $ycord = $margin_top + round(($hmax - abs($hdata[$i][0]))/$div);
                $xcord = ($margin_left - $x_div/2) + ($i+1) * $x_div;
                $yycord = $margin_top + round(($hmax - abs($hdata[$i+1][0]))/$div);
                $xxcord = ($margin_left - $x_div/2) + ($i+2) * $x_div;
                if($i+1 <12) {
                        imageline($im, $xcord, $ycord, $xxcord, $yycord, $red);
                }
                imageFilledEllipse($im, $xcord, $ycord, 4, 4, $red);
                $sale = round($hdata[$i][0]);
                $txtBox = imagettfbbox(7, 0, $efont, $sale);
                $ycord = $ycord - ($txtBox[3] - $txtBox[5])/2;
                $xcord = $xcord - ($txtBox[2] - $txtBox[0])/2;
                imagettftext($im, 7, 0, $xcord, $ycord, $red, $efont, $sale);
                //imagettftext($im, 10, 0, 280, $margin_top + 15 + ($i *15), $red1, $efont, "y = ".$ycord);
        }


        /*  #################  디버깅 용으로 사용한 부분  ###############
        for($i=0;$i<12;$i++){
                imagettftext($im, 10, 0, 480, $margin_top + 15 + ($i *15), $red1, $efont, "y = ".$hdata[$i][0]);
        }*/

        //imagettftext($im, 10, 0, 480, 20, $blue, $efont, "Max = ".$max);
        //imagettftext($im, 10, 0, 480, 35, $blue, $efont, "Min = ".$min);



        //XY축 그리기
        imageline($im, $margin_left - 3, $x_line, $margin_left + $x_div * 12,$x_line, $black);
        imageline($im, $margin_left, $margin_top, $margin_left, $margin_top + $y_height + 3, $black);


} // if(!$prod_name) 끝

header("Content-type: image/png");                                        // 이미지 출력
imagepng($im);
imagedestroy($im);


function isIconv($str) {
        if(extension_loaded("iconv")){
                $str = iconv("EUC-KR","UTF-8", $str);
        }
        return $str;
}

function getMaxMin($gdata, $offset) {
        for($i=0;$i<count($gdata);$i++){
                if($max < $gdata[$i][$offset]) $max = $gdata[$i][$offset];
                if($i==0) {
                        $min = $gdata[$i][$offset];
                }else{
                        if($min > $gdata[$i][$offset]) $min = $gdata[$i][$offset];
                }
        }
        if($max>=5000){
                $max_div = 1000;
        }elseif($max>=500 && $max < 5000) {
                $max_div = 100;
        }else{
                $max_div = 10;
        }
        if($min < 100) {
                $min_div = 10;
        }elseif($min < 1000 && $min >= 100) {
                $min_div = 100;
        }elseif($min >= 1000) {
                $min_div = 1000;
        }

        $tmax = ceil($max/$max_div) * $max_div;
        $tmin = floor($min/$min_div) * $min_div;
        return array($tmax, $tmin);
}

 

관련자료

댓글 0
등록된 댓글이 없습니다.
Today's proverb
인생은 한 권의 책과 같다. 어리석은 이는 그것을 마구 넘겨 버리지만, 현명한 이는 열심히 읽는다. 인생은 단 한 번만 읽을 수 있다는 것을 알기 때문이다. (상 파울)