Merge branch 'maint/7.0'
[ninja.git] / application / vendor / mfchart / BarChart.php
blob906062fa7a365e167d6fa7eeacea3ac22783be89
1 <?php
3 class BarChart extends Chart {
5 protected $type = NULL; // NULL, stacked, multiple
7 protected $bar_width = 25;
9 protected $approx_line_gap = 40; // how much space should be approximately between each line
11 protected $plot_bg_color = array('#fff', '#ccc'); // also supports arrays as array('#fff', '#333', '#432', ...) for gradients
13 protected $plot_bg_by_lines = FALSE; // if set to true bg colors will be rendered in areas separated by lines (useful for gradients)
15 protected $background_style = 'lines'; // [dotted / lines / NULL]
17 protected $legend_y = ''; // y axis legend
19 protected $legend_x = ''; // x axis legend
21 protected $bar_legend = TRUE; // display legend above the bars?
23 protected $vertical_bar_lines = false; // display vertical lines in the middle of the bars?
26 public function __construct($width=NULL, $height=NULL)
28 parent::__construct($width, $height);
30 $this->set_margins(5);
32 $this->colors['bar_color'] = array('#e0d62e', NULL, NULL);
33 $this->colors['bar_border_color'] = array('#747014', 10, NULL);
34 $this->colors['line_color'] = array('#dfdfdf', NULL, NULL); // primary color of lines
35 $this->colors['line_color2'] = array('#969696', NULL, NULL); // for short lines by the legend for example
38 public function set_bar_legend($value)
40 $this->bar_legend = $value;
43 public function set_background_style($value)
45 $this->background_style = $value;
48 public function set_legend_y($value)
50 $this->legend_y = $value;
53 public function set_legend_x($value)
55 $this->legend_x = $value;
58 // it's approximate values because gap will be exactly counted so it's nicely drawn. see ( --gap-line-- )
59 public function set_approx_line_gap($value)
61 $this->approx_line_gap = $value;
64 // also supports arays for gradients
65 public function set_plot_bg_color($values, $by_lines = FALSE)
67 $this->plot_bg_color = $values;
68 $this->plot_bg_by_lines = $by_lines;
71 public function set_bar_width($value)
73 $this->bar_width = $value;
76 public function draw()
78 parent::draw();
80 if ($this->type == 'stacked')
82 $values = array();
83 foreach ($this->values as $v)
84 $values[] = array_sum($v);
86 else
88 $values = $this->values;
91 $max_value = utilities::max($values);
92 $min_value = utilities::min($values);
94 $max = max($max_value, abs($min_value));
96 $box_points = imagettfbbox($this->font_size, 0, $this->font, '0');
97 $fheight = $box_points[3]-$box_points[5]; // font height
98 $vpp = $max/$this->height; // get approximate value per px -- exact value could be get only later so try it this way
99 $plus = ceil( $vpp * ($fheight + ($this->bar_legend ? $fheight : 0)) * 2.3 );
101 $max_value += $max_value > 0 ? $plus : 0; // add PLUS so the legend for bars is in the graph borders if there is any
102 $min_value -= $min_value < 0 ? $plus : 0; // subtract PLUS so the legend for bars is in the graph borders if there is any
104 $max = max($max_value, abs($min_value));
106 // get the next "nice" value for max
107 $pow = 0;
108 while (pow(10, ++$pow) < $max);
109 $step = pow(10, $pow-2);
111 if ($max_value > 0)
113 $from = round($max_value, -$pow+2);
114 if ($from < $max_value) // if it was rounded down
115 $from += $step;
116 $max_value = $from;
118 else
120 $max_value = 0;
123 // get the prev "nice" value for min
124 if ($min_value < 0)
126 $from = round(abs($min_value), -$pow+2);
127 if ($from < abs($min_value)) // if it was rounded down
128 $from += $step;
129 $min_value = -$from;
131 else
133 $min_value = 0;
136 # discard max_value calculated above and always keep
137 # it at 100 for the SLA reports
138 $max_value = 100;
140 // -- start: sizes of titles and labels of axis
142 // y axis title
143 if (!empty($this->legend_y))
145 $box_points = imagettfbbox($this->font_size, 0, $this->font, $this->legend_y);
146 $y_legend_width = $box_points[3]-$box_points[5]; // y-axis legend height
147 $y_legend_gap = $this->margin_left;
149 $this->margin_left += ($y_legend_width*2)-30; // modify size of the left margin
152 // y axis labels
153 $box_points = imagettfbbox($this->font_size, 0, $this->font, max($max_value, abs($min_value)).'-.0'); // - added for minus, . added for point, 0 added for decimal number
154 $y_legend_labels_width = $box_points[4]-$box_points[6]; // y-axis labels width
155 $y_legend_labels_height = $box_points[3]-$box_points[5]; // y-axis labels height
157 $this->margin_left += $y_legend_labels_width + 5; // modify size of the left margin
159 // x axis title
160 if (!empty($this->legend_x))
162 $box_points = imagettfbbox($this->font_size, 0, $this->font, $this->legend_x);
163 $x_legend_height = $box_points[3]-$box_points[5];
164 $x_legend_gap = $this->margin_bottom;
166 $this->margin_bottom += $x_legend_height*2 + 2;
169 // x axis labels
170 $box_points = imagettfbbox($this->font_size, 0, $this->font, implode(array_keys($this->values)));
171 $x_legend_labels_height = $box_points[3]-$box_points[5]; // y-axis labels height
173 $this->margin_bottom += $x_legend_labels_height + 5; // modify size of the left margin
175 // -- end: sizes of titles and labels of axis
177 if (!empty($this->legend))
178 $this->margin_right += 15;
180 $plot_sizes = $this->get_plot_area(); // size of the graph area
182 if (($max_value+abs($min_value)) == 0)
183 $ratio = $plot_sizes[1]; // default value when there are only zero data
184 else
185 $ratio = $plot_sizes[1]/($max_value+abs($min_value)); // how much value is for one pixel? -- sorry for the bad English
187 $horizontal_lines = floor($plot_sizes[1]/$this->approx_line_gap); // --gap-line-- count exact count of the horizontal lines
188 $horizontal_gap = $plot_sizes[1]/$horizontal_lines; // count exact space between these lines
191 // draw graph background
192 if (!is_array($this->plot_bg_color))
193 { // draw solid color
194 $plot_bg_color_rgb = utilities::hex2rgb($this->plot_bg_color);
195 $plot_bg_color = imagecolorallocate($this->image, $plot_bg_color_rgb[0], $plot_bg_color_rgb[1], $plot_bg_color_rgb[2]);
196 imagefilledrectangle($this->image, $this->margin_left, $this->margin_top, $this->width-1-$this->margin_right, $this->height-1-$this->margin_bottom, $plot_bg_color);
198 else
199 { // draw gradient
200 if (!$this->plot_bg_by_lines)
201 { // one for the whole bg
202 $gradient_height = $plot_sizes[1]; // how much should gradient take?
203 $goesto = 0;
205 else
206 { // one for each horizontal gap separated by y axis lines
207 $gradient_height = ceil($horizontal_gap); // how much should gradient take?
208 $goesto = $horizontal_lines-1;
210 for ($i=0; $i<=$goesto; $i++)
212 $color_index = ($i*2)%count($this->plot_bg_color);
213 $c1 = $this->plot_bg_color[$color_index]; // start color
214 $c2 = isset($this->plot_bg_color[$color_index+1]) ? $this->plot_bg_color[$color_index+1] : $this->plot_bg_color[$color_index]; // end color
215 $gradient = new Gradient(NULL, $plot_sizes[0], $gradient_height, 'vertical', $c1, $c2, 0); // make gradient
216 imagecopymerge($this->image, $gradient->image, $this->margin_left, $this->margin_top+$gradient_height*$i, 0, 0, $this->width-$this->margin_left-$this->margin_right, $gradient_height, 100); // copy the gradient to the graph
220 if (!empty($this->legend_y))
221 // draw y axis legend
222 utilities::imagestringbox($this->image, $this->font, $this->font_size, $y_legend_gap-10, $this->margin_top, $y_legend_gap+$y_legend_width, $this->height-$this->margin_bottom, ALIGN_CENTER, VALIGN_MIDDLE, 0, $this->legend_y, $this->get_color('font_color2'), TRUE);
223 if (!empty($this->legend_x))
224 // draw x axis legend
225 utilities::imagestringbox($this->image, $this->font, $this->font_size, $this->margin_left, $this->height-$x_legend_gap-$x_legend_height, $this->width-$this->margin_right, $this->height-$x_legend_gap, ALIGN_CENTER, VALIGN_MIDDLE, 0, $this->legend_x, $this->get_color('font_color2'));
227 $style = array($this->get_color('line_color'), $this->get_color('line_color'), $this->get_color('line_color'), $this->get_color('line_color'), $this->get_color('line_color'), IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT, IMG_COLOR_TRANSPARENT);
228 imagesetstyle($this->image, $style); // set style of the line
230 for ($i=0; $i<=$horizontal_lines; $i++)
232 $y = $this->height - $this->margin_bottom - $horizontal_gap * $i;
233 imageline($this->image, $this->margin_left, $y, $this->width-$this->margin_right, $y, IMG_COLOR_STYLED); // draw the line in graph
234 imageline($this->image, $this->margin_left-2, $y, $this->margin_left, $y, $this->get_color('line_color2')); // draw the graph by the legend
236 $v = round($horizontal_gap * $i / $ratio, 0) + $min_value;
237 $y_legend_y = $y-round($y_legend_labels_height/2);
239 utilities::imagestringbox($this->image, $this->font, $this->font_size, $this->margin_left-$y_legend_labels_width, $y_legend_y, $this->margin_left-6, $y_legend_y+$y_legend_labels_height, ALIGN_RIGHT, VALIGN_MIDDLE, 0, $v, $this->get_color('font_color'));
242 #die();
243 // draw graph borders
244 imageline($this->image, $this->margin_left, $this->margin_top, $this->margin_left, $this->height-$this->margin_bottom, $this->get_color('line_color2')); // left
245 imageline($this->image, $this->margin_left, $this->height-$this->margin_bottom, $this->width-$this->margin_right, $this->height-$this->margin_bottom, $this->get_color('line_color2')); // bottom
246 imageline($this->image, $this->margin_left+1, $this->margin_top, $this->width-$this->margin_right, $this->margin_top, $this->get_color('line_color')); // top
247 imageline($this->image, $this->width-$this->margin_right, $this->margin_top, $this->width-$this->margin_right, $this->height-$this->margin_bottom-1, $this->get_color('line_color')); // right
249 // draw the background image
250 if (!empty($this->background_style)) {
251 switch ($this->background_style)
253 case 'dotted':
254 $bgs_color = $this->get_color('shade_color2');
255 case 'lines':
256 $bgs_color = $this->get_color('shade_color3');
258 utilities::imagefilledrectanglestyled($this->image, $this->margin_left, $this->margin_top, $this->width-$this->margin_right, $this->height-$this->margin_bottom, $this->background_style, $bgs_color);
261 $zeroline = abs($min_value)*$ratio; // where should be y=0 placed?
262 imagefilledrectangle($this->image, $this->margin_left, $this->height-$this->margin_bottom-$zeroline, $this->width-$this->margin_right, $this->height-$this->margin_bottom-$zeroline, $this->get_color('shade_color')); // draw shade of bar
264 $this->draw_values($zeroline, $ratio); // draw bars
265 $this->draw_legend('bar_color'); // draw box with the legend
268 protected function draw_values($zeroline, $ratio)
270 $plot_sizes = $this->get_plot_area();
271 $font_bar_legend = $this->font_size < 1 ? $this->font_size : $this->font_size-1;
273 $total_bars = count($this->values); // count of all bars
274 $gap = ($plot_sizes[0] - $total_bars*$this->bar_width ) / ($total_bars+1); // gap between bars
277 $i=0;
278 foreach ($this->values AS $key => $v)
280 $x1 = $this->margin_left + $gap + $i*($gap+$this->bar_width);
281 $x2 = $x1 + $this->bar_width;
282 $y2 = $this->height - $this->margin_bottom - $zeroline;
283 $y1 = $y2 - $v*$ratio;
285 if ($this->vertical_bar_lines)
286 imageline($this->image, $x1+$this->bar_width/2, $this->margin_top-1, $x1+$this->bar_width/2, $this->height-$this->margin_bottom-1, IMG_COLOR_STYLED);
288 imagefilledrectangle($this->image, $x1, $y1, $x2, $y2, $this->get_color('bar_color')); // draw bar
289 $this->add_occupied($x1, $y1, $x2, $y2);
291 if ($this->get_color('bar_border_color'))
292 { // draw bar border
293 imageline($this->image, $x1, $y1, $x1, $y2, $this->get_color('bar_border_color')); // left
294 imageline($this->image, $x1, $y1, $x2, $y1, $this->get_color('bar_border_color')); // top
295 imageline($this->image, $x2, $y1, $x2, $y2, $this->get_color('bar_border_color')); // right
298 if ($v != 0)
299 imagefilledrectangle($this->image, $x2, $y1+($v > 0 ? 1 : -1), $x2+1, $y2, $this->get_color('shade_color')); // draw shade of bar
301 $box_points = imagettfbbox($this->font_size, 0, $this->font, $v);
302 $bar_middle = $x1 + $this->bar_width/2;
303 $bar_legend_hwidth = ($box_points[4]-$box_points[6]) / 2;
304 $fheight = $box_points[3]-$box_points[5];
306 // bar legend
307 if ($this->bar_legend)
309 if ($v >= 0)
311 utilities::imagestringbox($this->image, $this->font, $font_bar_legend, $bar_middle-$bar_legend_hwidth, $y1-$fheight-5, $bar_middle+$bar_legend_hwidth, $y1, ALIGN_CENTER, VALIGN_MIDDLE, 0, $v, $this->get_color('font_color3'));
312 $this->add_occupied($bar_middle-$bar_legend_hwidth, $y1-$fheight-5, $bar_middle+$bar_legend_hwidth, $y1);
314 else
316 utilities::imagestringbox($this->image, $this->font, $font_bar_legend, $bar_middle-$bar_legend_hwidth, $y1+5, $bar_middle+$bar_legend_hwidth, $y1+$fheight+5, ALIGN_CENTER, VALIGN_MIDDLE, 0, $v, $this->get_color('font_color3'));
317 $this->add_occupied($bar_middle-$bar_legend_hwidth, $y1+5, $bar_middle+$bar_legend_hwidth, $y1+$fheight+5);
322 $box_points = imagettfbbox($this->font_size, 0, $this->font, $key);
323 $y_legend_hwidth = ($box_points[4]-$box_points[6]) / 2;
325 // x axis legend
326 utilities::imagestringbox($this->image, $this->font, $this->font_size, $bar_middle-$y_legend_hwidth, $this->margin_top+$plot_sizes[1]+5, $bar_middle+$y_legend_hwidth, $this->margin_top+$plot_sizes[1]+5+$fheight, ALIGN_CENTER, VALIGN_MIDDLE, 0, $key, $this->get_color('font_color'));
328 $i++;