1 | <?php |
---|
2 | /*======================================================================= |
---|
3 | // File: JPGRAPH_BAR.PHP |
---|
4 | // Description: Bar plot extension for JpGraph |
---|
5 | // Created: 2001-01-08 |
---|
6 | // Author: Johan Persson (johanp@aditus.nu) |
---|
7 | // Ver: $Id: jpgraph_bar.php 18250 2005-05-07 14:13:43Z ralfbecker $ |
---|
8 | // |
---|
9 | // License: This code is released under QPL |
---|
10 | // Copyright (C) 2001 Johan Persson |
---|
11 | //======================================================================== |
---|
12 | */ |
---|
13 | |
---|
14 | //=================================================== |
---|
15 | // CLASS Gradient |
---|
16 | // Description: Handles gradient fills. This is to be |
---|
17 | // considered a "friend" class of Class Image. The |
---|
18 | // Gradient takes care of production a gradient fill for |
---|
19 | // the bars. |
---|
20 | //=================================================== |
---|
21 | class Gradient { |
---|
22 | var $img=null; |
---|
23 | //--------------- |
---|
24 | // CONSTRUCTOR |
---|
25 | function Gradient(&$img) { |
---|
26 | $this->img = $img; |
---|
27 | } |
---|
28 | |
---|
29 | //--------------- |
---|
30 | // PUBLIC METHODS |
---|
31 | // Produce a gradient filled rectangle with a smooth transition between |
---|
32 | // two colors. |
---|
33 | // ($xl,$yt) Top left corner |
---|
34 | // ($xr,$yb) Bottom right |
---|
35 | // $from_color Starting color in gradient |
---|
36 | // $to_color End color in the gradient |
---|
37 | // $style Which way is the gradient oriented? |
---|
38 | function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) { |
---|
39 | switch( $style ) { |
---|
40 | case 1: // HORIZONTAL |
---|
41 | $steps = abs($xr-$xl); |
---|
42 | $delta = $xr>=$xl ? 1 : -1; |
---|
43 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
44 | for( $i=0, $x=$xl; $i<$steps; ++$i ) { |
---|
45 | $this->img->current_color = $colors[$i]; |
---|
46 | $this->img->Line($x,$yt,$x,$yb); |
---|
47 | $x += $delta; |
---|
48 | } |
---|
49 | break; |
---|
50 | |
---|
51 | case 2: // VERTICAL |
---|
52 | $steps = abs($yb-$yt); |
---|
53 | $delta = $yb>=$yt ? 1 : -1; |
---|
54 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
55 | for($i=0,$y=$yt; $i<$steps; ++$i) { |
---|
56 | $this->img->current_color = $colors[$i]; |
---|
57 | $this->img->Line($xl,$y,$xr,$y); |
---|
58 | $y += $delta; |
---|
59 | } |
---|
60 | break; |
---|
61 | |
---|
62 | case 3: // VERTICAL FROM MIDDLE |
---|
63 | $steps = abs($yb-$yt)/2; |
---|
64 | $delta = $yb>=$yt ? 1 : -1; |
---|
65 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
66 | for($y=$yt, $i=0; $i<$steps; ++$i) { |
---|
67 | $this->img->current_color = $colors[$i]; |
---|
68 | $this->img->Line($xl,$y,$xr,$y); |
---|
69 | $y += $delta; |
---|
70 | } |
---|
71 | --$i; |
---|
72 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
73 | $this->img->current_color = $colors[$i]; |
---|
74 | $this->img->Line($xl,$y,$xr,$y); |
---|
75 | $y += $delta; |
---|
76 | } |
---|
77 | $this->img->Line($xl,$y,$xr,$y); |
---|
78 | break; |
---|
79 | |
---|
80 | case 4: // HORIZONTAL FROM MIDDLE |
---|
81 | $steps = abs($xr-$xl)/2; |
---|
82 | $delta = $xr>=$xl ? 1 : -1; |
---|
83 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
84 | for($x=$xl, $i=0; $i<$steps; ++$i) { |
---|
85 | $this->img->current_color = $colors[$i]; |
---|
86 | $this->img->Line($x,$yb,$x,$yt); |
---|
87 | $x += $delta; |
---|
88 | } |
---|
89 | --$i; |
---|
90 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
91 | $this->img->current_color = $colors[$i]; |
---|
92 | $this->img->Line($x,$yb,$x,$yt); |
---|
93 | $x += $delta; |
---|
94 | } |
---|
95 | $this->img->Line($x,$yb,$x,$yt); |
---|
96 | break; |
---|
97 | |
---|
98 | case 6: // HORIZONTAL WIDER MIDDLE |
---|
99 | $steps = abs($xr-$xl)/3; |
---|
100 | $delta = $xr>=$xl ? 1 : -1; |
---|
101 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
102 | for($x=$xl, $i=0; $i<$steps; ++$i) { |
---|
103 | $this->img->current_color = $colors[$i]; |
---|
104 | $this->img->Line($x,$yb,$x,$yt); |
---|
105 | $x += $delta; |
---|
106 | } |
---|
107 | --$i; |
---|
108 | $this->img->current_color = $colors[$i]; |
---|
109 | for($j=0; $j< $steps; ++$j) { |
---|
110 | $this->img->Line($x,$yb,$x,$yt); |
---|
111 | $x += $delta; |
---|
112 | } |
---|
113 | |
---|
114 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
115 | $this->img->current_color = $colors[$i]; |
---|
116 | $this->img->Line($x,$yb,$x,$yt); |
---|
117 | $x += $delta; |
---|
118 | } |
---|
119 | break; |
---|
120 | |
---|
121 | case 7: // VERTICAL WIDER MIDDLE |
---|
122 | $steps = abs($yb-$yt)/3; |
---|
123 | $delta = $yb>=$yt? 1 : -1; |
---|
124 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
125 | for($y=$yt, $i=0; $i<$steps; ++$i) { |
---|
126 | $this->img->current_color = $colors[$i]; |
---|
127 | $this->img->Line($xl,$y,$xr,$y); |
---|
128 | $y += $delta; |
---|
129 | } |
---|
130 | --$i; |
---|
131 | $this->img->current_color = $colors[$i]; |
---|
132 | for($j=0; $j< $steps; ++$j) { |
---|
133 | $this->img->Line($xl,$y,$xr,$y); |
---|
134 | $y += $delta; |
---|
135 | } |
---|
136 | for($j=0; $j<$steps; ++$j, --$i) { |
---|
137 | $this->img->current_color = $colors[$i]; |
---|
138 | $this->img->Line($xl,$y,$xr,$y); |
---|
139 | $y += $delta; |
---|
140 | } |
---|
141 | break; |
---|
142 | |
---|
143 | case 5: // Rectangle |
---|
144 | $steps = floor(min(($yb-$yt)+1,($xr-$xl)+1)/2); |
---|
145 | $this->GetColArray($from_color,$to_color,$steps,$colors); |
---|
146 | $dx = ($xr-$xl)/2; |
---|
147 | $dy = ($yb-$yt)/2; |
---|
148 | $x=$xl;$y=$yt;$x2=$xr;$y2=$yb; |
---|
149 | for($x=$xl, $i=0; $x<$xl+$dx && $y<$yt+$dy ; ++$x, ++$y, --$x2, --$y2, ++$i) { |
---|
150 | assert($i<count($colors)); |
---|
151 | $this->img->current_color = $colors[$i]; |
---|
152 | $this->img->Rectangle($x,$y,$x2,$y2); |
---|
153 | } |
---|
154 | $this->img->Line($x,$y,$x2,$y2); |
---|
155 | break; |
---|
156 | |
---|
157 | default: |
---|
158 | die("JpGraph Error: Unknown gradient style (=$style)."); |
---|
159 | break; |
---|
160 | } |
---|
161 | } |
---|
162 | |
---|
163 | //--------------- |
---|
164 | // PRIVATE METHODS |
---|
165 | // Add to the image color map the necessary colors to do the transition |
---|
166 | // between the two colors using $numcolors intermediate colors |
---|
167 | function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) { |
---|
168 | if( $arr_size==0 ) return; |
---|
169 | // If color is give as text get it's corresponding r,g,b values |
---|
170 | $from_color = $this->img->rgb->Color($from_color); |
---|
171 | $to_color = $this->img->rgb->Color($to_color); |
---|
172 | |
---|
173 | $rdelta=($to_color[0]-$from_color[0])/$numcols; |
---|
174 | $gdelta=($to_color[1]-$from_color[1])/$numcols; |
---|
175 | $bdelta=($to_color[2]-$from_color[2])/$numcols; |
---|
176 | $stepspercolor = $numcols/$arr_size; |
---|
177 | $prevcolnum = -1; |
---|
178 | for ($i=0; $i<$arr_size; ++$i) { |
---|
179 | $colnum = floor($stepspercolor*$i); |
---|
180 | if ( $colnum == $prevcolnum ) |
---|
181 | $colors[$i] = $colidx; |
---|
182 | else { |
---|
183 | $r = floor($from_color[0] + $colnum*$rdelta); |
---|
184 | $g = floor($from_color[1] + $colnum*$gdelta); |
---|
185 | $b = floor($from_color[2] + $colnum*$bdelta); |
---|
186 | $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b)); |
---|
187 | $colors[$i] = $colidx; |
---|
188 | } |
---|
189 | $prevcolnum = $colnum; |
---|
190 | } |
---|
191 | } |
---|
192 | } // Class |
---|
193 | |
---|
194 | |
---|
195 | //=================================================== |
---|
196 | // CLASS BarPlot |
---|
197 | // Description: Main code to produce a bar plot |
---|
198 | //=================================================== |
---|
199 | class BarPlot extends Plot { |
---|
200 | var $width=0.4; // in percent of major ticks |
---|
201 | var $abswidth=-1; // Width in absolute pixels |
---|
202 | var $fill_color="lightblue"; // Default is to fill with light blue |
---|
203 | var $ybase=0; // Bars start at 0 |
---|
204 | var $align="left"; |
---|
205 | var $grad=false,$grad_style=1; |
---|
206 | var $grad_fromcolor=array(50,50,200),$grad_tocolor=array(255,255,255); |
---|
207 | var $bar_shadow=false; |
---|
208 | var $bar_shadow_color="black"; |
---|
209 | var $bar_shadow_hsize=3,$bar_shadow_vsize=3; |
---|
210 | var $show_value=false,$show_value_format="%d",$show_value_angle=0; |
---|
211 | var $show_value_ff=FF_FONT1,$show_value_fs=FS_NORMAL,$show_value_fsize=12; |
---|
212 | var $show_value_color="black",$show_value_margin=3; |
---|
213 | |
---|
214 | //--------------- |
---|
215 | // CONSTRUCTOR |
---|
216 | function BarPlot(&$datay,$datax=false) { |
---|
217 | $this->Plot($datay,$datax); |
---|
218 | ++$this->numpoints; |
---|
219 | } |
---|
220 | |
---|
221 | //--------------- |
---|
222 | // PUBLIC METHODS |
---|
223 | |
---|
224 | // Set a drop shadow for the bar (or rather an "up-right" shadow) |
---|
225 | function SetShadow($color="black",$hsize=3,$vsize=3) { |
---|
226 | $this->bar_shadow=true; |
---|
227 | $this->bar_shadow_color=$color; |
---|
228 | $this->bar_shadow_vsize=$vsize; |
---|
229 | $this->bar_shadow_hsize=$hsize; |
---|
230 | |
---|
231 | // Adjust the value margin to compensate for shadow |
---|
232 | $this->show_value_margin += $vsize; |
---|
233 | } |
---|
234 | |
---|
235 | // Display the value of the bar at the top of bar |
---|
236 | function ShowValue($f=true) { |
---|
237 | $this->show_value = $f; |
---|
238 | } |
---|
239 | |
---|
240 | function SetValueFormat($format="%d",$angle=0) { |
---|
241 | $this->show_value_format = $format; |
---|
242 | $this->show_value_angle = $angle; |
---|
243 | } |
---|
244 | |
---|
245 | function SetValueFont($ff=FF_FONT1,$fs=FS_NORMAL,$size=10) { |
---|
246 | $this->show_value_ff=$ff; |
---|
247 | $this->show_value_fs=$fs; |
---|
248 | $this->show_value_fsize=$size; |
---|
249 | } |
---|
250 | |
---|
251 | function SetValueColor($color) { |
---|
252 | $this->show_value_color=$color; |
---|
253 | } |
---|
254 | |
---|
255 | function SetValueMargin($m) { |
---|
256 | $this->show_value_margin=$m; |
---|
257 | } |
---|
258 | |
---|
259 | function SetYStart($y) { |
---|
260 | die("JpGraph Error: Deprecated function SetYStart. Use SetYMin() instead."); |
---|
261 | } |
---|
262 | |
---|
263 | // DEPRECATED use SetYBase instead |
---|
264 | function SetYMin($y) { |
---|
265 | $this->ybase=$y; |
---|
266 | } |
---|
267 | |
---|
268 | // |
---|
269 | function SetYBase($y) { |
---|
270 | $this->ybase=$y; |
---|
271 | } |
---|
272 | |
---|
273 | function Legend(&$graph) { |
---|
274 | if( $this->fill_color && $this->legend!="" ) { |
---|
275 | if( is_array($this->fill_color) ) |
---|
276 | $graph->legend->Add($this->legend,$this->fill_color[0]); |
---|
277 | else |
---|
278 | $graph->legend->Add($this->legend,$this->fill_color); |
---|
279 | } |
---|
280 | } |
---|
281 | |
---|
282 | // Gets called before any axis are stroked |
---|
283 | function PreStrokeAdjust(&$graph) { |
---|
284 | parent::PreStrokeAdjust($graph); |
---|
285 | |
---|
286 | // For a "text" X-axis scale we will adjust the |
---|
287 | // display of the bars a little bit. |
---|
288 | if( substr($graph->axtype,0,3)=="tex" ) { |
---|
289 | // Position the ticks between the bars |
---|
290 | $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0); |
---|
291 | |
---|
292 | // Position the labels under each bar in the middle of the |
---|
293 | // major steps. |
---|
294 | $graph->SetTextScaleOff(0.5-$this->width/2); |
---|
295 | } |
---|
296 | else { |
---|
297 | // We only set an absolute width for linear and int scale |
---|
298 | // for text scale the width will be set to a fraction of |
---|
299 | // the majstep width. |
---|
300 | if( $this->abswidth == -1 ) // Not set |
---|
301 | // set width to a visuable sensible default |
---|
302 | $this->abswidth = $graph->img->plotwidth/(2*count($this->coords[0])); |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | function Min() { |
---|
307 | $m = parent::Min(); |
---|
308 | if( $m[1] >= $this->ybase ) |
---|
309 | $m[1] = $this->ybase; |
---|
310 | return $m; |
---|
311 | } |
---|
312 | |
---|
313 | function Max() { |
---|
314 | $m = parent::Max(); |
---|
315 | if( $m[1] <= $this->ybase ) |
---|
316 | $m[1] = $this->ybase; |
---|
317 | return $m; |
---|
318 | } |
---|
319 | |
---|
320 | // Specify width as fractions of the major stepo size |
---|
321 | function SetWidth($w) { |
---|
322 | assert($w > 0 && $w <= 1.0); |
---|
323 | $this->width=$w; |
---|
324 | } |
---|
325 | |
---|
326 | // Specify width in absolute pixels. If specified this |
---|
327 | // overrides SetWidth() |
---|
328 | function SetAbsWidth($w) { |
---|
329 | $this->abswidth=$w; |
---|
330 | } |
---|
331 | |
---|
332 | function SetAlign($a) { |
---|
333 | $this->align=$a; |
---|
334 | } |
---|
335 | |
---|
336 | function SetNoFill() { |
---|
337 | $this->grad = false; |
---|
338 | $this->fill_color=false; |
---|
339 | } |
---|
340 | |
---|
341 | function SetFillColor($c) { |
---|
342 | $this->fill_color=$c; |
---|
343 | } |
---|
344 | |
---|
345 | function SetFillGradient($from_color,$to_color,$style) { |
---|
346 | $this->grad=true; |
---|
347 | $this->grad_fromcolor=$from_color; |
---|
348 | $this->grad_tocolor=$to_color; |
---|
349 | $this->grad_style=$style; |
---|
350 | } |
---|
351 | |
---|
352 | function Stroke(&$img,&$xscale,&$yscale) { |
---|
353 | |
---|
354 | $numpoints = count($this->coords[0]); |
---|
355 | if( isset($this->coords[1]) ) { |
---|
356 | if( count($this->coords[1])!=$numpoints ) |
---|
357 | die("JpGraph Error: Number of X and Y points are not equal.<br> |
---|
358 | Number of X-points:".count($this->coords[1])."<br> |
---|
359 | Number of Y-points:$numpoints"); |
---|
360 | else |
---|
361 | $exist_x = true; |
---|
362 | } |
---|
363 | else |
---|
364 | $exist_x = false; |
---|
365 | |
---|
366 | |
---|
367 | $numbars=count($this->coords[0]); |
---|
368 | if( $yscale->scale[0] >= 0 ) |
---|
369 | $zp=$yscale->scale_abs[0]; |
---|
370 | else |
---|
371 | $zp=$yscale->Translate(0.0); |
---|
372 | |
---|
373 | if( $this->abswidth > -1 ) |
---|
374 | $abswidth=$this->abswidth; |
---|
375 | else |
---|
376 | $abswidth=round($this->width*$xscale->scale_factor,0); |
---|
377 | |
---|
378 | |
---|
379 | for($i=0; $i<$numbars; $i++) { |
---|
380 | if( $exist_x ) $x=$this->coords[1][$i]; |
---|
381 | else $x=$i; |
---|
382 | |
---|
383 | $x=$xscale->Translate($x); |
---|
384 | |
---|
385 | if($this->align=="center") |
---|
386 | $x -= $abswidth/2; |
---|
387 | elseif($this->align=="right") |
---|
388 | $x -= $abswidth; |
---|
389 | $pts=array( |
---|
390 | $x,$zp, |
---|
391 | $x,$yscale->Translate($this->coords[0][$i]), |
---|
392 | $x+$abswidth,$yscale->Translate($this->coords[0][$i]), |
---|
393 | $x+$abswidth,$zp); |
---|
394 | if( $this->grad ) { |
---|
395 | $grad = new Gradient($img); |
---|
396 | $grad->FilledRectangle($pts[2],$pts[3], |
---|
397 | $pts[6],$pts[7], |
---|
398 | $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style); |
---|
399 | } |
---|
400 | elseif( !empty($this->fill_color) ) { |
---|
401 | if(is_array($this->fill_color)) { |
---|
402 | $img->PushColor($this->fill_color[$i % count($this->fill_color)]); |
---|
403 | } else { |
---|
404 | $img->PushColor($this->fill_color); |
---|
405 | } |
---|
406 | $img->FilledPolygon($pts); |
---|
407 | $img->PopColor(); |
---|
408 | } |
---|
409 | |
---|
410 | // Remember value of this bar |
---|
411 | $val=$this->coords[0][$i]; |
---|
412 | |
---|
413 | if( $this->bar_shadow && $val != 0 ) { |
---|
414 | $ssh = $this->bar_shadow_hsize; |
---|
415 | $ssv = $this->bar_shadow_vsize; |
---|
416 | // Create points to create a "upper-right" shadow |
---|
417 | if( $val > 0 ) { |
---|
418 | $sp[0]=$pts[6]; $sp[1]=$pts[7]; |
---|
419 | $sp[2]=$pts[4]; $sp[3]=$pts[5]; |
---|
420 | $sp[4]=$pts[2]; $sp[5]=$pts[3]; |
---|
421 | $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; |
---|
422 | $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; |
---|
423 | $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; |
---|
424 | } |
---|
425 | elseif( $val < 0 ) { |
---|
426 | $sp[0]=$pts[4]; $sp[1]=$pts[5]; |
---|
427 | $sp[2]=$pts[6]; $sp[3]=$pts[7]; |
---|
428 | $sp[4]=$pts[0]; $sp[5]=$pts[1]; |
---|
429 | $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv; |
---|
430 | $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv; |
---|
431 | $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv; |
---|
432 | } |
---|
433 | |
---|
434 | $img->PushColor($this->bar_shadow_color); |
---|
435 | $img->FilledPolygon($sp); |
---|
436 | $img->PopColor(); |
---|
437 | } |
---|
438 | |
---|
439 | // Stroke the outline of the bar |
---|
440 | if( is_array($this->color) ) |
---|
441 | $img->SetColor($this->color[$i % count($this->color)]); |
---|
442 | else |
---|
443 | $img->SetColor($this->color); |
---|
444 | $img->SetLineWeight($this->weight); |
---|
445 | $img->Polygon($pts); |
---|
446 | |
---|
447 | if( $this->show_value) { |
---|
448 | $sval=sprintf($this->show_value_format,$val); |
---|
449 | $txt = new Text($sval); |
---|
450 | $txt->SetFont($this->show_value_ff,$this->show_value_fs,$this->show_value_fsize); |
---|
451 | $txt->SetColor($this->show_value_color); |
---|
452 | $x=$pts[2]+($pts[4]-$pts[2])/2; |
---|
453 | if($this->bar_shadow) |
---|
454 | $x += $ssh; |
---|
455 | |
---|
456 | if( $val >= 0 ) { |
---|
457 | $txt->Pos($x,$pts[3]-$this->show_value_margin); |
---|
458 | $txt->Align("center","bottom"); |
---|
459 | } |
---|
460 | else { |
---|
461 | $txt->Pos($x,$pts[3]+$this->show_value_margin); |
---|
462 | $txt->Align("center","top"); |
---|
463 | } |
---|
464 | $txt->SetOrientation($this->show_value_angle); |
---|
465 | $txt->Stroke($img); |
---|
466 | } |
---|
467 | |
---|
468 | // Create the client side image map |
---|
469 | $this->csimareas.= "<area shape=\"rect\" coords=\""; |
---|
470 | // Hmmm, this is fishy. Fixes a bug in Opera whereby if Y2<Y1 or X2<X1 the csim doesn't work |
---|
471 | if ($pts[3] < $pts[7]) { |
---|
472 | if ($pts[2] < $pts[6]) |
---|
473 | $this->csimareas .= "$pts[2], $pts[3], $pts[6], $pts[7]\""; |
---|
474 | else |
---|
475 | $this->csimareas .= "$pts[6], $pts[3], $pts[2], $pts[7]\""; |
---|
476 | } else { |
---|
477 | if ($pts[2] < $pts[6]) |
---|
478 | $this->csimareas .= "$pts[2], $pts[7], $pts[6], $pts[3]\""; |
---|
479 | else |
---|
480 | $this->csimareas .= "$pts[6], $pts[7], $pts[2], $pts[3]\""; |
---|
481 | } |
---|
482 | if( !empty($this->csimtargets[$i]) ) |
---|
483 | $this->csimareas .= " href=\"".$this->csimtargets[$i]."\""; |
---|
484 | if( !empty($this->csimalts[$i]) ) { |
---|
485 | $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]); |
---|
486 | $this->csimareas .= " alt=\"$sval\" title=\"$sval\" "; |
---|
487 | } |
---|
488 | $this->csimareas .= ">\r\n"; |
---|
489 | } |
---|
490 | return true; |
---|
491 | } |
---|
492 | } // Class |
---|
493 | |
---|
494 | //=================================================== |
---|
495 | // CLASS GroupBarPlot |
---|
496 | // Description: Produce grouped bar plots |
---|
497 | //=================================================== |
---|
498 | class GroupBarPlot extends BarPlot { |
---|
499 | var $plots; |
---|
500 | var $width=0.7; |
---|
501 | var $nbrplots=0; |
---|
502 | var $numpoints; |
---|
503 | //--------------- |
---|
504 | // CONSTRUCTOR |
---|
505 | function GroupBarPlot($plots) { |
---|
506 | $this->plots = $plots; |
---|
507 | $this->nbrplots = count($plots); |
---|
508 | $this->numpoints = $plots[0]->numpoints; |
---|
509 | } |
---|
510 | |
---|
511 | //--------------- |
---|
512 | // PUBLIC METHODS |
---|
513 | function Legend(&$graph) { |
---|
514 | $n = count($this->plots); |
---|
515 | for($i=0; $i<$n; ++$i) |
---|
516 | $this->plots[$i]->Legend($graph); |
---|
517 | } |
---|
518 | |
---|
519 | function Min() { |
---|
520 | list($xmin,$ymin) = $this->plots[0]->Min(); |
---|
521 | $n = count($this->plots); |
---|
522 | for($i=0; $i<$n; ++$i) { |
---|
523 | list($xm,$ym) = $this->plots[$i]->Min(); |
---|
524 | $xmin = max($xmin,$xm); |
---|
525 | $ymin = min($ymin,$ym); |
---|
526 | } |
---|
527 | return array($xmin,$ymin); |
---|
528 | } |
---|
529 | |
---|
530 | function Max() { |
---|
531 | list($xmax,$ymax) = $this->plots[0]->Max(); |
---|
532 | $n = count($this->plots); |
---|
533 | for($i=0; $i<$n; ++$i) { |
---|
534 | list($xm,$ym) = $this->plots[$i]->Max(); |
---|
535 | $xmax = max($xmax,$xm); |
---|
536 | $ymax = max($ymax,$ym); |
---|
537 | } |
---|
538 | return array($xmax,$ymax); |
---|
539 | } |
---|
540 | |
---|
541 | function GetCSIMareas() { |
---|
542 | $n = count($this->plots); |
---|
543 | for($i=0; $i<$n; ++$i) { |
---|
544 | $csimareas.= $this->plots[$i]->csimareas; |
---|
545 | } |
---|
546 | return $csimareas; |
---|
547 | } |
---|
548 | |
---|
549 | // Stroke all the bars next to each other |
---|
550 | function Stroke(&$img,&$xscale,&$yscale) { |
---|
551 | $tmp=$xscale->off; |
---|
552 | $n = count($this->plots); |
---|
553 | for( $i=0; $i<$n; ++$i ) { |
---|
554 | $this->plots[$i]->ymin=$this->ybase; |
---|
555 | $this->plots[$i]->SetWidth($this->width/$this->nbrplots); |
---|
556 | $xscale->off = $tmp+$i*round($xscale->ticks->major_step*$xscale->scale_factor*$this->width/$this->nbrplots); |
---|
557 | $this->plots[$i]->Stroke($img,$xscale,$yscale); |
---|
558 | } |
---|
559 | $xscale->off=$tmp; |
---|
560 | } |
---|
561 | } // Class |
---|
562 | |
---|
563 | //=================================================== |
---|
564 | // CLASS AccBarPlot |
---|
565 | // Description: Produce accumulated bar plots |
---|
566 | //=================================================== |
---|
567 | class AccBarPlot extends BarPlot { |
---|
568 | var $plots=null,$nbrplots=0,$numpoints=0; |
---|
569 | //--------------- |
---|
570 | // CONSTRUCTOR |
---|
571 | function AccBarPlot($plots) { |
---|
572 | $this->plots = $plots; |
---|
573 | $this->nbrplots = count($plots); |
---|
574 | $this->numpoints = $plots[0]->numpoints; |
---|
575 | } |
---|
576 | |
---|
577 | //--------------- |
---|
578 | // PUBLIC METHODS |
---|
579 | function Legend(&$graph) { |
---|
580 | $n = count($this->plots); |
---|
581 | for( $i=0; $i<$n; ++$i ) |
---|
582 | $this->plots[$i]->Legend($graph); |
---|
583 | } |
---|
584 | |
---|
585 | function Max() { |
---|
586 | list($xmax) = $this->plots[0]->Max(); |
---|
587 | $nmax=0; |
---|
588 | for($i=0; $i<count($this->plots); ++$i) { |
---|
589 | $n = count($this->plots[$i]->coords[0]); |
---|
590 | $nmax = max($nmax,$n); |
---|
591 | list($x) = $this->plots[$i]->Max(); |
---|
592 | $xmax = Max($xmax,$x); |
---|
593 | } |
---|
594 | for( $i = 0; $i < $nmax; $i++ ) { |
---|
595 | // Get y-value for bar $i by adding the |
---|
596 | // individual bars from all the plots added. |
---|
597 | // It would be wrong to just add the |
---|
598 | // individual plots max y-value since that |
---|
599 | // would in most cases give to large y-value. |
---|
600 | $y=$this->plots[0]->coords[0][$i]; |
---|
601 | for( $j = 1; $j < $this->nbrplots; $j++ ) { |
---|
602 | $y += $this->plots[ $j ]->coords[0][$i]; |
---|
603 | } |
---|
604 | $ymax[$i] = $y; |
---|
605 | } |
---|
606 | $ymax = max($ymax); |
---|
607 | |
---|
608 | // Bar always start at baseline |
---|
609 | if( $ymax <= $this->ybase ) |
---|
610 | $ymax = $this->ybase; |
---|
611 | return array($xmax,$ymax); |
---|
612 | } |
---|
613 | |
---|
614 | function Min() { |
---|
615 | $nmax=0; |
---|
616 | list($xmin,$ysetmin) = $this->plots[0]->Min(); |
---|
617 | for($i=0; $i<count($this->plots); ++$i) { |
---|
618 | $n = count($this->plots[$i]->coords[0]); |
---|
619 | $nmax = max($nmax,$n); |
---|
620 | list($x,$y) = $this->plots[$i]->Min(); |
---|
621 | $xmin = Min($xmin,$x); |
---|
622 | $ysetmin = Min($y,$ysetmin); |
---|
623 | } |
---|
624 | for( $i = 0; $i < $nmax; $i++ ) { |
---|
625 | // Get y-value for bar $i by adding the |
---|
626 | // individual bars from all the plots added. |
---|
627 | // It would be wrong to just add the |
---|
628 | // individual plots max y-value since that |
---|
629 | // would in most cases give to large y-value. |
---|
630 | $y=$this->plots[0]->coords[0][$i]; |
---|
631 | for( $j = 1; $j < $this->nbrplots; $j++ ) { |
---|
632 | $y += $this->plots[ $j ]->coords[0][$i]; |
---|
633 | } |
---|
634 | $ymin[$i] = $y; |
---|
635 | } |
---|
636 | $ymin = Min($ysetmin,Min($ymin)); |
---|
637 | // Bar always start at baseline |
---|
638 | if( $ymin >= $this->ybase ) |
---|
639 | $ymin = $this->ybase; |
---|
640 | return array($xmin,$ymin); |
---|
641 | } |
---|
642 | |
---|
643 | // Method description |
---|
644 | function Stroke(&$img,&$xscale,&$yscale) { |
---|
645 | $img->SetLineWeight($this->weight); |
---|
646 | for($i=0; $i<$this->numpoints-1; $i++) { |
---|
647 | $accy = 0; |
---|
648 | $accy_neg = 0; |
---|
649 | for($j=0; $j<$this->nbrplots; ++$j ) { |
---|
650 | $img->SetColor($this->plots[$j]->color); |
---|
651 | if ($this->plots[$j]->coords[0][$i] > 0) { |
---|
652 | $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy); |
---|
653 | $accyt=$yscale->Translate($accy); |
---|
654 | $accy+=$this->plots[$j]->coords[0][$i]; |
---|
655 | } else { |
---|
656 | $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg); |
---|
657 | $accyt=$yscale->Translate($accy_neg); |
---|
658 | $accy_neg+=$this->plots[$j]->coords[0][$i]; |
---|
659 | } |
---|
660 | |
---|
661 | $xt=$xscale->Translate($i); |
---|
662 | $abswidth=round($this->width*$xscale->scale_factor,0); |
---|
663 | $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt); |
---|
664 | |
---|
665 | if( $this->plots[$j]->grad ) { |
---|
666 | $grad = new Gradient($img); |
---|
667 | $grad->FilledRectangle( |
---|
668 | $pts[2],$pts[3], |
---|
669 | $pts[6],$pts[7], |
---|
670 | $this->plots[$j]->grad_fromcolor, |
---|
671 | $this->plots[$j]->grad_tocolor, |
---|
672 | $this->plots[$j]->grad_style); |
---|
673 | } elseif ($this->plots[$j]->fill_color ) { |
---|
674 | $img->SetColor($this->plots[$j]->fill_color); |
---|
675 | $img->FilledPolygon($pts,4); |
---|
676 | $img->SetColor($this->plots[$j]->color); |
---|
677 | } |
---|
678 | |
---|
679 | if( $this->bar_shadow ) { |
---|
680 | $ssh = $this->bar_shadow_hsize; |
---|
681 | $ssv = $this->bar_shadow_vsize; |
---|
682 | // Create points to create a "upper-right" shadow |
---|
683 | $sp[0]=$pts[6]; $sp[1]=$pts[7]; |
---|
684 | $sp[2]=$pts[4]; $sp[3]=$pts[5]; |
---|
685 | $sp[4]=$pts[2]; $sp[5]=$pts[3]; |
---|
686 | $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv; |
---|
687 | $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv; |
---|
688 | $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv; |
---|
689 | $img->SetColor($this->bar_shadow_color); |
---|
690 | $img->FilledPolygon($sp,4); |
---|
691 | } |
---|
692 | |
---|
693 | if( $i < count($this->plots[$j]->csimtargets) ) { |
---|
694 | $this->csimareas.= "<area shape=\"rect\" coords=\""; |
---|
695 | // Hmmm, this is fishy. Fixes a bug in Opera whereby if Y2<Y1 or X2<X1 the csim doesn't work |
---|
696 | // This means that the area MUST specify top left and bottom right corners |
---|
697 | if ($pts[3] < $pts[7]) { |
---|
698 | if ($pts[2] < $pts[6]) { |
---|
699 | $this->csimareas.= "$pts[2], $pts[3], $pts[6], $pts[7]\""; |
---|
700 | } else { |
---|
701 | $this->csimareas.= "$pts[6], $pts[3], $pts[2], $pts[7]\""; |
---|
702 | } |
---|
703 | } else { |
---|
704 | if ($pts[2] < $pts[6]) { |
---|
705 | $this->csimareas.= "$pts[2], $pts[7], $pts[6], $pts[3]\""; |
---|
706 | } else { |
---|
707 | $this->csimareas.= "$pts[6], $pts[7], $pts[2], $pts[3]\""; |
---|
708 | } |
---|
709 | } |
---|
710 | $this->csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\""; |
---|
711 | if( !empty($this->plots[$j]->csimalts[$i]) ) { |
---|
712 | $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]); |
---|
713 | $this->csimareas .= " alt=\"$sval\" title=\"$sval\" "; |
---|
714 | } |
---|
715 | $this->csimareas .= ">\r\n"; |
---|
716 | } |
---|
717 | |
---|
718 | $img->Polygon($pts,4); |
---|
719 | } |
---|
720 | |
---|
721 | $yt=$yscale->Translate($accy); |
---|
722 | |
---|
723 | if( $this->show_value) { |
---|
724 | $sval=sprintf($this->show_value_format,$accy); |
---|
725 | $txt = new Text($sval); |
---|
726 | $txt->SetFont($this->show_value_ff,$this->show_value_fs,$this->show_value_fsize); |
---|
727 | $txt->SetColor($this->show_value_color); |
---|
728 | $x=$pts[2]+($pts[4]-$pts[2])/2; |
---|
729 | if($this->bar_shadow) |
---|
730 | $x += $ssh; |
---|
731 | $txt->Pos($x,$yt-$this->show_value_margin); |
---|
732 | $txt->Align("center","bottom"); |
---|
733 | $txt->SetOrientation($this->show_value_angle); |
---|
734 | $txt->Stroke($img); |
---|
735 | } |
---|
736 | } |
---|
737 | return true; |
---|
738 | } |
---|
739 | } // Class |
---|
740 | |
---|
741 | /* EOF */ |
---|
742 | ?> |
---|