. */ class Chart { private $title; private $data; private $padding; private $tmpdir; private $size; private $color; /* * Constructor * - parameters: * - $title: the title of the Chart. Printed at top. * - $data: an array of values to be printed in the chart. The keys are the X-values, the array values the Y-values * - $padding: the padding around the different parts. Only one padding is used between items. * - $tmpdir: the temp directory which can be used to write temporally files to * - return value: * [void] */ public function __construct($title, $data, $padding=10, $tmpdir="/tmp/") { $this->title = $title; $this->data = $data; $this->padding = $padding; $this->tmpdir = $tmpdir; $this->size = array(); $this->color['background'] = array(245, 245, 245); $this->color['outline'] = array(0, 0, 0); $this->color['text'] = array(0, 0, 0); $this->color['footer'] = array(100, 100, 100); $this->color['grid'] = array(204, 204, 204); $this->color['grid_mark'] = array(0, 0, 255); $this->color['label'] = array(0, 0, 0); $this->color['label_mark'] = array(0, 0, 255); if( count($data)>=1 ) $this->color['data'][0] = array(255, 0, 0); if( count($data)>=2 ) $this->color['data'][1] = array(255, 0, 255); if( count($data)>=3 ) $this->color['data'][2] = array(0, 0, 255); if( count($data)>=4 ) $this->color['data'][3] = array(0, 255, 255); if( count($data)>=5 ) $this->color['data'][4] = array(0, 255, 0); if( count($data)>=6 ) $this->color['data'][5] = array(255, 255, 0); if( count($data)>=7 ) $this->color['data'][6] = array(127, 0, 0); if( count($data)>=8 ) $this->color['data'][7] = array(127, 0, 127); if( count($data)>=9 ) $this->color['data'][8] = array(0, 0, 127); if( count($data)>=10 ) $this->color['data'][9] = array(0, 127, 127); if( count($data)>=11 ) $this->color['data'][10] = array(0, 127, 0); if( count($data)>=12 ) $this->color['data'][11] = array(127, 127, 0); for( $i=12; $icolor['data'][$i] = array(255*mt_rand(), 255*mt_rand(), 255*mt_rand()); } /* * Destructor * - parameters: * [none] * - return value: * [void] */ public function __destruct() { } /* * Change a default color into another value * - parameters: * - $type: the color of which item should be changed * - $color: an array with 3 values denoting the R, G, B color ('array(255, 0, 0)' for red). * - $index: in case the color of the data elements is changed, the color to be set. Only for 'pie' it makes sense to change anything else than element 0. * - return value: * - boolean: true in case color is changed, false otherwise */ public function set_color($type, $color, $index=-1) { if( $type=="data" ) { if( check_color($color) AND $index>=0 AND $index<=count($this->data) ) { $this->color[$type][$index] = $color; return true; }else { return false; } }else { if( check_color($color) AND array_key_exists($type, $this->color) ) { $this->color[$type] = $color; return true; }else { return false; } } } /* * Get the height of the last generated graph of a certain type * - parameters: * - $graph: the type of graph for which height should be returned. Can be 'bar', 'line' or 'pie' * - return value: * - int: height of the whole image in pixels, or false otherwise */ public function get_height($graph) { if( isset($this->size[$graph]['height']) ) return $this->size[$graph]['height']; else return false; } /* * Get the width of the last generated graph of a certain type * - parameters: * - $graph: the type of graph for which width should be returned. Can be 'bar', 'line' or 'pie' * - return value: * - int: width of the whole image in pixels, or false otherwise */ public function get_width($graph) { if( isset($this->size[$graph]['width']) ) return $this->size[$graph]['width']; else return false; } /* * Create a bar chart * - parameters: * - $x_size: width of the chart itself * - $y_size: height of the chart itself * - $x_labels: interval of showing labels on X axis (0 for none, -1 for auto) * - $y_labels: interval of showing labels on Y axis (0 for none, -1 for auto) * - $x_grid: interval of showing grid on X axis (0 for none, -1 for auto) * - $y_grid: interval of showing grid on Y axis (0 for none, -1 for auto) * - $x_grid_mark: array of x-values that should be marked with different color grid line * - $y_grid_mark: array of y-values that should be marked with different color grid line * - $x_label_mark: array of x-values where the label should be marked with different color * - $y_label_mark: array of y-values where the label should be marked with different color * - return value: * a PNG image, or 'false' in case of error */ public function bar($x_size, $y_size, $x_labels=-1, $y_labels=-1, $x_grid=-1, $y_grid=-1, $x_grid_mark=array(), $y_grid_mark=array(), $x_label_mark=array(), $y_label_mark=array()) { $k = array_keys($this->data); $x_max_len = 0; for( $i=0; $idata[ $k[$i] ]); $textpadding = 3; // Check parameters if( $x_size<(imagefontwidth(1) * strlen("[created ".date("H\hi T d.m.Y")."]") - 2 * $this->padding) OR $x_size>10000 ) return false; if( $y_size<(imagefontwidth(1) * strlen("[created ".date("H\hi T d.m.Y")."]") - 2 * $this->padding) OR $y_size>10000 ) return false; if( $x_labels<-1 OR $x_labels>100 ) return false; if( $y_labels<-1 OR $y_labels>10000 ) return false; if( $x_grid<-1 OR $x_grid>100 ) return false; if( $y_grid<-1 OR $y_grid>10000 ) return false; if( !is_array($x_grid_mark) ) return false; if( !is_array($y_grid_mark) ) return false; if( !is_array($x_label_mark) ) return false; if( !is_array($y_label_mark) ) return false; // Calculate values for auto parameters if( $x_labels==-1 ) $x_labels = max(1, ceil(count($k) / ($x_size / imagefontheight(2)))); if( $y_labels==-1 ) $y_labels = max(1, ceil($y_max / ($y_size / imagefontheight(2)))); if( $x_grid==-1 ) $x_grid = $x_labels; #max(1, round(count($k) / ($x_size / 10))); if( $y_grid==-1 ) $y_grid = $y_labels; #max(1, round($y_max / ($y_size / 25))); // Find the biggest font size for the title that still fits in the image (max 5) $titlefontsize = 1; for( $i=1; $i<=5; $i++ ) if( imagefontwidth($i)*strlen($this->title)<($x_size + strlen($y_max) * imagefontwidth(2)) ) $titlefontsize = $i; // Create image $im = imagecreate(2 * $this->padding + $x_size + strlen($y_max) * imagefontwidth(2) + $textpadding, 3 * $this->padding + imagefontheight($titlefontsize) + $y_size + $x_max_len * imagefontwidth(2) + imagefontheight(1) + $textpadding); $this->size['bar']['height'] = 3 * $this->padding + imagefontheight($titlefontsize) + $y_size + $x_max_len * imagefontwidth(2) + imagefontheight(1) + $textpadding; $this->size['bar']['width'] = 2 * $this->padding + $x_size + strlen($y_max) * imagefontwidth(2) + $textpadding; // Initialize colors $c = array_keys($this->color); for( $i=0; $icolor[ $c[$i] ][0], $this->color[ $c[$i] ][1], $this->color[ $c[$i] ][2]); }else { for( $j=0; $jcolor[ $c[$i] ]); $j++ ) $color[ $c[$i] ][$j] = imagecolorallocate($im, $this->color[ $c[$i] ][$j][0], $this->color[ $c[$i] ][$j][1], $this->color[ $c[$i] ][$j][2]); } } // Draw title imagestring($im, $titlefontsize, $this->padding + .5 * $textpadding + .5 * ($x_size + strlen($y_max) * imagefontwidth(2)) - .5 * strlen($this->title) * imagefontwidth($titlefontsize), $this->padding, $this->title, $color['text']); // Draw footer $footer = "[created ".date("H\hi T d.m.Y")."]"; imagestring($im, 1, 2 * $this->padding + $x_size + strlen($y_max) * imagefontwidth(2) + $textpadding - strlen($footer) * imagefontwidth(1), 3 * $this->padding + imagefontheight($titlefontsize) + $y_size + $textpadding + $x_max_len * imagefontwidth(2), $footer, $color['footer']); // Draw axis imageline($im, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding, 2 * $this->padding + imagefontheight($titlefontsize), $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size, $color['outline']); imageline($im, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + $x_size, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size, $color['outline']); // Draw X labels if( $x_labels>0 ) for( $i=0; $ipadding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / count($k)) * ($i + .5) - .5 * imagefontheight(2), 2 * $this->padding + imagefontheight($titlefontsize) + $y_size + $textpadding + strlen($k[$i]) * imagefontwidth(2), $k[$i], (in_array($k[$i], $x_label_mark)?$color['label_mark']:$color['label'])); // Draw Y labels if( $y_labels>0 ) for( $i=0; $i<=$y_max; $i+=$y_labels ) imagestring($im, 2, $this->padding + (strlen($y_max) - strlen($i)) * imagefontwidth(2), 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $i - .5 * imagefontheight(2), $i, (in_array($i, $y_label_mark)?$color['label_mark']:$color['label'])); // Draw graph for( $i=0; $idata[ $k[$i] ]>0 ) imagefilledrectangle($im, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / count($k)) * ($i) + 1, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $this->data[ $k[$i] ], $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / count($k)) * ($i + 1), 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - 1, $color['data'][0]); // Draw Y grid if( $y_grid>0 ) for( $i=$y_grid; $i<=$y_max; $i+=$y_grid ) imageline($im, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + 1, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $i, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + $x_size, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $i, (in_array($i, $y_grid_mark)?$color['grid_mark']:$color['grid'])); // Store image, read, and return it $tmpfile = tempnam($this->tmpdir, "phpchart"); imagepng($im, $tmpfile); imagedestroy($im); $image = file_get_contents($tmpfile); unlink($tmpfile); return $image; } /* * Create a line chart * - parameters: * - $x_size: width of the chart itself * - $y_size: height of the chart itself * - $x_labels: interval of showing labels on X axis (0 for none, -1 for auto) * - $y_labels: interval of showing labels on Y axis (0 for none, -1 for auto) * - $x_grid: interval of showing grid on X axis (0 for none, -1 for auto) * - $y_grid: interval of showing grid on Y axis (0 for none, -1 for auto) * - $x_grid_mark: array of x-values that should be marked with different color grid line * - $y_grid_mark: array of y-values that should be marked with different color grid line * - $x_label_mark: array of x-values where the label should be marked with different color * - $y_label_mark: array of y-values where the label should be marked with different color * - return value: * a PNG image, or 'false' in case of error */ public function line($x_size, $y_size, $x_labels=-1, $y_labels=-1, $x_grid=-1, $y_grid=-1, $x_grid_mark=array(), $y_grid_mark=array(), $x_label_mark=array(), $y_label_mark=array()) { $k = array_keys($this->data); $x_max_len = 0; for( $i=0; $idata[ $k[$i] ]); $textpadding = 3; // Check parameters if( $x_size<(imagefontwidth(1) * strlen("[created ".date("H\hi T d.m.Y")."]") - 2 * $this->padding) OR $x_size>10000 ) return false; if( $y_size<(imagefontwidth(1) * strlen("[created ".date("H\hi T d.m.Y")."]") - 2 * $this->padding) OR $y_size>10000 ) return false; if( $x_labels<-1 OR $x_labels>100 ) return false; if( $y_labels<-1 OR $y_labels>10000 ) return false; if( $x_grid<-1 OR $x_grid>100 ) return false; if( $y_grid<-1 OR $y_grid>10000 ) return false; if( !is_array($x_grid_mark) ) return false; if( !is_array($y_grid_mark) ) return false; if( !is_array($x_label_mark) ) return false; if( !is_array($y_label_mark) ) return false; // Calculate values for auto parameters if( $x_labels==-1 ) $x_labels = max(1, ceil(count($k) / ($x_size / imagefontheight(2)))); if( $y_labels==-1 ) $y_labels = max(1, ceil($y_max / ($y_size / imagefontheight(2)))); if( $x_grid==-1 ) $x_grid = $x_labels; #max(1, round(count($k) / ($x_size / 10))); if( $y_grid==-1 ) $y_grid = $y_labels; #max(1, round($y_max / ($y_size / 25))); // Find the biggest font size for the title that still fits in the image (max 5) $titlefontsize = 1; for( $i=1; $i<=5; $i++ ) if( imagefontwidth($i)*strlen($this->title)<($x_size + strlen($y_max) * imagefontwidth(2)) ) $titlefontsize = $i; // Create image $im = imagecreate(2 * $this->padding + $x_size + strlen($y_max) * imagefontwidth(2) + $textpadding, 3 * $this->padding + imagefontheight($titlefontsize) + $y_size + $x_max_len * imagefontwidth(2) + imagefontheight(1) + $textpadding); $this->size['line']['height'] = 3 * $this->padding + imagefontheight($titlefontsize) + $y_size + $x_max_len * imagefontwidth(2) + imagefontheight(1) + $textpadding; $this->size['line']['width'] = 2 * $this->padding + $x_size + strlen($y_max) * imagefontwidth(2) + $textpadding; // Initialize colors $c = array_keys($this->color); for( $i=0; $icolor[ $c[$i] ][0], $this->color[ $c[$i] ][1], $this->color[ $c[$i] ][2]); }else { for( $j=0; $jcolor[ $c[$i] ]); $j++ ) $color[ $c[$i] ][$j] = imagecolorallocate($im, $this->color[ $c[$i] ][$j][0], $this->color[ $c[$i] ][$j][1], $this->color[ $c[$i] ][$j][2]); } } // Draw title imagestring($im, $titlefontsize, $this->padding + .5 * $textpadding + .5 * ($x_size + strlen($y_max) * imagefontwidth(2)) - .5 * strlen($this->title) * imagefontwidth($titlefontsize), $this->padding, $this->title, $color['text']); // Draw footer $footer = "[created ".date("H\hi T d.m.Y")."]"; imagestring($im, 1, 2 * $this->padding + $x_size + strlen($y_max) * imagefontwidth(2) + $textpadding - strlen($footer) * imagefontwidth(1), 3 * $this->padding + imagefontheight($titlefontsize) + $y_size + $textpadding + $x_max_len * imagefontwidth(2), $footer, $color['footer']); // Draw axis imageline($im, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding, 2 * $this->padding + imagefontheight($titlefontsize), $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size, $color['outline']); imageline($im, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + $x_size, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size, $color['outline']); // Draw X labels if( $x_labels>0 ) for( $i=0; $ipadding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / (count($k) - 1)) * $i - .5 * imagefontheight(2), 2 * $this->padding + imagefontheight($titlefontsize) + $y_size + $textpadding + strlen($k[$i]) * imagefontwidth(2), $k[$i], (in_array($k[$i], $x_label_mark)?$color['label_mark']:$color['label'])); // Draw Y labels if( $y_labels>0 ) for( $i=0; $i<=$y_max; $i+=$y_labels ) imagestring($im, 2, $this->padding + (strlen($y_max) - strlen($i)) * imagefontwidth(2), 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $i - .5 * imagefontheight(2), $i, (in_array($i, $y_label_mark)?$color['label_mark']:$color['label'])); // Draw X grid if( $x_grid>0 ) for( $i=$x_grid; $ipadding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / (count($k) - 1)) * $i, 2 * $this->padding + imagefontheight($titlefontsize), $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / (count($k) - 1)) * $i, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - 1, (in_array($k[$i], $x_grid_mark)?$color['grid_mark']:$color['grid'])); // Draw Y grid if( $y_grid>0 ) for( $i=$y_grid; $i<=$y_max; $i++ ) if( ($i%$y_grid)==0 OR in_array($i, $y_grid_mark) ) imageline($im, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + 1, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $i, $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + $x_size, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $i, (in_array($i, $y_grid_mark)?$color['grid_mark']:$color['grid'])); // Draw graph for( $i=1; $ipadding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / (count($k) - 1)) * ($i - 1), 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $this->data[ $k[$i - 1] ], $this->padding + strlen($y_max) * imagefontwidth(2) + $textpadding + ($x_size / (count($k) - 1)) * $i, 2 * $this->padding + imagefontheight($titlefontsize) + $y_size - ($y_size / $y_max) * $this->data[ $k[$i] ], $color['data'][0]); // Store image, read, and return it $tmpfile = tempnam($this->tmpdir, "phpchart"); imagepng($im, $tmpfile); imagedestroy($im); $image = file_get_contents($tmpfile); unlink($tmpfile); return $image; } /* * Create a pie chart * - parameters: * - $diagonal: the diagonal of the pie. * - return value: * a PNG image, or 'false' in case of error */ public function pie($diagonal) { $k = array_keys($this->data); // Check parameters if( $diagonal<50 OR $diagonal>10000 ) return false; // Calculate the total sum of values $sum = 0; for( $i=0; $idata[ $k[$i] ]; // Find the biggest font size for the title that still fits in the image (max 5) $titlefontsize = 1; for( $i=1; $i<=5; $i++ ) if( imagefontwidth($i)*strlen($this->title)<$diagonal ) $titlefontsize = $i; // Create image $im = imagecreate(2 * $this->padding + $diagonal, 4 * $this->padding + imagefontheight($titlefontsize) + $diagonal + 20 * count($k) + imagefontheight(1)); $this->size['pie']['height'] = 4 * $this->padding + imagefontheight($titlefontsize) + $diagonal + 20 * count($k) + imagefontheight(1); $this->size['pie']['width'] = 2 * $this->padding + $diagonal; // Initialize colors $c = array_keys($this->color); for( $i=0; $icolor[ $c[$i] ][0], $this->color[ $c[$i] ][1], $this->color[ $c[$i] ][2]); }else { for( $j=0; $jcolor[ $c[$i] ]); $j++ ) $color[ $c[$i] ][$j] = imagecolorallocate($im, $this->color[ $c[$i] ][$j][0], $this->color[ $c[$i] ][$j][1], $this->color[ $c[$i] ][$j][2]); } } // Draw title imagestring($im, $titlefontsize, $this->padding + .5 * $diagonal - .5 * strlen($this->title) * imagefontwidth($titlefontsize), $this->padding, $this->title, $color['text']); // Draw footer $footer = "[created ".date("H\hi T d.m.Y")."]"; imagestring($im, 1, 2 * $this->padding + $diagonal - strlen($footer) * imagefontwidth(1), 4 * $this->padding + imagefontheight($titlefontsize) + $diagonal + 20 * count($k), $footer, $color['footer']); // Draw image $start = 0; $end = 0; for( $i=0; $idata[ $k[$i] ] / $sum * 360; // Draw index $label = $k[$i]." (".number_format(($end-$start)/3.6, 0)."%)"; imagefilledrectangle($im, $this->padding, 2 * $this->padding + imagefontheight($titlefontsize) + 20 * $i, $this->padding + 20, 2 * $this->padding + imagefontheight($titlefontsize) + 20 * $i + 15, $color['data'][$i]); imagerectangle($im, $this->padding, 2 * $this->padding + imagefontheight($titlefontsize) + 20 * $i, $this->padding + 20, 2 * $this->padding + imagefontheight($titlefontsize) + 20 * $i + 15, $color['outline']); imagestring($im, 3, $this->padding + 25, 2 * $this->padding + imagefontheight($titlefontsize) + 20 * $i + 2, $label, $color['label']); // Draw pie if( round($start)==0 AND round($end)==360 ) { imagefilledellipse($im, $this->padding + .5 * $diagonal, 3 * $this->padding + 20 * count($k) + imagefontheight($titlefontsize) + .5 * $diagonal, $diagonal, $diagonal, $color['data'][$i]); imageellipse($im, $this->padding + .5 * $diagonal, 3 * $this->padding + 20 * count($k) + imagefontheight($titlefontsize) + .5 * $diagonal, $diagonal, $diagonal, $color['outline']); }elseif( round($start)==round($end) ) { // do nothing, too small to be drawn }else { imagefilledarc($im, $this->padding + .5 * $diagonal, 3 * $this->padding + 20 * count($k) + imagefontheight($titlefontsize) + .5 * $diagonal, $diagonal, $diagonal, (round($start) - 90) % 360, (round($end) - 90) % 360, $color['data'][$i], 4); imagefilledarc($im, $this->padding + .5 * $diagonal, 3 * $this->padding + 20 * count($k) + imagefontheight($titlefontsize) + .5 * $diagonal, $diagonal, $diagonal, (round($start) - 90) % 360, (round($end) - 90) % 360, $color['outline'], 6); } } // Store image, read, and return it $tmpfile = tempnam($this->tmpdir, "phpchart"); imagepng($im, $tmpfile); imagedestroy($im); $image = file_get_contents($tmpfile); unlink($tmpfile); return $image; } /* * Check if the color is valid * - parameters: * $color: an array with 3 values denoting the RGB color (0-255) * - return value: * boolean: true for a correct color, false otherwise */ private function check_color($color) { if( is_array($color) AND count($color)==3 AND $color[0]>=0 AND $color[0]<=255 AND $color[1]>=0 AND $color[1]<=255 AND $color[2]>=0 AND $color[2]<=255 ) return true; else return false; } } ?>