source: trunk/client/modules/Elezioni/grafici/jpgraph_bar.php@ 265

Last change on this file since 265 was 265, checked in by roby, 5 years ago
File size: 46.2 KB
Line 
1<?php
2/*=======================================================================
3 // File: JPGRAPH_BAR.PHP
4 // Description: Bar plot extension for JpGraph
5 // Created: 2001-01-08
6 // Ver: $Id: jpgraph_bar.php 1905 2009-10-06 18:00:21Z ljp $
7 //
8 // Copyright (c) Asial Corporation. All rights reserved.
9 //========================================================================
10 */
11
12require_once('jpgraph_plotband.php');
13
14// Pattern for Bars
15DEFINE('PATTERN_DIAG1',1);
16DEFINE('PATTERN_DIAG2',2);
17DEFINE('PATTERN_DIAG3',3);
18DEFINE('PATTERN_DIAG4',4);
19DEFINE('PATTERN_CROSS1',5);
20DEFINE('PATTERN_CROSS2',6);
21DEFINE('PATTERN_CROSS3',7);
22DEFINE('PATTERN_CROSS4',8);
23DEFINE('PATTERN_STRIPE1',9);
24DEFINE('PATTERN_STRIPE2',10);
25
26//===================================================
27// CLASS BarPlot
28// Description: Main code to produce a bar plot
29//===================================================
30class BarPlot extends Plot {
31 public $fill=false,$fill_color="lightblue"; // Default is to fill with light blue
32 public $iPattern=-1,$iPatternDensity=80,$iPatternColor='black';
33 public $valuepos='top';
34 public $grad=false,$grad_style=1;
35 public $grad_fromcolor=array(50,50,200),$grad_tocolor=array(255,255,255);
36 public $ymin=0;
37 protected $width=0.4; // in percent of major ticks
38 protected $abswidth=-1; // Width in absolute pixels
39 protected $ybase=0; // Bars start at 0
40 protected $align="center";
41 protected $bar_shadow=false;
42 protected $bar_shadow_color="black";
43 protected $bar_shadow_hsize=3,$bar_shadow_vsize=3;
44 protected $bar_3d=false;
45 protected $bar_3d_hsize=3,$bar_3d_vsize=3;
46
47 //---------------
48 // CONSTRUCTOR
49 function __construct($datay,$datax=false) {
50 parent::__construct($datay,$datax);
51 ++$this->numpoints;
52 }
53
54 //---------------
55 // PUBLIC METHODS
56
57 // Set a drop shadow for the bar (or rather an "up-right" shadow)
58 function SetShadow($aColor="black",$aHSize=3,$aVSize=3,$aShow=true) {
59 $this->bar_shadow=$aShow;
60 $this->bar_shadow_color=$aColor;
61 $this->bar_shadow_vsize=$aVSize;
62 $this->bar_shadow_hsize=$aHSize;
63
64 // Adjust the value margin to compensate for shadow
65 $this->value->margin += $aVSize;
66 }
67
68 function Set3D($aHSize=3,$aVSize=3,$aShow=true) {
69 $this->bar_3d=$aShow;
70 $this->bar_3d_vsize=$aVSize;
71 $this->bar_3d_hsize=$aHSize;
72
73 $this->value->margin += $aVSize;
74 }
75
76 // DEPRECATED use SetYBase instead
77 function SetYMin($aYStartValue) {
78 //die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead.");
79 $this->ybase=$aYStartValue;
80 }
81
82 // Specify the base value for the bars
83 function SetYBase($aYStartValue) {
84 $this->ybase=$aYStartValue;
85 }
86
87 // The method will take the specified pattern anre
88 // return a pattern index that corresponds to the original
89 // patterm being rotated 90 degreees. This is needed when plottin
90 // Horizontal bars
91 function RotatePattern($aPat,$aRotate=true) {
92 $rotate = array(1 => 2, 2 => 1, 3 => 3, 4 => 5, 5 => 4, 6 => 6, 7 => 7, 8 => 8);
93 if( $aRotate ) {
94 return $rotate[$aPat];
95 }
96 else {
97 return $aPat;
98 }
99 }
100
101 function Legend($graph) {
102 if( $this->grad && $this->legend!="" && !$this->fill ) {
103 $color=array($this->grad_fromcolor,$this->grad_tocolor);
104 // In order to differentiate between gradients and cooors specified as an RGB triple
105 $graph->legend->Add($this->legend,$color,"",-$this->grad_style,
106 $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
107 }
108 elseif( $this->legend!="" && ($this->iPattern > -1 || is_array($this->iPattern)) ) {
109 if( is_array($this->iPattern) ) {
110 $p1 = $this->RotatePattern( $this->iPattern[0], $graph->img->a == 90 );
111 $p2 = $this->iPatternColor[0];
112 $p3 = $this->iPatternDensity[0];
113 }
114 else {
115 $p1 = $this->RotatePattern( $this->iPattern, $graph->img->a == 90 );
116 $p2 = $this->iPatternColor;
117 $p3 = $this->iPatternDensity;
118 }
119 if( $p3 < 90 ) $p3 += 5;
120 $color = array($p1,$p2,$p3,$this->fill_color);
121 // A kludge: Too mark that we add a pattern we use a type value of < 100
122 $graph->legend->Add($this->legend,$color,"",-101,
123 $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
124 }
125 elseif( $this->fill_color && $this->legend!="" ) {
126 if( is_array($this->fill_color) ) {
127 $graph->legend->Add($this->legend,$this->fill_color[0],"",0,
128 $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
129 }
130 else {
131 $graph->legend->Add($this->legend,$this->fill_color,"",0,
132 $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
133 }
134 }
135 }
136
137 // Gets called before any axis are stroked
138 function PreStrokeAdjust($graph) {
139 parent::PreStrokeAdjust($graph);
140
141 // If we are using a log Y-scale we want the base to be at the
142 // minimum Y-value unless the user have specifically set some other
143 // value than the default.
144 if( substr($graph->axtype,-3,3)=="log" && $this->ybase==0 )
145 $this->ybase = $graph->yaxis->scale->GetMinVal();
146
147 // For a "text" X-axis scale we will adjust the
148 // display of the bars a little bit.
149 if( substr($graph->axtype,0,3)=="tex" ) {
150 // Position the ticks between the bars
151 $graph->xaxis->scale->ticks->SetXLabelOffset(0.5,0);
152
153 // Center the bars
154 if( $this->abswidth > -1 ) {
155 $graph->SetTextScaleAbsCenterOff($this->abswidth);
156 }
157 else {
158 if( $this->align == "center" )
159 $graph->SetTextScaleOff(0.5-$this->width/2);
160 elseif( $this->align == "right" )
161 $graph->SetTextScaleOff(1-$this->width);
162 }
163 }
164 elseif( ($this instanceof AccBarPlot) || ($this instanceof GroupBarPlot) ) {
165 // We only set an absolute width for linear and int scale
166 // for text scale the width will be set to a fraction of
167 // the majstep width.
168 if( $this->abswidth == -1 ) {
169 // Not set
170 // set width to a visuable sensible default
171 $this->abswidth = $graph->img->plotwidth/(2*$this->numpoints);
172 }
173 }
174 }
175
176 function Min() {
177 $m = parent::Min();
178 if( $m[1] >= $this->ybase ) $m[1] = $this->ybase;
179 return $m;
180 }
181
182 function Max() {
183 $m = parent::Max();
184 if( $m[1] <= $this->ybase ) $m[1] = $this->ybase;
185 return $m;
186 }
187
188 // Specify width as fractions of the major stepo size
189 function SetWidth($aWidth) {
190 if( $aWidth > 1 ) {
191 // Interpret this as absolute width
192 $this->abswidth=$aWidth;
193 }
194 else {
195 $this->width=$aWidth;
196 }
197 }
198
199 // Specify width in absolute pixels. If specified this
200 // overrides SetWidth()
201 function SetAbsWidth($aWidth) {
202 $this->abswidth=$aWidth;
203 }
204
205 function SetAlign($aAlign) {
206 $this->align=$aAlign;
207 }
208
209 function SetNoFill() {
210 $this->grad = false;
211 $this->fill_color=false;
212 $this->fill=false;
213 }
214
215 function SetFillColor($aColor) {
216 // Do an extra error check if the color is specified as an RGB array triple
217 // In that case convert it to a hex string since it will otherwise be
218 // interpretated as an array of colors for each individual bar.
219
220 $aColor = RGB::tryHexConversion($aColor);
221 $this->fill = true ;
222 $this->fill_color=$aColor;
223
224 }
225
226 function SetFillGradient($aFromColor,$aToColor=null,$aStyle=null) {
227 $this->grad = true;
228 $this->grad_fromcolor = $aFromColor;
229 $this->grad_tocolor = $aToColor;
230 $this->grad_style = $aStyle;
231 }
232
233 function SetValuePos($aPos) {
234 $this->valuepos = $aPos;
235 }
236
237 function SetPattern($aPattern, $aColor='black'){
238 if( is_array($aPattern) ) {
239 $n = count($aPattern);
240 $this->iPattern = array();
241 $this->iPatternDensity = array();
242 if( is_array($aColor) ) {
243 $this->iPatternColor = array();
244 if( count($aColor) != $n ) {
245 JpGraphError::RaiseL(2001);//('NUmber of colors is not the same as the number of patterns in BarPlot::SetPattern()');
246 }
247 }
248 else {
249 $this->iPatternColor = $aColor;
250 }
251 for( $i=0; $i < $n; ++$i ) {
252 $this->_SetPatternHelper($aPattern[$i], $this->iPattern[$i], $this->iPatternDensity[$i]);
253 if( is_array($aColor) ) {
254 $this->iPatternColor[$i] = $aColor[$i];
255 }
256 }
257 }
258 else {
259 $this->_SetPatternHelper($aPattern, $this->iPattern, $this->iPatternDensity);
260 $this->iPatternColor = $aColor;
261 }
262 }
263
264 function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){
265 switch( $aPattern ) {
266 case PATTERN_DIAG1:
267 $aPatternValue= 1;
268 $aDensity = 92;
269 break;
270 case PATTERN_DIAG2:
271 $aPatternValue= 1;
272 $aDensity = 78;
273 break;
274 case PATTERN_DIAG3:
275 $aPatternValue= 2;
276 $aDensity = 92;
277 break;
278 case PATTERN_DIAG4:
279 $aPatternValue= 2;
280 $aDensity = 78;
281 break;
282 case PATTERN_CROSS1:
283 $aPatternValue= 8;
284 $aDensity = 90;
285 break;
286 case PATTERN_CROSS2:
287 $aPatternValue= 8;
288 $aDensity = 78;
289 break;
290 case PATTERN_CROSS3:
291 $aPatternValue= 8;
292 $aDensity = 65;
293 break;
294 case PATTERN_CROSS4:
295 $aPatternValue= 7;
296 $aDensity = 90;
297 break;
298 case PATTERN_STRIPE1:
299 $aPatternValue= 5;
300 $aDensity = 94;
301 break;
302 case PATTERN_STRIPE2:
303 $aPatternValue= 5;
304 $aDensity = 85;
305 break;
306 default:
307 JpGraphError::RaiseL(2002);
308 //('Unknown pattern specified in call to BarPlot::SetPattern()');
309 }
310 }
311
312 function Stroke($img,$xscale,$yscale) {
313
314 $numpoints = count($this->coords[0]);
315 if( isset($this->coords[1]) ) {
316 if( count($this->coords[1])!=$numpoints ) {
317 JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);
318 //"Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints");
319 }
320 else {
321 $exist_x = true;
322 }
323 }
324 else {
325 $exist_x = false;
326 }
327
328
329 $numbars=count($this->coords[0]);
330
331 // Use GetMinVal() instead of scale[0] directly since in the case
332 // of log scale we get a correct value. Log scales will have negative
333 // values for values < 1 while still not representing negative numbers.
334 if( $yscale->GetMinVal() >= 0 )
335 $zp=$yscale->scale_abs[0];
336 else {
337 $zp=$yscale->Translate(0);
338 }
339
340 if( $this->abswidth > -1 ) {
341 $abswidth=$this->abswidth;
342 }
343 else {
344 $abswidth=round($this->width*$xscale->scale_factor,0);
345 }
346
347 // Count pontetial pattern array to avoid doing the count for each iteration
348 if( is_array($this->iPattern) ) {
349 $np = count($this->iPattern);
350 }
351
352 $grad = null;
353 for($i=0; $i < $numbars; ++$i) {
354
355 // If value is NULL, or 0 then don't draw a bar at all
356 if ($this->coords[0][$i] === null || $this->coords[0][$i] === '' )
357 continue;
358
359 if( $exist_x ) {
360 $x=$this->coords[1][$i];
361 }
362 else {
363 $x=$i;
364 }
365
366 $x=$xscale->Translate($x);
367
368 // Comment Note: This confuses the positioning when using acc together with
369 // grouped bars. Workaround for fixing #191
370 /*
371 if( !$xscale->textscale ) {
372 if($this->align=="center")
373 $x -= $abswidth/2;
374 elseif($this->align=="right")
375 $x -= $abswidth;
376 }
377 */
378 // Stroke fill color and fill gradient
379 $pts=array(
380 $x,$zp,
381 $x,$yscale->Translate($this->coords[0][$i]),
382 $x+$abswidth,$yscale->Translate($this->coords[0][$i]),
383 $x+$abswidth,$zp);
384 if( $this->grad ) {
385 if( $grad === null ) {
386 $grad = new Gradient($img);
387 }
388 if( is_array($this->grad_fromcolor) ) {
389 // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array
390 // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be
391 // an array to specify both (from, to style) for each individual bar. The way to know the difference is
392 // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB
393 // triple.
394 $ng = count($this->grad_fromcolor);
395 if( $ng === 3 ) {
396 if( is_numeric($this->grad_fromcolor[0]) && $this->grad_fromcolor[0] > 0 && $this->grad_fromcolor[0] < 256 ) {
397 // RGB Triple
398 $fromcolor = $this->grad_fromcolor;
399 $tocolor = $this->grad_tocolor;
400 $style = $this->grad_style;
401 }
402 else {
403 $fromcolor = $this->grad_fromcolor[$i % $ng][0];
404 $tocolor = $this->grad_fromcolor[$i % $ng][1];
405 $style = $this->grad_fromcolor[$i % $ng][2];
406 }
407 }
408 else {
409 $fromcolor = $this->grad_fromcolor[$i % $ng][0];
410 $tocolor = $this->grad_fromcolor[$i % $ng][1];
411 $style = $this->grad_fromcolor[$i % $ng][2];
412 }
413 $grad->FilledRectangle($pts[2],$pts[3],
414 $pts[6],$pts[7],
415 $fromcolor,$tocolor,$style);
416 }
417 else {
418 $grad->FilledRectangle($pts[2],$pts[3],
419 $pts[6],$pts[7],
420 $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style);
421 }
422 }
423 elseif( !empty($this->fill_color) ) {
424 if(is_array($this->fill_color)) {
425 $img->PushColor($this->fill_color[$i % count($this->fill_color)]);
426 } else {
427 $img->PushColor($this->fill_color);
428 }
429 $img->FilledPolygon($pts);
430 $img->PopColor();
431 }
432
433/////////////////////////kokorahen rectangle polygon//////////////////////
434
435 // Remember value of this bar
436 $val=$this->coords[0][$i];
437
438 if( !empty($val) && !is_numeric($val) ) {
439 JpGraphError::RaiseL(2004,$i,$val);
440 //'All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\'');
441 }
442
443 // Determine the shadow
444 if( $this->bar_shadow && $val != 0) {
445
446 $ssh = $this->bar_shadow_hsize;
447 $ssv = $this->bar_shadow_vsize;
448 // Create points to create a "upper-right" shadow
449 if( $val > 0 ) {
450 $sp[0]=$pts[6]; $sp[1]=$pts[7];
451 $sp[2]=$pts[4]; $sp[3]=$pts[5];
452 $sp[4]=$pts[2]; $sp[5]=$pts[3];
453 $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv;
454 $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv;
455 $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv;
456 }
457 elseif( $val < 0 ) {
458 $sp[0]=$pts[4]; $sp[1]=$pts[5];
459 $sp[2]=$pts[6]; $sp[3]=$pts[7];
460 $sp[4]=$pts[0]; $sp[5]=$pts[1];
461 $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv;
462 $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv;
463 $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv;
464 }
465 if( is_array($this->bar_shadow_color) ) {
466 $numcolors = count($this->bar_shadow_color);
467 if( $numcolors == 0 ) {
468 JpGraphError::RaiseL(2005);//('You have specified an empty array for shadow colors in the bar plot.');
469 }
470 $img->PushColor($this->bar_shadow_color[$i % $numcolors]);
471 }
472 else {
473 $img->PushColor($this->bar_shadow_color);
474 }
475 $img->FilledPolygon($sp);
476 $img->PopColor();
477
478 } elseif( $this->bar_3d && $val != 0) {
479 // Determine the 3D
480
481 $ssh = $this->bar_3d_hsize;
482 $ssv = $this->bar_3d_vsize;
483
484 // Create points to create a "upper-right" shadow
485 if( $val > 0 ) {
486 $sp1[0]=$pts[6]; $sp1[1]=$pts[7];
487 $sp1[2]=$pts[4]; $sp1[3]=$pts[5];
488 $sp1[4]=$pts[4]+$ssh; $sp1[5]=$pts[5]-$ssv;
489 $sp1[6]=$pts[6]+$ssh; $sp1[7]=$pts[7]-$ssv;
490
491 $sp2[0]=$pts[4]; $sp2[1]=$pts[5];
492 $sp2[2]=$pts[2]; $sp2[3]=$pts[3];
493 $sp2[4]=$pts[2]+$ssh; $sp2[5]=$pts[3]-$ssv;
494 $sp2[6]=$pts[4]+$ssh; $sp2[7]=$pts[5]-$ssv;
495
496 }
497 elseif( $val < 0 ) {
498 $sp1[0]=$pts[4]; $sp1[1]=$pts[5];
499 $sp1[2]=$pts[6]; $sp1[3]=$pts[7];
500 $sp1[4]=$pts[6]+$ssh; $sp1[5]=$pts[7]-$ssv;
501 $sp1[6]=$pts[4]+$ssh; $sp1[7]=$pts[5]-$ssv;
502
503 $sp2[0]=$pts[6]; $sp2[1]=$pts[7];
504 $sp2[2]=$pts[0]; $sp2[3]=$pts[1];
505 $sp2[4]=$pts[0]+$ssh; $sp2[5]=$pts[1]-$ssv;
506 $sp2[6]=$pts[6]+$ssh; $sp2[7]=$pts[7]-$ssv;
507 }
508
509 $base_color = $this->fill_color;
510
511 $img->PushColor($base_color . ':0.7');
512 $img->FilledPolygon($sp1);
513 $img->PopColor();
514
515 $img->PushColor($base_color . ':1.1');
516 $img->FilledPolygon($sp2);
517 $img->PopColor();
518 }
519
520 // Stroke the pattern
521 if( is_array($this->iPattern) ) {
522 $f = new RectPatternFactory();
523 if( is_array($this->iPatternColor) ) {
524 $pcolor = $this->iPatternColor[$i % $np];
525 }
526 else {
527 $pcolor = $this->iPatternColor;
528 }
529 $prect = $f->Create($this->iPattern[$i % $np],$pcolor,1);
530 $prect->SetDensity($this->iPatternDensity[$i % $np]);
531
532 if( $val < 0 ) {
533 $rx = $pts[0];
534 $ry = $pts[1];
535 }
536 else {
537 $rx = $pts[2];
538 $ry = $pts[3];
539 }
540 $width = abs($pts[4]-$pts[0])+1;
541 $height = abs($pts[1]-$pts[3])+1;
542 $prect->SetPos(new Rectangle($rx,$ry,$width,$height));
543 $prect->Stroke($img);
544 }
545 else {
546 if( $this->iPattern > -1 ) {
547 $f = new RectPatternFactory();
548 $prect = $f->Create($this->iPattern,$this->iPatternColor,1);
549 $prect->SetDensity($this->iPatternDensity);
550 if( $val < 0 ) {
551 $rx = $pts[0];
552 $ry = $pts[1];
553 }
554 else {
555 $rx = $pts[2];
556 $ry = $pts[3];
557 }
558 $width = abs($pts[4]-$pts[0])+1;
559 $height = abs($pts[1]-$pts[3])+1;
560 $prect->SetPos(new Rectangle($rx,$ry,$width,$height));
561 $prect->Stroke($img);
562 }
563 }
564
565 // Stroke the outline of the bar
566 if( is_array($this->color) ) {
567 $img->SetColor($this->color[$i % count($this->color)]);
568 }
569 else {
570 $img->SetColor($this->color);
571 }
572
573 $pts[] = $pts[0];
574 $pts[] = $pts[1];
575
576 if( $this->weight > 0 ) {
577 $img->SetLineWeight($this->weight);
578 $img->Polygon($pts);
579 }
580
581 // Determine how to best position the values of the individual bars
582 $x=$pts[2]+($pts[4]-$pts[2])/2;
583 $this->value->SetMargin(5);
584
585 if( $this->valuepos=='top' ) {
586 $y=$pts[3];
587 if( $img->a === 90 ) {
588 if( $val < 0 ) {
589 $this->value->SetAlign('right','center');
590 }
591 else {
592 $this->value->SetAlign('left','center');
593 }
594
595 }
596 else {
597 if( $val < 0 ) {
598 $this->value->SetMargin(-5);
599 $y=$pts[1];
600 $this->value->SetAlign('center','bottom');
601 }
602 else {
603 $this->value->SetAlign('center','bottom');
604 }
605
606 }
607 $this->value->Stroke($img,$val,$x,$y);
608 }
609 elseif( $this->valuepos=='max' ) {
610 $y=$pts[3];
611 if( $img->a === 90 ) {
612 if( $val < 0 )
613 $this->value->SetAlign('left','center');
614 else
615 $this->value->SetAlign('right','center');
616 }
617 else {
618 if( $val < 0 ) {
619 $this->value->SetAlign('center','bottom');
620 }
621 else {
622 $this->value->SetAlign('center','top');
623 }
624 }
625 $this->value->SetMargin(-5);
626 $this->value->Stroke($img,$val,$x,$y);
627 }
628 elseif( $this->valuepos=='center' ) {
629 $y = ($pts[3] + $pts[1])/2;
630 $this->value->SetAlign('center','center');
631 $this->value->SetMargin(0);
632 $this->value->Stroke($img,$val,$x,$y);
633 }
634 elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) {
635 $y=$pts[1];
636 if( $img->a === 90 ) {
637 if( $val < 0 )
638 $this->value->SetAlign('right','center');
639 else
640 $this->value->SetAlign('left','center');
641 }
642 $this->value->SetMargin(3);
643 $this->value->Stroke($img,$val,$x,$y);
644 }
645 else {
646 JpGraphError::RaiseL(2006,$this->valuepos);
647 //'Unknown position for values on bars :'.$this->valuepos);
648 }
649 // Create the client side image map
650 $rpts = $img->ArrRotate($pts);
651 $csimcoord=round($rpts[0]).", ".round($rpts[1]);
652 for( $j=1; $j < 4; ++$j){
653 $csimcoord .= ", ".round($rpts[2*$j]).", ".round($rpts[2*$j+1]);
654 }
655 if( !empty($this->csimtargets[$i]) ) {
656 $this->csimareas .= '<area shape="poly" coords="'.$csimcoord.'" ';
657 $this->csimareas .= " href=\"".htmlentities($this->csimtargets[$i])."\"";
658
659 if( !empty($this->csimwintargets[$i]) ) {
660 $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
661 }
662
663 $sval='';
664 if( !empty($this->csimalts[$i]) ) {
665 $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]);
666 $this->csimareas .= " title=\"$sval\" alt=\"$sval\" ";
667 }
668 $this->csimareas .= " />\n";
669 }
670 }
671 return true;
672 }
673} // Class
674
675//===================================================
676// CLASS GroupBarPlot
677// Description: Produce grouped bar plots
678//===================================================
679class GroupBarPlot extends BarPlot {
680 public $plots;
681 private $nbrplots=0;
682 //---------------
683 // CONSTRUCTOR
684 function __construct($plots) {
685 $this->width=0.7;
686 $this->plots = $plots;
687 $this->nbrplots = count($plots);
688 if( $this->nbrplots < 1 ) {
689 JpGraphError::RaiseL(2007);//('Cannot create GroupBarPlot from empty plot array.');
690 }
691 for($i=0; $i < $this->nbrplots; ++$i ) {
692 if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) {
693 JpGraphError::RaiseL(2008,$i);//("Group bar plot element nbr $i is undefined or empty.");
694 }
695 }
696 $this->numpoints = $plots[0]->numpoints;
697 $this->width=0.7;
698 }
699
700 //---------------
701 // PUBLIC METHODS
702 function Legend($graph) {
703 $n = count($this->plots);
704 for($i=0; $i < $n; ++$i) {
705 $c = get_class($this->plots[$i]);
706 if( !($this->plots[$i] instanceof BarPlot) ) {
707 JpGraphError::RaiseL(2009,$c);
708 //('One of the objects submitted to GroupBar is not a BarPlot. Make sure that you create the Group Bar plot from an array of BarPlot or AccBarPlot objects. (Class = '.$c.')');
709 }
710 $this->plots[$i]->DoLegend($graph);
711 }
712 }
713
714 function Min() {
715 list($xmin,$ymin) = $this->plots[0]->Min();
716 $n = count($this->plots);
717 for($i=0; $i < $n; ++$i) {
718 list($xm,$ym) = $this->plots[$i]->Min();
719 $xmin = max($xmin,$xm);
720 $ymin = min($ymin,$ym);
721 }
722 return array($xmin,$ymin);
723 }
724
725 function Max() {
726 list($xmax,$ymax) = $this->plots[0]->Max();
727 $n = count($this->plots);
728 for($i=0; $i < $n; ++$i) {
729 list($xm,$ym) = $this->plots[$i]->Max();
730 $xmax = max($xmax,$xm);
731 $ymax = max($ymax,$ym);
732 }
733 return array($xmax,$ymax);
734 }
735
736 function GetCSIMareas() {
737 $n = count($this->plots);
738 $csimareas='';
739 for($i=0; $i < $n; ++$i) {
740 $csimareas .= $this->plots[$i]->csimareas;
741 }
742 return $csimareas;
743 }
744
745 // Stroke all the bars next to each other
746 function Stroke($img,$xscale,$yscale) {
747 $tmp=$xscale->off;
748 $n = count($this->plots);
749 $subwidth = $this->width/$this->nbrplots ;
750
751 for( $i=0; $i < $n; ++$i ) {
752 $this->plots[$i]->ymin=$this->ybase;
753 $this->plots[$i]->SetWidth($subwidth);
754
755 // If the client have used SetTextTickInterval() then
756 // major_step will be > 1 and the positioning will fail.
757 // If we assume it is always one the positioning will work
758 // fine with a text scale but this will not work with
759 // arbitrary linear scale
760 $xscale->off = $tmp+$i*round($xscale->scale_factor* $subwidth);
761 $this->plots[$i]->Stroke($img,$xscale,$yscale);
762 }
763 $xscale->off=$tmp;
764 }
765} // Class
766
767//===================================================
768// CLASS AccBarPlot
769// Description: Produce accumulated bar plots
770//===================================================
771class AccBarPlot extends BarPlot {
772 public $plots=null;
773 private $nbrplots=0;
774 //---------------
775 // CONSTRUCTOR
776 function __construct($plots) {
777 $this->plots = $plots;
778 $this->nbrplots = count($plots);
779 if( $this->nbrplots < 1 ) {
780 JpGraphError::RaiseL(2010);//('Cannot create AccBarPlot from empty plot array.');
781 }
782 for($i=0; $i < $this->nbrplots; ++$i ) {
783 if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) {
784 JpGraphError::RaiseL(2011,$i);//("Acc bar plot element nbr $i is undefined or empty.");
785 }
786 }
787
788 // We can only allow individual plost which do not have specified X-positions
789 for($i=0; $i < $this->nbrplots; ++$i ) {
790 if( !empty($this->plots[$i]->coords[1]) ) {
791 JpGraphError::RaiseL(2015);
792 //'Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-positions.');
793 }
794 }
795
796 // Use 0 weight by default which means that the individual bar
797 // weights will be used per part n the accumulated bar
798 $this->SetWeight(0);
799
800 $this->numpoints = $plots[0]->numpoints;
801 $this->value = new DisplayValue();
802 }
803
804 //---------------
805 // PUBLIC METHODS
806 function Legend($graph) {
807 $n = count($this->plots);
808 for( $i=$n-1; $i >= 0; --$i ) {
809 $c = get_class($this->plots[$i]);
810 if( !($this->plots[$i] instanceof BarPlot) ) {
811 JpGraphError::RaiseL(2012,$c);
812 //('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')');
813 }
814 $this->plots[$i]->DoLegend($graph);
815 }
816 }
817
818 function Max() {
819 list($xmax) = $this->plots[0]->Max();
820 $nmax=0;
821 for($i=0; $i < count($this->plots); ++$i) {
822 $n = count($this->plots[$i]->coords[0]);
823 $nmax = max($nmax,$n);
824 list($x) = $this->plots[$i]->Max();
825 $xmax = max($xmax,$x);
826 }
827 for( $i = 0; $i < $nmax; $i++ ) {
828 // Get y-value for bar $i by adding the
829 // individual bars from all the plots added.
830 // It would be wrong to just add the
831 // individual plots max y-value since that
832 // would in most cases give to large y-value.
833 $y=0;
834 if( !isset($this->plots[0]->coords[0][$i]) ) {
835 JpGraphError::RaiseL(2014);
836 }
837 if( $this->plots[0]->coords[0][$i] > 0 )
838 $y=$this->plots[0]->coords[0][$i];
839 for( $j = 1; $j < $this->nbrplots; $j++ ) {
840 if( !isset($this->plots[$j]->coords[0][$i]) ) {
841 JpGraphError::RaiseL(2014);
842 }
843 if( $this->plots[$j]->coords[0][$i] > 0 )
844 $y += $this->plots[$j]->coords[0][$i];
845 }
846 $ymax[$i] = $y;
847 }
848 $ymax = max($ymax);
849
850 // Bar always start at baseline
851 if( $ymax <= $this->ybase )
852 $ymax = $this->ybase;
853 return array($xmax,$ymax);
854 }
855
856 function Min() {
857 $nmax=0;
858 list($xmin,$ysetmin) = $this->plots[0]->Min();
859 for($i=0; $i < count($this->plots); ++$i) {
860 $n = count($this->plots[$i]->coords[0]);
861 $nmax = max($nmax,$n);
862 list($x,$y) = $this->plots[$i]->Min();
863 $xmin = Min($xmin,$x);
864 $ysetmin = Min($y,$ysetmin);
865 }
866 for( $i = 0; $i < $nmax; $i++ ) {
867 // Get y-value for bar $i by adding the
868 // individual bars from all the plots added.
869 // It would be wrong to just add the
870 // individual plots max y-value since that
871 // would in most cases give to large y-value.
872 $y=0;
873 if( $this->plots[0]->coords[0][$i] < 0 )
874 $y=$this->plots[0]->coords[0][$i];
875 for( $j = 1; $j < $this->nbrplots; $j++ ) {
876 if( $this->plots[$j]->coords[0][$i] < 0 )
877 $y += $this->plots[ $j ]->coords[0][$i];
878 }
879 $ymin[$i] = $y;
880 }
881 $ymin = Min($ysetmin,Min($ymin));
882 // Bar always start at baseline
883 if( $ymin >= $this->ybase )
884 $ymin = $this->ybase;
885 return array($xmin,$ymin);
886 }
887
888 // Stroke acc bar plot
889 function Stroke($img,$xscale,$yscale) {
890 $pattern=NULL;
891 $img->SetLineWeight($this->weight);
892 $grad=null;
893 for($i=0; $i < $this->numpoints-1; $i++) {
894 $accy = 0;
895 $accy_neg = 0;
896 for($j=0; $j < $this->nbrplots; ++$j ) {
897 $img->SetColor($this->plots[$j]->color);
898
899 if ( $this->plots[$j]->coords[0][$i] >= 0) {
900 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy);
901 $accyt=$yscale->Translate($accy);
902 $accy+=$this->plots[$j]->coords[0][$i];
903 }
904 else {
905 //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) {
906 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg);
907 $accyt=$yscale->Translate($accy_neg);
908 $accy_neg+=$this->plots[$j]->coords[0][$i];
909 }
910
911 $xt=$xscale->Translate($i);
912
913 if( $this->abswidth > -1 ) {
914 $abswidth=$this->abswidth;
915 }
916 else {
917 $abswidth=round($this->width*$xscale->scale_factor,0);
918 }
919
920 $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt);
921
922 if( $this->bar_shadow ) {
923 $ssh = $this->bar_shadow_hsize;
924 $ssv = $this->bar_shadow_vsize;
925
926 // We must also differ if we are a positive or negative bar.
927 if( $j === 0 ) {
928 // This gets extra complicated since we have to
929 // see all plots to see if we are negative. It could
930 // for example be that all plots are 0 until the very
931 // last one. We therefore need to save the initial setup
932 // for both the negative and positive case
933
934 // In case the final bar is positive
935 $sp[0]=$pts[6]+1; $sp[1]=$pts[7];
936 $sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv;
937
938 // In case the final bar is negative
939 $nsp[0]=$pts[0]; $nsp[1]=$pts[1];
940 $nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv;
941 $nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv;
942 $nsp[10]=$pts[6]+1; $nsp[11]=$pts[7];
943 }
944
945 if( $j === $this->nbrplots-1 ) {
946 // If this is the last plot of the bar and
947 // the total value is larger than 0 then we
948 // add the shadow.
949 if( is_array($this->bar_shadow_color) ) {
950 $numcolors = count($this->bar_shadow_color);
951 if( $numcolors == 0 ) {
952 JpGraphError::RaiseL(2013);//('You have specified an empty array for shadow colors in the bar plot.');
953 }
954 $img->PushColor($this->bar_shadow_color[$i % $numcolors]);
955 }
956 else {
957 $img->PushColor($this->bar_shadow_color);
958 }
959
960 if( $accy > 0 ) {
961 $sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv;
962 $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv;
963 $sp[8]=$pts[2]; $sp[9]=$pts[3]-1;
964 $sp[10]=$pts[4]+1; $sp[11]=$pts[5];
965 $img->FilledPolygon($sp,4);
966 }
967 elseif( $accy_neg < 0 ) {
968 $nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv;
969 $nsp[8]=$pts[4]+1; $nsp[9]=$pts[5];
970 $img->FilledPolygon($nsp,4);
971 }
972 $img->PopColor();
973 }
974 }
975
976
977 // If value is NULL or 0, then don't draw a bar at all
978 if ($this->plots[$j]->coords[0][$i] == 0 ) continue;
979
980 if( $this->plots[$j]->grad ) {
981 if( $grad === null ) {
982 $grad = new Gradient($img);
983 }
984 if( is_array($this->plots[$j]->grad_fromcolor) ) {
985 // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array
986 // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be
987 // an array to specify both (from, to style) for each individual bar. The way to know the difference is
988 // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB
989 // triple.
990 $ng = count($this->plots[$j]->grad_fromcolor);
991 if( $ng === 3 ) {
992 if( is_numeric($this->plots[$j]->grad_fromcolor[0]) && $this->plots[$j]->grad_fromcolor[0] > 0 &&
993 $this->plots[$j]->grad_fromcolor[0] < 256 ) {
994 // RGB Triple
995 $fromcolor = $this->plots[$j]->grad_fromcolor;
996 $tocolor = $this->plots[$j]->grad_tocolor;
997 $style = $this->plots[$j]->grad_style;
998 }
999 else {
1000 $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0];
1001 $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1];
1002 $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2];
1003 }
1004 }
1005 else {
1006 $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0];
1007 $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1];
1008 $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2];
1009 }
1010 $grad->FilledRectangle($pts[2],$pts[3],
1011 $pts[6],$pts[7],
1012 $fromcolor,$tocolor,$style);
1013 }
1014 else {
1015 $grad->FilledRectangle($pts[2],$pts[3],
1016 $pts[6],$pts[7],
1017 $this->plots[$j]->grad_fromcolor,
1018 $this->plots[$j]->grad_tocolor,
1019 $this->plots[$j]->grad_style);
1020 }
1021 } else {
1022 if (is_array($this->plots[$j]->fill_color) ) {
1023 $numcolors = count($this->plots[$j]->fill_color);
1024 $fillcolor = $this->plots[$j]->fill_color[$i % $numcolors];
1025 // If the bar is specified to be non filled then the fill color is false
1026 if( $fillcolor !== false ) {
1027 $img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]);
1028 }
1029 }
1030 else {
1031 $fillcolor = $this->plots[$j]->fill_color;
1032 if( $fillcolor !== false ) {
1033 $img->SetColor($this->plots[$j]->fill_color);
1034 }
1035 }
1036 if( $fillcolor !== false ) {
1037 $img->FilledPolygon($pts);
1038 }
1039 }
1040
1041 $img->SetColor($this->plots[$j]->color);
1042
1043 // Stroke the pattern
1044 if( $this->plots[$j]->iPattern > -1 ) {
1045 if( $pattern===NULL ) {
1046 $pattern = new RectPatternFactory();
1047 }
1048
1049 $prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1);
1050 $prect->SetDensity($this->plots[$j]->iPatternDensity);
1051 if( $this->plots[$j]->coords[0][$i] < 0 ) {
1052 $rx = $pts[0];
1053 $ry = $pts[1];
1054 }
1055 else {
1056 $rx = $pts[2];
1057 $ry = $pts[3];
1058 }
1059 $width = abs($pts[4]-$pts[0])+1;
1060 $height = abs($pts[1]-$pts[3])+1;
1061 $prect->SetPos(new Rectangle($rx,$ry,$width,$height));
1062 $prect->Stroke($img);
1063 }
1064
1065
1066 // CSIM array
1067
1068 if( $i < count($this->plots[$j]->csimtargets) ) {
1069 // Create the client side image map
1070 $rpts = $img->ArrRotate($pts);
1071 $csimcoord=round($rpts[0]).", ".round($rpts[1]);
1072 for( $k=1; $k < 4; ++$k){
1073 $csimcoord .= ", ".round($rpts[2*$k]).", ".round($rpts[2*$k+1]);
1074 }
1075 if( ! empty($this->plots[$j]->csimtargets[$i]) ) {
1076 $this->csimareas.= '<area shape="poly" coords="'.$csimcoord.'" ';
1077 $this->csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\" ";
1078
1079 if( ! empty($this->plots[$j]->csimwintargets[$i]) ) {
1080 $this->csimareas.= " target=\"".$this->plots[$j]->csimwintargets[$i]."\" ";
1081 }
1082
1083 $sval='';
1084 if( !empty($this->plots[$j]->csimalts[$i]) ) {
1085 $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]);
1086 $this->csimareas .= " title=\"$sval\" ";
1087 }
1088 $this->csimareas .= " alt=\"$sval\" />\n";
1089 }
1090 }
1091
1092 $pts[] = $pts[0];
1093 $pts[] = $pts[1];
1094 $img->SetLineWeight($this->plots[$j]->weight);
1095 $img->Polygon($pts);
1096 $img->SetLineWeight(1);
1097 }
1098
1099 // Daw potential bar around the entire accbar bar
1100 if( $this->weight > 0 ) {
1101 $y=$yscale->Translate(0);
1102 $img->SetColor($this->color);
1103 $img->SetLineWeight($this->weight);
1104 $img->Rectangle($pts[0],$y,$pts[6],$pts[5]);
1105 }
1106
1107 // Draw labels for each acc.bar
1108
1109 $x=$pts[2]+($pts[4]-$pts[2])/2;
1110 if($this->bar_shadow) $x += $ssh;
1111
1112 // First stroke the accumulated value for the entire bar
1113 // This value is always placed at the top/bottom of the bars
1114 if( $accy + $accy_neg < 0 ) {
1115 $y=$yscale->Translate($accy_neg);
1116 }
1117 else {
1118 $y=$yscale->Translate($accy);
1119 }
1120 $this->value->Stroke($img,$accy + $accy_neg,$x,$y);
1121
1122 $accy = 0;
1123 $accy_neg = 0;
1124 for($j=0; $j < $this->nbrplots; ++$j ) {
1125
1126 // We don't print 0 values in an accumulated bar plot
1127 if( $this->plots[$j]->coords[0][$i] == 0 ) continue;
1128
1129 if ($this->plots[$j]->coords[0][$i] > 0) {
1130 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy);
1131 $accyt=$yscale->Translate($accy);
1132 if( $this->plots[$j]->valuepos=='center' ) {
1133 $y = $accyt-($accyt-$yt)/2;
1134 }
1135 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1136 $y = $accyt;
1137 }
1138 else { // top or max
1139 $y = $accyt-($accyt-$yt);
1140 }
1141 $accy+=$this->plots[$j]->coords[0][$i];
1142 if( $this->plots[$j]->valuepos=='center' ) {
1143 $this->plots[$j]->value->SetAlign("center","center");
1144 $this->plots[$j]->value->SetMargin(0);
1145 }
1146 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1147 $this->plots[$j]->value->SetAlign('center','bottom');
1148 $this->plots[$j]->value->SetMargin(2);
1149 }
1150 else {
1151 $this->plots[$j]->value->SetAlign('center','top');
1152 $this->plots[$j]->value->SetMargin(1);
1153 }
1154 } else {
1155 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg);
1156 $accyt=$yscale->Translate($accy_neg);
1157 $accy_neg+=$this->plots[$j]->coords[0][$i];
1158 if( $this->plots[$j]->valuepos=='center' ) {
1159 $y = $accyt-($accyt-$yt)/2;
1160 }
1161 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1162 $y = $accyt;
1163 }
1164 else {
1165 $y = $accyt-($accyt-$yt);
1166 }
1167 if( $this->plots[$j]->valuepos=='center' ) {
1168 $this->plots[$j]->value->SetAlign("center","center");
1169 $this->plots[$j]->value->SetMargin(0);
1170 }
1171 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1172 $this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top');
1173 $this->plots[$j]->value->SetMargin(-2);
1174 }
1175 else {
1176 $this->plots[$j]->value->SetAlign('center','bottom');
1177 $this->plots[$j]->value->SetMargin(-1);
1178 }
1179 }
1180 $this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],round($x),round($y));
1181 }
1182
1183 }
1184 return true;
1185 }
1186} // Class
1187
1188/* EOF */
1189?>
Note: See TracBrowser for help on using the repository browser.