چارت خطی (نمودار) - بررسی تولید Class

siavashmusic

Active Member
در این آموزش علاوه بر اینکه روش ساخت یک جارت خطی رو یاد میگیرید همچنین جهت آشنایی جز به جز این کلاس رو بررسی میکنم

این اموزش یک روش سریع و حرفه ای هست بطوریکه اگه تا الان با کلاس ها و OOP کار نکردید و اشنایی ندارید توضیه میکنیم یه جستجویی داشته باشید اگه لازم شد یه مقاله در مورد OOP هم براتون میزارم

ملزومات :

نیازمند یک سرور باphp و کتابخانهgd

قسمت اول:

مقدار دهی اولیه کلاس جدید و تنظیمات متغیرها

ادیتور php خودتون رو بازکنید یک فایل جدید با نام line_chart.php ایجاد کنید
کدهای زیر رو در فایل موردنظرPast کنید

PHP:
class line_chart
{
//--------------------------------------------
// variables 
//--------------------------------------------
 
// The chart labels 
var $chart_title    = "Web Site Hits"; 
var $x_label	    = "Date"; 
var $y_label 	    = "Hits";
 
//The dimensions of your chart
var $chart_width     = 500;
var $chart_height    = 300;
 
//The perimeter of  your chart 
var $chart_perimeter = 50;
 
//The data that you want to be plotted 
var $data_array      = array();
 
//Your color array
var $color 			= array(); 
}//end of class


قسمت دوم : تنظیم متدها

چنانچه ازOOP بهره میگیرید این یک تمرین بسیاز خوب برای تنظیم متدها هست تا متعیرها رو تنظیم کنید ( با دانش بر اینکه شما این توانایی رو دارید )

کد زیر رو در فایل ساخته شده کپی کنید

PHP:
//--------------------------------------------
// set chart dimensions
// This function sets the dimensions of your chart. Right now they are set to default 500x300 but later
// you'll be able to use this function to change the dimensions to whatever you want. 
//--------------------------------------------
public function set_chart_dimensions($width, $height)
{
	$this->chart_width  = $width; 
	$this->chart_height = $height; 
}
//--------------------------------------------
// set chart perimeter
// This function sets the width of the perimeter, you can make the perimeter larger or smaller by passing
// a higher or lower integer. 
//--------------------------------------------
public function set_chart_perimeter($perimeter)
{
	$this->perimeter = $perimeter; 
}
//--------------------------------------------
// set labels
// This function sets the labels for your graph. You can also remove your labels by setting each value to an
// empty string ( "" ) 
//--------------------------------------------
public function set_labels($title, $xLabel, $yLabel)
{
	$this->graphTitle = $title; 
	$this->xLabel     = $xLabel; 
	$this->yLabel     = $yLabel; 
}
//--------------------------------------------
// add line
// This function passes an array of information to your data_array. This data will be plotted 
// note that I'm using brackets [], this will let me have multiple lines on a graph. (great for making comparisons) 
//--------------------------------------------	
{
	$this->data_array[] = $new_data; 
}


کلیه مراحل با موفقیت انجام شد حال نوبت به برنامه نویسی میرسه کد زیر رو درون کلاس Past میکنیم

PHP:
//--------------------------------------------
// prepare canvas
//--------------------------------------------	
private function prepare_canvas()
{
	//this->chart is the variable that will store your image. It is the canvas for all of your work. 
	$this->chart = imagecreatetruecolor($this->chart_width, $this->chart_height); 
 
 
 
	//By default the canvas only comes with one color. . black (which really isn't a color at all, it's the absence of color :P) anyway
	//it would be memory intensive for php to automatically allocate every color into memory (as there are millions of colors) 
	//so we must do each manually. 
 
	$this->color['white']     = imagecolorallocate($this->chart, 255, 255, 255); 
	$this->color['black']     = imagecolorallocate($this->chart, 0,0,0); 
	$this->color['yellow']    = imagecolorallocate($this->chart, 248, 255, 190);
	$this->color['blue']      = imagecolorallocate($this->chart, 3,12,94); 
	$this->color['gray']      = imagecolorallocate($this->chart, 102, 102, 102); 
	$this->color['lightGray'] = imagecolorallocate($this->chart, 216, 216, 216); 
 
 
	//later when we want to adjust the position of our fonts we'll need to know the width and height. 
	//I'm setting my font size to 2. 
	$this->font_width  = imagefontwidth(2);
	$this->font_height = imagefontheight(2); 
 
	//This function as you might expect, fills the canvas with a color. In this case, I'm filling it with light gray 
	imagefill($this->chart, 0,0, $this->color['lightGray']); 
}

در این مرحله میبایست بیشترین و کمترین مقدار Y-Axis رو پیدا کنیم برای اینکار بیشترین و کمترین مقدار در Array بصورت 608 و 108 درنظر گرفتیم که در این روش خط کناری سمت راست زیاد متناسب نمیشد

001.jpg

جهت بهبود این مورد یک buffer ساختیم

کد زیر رو در قسمت زیر فانکشن قبلی قرار بدید
PHP:
//--------------------------------------------
// get min and max y values 
//--------------------------------------------	
private function calculate_min_and_max_y_values()
{
 
//because we might have multiple lines of data (multiple arrays), 
//we'll need to search through all of them in order to find the 
//highest and lowest value. 
 
for($i=0; $i<count($this->data_array); $i++)
{
	$current_line = $this->data_array[$i];
	if( min($current_line)>$y_min ) $y_min = min($current_line);
	if( max($current_line)>$y_max ) $y_max = max($current_line);  
}
 
//min
$places   = strlen($y_min);				//string length of minimum value. 		  		  so strlen(1) = 1;
$mod      = pow(10, $places-1); 	    //raising that number minus 1 to the power of 10. so pow(10, 0) = 1;
$y_min    = $mod - $y_min; 				//subtracting that from the minimum. 			  so 1 - 1 = 0; <-your y-axis minimum 
 
 
//We can't have negative hits so if $y_min is less than 0 we 
//just set that to 0. 
if($y_min<0) $y_min = 0; 
 
//max
$places = strlen($y_max);
$mod    = pow(10, $places-1);	
$y_max 	= $mod + $y_max;
 
 
//Saving this mod value to a class variable 
//(it will be useful later) 
$this->mod = $mod; 
 
 
//Saving the $y_min and $y_max values so that they can be 
//accessed by a different method in the class.
 
$this->y_axis_values['min'] = $y_min; 
$this->y_axis_values['max'] = $y_max; 
}

سخترین مرحله این اموزش همینجاست حالا میبایست شبکه های چارت رو ایجاد کنیم
اعمال پیرامون درنظر به اینکه یک buffer مابین لبه خط شبکه شما قرار میگیرد پیرامون مکانی است که برچسب های چارت رو اونجا قرار میدید

002.jpg

فانکشن زیر رو رو کپی کنید و ادامه فایل موردنظر Past کنید

PHP:
private function prepare_grid()
{
 
	//The grid width. We don't want the grid to be the same size as the chart otherwise the entire
	//document will be just one grid with no place for labels. Therefore, subtract the perimeter width from all sides. 
	$gridWidth  = $this->chart_width  - ($this->chart_perimeter*2); 
	$gridHeight = $this->chart_height - ($this->chart_perimeter*2); 
 
	//I prefer to work with coordinates, it makes it easy to visualize the process. If you observe below you'll see
	//That I've made four corners. 
	$this->c1 = array("x"=>$this->chart_perimeter,             "y"=>$this->chart_perimeter); 
	$this->c2 = array("x"=>$this->chart_perimeter+$gridWidth,  "y"=>$this->chart_perimeter); 
	$this->c3 = array("x"=>$this->chart_perimeter+$gridWidth,  "y"=>$this->chart_perimeter+$gridHeight); 
	$this->c4 = array("x"=>$this->chart_perimeter,             "y"=>$this->chart_perimeter+$gridHeight);

003.jpg
در مرحله بعد کد زیر رو در ادامه فانکشن قبلی قرار بدید

PHP:
//now that I've made the grid coordinates its time to connect the dots and create a grid plane. 
//In this function I'm creating a solid white rectangle 
imagefilledrectangle($this->chart, $this->c1['x'], $this->c1['y'], $this->c3['x'], $this->c3['y'], $this->color['white']);

004.jpg

مجددا . . .

PHP:
//getting the biggest array 
//now I need to find the highest x-value but unlike the y-value that I found earlier, I'm not trying to find
//the highest data value but rather the highest count value. 
//To put it simply, which array has the most entries? 
 
$biggest_array = array(); 
for($i=0; $i<count($this->data_array); $i++)
{
	if(count($biggest_array) < count($this->data_array[$i])) $biggest_array = $this->data_array[$i];

جهت توسعه شبکه نیازمند این هستیم تا طول و عرض یک شبکه واخد رو براساس پسکسل پیدا کنیم

PHP:
$this->square['w'] = $gridWidth/count($biggest_array);
$this->square['h'] = $gridHeight/$this->y_axis_values['max'];

005.jpg

همچنین میتونیم یک فاصه یا لفافه میان خط اول و گوشه چپ نمودار درست کنیم در غیر این صورت چارت زیاد بزرگ و متناسب به نظر نمیرسه

006.jpg


PHP:
$this->vertical_padding = $this->square['w']/2;

مجددا . . ..

PHP:
//------------------------------------------------ 
//drawing the vertical lines and axis labels
//------------------------------------------------
foreach($biggest_array as $assoc=>$value)
{	
	//drawing the line
	imageline($this->chart,  $this->vertical_padding+$this->c4['x']+$increment,   $this->c4['y'], $this->vertical_padding+$this->c1['x']+$increment, $this->c1['y'], $this->color['black']);
 
	//axis values
	//finding the width of the word so that we can accuratly position it
	$wordWidth = strlen($assoc)*$this->font_width; 
 
	//the x-position of the line, this will be incremented on every loop
	$xPos = $this->c4['x']+$increment+$this->vertical_padding-($wordWidth/2); 
 
	//creating the axis value label
	ImageString($this->chart, 2, $xPos, $this->c4['y'], $assoc, $this->color['black']);
 
 
	$increment += $this->square['w'];
}

007.jpg

در این مرحله میبایست خطوط horizontal جهت اتمام شبکه ایجاد کنیم
لطفا کد زیر رو . . .

PHP:
//------------------------------------------------ 
//drawing the horizontel lines and axis labels
//------------------------------------------------
//resetting the increment back to 0
$increment = 0; 
for($i=$this->y_axis_values['min']; $i<$this->y_axis_values['max']; $i++)
{
	//main lines	
	//often the y-values can be in the thousands, if this is the case then we don't want to draw every single
	//line so we need to make sure that a line is only drawn every 50 or 100 units.  
	if($i%$this->mod==0){
		//drawing the line
		imageline($this->chart, $this->c4['x'], $this->c4['y']+$increment, $this->c3['x'], $this->c3['y']+$increment, $this->color['grey']);
 
		//axis values
		$xPos = $this->c1['x']-($this->font_width*strlen($i))-5; 
		ImageString($this->chart, 2, $xPos, $this->c4['y']+$increment-($this->font_height/2), $i, $this->color['black']);
 
	}
	//tics
	//these are the smaller lines between the longer, main lines. 
	elseif(($this->mod/5)>1 && $i%($this->mod/5)==0)
	{
		imageline($this->chart, $this->c4['x'], $this->c4['y']+$increment, $this->c4['x']+10, $this->c4['y']+$increment, $this->color['grey']);
	}
	$increment-=$this->square['h'];
}
 
//------------------------------------------------ 
//creating the left line
//------------------------------------------------
imageline($this->chart, $this->c1['x'], $this->c1['y'], $this->c4['x'], $this->c4['y'], $this->color['black']); 
 
}

008.jpg

جهت بهتر شدن نمودار در سمت چپ یک خط رسم کنید میتونید در عکس مشاهده کنید

009.jpg

هر نموداری نیازمند تعدادی برچسب هست :

PHP:
private function draw_chart_labels()
{
	//------------------------------------------------
	// Making the chart labels 
	//------------------------------------------------
 
	//Graph Title
	ImageString(
	$this->chart, 2, 
	($this->chart_width/2)-(strlen($this->chart_title)*$this->font_width)/2, $this->c1['y']-($this->chart_perimeter/2), 
	$this->chart_title,  
	$this->color['green']); 
 
	//X-Axis
	ImageString(
	$this->chart, 2, 
	($this->chart_width/2)-(strlen($this->x_label)*$this->font_width)/2,  $this->c4['y']+($this->chart_perimeter/2), 
	$this->x_label, 
	$this->color['green']); 
 
	//Y-Axis
	ImageStringUp(
	$this->chart, 2, 
	$this->c1['x']-$this->font_height*3, $this->chart_height/2+(strlen($this->y_label)*$this->font_width)/2, 
	$this->y_label, 
	$this->color['green']); 
}

در قسمت زیر نمودار همراه با چند برچپ قابل مشاهده هست
010.jpg
در بهترین قسمت این آموزش میرسم به رسم خطوط بر روی نمودار

PHP:
//--------------------------------------------
// plot lines
//--------------------------------------------	
private function plot_lines()
{
//------------------------------------------------
// Making chart lines
//------------------------------------------------
$increment = 0; 		//resetting the increment value
 
//looping through each array of data 
//(in this case there is only one set of data
//but later you'll be able to add more) 
for($i=0; $i<count($this->data_array); $i++)
{
 
	$line = $this->data_array[$i]; 
	//getting the first value 
	$firstVal = end(array_reverse($line)); 
 
	$increment = 0; 
	//getting the first point for your line
	$point1 = array($this->c4['x']+$increment+$this->vertical_padding,$this->c4['y']-($firstVal*$this->square['h'])); 
 
	//looping through your current array of data
	foreach($line as $assoc=>$value)
	{
		//getting the second point for your line
		$yPos 	= $this->c4['y']-($value*$this->square['h']);
		$xPos 	= $this->c4['x']+$increment+$this->vertical_padding; 
		$point2 = array($xPos, $yPos); 
 
		//drawing your line
		imageline($this->chart, $point1[0], $point1[1], $point2[0], $point2[1], $this->color['blue']);
 
		//point1 becomes point2 
		$point1 = $point2; 
 
		//increment to the next x position 
		$increment += $this->square['w']; 
	}
}

ثبت فانکشن خروجی :

PHP:
//--------------------------------------------
// output 
//--------------------------------------------	
private function output()
{
//sets the type of output (in this case a jpg image) 
header("content-type: image/jpg"); 
imagejpeg($this->chart); 
 
//after output it removes the image from the buffer to free up memory
imagedestroy($this->chart); 
}

فانکشن خطوط نمودار:

کافیست کد زیر را در فایل مربوطه کپی کنید

PHP:
//--------------------------------------------
// plot
//--------------------------------------------	
public function plot()
{
	$this->prepare_canvas(); 
	$this->calculate_min_and_max_y_values(); 
	$this->prepare_grid();
	$this->plot_lines(); 
	$this->draw_chart_labels(); 
	$this->output(); 
}

این کلاس بطوری نوشته شده که کاملا قابل میرایش هست فقط کافیه از php سر رشته داشته باشید براحتی میتونید تغییرات خودتون رو اعمال کنید
در کلیه فانکشن ها کامنت های کاملی گذاشته شده میتونید از اونها جهت توسعه این کلاس بهره ببرید

در مرحله آخر کافیست کد زیر رو در ادامه کلاس مربوطه Past کنید


PHP:
//Your Chart Data (this is what will be plotted) 
$data['May 10'] = 108;
$data['May 11'] = 419; 
$data['May 12'] = 305; 
$data['May 13'] = 433; 
$data['May 14'] = 608; 
$data['May 15'] = 702; 
$data['May 16'] = 498;
$data['May 17'] = 500;
$data['May 18'] = 208;
 
//creates a new instance of your line_chart class
$myChart = new line_chart; 
 
 
//set the dimensions of your chart
$myChart->set_chart_dimensions(500,300); 
 
//set the perimeter of your chart
$myChart->set_chart_perimeter(50); 
 
//set the different chart labels
$myChart->set_labels("My Title", "My X-Label", "My Y-Label");
 
//this references your add_line function and sets your data 
$myChart->add_line($data);
 
//outputs your chart;  
$myChart->plot();

خوب حالا میتونید نتیجه کار رو در عکس زیر مشاهده کنید

011.jpg

012.jpg
توسط 6 خط کد تونستید یک نمودار خوب تولید کنید در صورتی که تمایل دارید میتونید این خطوط رو کاهش بدید کافیست set_chart_dimensionsو set_labels و set_chart_perimeter
فانکشن رو حذف کنید

امیدوارم مفید باشه
سیاوش عقیلی
siavash aghili
 

RainDigital

Member
php که انقدر قدرت داره چرا نشه چارت هایی به قشنگی سرویس های ASP,Net مثل وب گذر تولید کنه؟
 

siavashmusic

Active Member
سلام

باید عرض کنم که اینجا مسله آموزش کلاس نویسی هست ! در مورد زیبایی شناسی باید بعدا صحبت کرد مسلما قدرت در نمایش و امکانات رکن اصلی یک نمودار حرفه ای هست ظاهر در مرحله اخر قرار داره
 

RainDigital

Member
میگم بهتر نیست این تاپیکو منتقل کنید به انجمن های جدید،

واقعا از این اسکریپت به این باحالی چقدر استقبال شد.متاسفم

همه دنبال لقمه آمادن تا آموزش این که چطوری لقمه رو درست کنن.
 

siavashmusic

Active Member
بله متاسفانه حق با شماست
متاسفانه انجمن php خیلی سطح پایینی پیدا کرده دارم یه راه کار برای این موضوع پیدا میکنم
حدودا 70 درصد کاربران این بخش قوانین رو نقض میکنند 60 درصد سوالات رو بدون جستجو تاپیک میزنند 50 درصد هم تاپیک به امان خدا باز میکنند یعنی طرف اصلا اصل سوال خودش رو درک نکرده اما . . .؟! یا طرف php رو فقط در حد برداشتن کپی رایت از بالای فایل ها یادگرفته میاد توی یه تاپیک میخواد ابراز وجود کنه کل یه سوال رو بهم میزنه

الان برخی از کاربران این قبیلی رو دارم شناسایی میکنم انشالله یه روش مشتی براشون دارم تا زحمات چند ساله یه گروه به راحتی یه ENTER از بین نره

فقط کافیه یه نگاه به نتایج جستجو توی این بخش بندازی اون وقت می فهمی من چی میگم
 

RainDigital

Member
دو تا مشکل دارم. php به کلمه private ایراد میگیره چی کار کنم؟حذفشون کنم کافیه؟؟

یه قسمت از اسکریپت رو اصلا نه توصیحشو فهمیدم نه تونستم کپی کنم. میشه کل اسکریپت رو پیوست کنید؟
 

irdavidnet

Banned
اگه میشه پیوست کنید ، اینطوری من هم نفهمیدم ، اما در جواب RAIN DIGITAL باید بگم ، توی ادیتور من به privet ایراد نمی گیره ، فکر کنم privet برای مخفی کردن فانکشن یا کلاس به کار بره . درسته ؟
 

alireza82

Well-Known Member
دو تا مشکل دارم. php به کلمه private ایراد میگیره چی کار کنم؟حذفشون کنم کافیه؟؟

یه قسمت از اسکریپت رو اصلا نه توصیحشو فهمیدم نه تونستم کپی کنم. میشه کل اسکریپت رو پیوست کنید؟

نسخه php ایت چنده؟
 

amirepsilon

Active Member
سلام
هیلی عالیه
ولی دوستان باید مد نظر داشته باشند ثدرت php به پای .net نمیرسه !
یا علی
 

my friend

Member
سلام
هیلی عالیه
ولی دوستان باید مد نظر داشته باشند ثدرت php به پای .net نمیرسه !
یا علی
به عنوان یک هوادار تعصبی و سرسخت PHP ،
مخالفم!

من تا حالا نشده به فکر چیزی بیفتم که با php نتونم انجامش بدم...(اگرهم انجامش نداده باشم ، حداقل تو ذهنم الگوریتمش رو مرور کردم و به یه نتیجه رسیدم.)
اگه کمی سعی کنید چارت های زیباتر از چارت های وبگذر هم میتونید با php بسازید...
 
آخرین ویرایش:

جدیدترین ارسال ها

بالا