Trunk updated to 0.9 git-svn-id: http://kusabax.cultnet.net/svn/repo/stable@176 73d99b7e-4f53-4972-b7b7-2ecd3c4d89ee
1268 lines
42 KiB
PHP
1268 lines
42 KiB
PHP
<?php
|
|
///////////////////////////////////////////////////////////
|
|
//PHPGraphLib - PHP Graphing Library v2.02
|
|
//Author: Elliott Brueggeman
|
|
//PHP v4.04 + compatible
|
|
//Please visit www.ebrueggeman.com for usage policy
|
|
//and full documentation + examples
|
|
///////////////////////////////////////////////////////////
|
|
class PHPGraphLib
|
|
{
|
|
//---------------USER CHANGEABLE DEFAULTS----------------/
|
|
var $height=300;
|
|
var $width=400;
|
|
var $data_max_allowable=9999999999999999;
|
|
var $data_min_allowable=-9999999999999999;
|
|
var $data_set_count=0;
|
|
//SET TO ACTUAL FONT HEIGHTS AND WIDTHS USED
|
|
var $title_char_width=6;
|
|
var $title_char_height=12;
|
|
var $text_width=6;
|
|
var $text_height=12;
|
|
var $data_value_text_width=6;
|
|
var $data_value_text_height=12;
|
|
//PADDING BETWEEN AXIS AND VALUE DISPLAYED
|
|
var $axis_value_padding=5;
|
|
//SPACE B/T TOP OF BAR OR CENTER OF POINT AND DATA VALUE
|
|
var $data_value_padding=5;
|
|
//DEFAULT MARGIN % OF WIDTH / HEIGHT
|
|
var $x_axis_default_percent=12;
|
|
var $y_axis_default_percent=8;
|
|
//DATA POINT DIAMETER IN PX
|
|
var $data_point_width=6;
|
|
//USER CHANGEABLE DEFAULT BOOLEANS (SHOW ELEMENT BY DEFAULT?)
|
|
var $bool_bar_outline=true;
|
|
var $bool_x_axis=true;
|
|
var $bool_y_axis=true;
|
|
var $bool_x_axis_values=true;
|
|
var $bool_y_axis_values=true;
|
|
var $bool_grid=true;
|
|
var $bool_line=false;
|
|
var $bool_data_values=false;
|
|
var $bool_x_axis_values_vert=true;
|
|
var $bool_data_points=false;
|
|
var $bool_title_left=false;
|
|
var $bool_title_right=false;
|
|
var $bool_title_center=true;
|
|
//----------INTERNAL VARIABLES (DO NOT CHANGE)------------/
|
|
var $image;
|
|
var $error;
|
|
var $bool_x_axis_setup=false;
|
|
var $bool_y_axis_setup=false;
|
|
var $bool_data=false;
|
|
var $bool_bars_generate=true;
|
|
var $bool_bars=true;
|
|
var $bool_background=false;
|
|
var $bool_title=false;
|
|
var $bool_all_negative=false;
|
|
var $bool_all_positive=false;
|
|
var $bool_gradient=false;
|
|
var $bool_user_data_range=false;
|
|
var $bool_gradient_colors_found;//INIT AS ARRAY
|
|
//COLOR VARS
|
|
var $background_color;
|
|
var $grid_color;
|
|
var $bar_color;
|
|
var $outline_color;
|
|
var $x_axis_text_color;
|
|
var $y_axis_text_color;
|
|
var $title_color;
|
|
var $x_axis_color;
|
|
var $y_axis_color;
|
|
var $data_point_color;
|
|
var $data_value_color;
|
|
var $line_color;
|
|
var $line_color_default;
|
|
var $goal_line_color;
|
|
//GRADIENT COLORS STORED AS ARRAYS, NOT ALLOCATED COLOR
|
|
var $gradient_color_1;
|
|
var $gradient_color_2;
|
|
var $gradient_color_array;
|
|
var $gradient_max=200;
|
|
var $gradient_handicap;
|
|
//DATA VARS
|
|
var $data_array;
|
|
var $data_count;
|
|
var $data_min;
|
|
var $data_max;
|
|
//BAR VARS / SCALE
|
|
var $bar_spaces;
|
|
var $bar_width;
|
|
var $space_width;
|
|
var $unit_scale;
|
|
var $goal_line_array;
|
|
//TEXT / FONT
|
|
var $title_x;
|
|
var $title_y;
|
|
//AXIS POINTS
|
|
var $x_axis_x1;
|
|
var $x_axis_y1;
|
|
var $x_axis_x2;
|
|
var $x_axis_y2;
|
|
var $y_axis_x1;
|
|
var $y_axis_y1;
|
|
var $y_axis_x2;
|
|
var $y_axis_y2;
|
|
var $x_axis_margin; //AKA BOTTOM MARGIN
|
|
var $y_axis_margin; //AKA LEFT MARGIN
|
|
var $data_range_max;
|
|
var $data_range_min;
|
|
var $top_margin=0;
|
|
var $right_margin=0;
|
|
var $range_divisor_factor=25; //CONTROLS AUTO-ADJUSTING GRID INTERVAL
|
|
var $data_point_array;
|
|
//MULTIPLE DATASET VARIABLES
|
|
var $bool_multi_offset=true;
|
|
var $multi_offset_two=24; //PERCENT OF BAR WIDTH
|
|
var $multi_offset_three=15; //PERCENT OF BAR WIDTH
|
|
var $multi_gradient_colors_1;
|
|
var $multi_gradient_colors_2;
|
|
var $multi_bar_colors;
|
|
var $color_darken_factor=30 ;//PERCENT DECREASE
|
|
//LEGEND VARIABLES
|
|
var $bool_legend=false;
|
|
var $legend_text_width=6; //IN PX...
|
|
var $legend_max_chars=15;
|
|
var $legend_total_chars;
|
|
var $legend_text_height=12;
|
|
var $legend_padding=4; //PADDING INSIDE LEGEND BOX
|
|
var $legend_width;
|
|
var $legend_height;
|
|
var $legend_x;
|
|
var $legend_y;
|
|
var $legend_text_color;
|
|
var $legend_outline_color;
|
|
var $legend_swatch_outline_color;
|
|
var $legend_color;
|
|
var $legend_titles=array();
|
|
//--------------------"PUBLIC" CONSTRUCTOR----------------------//
|
|
function PHPGraphLib($width='', $height='')
|
|
{
|
|
if(!empty($width)&&!empty($height))
|
|
{
|
|
$this->width=$width;
|
|
$this->height=$height;
|
|
}
|
|
$this->initialize();
|
|
$this->allocateColors(); //SETS DEFAULT COLORS
|
|
}
|
|
//----------------"PRIVATE" MAIN PROGRAM FUNCTIONS ----------------//
|
|
function initialize()
|
|
{
|
|
//HEADER MUST BE SENT BEFORE ANY HTML OR BLANK SPACE OUTPUT
|
|
header("Content-type: image/png");
|
|
$this->image = @imagecreate($this->width, $this->height)
|
|
or die("Cannot Initialize new GD image stream - Check your PHP setup");
|
|
$this->data_point_array=array();
|
|
$this->goal_line_array=array();
|
|
$this->multi_bar_colors=array();
|
|
$this->multi_gradient_colors_1=array();
|
|
$this->multi_gradient_colors_2=array();
|
|
//THESE VALUES ARE NOW ARRAYS
|
|
$this->gradient_handicap=array();
|
|
$this->bool_gradient_colors_found=array();
|
|
$this->legend_total_chars=array();
|
|
$this->line_color=array();
|
|
}
|
|
function createGraph() //MAIN CLASS METHOD - CALLED LAST
|
|
{
|
|
//SETUP AXIS IF NOT ALREADY SETUP BY USER
|
|
if($this->bool_data){
|
|
if(!$this->bool_x_axis_setup){ $this->setupXAxis(); }
|
|
if(!$this->bool_y_axis_setup){ $this->setupYAxis(); }
|
|
//CALCULATIONS
|
|
$this->calcTopMargin();
|
|
$this->calcRightMargin();
|
|
$this->calcCoords();
|
|
$this->setupData();
|
|
//START CREATING ACTUAL IMAGE ELEMENTS
|
|
if($this->bool_background){ $this->generateBackgound(); }
|
|
//ALWAYS GEN GRID VALUES, EVEN IF NOT DISPLAYED
|
|
$this->generateGrid();
|
|
if($this->bool_bars_generate){$this->generateBars(); }
|
|
if($this->bool_data_points){$this->generateDataPoints(); }
|
|
if($this->bool_legend){ $this->generateLegend(); }
|
|
if($this->bool_title) { $this->generateTitle(); }
|
|
if($this->bool_x_axis){ $this->generateXAxis(); }
|
|
if($this->bool_y_axis){ $this->generateYAxis(); }
|
|
}
|
|
else
|
|
{
|
|
$this->error[]="No valid data added to graph. Add data with the addData() function.";
|
|
}
|
|
//DISPLAY ERRORS
|
|
$this->displayErrors();
|
|
//OUTPUT TO BROWSER
|
|
imagepng($this->image);
|
|
imagedestroy($this->image);
|
|
}
|
|
function setupData()
|
|
{
|
|
$this->bar_spaces=($this->data_count*2)+1;
|
|
$unit_width=($this->width-$this->y_axis_margin-$this->right_margin)/(($this->data_count*2)+($this->data_count));
|
|
if($unit_width<1)
|
|
{
|
|
//ERROR UNITS TOO SMALL, TOO MANY DATA POINTS OR NOT LARGE ENOUGH GRAPH
|
|
$this->bool_bars_generate=false;
|
|
$this->error[]="Graph too small or too many data points.";
|
|
}
|
|
else
|
|
{
|
|
//DEFAULT SPACE BETWEEN BARS IS 1/2 THE WIDTH OF THE BAR
|
|
//FIND BAR AND SPACE WIDTHS. BAR = 2 UNITS, SPACE = 1 UNIT
|
|
$this->bar_width=2*$unit_width;
|
|
$this->space_width=$unit_width;
|
|
//NOW CALCULATE HEIGHT (SCALE) UNITS
|
|
$availVertSpace=$this->height-$this->x_axis_margin-$this->top_margin;
|
|
if($availVertSpace<1)
|
|
{
|
|
$this->bool_bars_generate=false;
|
|
$this->error[]="Graph height not tall enough.";
|
|
//ERROR SCALE UNITS TOO SMALL, X AXIS MARGIN TOO BIG OR GRAPH HEIGHT NOT TALL ENOUGH
|
|
}
|
|
else
|
|
{
|
|
if($this->bool_user_data_range)
|
|
{
|
|
if(($this->data_range_max<$this->data_max)||($this->data_range_min>$this->data_min))
|
|
{
|
|
$this->error[]="Data not usable with setRange() function. All data must be within range!";
|
|
}
|
|
if($this->data_min<0)
|
|
{
|
|
$this->error[]="Data not usable with setRange() function. All data must be >= 0.";
|
|
}
|
|
else
|
|
{
|
|
$graphTopScale=$this->data_range_max;
|
|
$graphBottomScale=$this->data_range_min;
|
|
$graphScaleRange=$graphTopScale-$graphBottomScale;
|
|
$this->unit_scale=$availVertSpace/$graphScaleRange;
|
|
$this->data_max=$this->data_range_max;
|
|
$this->data_min=$this->data_range_min;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//START AT Y VALUE 0 OR DATA MIN, WHICHEVER IS LESS
|
|
$graphBottomScale=($this->data_min<0) ? $this->data_min : 0;
|
|
$graphTopScale=($this->data_max<0) ? 0 : $this->data_max;
|
|
$graphScaleRange=$graphTopScale-$graphBottomScale;
|
|
$this->unit_scale=$availVertSpace/$graphScaleRange;
|
|
//NOW ADJUST X AXIS IN Y VALUE IF NEGATIVE VALUES
|
|
if($this->data_min<0)
|
|
{
|
|
$this->x_axis_y1-=(int)($this->unit_scale*abs($this->data_min));
|
|
$this->x_axis_y2-=(int)($this->unit_scale*abs($this->data_min));
|
|
}
|
|
}
|
|
$this->bool_bars_generate=true;
|
|
}
|
|
}
|
|
}
|
|
function generateBars()
|
|
{
|
|
$this->finalizeColors();
|
|
$barCount=0;
|
|
$adjustment=0;
|
|
if($this->bool_user_data_range)
|
|
{
|
|
$adjustment=$this->data_min*$this->unit_scale;
|
|
}
|
|
//REVERSE ARRAY TO ORDER DATA SETS IN ORDER OF PRIORITY
|
|
$this->data_array=array_reverse($this->data_array);
|
|
$dataset_offset=0;
|
|
if($this->bool_multi_offset)
|
|
{
|
|
//SET DIFFERENT OFFSETS BASED ON NUMBER OF DATA SETS
|
|
$dataset_offset=($this->data_set_count>2) ?
|
|
$this->bar_width*($this->multi_offset_three/100) : $this->bar_width*($this->multi_offset_two/100);
|
|
}
|
|
foreach($this->data_array as $data_set_num => $data_set)
|
|
{
|
|
$lineX2=NULL;
|
|
$xStart=$this->y_axis_x1+$this->space_width/2;
|
|
foreach($data_set as $key => $item)
|
|
{
|
|
$x1=(int)$xStart+($dataset_offset*$data_set_num);
|
|
$x2=(int)($xStart+$this->bar_width)+($dataset_offset*$data_set_num);
|
|
$y1=(int)($this->x_axis_y1-($item*$this->unit_scale)+$adjustment);
|
|
$y2=(int)$this->x_axis_y1;
|
|
|
|
//DRAW BAR
|
|
if($this->bool_bars)
|
|
{
|
|
if($this->bool_gradient)
|
|
{
|
|
//DRAW GRADIENT IF DESIRED
|
|
$this->drawGradientBar($x1, $y1, $x2, $y2, $this->multi_gradient_colors_1[$data_set_num], $this->multi_gradient_colors_2[$data_set_num], $data_set_num);
|
|
}
|
|
else
|
|
{
|
|
//IF/ELSE NECESSARY B/C OF BUG IN ARG ORDER OF imagefilledrectangle() FUNCTION
|
|
if($y1<$y2){ imagefilledrectangle($this->image, $x1, $y1,$x2, $y2, $this->multi_bar_colors[$data_set_num]); }
|
|
else{ imagefilledrectangle($this->image, $x1, $y2,$x2, $y1, $this->multi_bar_colors[$data_set_num]); }
|
|
}
|
|
//DRAW BAR OUTLINE
|
|
if($this->bool_bar_outline)
|
|
{
|
|
imagerectangle($this->image, $x1, $y2, $x2, $y1, $this->outline_color);
|
|
}
|
|
}
|
|
// DRAW LINE
|
|
if($this->bool_line)
|
|
{
|
|
$lineX1=$x1+($this->bar_width)/2;
|
|
$lineY1=$y1;
|
|
if(isset($lineX2))
|
|
{
|
|
imageline($this->image, $lineX2, $lineY2, $lineX1, $lineY1, $this->line_color[$data_set_num]);
|
|
$lineX2=$lineX1;
|
|
$lineY2=$lineY1;
|
|
}
|
|
else
|
|
{
|
|
$lineX2=$lineX1;
|
|
$lineY2=$lineY1;
|
|
}
|
|
}
|
|
// DISPLAY DATA POINTS
|
|
if($this->bool_data_points)
|
|
{
|
|
//DONT DRAW DATAPOINTS HERE OR WILL OVERLAP POORLY WITH LINE
|
|
//INSTEAD COLLECT COORDINATES
|
|
$pointX=$x1+($this->bar_width)/2;
|
|
$this->data_point_array[]=array($pointX, $y1);
|
|
}
|
|
// DISPLAY DATA VALUES
|
|
if($this->bool_data_values)
|
|
{
|
|
$dataX=($x1+($this->bar_width)/2)-((strlen($item)*$this->data_value_text_width)/2);
|
|
$dataY=($item>=0) ? $y1-$this->data_value_padding-$this->data_value_text_height : $y1+$this->data_value_padding;
|
|
imagestring($this->image, 2, $dataX, $dataY, $item, $this->data_value_color);
|
|
}
|
|
|
|
//WRITE X AXIS VALUE
|
|
if($this->bool_x_axis_values)
|
|
{
|
|
if($data_set_num==$this->data_set_count-1)
|
|
{
|
|
if($this->bool_x_axis_values_vert)
|
|
{
|
|
if($this->bool_all_negative)
|
|
{
|
|
//WE MUST PUT VALUES ABOVE 0 LINE
|
|
$textVertPos=(int)($this->y_axis_y2-$this->axis_value_padding);
|
|
}
|
|
else
|
|
{
|
|
//MIX OF BOTH POS AND NEG NUMBERS
|
|
//WRITE VALUE Y AXIS BOTTOM VALUE (WILL BE UNDER BOTTOM OF GRID EVEN IF X AXIS IS FLOATING DUE TO
|
|
$textVertPos=(int)($this->y_axis_y1+strlen($key)*$this->text_width+$this->axis_value_padding);
|
|
}
|
|
$textHorizPos=(int)($xStart+($this->bar_width/2)-($this->text_height/2));
|
|
imagestringup($this->image, 2, $textHorizPos, $textVertPos, $key, $this->x_axis_text_color);
|
|
}
|
|
else
|
|
{
|
|
if($this->bool_all_negative)
|
|
{
|
|
//WE MUST PUT VALUES ABOVE 0 LINE
|
|
$textVertPos=(int)($this->y_axis_y2-$this->text_height-$this->axis_value_padding);
|
|
}
|
|
else
|
|
{
|
|
//MIX OF BOTH POS AND NEG NUMBERS
|
|
//WRITE VALUE Y AXIS BOTTOM VALUE (WILL BE UNDER BOTTOM OF GRID EVEN IF X AXIS IS FLOATING DUE TO
|
|
$textVertPos=(int)($this->y_axis_y1+($this->text_height*2/3)-$this->axis_value_padding);
|
|
}
|
|
//HORIZONTAL DATA KEYS
|
|
$textHorizPos=(int)($xStart+($this->bar_width/2)-((strlen($key)*$this->text_width)/2));
|
|
imagestring($this->image, 2, $textHorizPos, $textVertPos, $key, $this->x_axis_text_color);
|
|
}
|
|
}
|
|
}
|
|
$xStart+=$this->bar_width+$this->space_width;
|
|
}
|
|
}
|
|
}
|
|
function finalizeColors()
|
|
{
|
|
if($this->bool_gradient)
|
|
{
|
|
$num_set=count($this->multi_gradient_colors_1);
|
|
//LOOP THROUGH SET COLORS AND ADD BACKING COLORS IF NECESSARY
|
|
if($num_set!=$this->data_set_count)
|
|
{
|
|
$color_darken_decimal=(100-$this->color_darken_factor)/100;
|
|
while($num_set<$this->data_set_count)
|
|
{
|
|
$color_ref_1=$this->multi_gradient_colors_1[$num_set-1];
|
|
$color_ref_2=$this->multi_gradient_colors_2[$num_set-1];
|
|
$this->multi_gradient_colors_1[]=array(
|
|
(int)$color_ref_1[0]*$color_darken_decimal,
|
|
(int)$color_ref_1[1]*$color_darken_decimal,
|
|
(int)$color_ref_1[2]*$color_darken_decimal);
|
|
$this->multi_gradient_colors_2[]=array(
|
|
(int)$color_ref_2[0]*$color_darken_decimal,
|
|
(int)$color_ref_2[1]*$color_darken_decimal,
|
|
(int)$color_ref_2[2]*$color_darken_decimal);
|
|
$num_set++;
|
|
}
|
|
}
|
|
while(count($this->multi_gradient_colors_1)>$this->data_set_count)
|
|
{
|
|
$temp=array_pop($this->multi_gradient_colors_1);
|
|
}
|
|
while(count($this->multi_gradient_colors_2)>$this->data_set_count)
|
|
{
|
|
$temp=array_pop($this->multi_gradient_colors_2);
|
|
}
|
|
$this->multi_gradient_colors_1=array_reverse($this->multi_gradient_colors_1);
|
|
$this->multi_gradient_colors_2=array_reverse($this->multi_gradient_colors_2);
|
|
}
|
|
else if(!$this->bool_gradient)
|
|
{
|
|
$num_set=count($this->multi_bar_colors);
|
|
if($num_set==0)
|
|
{
|
|
$this->multi_bar_colors[0]=$this->bar_color;
|
|
$num_set=1;
|
|
}
|
|
//LOOP THROUGH SET COLORS AND ADD BACKING COLORS IF NECESSARY
|
|
while($num_set<$this->data_set_count)
|
|
{
|
|
$color_ref=$this->multi_bar_colors[$num_set-1];
|
|
$color_parts=imagecolorsforindex($this->image, $color_ref);
|
|
$color_darken_decimal=(100-$this->color_darken_factor)/100;
|
|
$this->multi_bar_colors[$num_set]=imagecolorallocate($this->image,
|
|
(int)$color_parts['red']*$color_darken_decimal,
|
|
(int)$color_parts['green']*$color_darken_decimal,
|
|
(int)$color_parts['blue']*$color_darken_decimal);
|
|
$num_set++;
|
|
}
|
|
while(count($this->multi_bar_colors)>$this->data_set_count)
|
|
{
|
|
$temp=array_pop($this->multi_bar_colors);
|
|
}
|
|
$this->multi_bar_colors=array_reverse($this->multi_bar_colors);
|
|
}
|
|
if($this->bool_line)
|
|
{
|
|
if(!$this->bool_bars)
|
|
{
|
|
$num_set=count($this->line_color);
|
|
if($num_set==0)
|
|
{
|
|
$this->line_color[0]=$this->line_color_default;
|
|
$num_set=1;
|
|
}
|
|
//ONLY DARKEN EACH DATA SET'S LINES WHEN NO BARS PRESENT
|
|
while($num_set<$this->data_set_count)
|
|
{
|
|
$color_ref=$this->line_color[$num_set-1];
|
|
$color_parts=imagecolorsforindex($this->image, $color_ref);
|
|
$color_darken_decimal=(100-$this->color_darken_factor)/100;
|
|
$this->line_color[$num_set]=imagecolorallocate($this->image,
|
|
(int)$color_parts['red']*$color_darken_decimal,
|
|
(int)$color_parts['green']*$color_darken_decimal,
|
|
(int)$color_parts['blue']*$color_darken_decimal);
|
|
$num_set++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$num_set=count($this->line_color);
|
|
while($num_set<$this->data_set_count)
|
|
{
|
|
$this->line_color[$num_set]=$this->line_color_default;
|
|
$num_set++;
|
|
}
|
|
}
|
|
while(count($this->line_color)>$this->data_set_count)
|
|
{
|
|
$temp=array_pop($this->line_color);
|
|
}
|
|
$this->line_color=array_reverse($this->line_color);
|
|
}
|
|
}
|
|
function drawGradientBar($x1, $y1, $x2, $y2, $colorArr1, $colorArr2, $data_set_num)
|
|
{
|
|
if(!isset($this->bool_gradient_colors_found[$data_set_num])||$this->bool_gradient_colors_found[$data_set_num]==false)
|
|
{
|
|
$this->gradient_handicap[$data_set_num]=0;
|
|
$numLines=abs($x1-$x2)+1;
|
|
while($numLines*$this->data_set_count>$this->gradient_max)
|
|
{
|
|
//WE HAVE MORE LINES THAN ALLOWABLE COLORS
|
|
//USE HANDICAP TO RECORD THIS
|
|
$numLines/=2;
|
|
$this->gradient_handicap[$data_set_num]++;
|
|
}
|
|
$color1R=$colorArr1[0];
|
|
$color1G=$colorArr1[1];
|
|
$color1B=$colorArr1[2];
|
|
$color2R=$colorArr2[0];
|
|
$color2G=$colorArr2[1];
|
|
$color2B=$colorArr2[2];
|
|
$rScale=($color1R-$color2R)/$numLines;
|
|
$gScale=($color1G-$color2G)/$numLines;
|
|
$bScale=($color1B-$color2B)/$numLines;
|
|
$this->allocateGradientColors($color1R, $color1G, $color1B, $rScale, $gScale, $bScale, $numLines, $data_set_num);
|
|
}
|
|
$numLines=abs($x1-$x2)+1;
|
|
if($this->gradient_handicap[$data_set_num]>0)
|
|
{
|
|
//IF HANDICAP IS USED, IT WILL ALLOW US TO MOVE THROUGH THE ARRAY MORE SLOWLY, DEPENDING ON THE SET VALUE
|
|
$interval=$this->gradient_handicap[$data_set_num];
|
|
for($i=0;$i<$numLines;$i++)
|
|
{
|
|
$adjusted_index=ceil($i/pow(2,$interval))-1;
|
|
if($adjusted_index<0)
|
|
{
|
|
$adjusted_index=0;
|
|
}
|
|
imageline($this->image, $x1+$i, $y1, $x1+$i, $y2, $this->gradient_color_array[$data_set_num][$adjusted_index]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//NORMAL GRADIENTS WITH COLORS < $this->gradient_max
|
|
for($i=0;$i<$numLines;$i++)
|
|
{
|
|
imageline($this->image, $x1+$i, $y1, $x1+$i, $y2, $this->gradient_color_array[$data_set_num][$i]);
|
|
}
|
|
}
|
|
}
|
|
function generateGrid()
|
|
{
|
|
//DETERMINE HORIZONTAL GRID LINES
|
|
$horizGridArray=array();
|
|
if($this->bool_user_data_range)
|
|
{
|
|
$min=$this->data_min;
|
|
}
|
|
else
|
|
{
|
|
$min=0;
|
|
}
|
|
$horizGridArray[]=$min;
|
|
//USE OUR FUNCTION TO DETERMINE IDEAL Y AXIS SCALE INTERVAL
|
|
$intervalFromZero=$this->determineAxisMarkerScale($this->data_max, $this->data_min);
|
|
//IF WE HAVE POSITIVE VALUES, ADD GRID VALUES TO ARRAY
|
|
//UNTIL WE REACH THE MAX NEEDED (WE WILL GO 1 OVER)
|
|
$cur=$min;
|
|
while($cur<$this->data_max)
|
|
{
|
|
$cur+=$intervalFromZero;
|
|
$horizGridArray[]=$cur;
|
|
}
|
|
//IF WE HAVE NEGATIVE VALUES, ADD GRID VALUES TO ARRAY
|
|
//UNTIL WE REACH THE MIN NEEDED (WE WILL GO 1 OVER)
|
|
$cur=$min;
|
|
while($cur>$this->data_min)
|
|
{
|
|
$cur-=$intervalFromZero;
|
|
$horizGridArray[]=$cur;
|
|
}
|
|
//SORT NEEDED B/C WE WILL USE LAST VALUE LATER (MAX)
|
|
sort($horizGridArray);
|
|
//DETERMINE VERTICAL GRID LINES
|
|
$vertGridArray=array();
|
|
$vertGrids=$this->data_count+1;
|
|
$interval=$this->bar_width+$this->space_width;
|
|
//ASSEMBLE VERT GRIDLINE ARRAY
|
|
for($i=1;$i<$vertGrids;$i++)
|
|
{
|
|
$vertGridArray[]=$this->y_axis_x1+($interval*$i);
|
|
}
|
|
//LOOP THROUGH EACH HORIZONTAL LINE
|
|
if($this->bool_user_data_range)
|
|
{
|
|
$adjustment=$this->data_min*$this->unit_scale;
|
|
}
|
|
else
|
|
{
|
|
$adjustment=0;
|
|
}
|
|
|
|
foreach($horizGridArray as $value)
|
|
{
|
|
$yValue=(int)($this->x_axis_y1-($value*$this->unit_scale)+$adjustment);
|
|
if($this->bool_grid)
|
|
{
|
|
imageline($this->image, $this->y_axis_x1, $yValue, $this->x_axis_x2 , $yValue, $this->grid_color);
|
|
}
|
|
//DISPLAY VALUE ON Y AXIS IF DESIRED USING CALC'D GRID VALUES
|
|
if($this->bool_y_axis_values)
|
|
{
|
|
$adjustedYValue=$yValue-($this->text_height/2);
|
|
$adjustedXValue=$this->y_axis_x1-(strlen($value)*$this->text_width)-$this->axis_value_padding;
|
|
imagestring($this->image, 2, $adjustedXValue, $adjustedYValue, $value, $this->y_axis_text_color);
|
|
}
|
|
}
|
|
if(!$this->bool_all_positive&&!$this->bool_user_data_range)
|
|
{
|
|
//RESET WITH BETTER VALUE BASED ON GRID MIN VALUE CALCULATIONS, NOT DATA MIN
|
|
$this->y_axis_y1=$this->x_axis_y1-($horizGridArray[0]*$this->unit_scale);
|
|
}
|
|
//RESET WITH BETTER VALUE BASED ON GRID VALUE CALCULATIONS, NOT DATA MIN
|
|
$this->y_axis_y2=$yValue;
|
|
//LOOP THROUGH EACH VERTICAL LINE
|
|
if($this->bool_grid)
|
|
{
|
|
foreach($vertGridArray as $value)
|
|
{
|
|
$xValue=$this->y_axis_y1;
|
|
imageline($this->image, $value, $this->y_axis_y2, $value, $xValue , $this->grid_color);
|
|
}
|
|
}
|
|
//DRAW GOAL LINES IF PRESENT (AFTER GRID) - DOESN'T GET EXECUTED IF ARRAY EMPTY
|
|
foreach($this->goal_line_array as $yLocation)
|
|
{
|
|
$yLocation=(int)($this->x_axis_y1-($yLocation*$this->unit_scale)+$adjustment);
|
|
imageline($this->image, $this->y_axis_x1, $yLocation, $this->x_axis_x2 , $yLocation, $this->goal_line_color);
|
|
}
|
|
}
|
|
function generateDataPoints()
|
|
{
|
|
foreach($this->data_point_array as $pointArray)
|
|
{
|
|
imagefilledellipse($this->image, $pointArray[0], $pointArray[1], $this->data_point_width, $this->data_point_width, $this->data_point_color);
|
|
}
|
|
}
|
|
function generateXAxis()
|
|
{
|
|
imageline($this->image, $this->x_axis_x1, $this->x_axis_y1, $this->x_axis_x2, $this->x_axis_y2, $this->x_axis_color);
|
|
}
|
|
function generateYAxis()
|
|
{
|
|
imageline($this->image, $this->y_axis_x1, $this->y_axis_y1, $this->y_axis_x2, $this->y_axis_y2, $this->y_axis_color);
|
|
}
|
|
function generateBackgound()
|
|
{
|
|
imagefilledrectangle($this->image, 0, 0, $this->width, $this->height, $this->background_color);
|
|
}
|
|
function generateTitle()
|
|
{
|
|
//SPACING MAY HAVE CHANGED SINCE EARLIER
|
|
//USE TOP MARGIN OR GRID TOP Y, WHICHEVER LESS
|
|
$highestElement=($this->top_margin<$this->y_axis_y2) ? $this->top_margin : $this->y_axis_y2;
|
|
$textVertPos=($highestElement/2)-($this->title_char_height/2); //CENTERED
|
|
$titleLength=strlen($this->title_text);
|
|
if($this->bool_title_center)
|
|
{
|
|
$this->title_x=($this->width/2)-(($titleLength*$this->title_char_width)/2);
|
|
$this->title_y=$textVertPos;
|
|
}
|
|
else if($this->bool_title_left)
|
|
{
|
|
$this->title_x=$this->y_axis_x1;
|
|
$this->title_y=$textVertPos;
|
|
}
|
|
else if($this->bool_title_right)
|
|
{
|
|
$this->title_x=$this->x_axis_x2-($titleLength*$this->title_char_width);
|
|
$this->title_y=$textVertPos;
|
|
}
|
|
imagestring($this->image, 2, $this->title_x , $this->title_y , $this->title_text, $this->title_color);
|
|
}
|
|
function calcTopMargin()
|
|
{
|
|
if($this->bool_title)
|
|
{
|
|
//INCLUDE SPACE FOR TITLE, APPROX MARGIN + 3*TITLE HEIGHT
|
|
$this->top_margin=($this->height*($this->x_axis_default_percent/100))+$this->title_char_height;
|
|
}
|
|
else
|
|
{
|
|
//JUST USE DEFAULT SPACING
|
|
$this->top_margin=$this->height*($this->x_axis_default_percent/100);
|
|
}
|
|
}
|
|
function calcRightMargin()
|
|
{
|
|
//JUST USE DEFAULT SPACING
|
|
$this->right_margin=$this->width*($this->y_axis_default_percent/100);
|
|
}
|
|
function calcCoords()
|
|
{
|
|
//CALCULATE AXIS POINTS, ALSO USED FOR OTHER CALCULATIONS
|
|
$this->x_axis_x1=$this->y_axis_margin;
|
|
$this->x_axis_y1=$this->height-$this->x_axis_margin;
|
|
$this->x_axis_x2=$this->width-$this->right_margin;
|
|
$this->x_axis_y2=$this->height-$this->x_axis_margin;
|
|
$this->y_axis_x1=$this->y_axis_margin;
|
|
$this->y_axis_y1=$this->height-$this->x_axis_margin;
|
|
$this->y_axis_x2=$this->y_axis_margin;
|
|
$this->y_axis_y2=$this->top_margin;
|
|
}
|
|
function determineAxisMarkerScale($max, $min)
|
|
{
|
|
//FOR CALCLATION, TAKE RANGE OR MAX-0
|
|
if($this->bool_user_data_range)
|
|
{
|
|
$range=abs($max-$min);
|
|
}
|
|
else
|
|
{
|
|
$range=(abs($max-$min)>abs($max-0)) ? abs($max-$min) : abs($max-0);
|
|
}
|
|
//MULTIPLY UP TO OVER 100, TO BETTER FIGURE INTERVAL
|
|
$count=0;
|
|
while(abs($range)<100)
|
|
{
|
|
$range*=10;
|
|
$count++;
|
|
}
|
|
//DIVIDE INTO INTERVALS BASED ON HEIGHT / PRESET CONSTANT - AFTER ROUNDING WILL BE APPROX
|
|
$divisor=round($this->height/$this->range_divisor_factor);
|
|
$divided=round($range/$divisor);
|
|
$result=$this->roundUpOneExtraDigit($divided);
|
|
//IF ROUNDED UP W/ EXTRA DIGIT IS MORE THAN 200% OF DIVIDED VALUE,
|
|
//ROUND UP TO NEXT SIG NUMBER WITH SAME NUM OF DIGITS
|
|
if($result/$divided>=2)
|
|
{
|
|
$result=$this->roundUpSameDigits($divided);
|
|
}
|
|
//DIVIDE BACK DOWN, IF NEEDED
|
|
for($i=0;$i<$count;$i++)
|
|
{
|
|
$result/=10;
|
|
}
|
|
return $result;
|
|
}
|
|
function roundUpSameDigits($num)
|
|
{
|
|
$len=strlen($num);
|
|
if(round($num, -1*($len-1))==$num)
|
|
{
|
|
//WE ALREADY HAVE A SIG NUMBER
|
|
return $num;
|
|
}
|
|
else
|
|
{
|
|
$firstDig=substr($num, 0,1);
|
|
$secondDig=substr($num, 1,1);
|
|
$rest=substr($num, 2);
|
|
$secondDig=5;
|
|
$altered=$firstDig.$secondDig.$rest;
|
|
//AFTER REASSEMBLY, ROUND UP TO NEXT SIG NUMBER, SAME # OF DIGITS
|
|
return round((int)$altered, -1*($len-1));
|
|
}
|
|
}
|
|
function roundUpOneExtraDigit($num)
|
|
{
|
|
$len=strlen($num);
|
|
$firstDig=substr($num, 0,1);
|
|
$rest=substr($num, 1);
|
|
$firstDig=5;
|
|
$altered=$firstDig.$rest;
|
|
//AFTER REASSEMBLY, ROUND UP TO NEXT SIG NUMBER, ONE EXTRA # OF DIGITS
|
|
return round((int)$altered, -1*($len));
|
|
}
|
|
function displayErrors()
|
|
{
|
|
if(count($this->error)>0)
|
|
{
|
|
$lineHeight=12;
|
|
$errorColor = imagecolorallocate($this->image, 0, 0, 0);
|
|
$errorBackColor = imagecolorallocate($this->image, 255, 204, 0);
|
|
imagefilledrectangle($this->image, 0, 0, $this->width-1, 2*$lineHeight, $errorBackColor);
|
|
imagestring($this->image, 3, 2, 0, "!!----- PHPGraphLib Error -----!!", $errorColor);
|
|
foreach($this->error as $key => $errorText)
|
|
{
|
|
|
|
imagefilledrectangle($this->image, 0, ($key*$lineHeight)+$lineHeight, $this->width-1, ($key*$lineHeight)+2*$lineHeight, $errorBackColor);
|
|
imagestring($this->image, 2, 2, ($key*$lineHeight)+$lineHeight, "[". ($key+1) . "] ". $errorText, $errorColor);
|
|
}
|
|
$errorOutlineColor = imagecolorallocate($this->image, 255, 0, 0);
|
|
imagerectangle($this->image, 0, 0, $this->width-1,($key*$lineHeight)+2*$lineHeight, $errorOutlineColor);
|
|
}
|
|
}
|
|
function addData($data, $data2='',$data3='')
|
|
{
|
|
if(is_array($data)){ $this->data_array[]=$data; }
|
|
if(is_array($data2)){ $this->data_array[]=$data2; }
|
|
if(is_array($data3)){ $this->data_array[]=$data3; }
|
|
|
|
//ASSESS DATA
|
|
$min=$this->data_max_allowable;
|
|
$max=$this->data_min_allowable;
|
|
$nonZero=false;
|
|
$this->data_count=0;
|
|
//GET RID OF BAD DATA, FIND MAX, MIN
|
|
foreach($this->data_array as $data_set_num => $data_set)
|
|
{
|
|
foreach($data_set as $key => $item)
|
|
{
|
|
if(!is_numeric($item))
|
|
{
|
|
unset($this->data_array[$data_set_num][$key]);
|
|
}
|
|
else
|
|
{
|
|
if($item>0||$item<0){ $nonZero=true; }
|
|
if($item<$min){ $min=$item; }
|
|
if($item>$max){ $max=$item; }
|
|
}
|
|
}
|
|
$count=count($this->data_array[$data_set_num]);
|
|
$count>$this->data_count ? $this->data_count=$count : NULL;
|
|
if(!$nonZero||$this->data_count==0)
|
|
{
|
|
$this->error[]="Dataset " . ($data_set_num+1) . " contains invalid data.";
|
|
}
|
|
}
|
|
$set_count=count($this->data_array);
|
|
$this->data_set_count=$set_count;
|
|
if($set_count==0)
|
|
{
|
|
$this->error[]="No valid datasets added in adddata() function.";
|
|
}
|
|
else
|
|
{
|
|
$this->bool_data=true;
|
|
//MIN AND MAX FOR ALL DATASETS
|
|
$this->data_min=$min;
|
|
$this->data_max=$max;
|
|
if($this->data_min>=0)
|
|
{
|
|
$this->bool_all_positive=true;
|
|
}
|
|
else if($this->data_max<=0)
|
|
{
|
|
$this->bool_all_negative=true;
|
|
}
|
|
}
|
|
}
|
|
function setupXAxis($percent='', $color='')
|
|
{
|
|
if($percent===false)
|
|
{
|
|
$this->bool_x_axis=false;
|
|
}
|
|
else
|
|
{
|
|
$this->bool_x_axis=true;
|
|
}
|
|
$this->bool_x_axis_setup=true;
|
|
if(!empty($color)&&$arr=$this->returnColorArray($color))
|
|
{
|
|
$this->x_axis_color = imagecolorallocate($this->image, $arr[0], $arr[1], $arr[2]);
|
|
}
|
|
if(is_numeric($percent)&&$percent>0)
|
|
{
|
|
$percent=$percent/100;
|
|
$this->x_axis_margin=(int)($this->height*$percent);
|
|
}
|
|
else
|
|
{
|
|
$percent=$this->x_axis_default_percent/100;
|
|
$this->x_axis_margin=(int)($this->height*$percent);
|
|
}
|
|
}
|
|
function setupYAxis($percent='', $color='')
|
|
{
|
|
if($percent===false)
|
|
{
|
|
$this->bool_y_axis=false;
|
|
}
|
|
else
|
|
{
|
|
$this->bool_y_axis=true;
|
|
}
|
|
$this->bool_y_axis_setup=true;
|
|
if(!empty($color)&&$arr=$this->returnColorArray($color))
|
|
{
|
|
$this->y_axis_color = imagecolorallocate($this->image, $arr[0], $arr[1], $arr[2]);
|
|
}
|
|
if(is_numeric($percent)&&$percent>0)
|
|
{
|
|
$this->y_axis_margin=(int)($this->width*($percent/100));
|
|
}
|
|
else
|
|
{
|
|
$percent=$this->y_axis_default_percent/100;
|
|
$this->y_axis_margin=(int)($this->width*$percent);
|
|
}
|
|
}
|
|
function setRange($max, $min)
|
|
{
|
|
if($min<0||$max<=0){ $this->error[]="Range in setRange() must be non-negative."; }
|
|
else if(is_numeric($max)&&is_numeric($min)&&$max>$min)
|
|
{
|
|
$this->data_range_max=$max;
|
|
$this->data_range_min=$min;
|
|
$this->bool_user_data_range=true;
|
|
}
|
|
else{ $this->error[]="Range in setRange() not specified properly. Consult documentation."; }
|
|
}
|
|
function setTitle($title)
|
|
{
|
|
if(!empty($title))
|
|
{
|
|
$this->title_text=$title;
|
|
$this->bool_title=true;
|
|
}
|
|
else{ $this->error[]="String arg for setTitle() not specified properly."; }
|
|
}
|
|
function setTitleLocation($location)
|
|
{
|
|
$this->bool_title_left=false;
|
|
$this->bool_title_right=false;
|
|
$this->bool_title_center=false;
|
|
switch(strtolower($location))
|
|
{
|
|
case 'left': $this->bool_title_left=true; break;
|
|
case 'right': $this->bool_title_right=true; break;
|
|
case 'center': $this->bool_title_center=true; break;
|
|
default: $this->error[]="String arg for setTitleLocation() not specified properly.";
|
|
}
|
|
}
|
|
function setBars($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_bars=$bool;}
|
|
else{ $this->error[]="Boolean arg for setBars() not specified properly."; }
|
|
}
|
|
function setGrid($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_grid=$bool;}
|
|
else{ $this->error[]="Boolean arg for setGrid() not specified properly."; }
|
|
}
|
|
function setXValues($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_x_axis_values=$bool;}
|
|
else{ $this->error[]="Boolean arg for setXValues() not specified properly."; }
|
|
}
|
|
function setYValues($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_y_axis_values=$bool;}
|
|
else{ $this->error[]="Boolean arg for setYValues() not specified properly."; }
|
|
}
|
|
function setXValuesHorizontal($bool)
|
|
{
|
|
if(is_bool($bool)){
|
|
($bool) ? $this->bool_x_axis_values_vert=false : $this->bool_x_axis_values_vert=true;
|
|
}
|
|
else{ $this->error[]="Boolean arg for setXValuesHorizontal() not specified properly."; }
|
|
}
|
|
function setXValuesVertical($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_x_axis_values_vert=$bool;}
|
|
else{ $this->error[]="Boolean arg for setXValuesVertical() not specified properly."; }
|
|
}
|
|
function setBarOutline($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_bar_outline=$bool;}
|
|
else{ $this->error[]="Boolean arg for setBarOutline() not specified properly."; }
|
|
}
|
|
function setDataPoints($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_data_points=$bool;}
|
|
else{ $this->error[]="Boolean arg for setDataPoints() not specified properly."; }
|
|
}
|
|
function setDataPointSize($size)
|
|
{
|
|
if(is_numeric($size)){ $this->data_point_width=$size;}
|
|
else{ $this->error[]="Data point size in setDataPointSize() not specified properly."; }
|
|
}
|
|
function setDataValues($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_data_values=$bool;}
|
|
else{ $this->error[]="Boolean arg for setDataValues() not specified properly."; }
|
|
}
|
|
function setLine($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_line=$bool;}
|
|
else{ $this->error[]="Boolean arg for setLine() not specified properly."; }
|
|
}
|
|
function setGoalLine($yValue)
|
|
{
|
|
if(is_numeric($yValue))
|
|
{
|
|
$this->goal_line_array[]=$yValue;
|
|
}
|
|
else
|
|
{
|
|
$this->error[]="Goal line Y axis value not specified properly.";
|
|
}
|
|
}
|
|
//-------------"PRIVATE" COLOR HANDLING FUNCTIONS---------------//
|
|
function allocateColors()
|
|
{
|
|
$this->background_color = imagecolorallocate($this->image, 255, 255, 255);
|
|
$this->grid_color = imagecolorallocate($this->image, 220, 220, 220);
|
|
$this->bar_color = imagecolorallocate($this->image, 200, 200, 200);
|
|
$this->line_color_default = imagecolorallocate($this->image, 100, 100, 100);
|
|
$this->x_axis_text_color = $this->line_color_default;
|
|
$this->y_axis_text_color = $this->line_color_default;
|
|
$this->data_value_color = $this->line_color_default;
|
|
$this->title_color = imagecolorallocate($this->image, 0, 0, 0);
|
|
$this->outline_color = $this->title_color;
|
|
$this->data_point_color = $this->title_color;
|
|
$this->x_axis_color = $this->title_color;
|
|
$this->y_axis_color = $this->title_color;
|
|
$this->goal_line_color = $this->title_color;
|
|
//New Legend Colors
|
|
$this->legend_outline_color=$this->grid_color;
|
|
$this->legend_color=$this->background_color;
|
|
$this->legend_text_color=$this->line_color_default;
|
|
$this->legend_swatch_outline_color=$this->line_color_default;
|
|
}
|
|
function returnColorArray($color)
|
|
{
|
|
//CHECK TO SEE IF NUMERIC COLOR PASSED THROUGH IN FORM '128,128,128'
|
|
if(strpos($color,',')!==false)
|
|
{
|
|
return explode(',',$color);
|
|
}
|
|
switch(strtolower($color))
|
|
{
|
|
//NAMED COLORS BASED ON W3C's RECOMMENDED HTML COLORS
|
|
case 'black': return array(0,0,0); break;
|
|
case 'silver': return array(192,192,192); break;
|
|
case 'gray': return array(128,128,128); break;
|
|
case 'white': return array(255,255,255); break;
|
|
case 'maroon': return array(128,0,0); break;
|
|
case 'red': return array(255,0,0); break;
|
|
case 'purple': return array(128,0,128); break;
|
|
case 'fuscia': return array(255,0,255); break;
|
|
case 'green': return array(0,128,0); break;
|
|
case 'lime': return array(0,255,0); break;
|
|
case 'olive': return array(128,128,0); break;
|
|
case 'yellow': return array(255,255,0); break;
|
|
case 'navy': return array(0,0,128); break;
|
|
case 'blue': return array(0,0,255); break;
|
|
case 'teal': return array(0,128,128); break;
|
|
case 'aqua': return array(0,255,255); break;
|
|
}
|
|
$this->error[]="Color name \"$color\" not recogized.";
|
|
return false;
|
|
}
|
|
function allocateGradientColors($color1R, $color1G, $color1B, $rScale, $gScale, $bScale, $num, $data_set_num)
|
|
{
|
|
//CALUCLATE THE COLORS USED IN OUR GRADIENT AND STORE THEM IN ARRAY
|
|
$this->gradient_color_array[$data_set_num]=array();
|
|
for($i=0;$i<=$num+1;$i++)
|
|
{
|
|
$this->gradient_color_array[$data_set_num][$i] = imagecolorallocate($this->image, $color1R-($rScale*$i), $color1G-($gScale*$i), $color1B-($bScale*$i));
|
|
}
|
|
$this->bool_gradient_colors_found[$data_set_num]=true;
|
|
}
|
|
function setGenericColor($inputColor, $var, $errorMsg)
|
|
{
|
|
//CAN BE USED FOR MOST COLOR SETTING OPTIONS
|
|
if(!empty($inputColor)&&$arr=$this->returnColorArray($inputColor))
|
|
{
|
|
eval($var . ' = imagecolorallocate($this->image, $arr[0], $arr[1], $arr[2]);');
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
$this->error[]=$errorMsg;
|
|
return false;
|
|
}
|
|
}
|
|
//-------------------"PUBLIC" COLOR FUNCTIONS----------------------//
|
|
function setBackgroundColor($color)
|
|
{
|
|
if($this->setGenericColor($color, '$this->background_color', "Background color not specified properly."))
|
|
{
|
|
$this->bool_background=true;
|
|
}
|
|
}
|
|
function setTitleColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->title_color', "Title color not specified properly.");
|
|
}
|
|
function setTextColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->x_axis_text_color', "X axis text color not specified properly.");
|
|
$this->setGenericColor($color, '$this->y_axis_text_color', "Y axis Text color not specified properly.");
|
|
}
|
|
function setXAxisTextColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->x_axis_text_color', "X axis text color not specified properly.");
|
|
}
|
|
function setYAxisTextColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->y_axis_text_color', "Y axis Text color not specified properly.");
|
|
}
|
|
function setBarColor($color,$color2='',$color3='')
|
|
{
|
|
$this->setGenericColor($color, '$this->multi_bar_colors[]', "Bar color not specified properly.");
|
|
if(!empty($color2)){
|
|
$this->setGenericColor($color2, '$this->multi_bar_colors[]', "Bar color 2 not specified properly.");
|
|
}
|
|
if(!empty($color3)){
|
|
$this->setGenericColor($color3, '$this->multi_bar_colors[]', "Bar color 3 not specified properly.");
|
|
}
|
|
}
|
|
function setGridColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->grid_color', "Grid color not specified properly.");
|
|
}
|
|
function setBarOutlineColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->outline_color', "Bar outline color not specified properly.");
|
|
}
|
|
function setDataPointColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->data_point_color', "Data point color not specified properly.");
|
|
}
|
|
function setDataValueColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->data_value_color', "Data value color not specified properly.");
|
|
}
|
|
function setLineColor($color, $color2='', $color3='')
|
|
{
|
|
$this->setGenericColor($color, '$this->line_color[]', "Line color not specified properly.");
|
|
if(!empty($color2)){
|
|
$this->setGenericColor($color2, '$this->line_color[]', "Line color 2 not specified properly.");
|
|
}
|
|
if(!empty($color3)){
|
|
$this->setGenericColor($color3, '$this->line_color[]', "Line color 3 not specified properly.");
|
|
}
|
|
}
|
|
function setGoalLineColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->goal_line_color', "Goal line color not specified properly.");
|
|
}
|
|
function setGradient($color1, $color2, $color3='', $color4='', $color5='', $color6='')
|
|
{
|
|
if(!empty($color1)&&!empty($color2)&&($arr1=$this->returnColorArray($color1))&&($arr2=$this->returnColorArray($color2)))
|
|
{
|
|
$this->bool_gradient=true;
|
|
$this->multi_gradient_colors_1[]=$arr1;
|
|
$this->multi_gradient_colors_2[]=$arr2;
|
|
}
|
|
else
|
|
{
|
|
$this->error[]="Gradient color(s) not specified properly.";
|
|
}
|
|
//GRADIENTS 3,4,5,6 OPTIONAL
|
|
if(!empty($color3)&&!empty($color4)&&($arr1=$this->returnColorArray($color3))&&($arr2=$this->returnColorArray($color4)))
|
|
{
|
|
$this->bool_gradient=true;
|
|
$this->multi_gradient_colors_1[]=$arr1;
|
|
$this->multi_gradient_colors_2[]=$arr2;
|
|
}
|
|
if(!empty($color5)&&!empty($color6)&&($arr1=$this->returnColorArray($color5))&&($arr2=$this->returnColorArray($color6)))
|
|
{
|
|
$this->bool_gradient=true;
|
|
$this->multi_gradient_colors_1[]=$arr1;
|
|
$this->multi_gradient_colors_2[]=$arr2;
|
|
}
|
|
}
|
|
//Legend Related Functions
|
|
function setLegend($bool)
|
|
{
|
|
if(is_bool($bool)){ $this->bool_legend=$bool;}
|
|
else{ $this->error[]="Boolean arg for setLegend() not specified properly."; }
|
|
}
|
|
function setLegendColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->legend_color', "Legend color not specified properly.");
|
|
}
|
|
function setLegendTextColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->legend_text_color', "Legend text color not specified properly.");
|
|
}
|
|
function setLegendOutlineColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->legend_outline_color', "Legend outline color not specified properly.");
|
|
}
|
|
function setSwatchOutlineColor($color)
|
|
{
|
|
$this->setGenericColor($color, '$this->legend_swatch_outline_color', "Swatch outline color not specified properly.");
|
|
}
|
|
function setLegendTitle($title, $title2='', $title3='')
|
|
{
|
|
if(!empty($title)){
|
|
$len=strlen($title);
|
|
if($len>$this->legend_max_chars){
|
|
$title=substr($title, 0, $this->legend_max_chars);
|
|
$this->legend_total_chars[]=$this->legend_max_chars;
|
|
}
|
|
else{$this->legend_total_chars[]=$len;}
|
|
$this->legend_titles[]=$title;
|
|
}
|
|
else{$this->error[]="String arg 1 for setLegendTitles() not specified properly."; }
|
|
if(!empty($title2)){
|
|
$len=strlen($title2);
|
|
if($len>$this->legend_max_chars){
|
|
$title2=substr($title2, 0, $this->legend_max_chars);
|
|
$this->legend_total_chars[]=$this->legend_max_chars;
|
|
}
|
|
else{$this->legend_total_chars[]=$len;}
|
|
$this->legend_titles[]=$title2;
|
|
}
|
|
if(!empty($title3)){
|
|
$len=strlen($title3);
|
|
if($len>$this->legend_max_chars){
|
|
$title3=substr($title3, 0, $this->legend_max_chars);
|
|
$this->legend_total_chars[]=$this->legend_max_chars;
|
|
}
|
|
else{$this->legend_total_chars[]=$len;}
|
|
$this->legend_titles[]=$title3;
|
|
}
|
|
}
|
|
function generateLegend()
|
|
{
|
|
$swatchToTextOffset=($this->legend_text_height-6)/2;
|
|
$swatchSize=$this->legend_text_height-2*$swatchToTextOffset;
|
|
//CALC HEIGHT / WIDTH BASED ON # OF DATA SETS
|
|
$this->legend_height=$this->legend_text_height+(2*$this->legend_padding);
|
|
$totalChars=0;
|
|
for($i=0;$i<$this->data_set_count;$i++)
|
|
{
|
|
//COULD HAVE MORE TITLES THAN DATA SETS - CHECK FOR THIS
|
|
if(isset($this->legend_total_chars[$i])){ $totalChars+=$this->legend_total_chars[$i]; }
|
|
}
|
|
$this->legend_width=$totalChars*$this->legend_text_width+($this->legend_padding*1.5)+
|
|
($this->data_set_count*($swatchSize+($this->legend_padding*2)));
|
|
$this->legend_x=$this->x_axis_x2-$this->legend_width;
|
|
$highestElement=($this->top_margin<$this->y_axis_y2) ? $this->top_margin : $this->y_axis_y2;
|
|
$this->legend_y=($highestElement/2)-($this->legend_height/2); //CENTERED
|
|
|
|
//BACKGROUND
|
|
imagefilledrectangle($this->image, $this->legend_x, $this->legend_y, $this->legend_x+$this->legend_width,
|
|
$this->legend_y+$this->legend_height, $this->legend_color);
|
|
//BORDER
|
|
imagerectangle($this->image, $this->legend_x, $this->legend_y, $this->legend_x+$this->legend_width,
|
|
$this->legend_y+$this->legend_height, $this->legend_outline_color);
|
|
|
|
$length_covered=0;
|
|
for($i=0;$i<$this->data_set_count;$i++)
|
|
{
|
|
$data_label='';
|
|
if(isset($this->legend_titles[$i]))
|
|
{
|
|
$data_label=$this->legend_titles[$i];
|
|
}
|
|
$yValue=$this->legend_y+$this->legend_padding;
|
|
$xValue=$this->legend_x+$this->legend_padding+($length_covered*$this->legend_text_width)+($i*4*$this->legend_padding);
|
|
$length_covered+=strlen($data_label);
|
|
//DRAW COLOR BOXES
|
|
if($this->bool_bars)
|
|
{
|
|
if($this->bool_gradient){
|
|
$color=$this->gradient_color_array[$this->data_set_count-$i-1][0];
|
|
}
|
|
else{
|
|
$color=$this->multi_bar_colors[$this->data_set_count-$i-1];
|
|
}
|
|
}
|
|
else if($this->bool_line&&!$this->bool_bars)
|
|
{
|
|
$color=$this->line_color[$this->data_set_count-$i-1];
|
|
}
|
|
|
|
imagefilledrectangle($this->image, $xValue, $yValue+$swatchToTextOffset, $xValue+$swatchSize, $yValue+$swatchToTextOffset+$swatchSize, $color);
|
|
imagerectangle($this->image, $xValue, $yValue+$swatchToTextOffset, $xValue+$swatchSize, $yValue+$swatchToTextOffset+$swatchSize, $this->legend_swatch_outline_color);
|
|
imagestring($this->image, 2, $xValue+(2*$this->legend_padding+2), $yValue, $data_label, $this->legend_text_color);
|
|
}
|
|
}
|
|
}
|
|
?>
|