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

Last change on this file since 430 was 346, checked in by roby, 4 years ago

ulteriori modifiche per adeguamento a php7
Client: aggiornamento jpgraph

File size: 46.5 KB
RevLine 
[2]1<?php
2/*=======================================================================
[284]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 */
[2]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
[284]28// Description: Main code to produce a bar plot
[2]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
[284]39 protected $ybase=0; // Bars start at 0
[2]40 protected $align="center";
41 protected $bar_shadow=false;
42 protected $bar_shadow_color="black";
[284]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;
[2]52 }
53
[284]54 //---------------
55 // PUBLIC METHODS
56
[2]57 // Set a drop shadow for the bar (or rather an "up-right" shadow)
[284]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;
[2]66 }
[284]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
[2]76 // DEPRECATED use SetYBase instead
77 function SetYMin($aYStartValue) {
[284]78 //die("JpGraph Error: Deprecated function SetYMin. Use SetYBase() instead.");
79 $this->ybase=$aYStartValue;
[2]80 }
81
82 // Specify the base value for the bars
83 function SetYBase($aYStartValue) {
[284]84 $this->ybase=$aYStartValue;
[2]85 }
[284]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
[2]101 function Legend($graph) {
[284]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 }
[2]135 }
136
137 // Gets called before any axis are stroked
138 function PreStrokeAdjust($graph) {
[284]139 parent::PreStrokeAdjust($graph);
[2]140
[284]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();
[2]146
[284]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 ) {
[2]169 // Not set
[284]170 // set width to a visuable sensible default
171 $this->abswidth = $graph->img->plotwidth/(2*$this->numpoints);
172 }
173 }
[2]174 }
175
176 function Min() {
[284]177 $m = parent::Min();
178 if( $m[1] >= $this->ybase ) $m[1] = $this->ybase;
179 return $m;
[2]180 }
181
182 function Max() {
[284]183 $m = parent::Max();
184 if( $m[1] <= $this->ybase ) $m[1] = $this->ybase;
185 return $m;
186 }
187
[2]188 // Specify width as fractions of the major stepo size
189 function SetWidth($aWidth) {
[284]190 if( $aWidth > 1 ) {
191 // Interpret this as absolute width
192 $this->abswidth=$aWidth;
193 }
194 else {
195 $this->width=$aWidth;
196 }
[2]197 }
[284]198
[2]199 // Specify width in absolute pixels. If specified this
200 // overrides SetWidth()
201 function SetAbsWidth($aWidth) {
[284]202 $this->abswidth=$aWidth;
[2]203 }
[284]204
[2]205 function SetAlign($aAlign) {
[284]206 $this->align=$aAlign;
[2]207 }
[284]208
[2]209 function SetNoFill() {
[284]210 $this->grad = false;
211 $this->fill_color=false;
212 $this->fill=false;
[2]213 }
[284]214
[2]215 function SetFillColor($aColor) {
[284]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
[2]224 }
[284]225
[2]226 function SetFillGradient($aFromColor,$aToColor=null,$aStyle=null) {
[284]227 $this->grad = true;
228 $this->grad_fromcolor = $aFromColor;
229 $this->grad_tocolor = $aToColor;
230 $this->grad_style = $aStyle;
[2]231 }
[284]232
[2]233 function SetValuePos($aPos) {
[284]234 $this->valuepos = $aPos;
[2]235 }
236
237 function SetPattern($aPattern, $aColor='black'){
[284]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 }
[2]262 }
263
264 function _SetPatternHelper($aPattern, &$aPatternValue, &$aDensity){
[284]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 }
[2]310 }
311
[346]312
313 /**
314 * @override
315 * Without overriding this method, $this->numpoints does not updated correctly.
316 */
317 function Clear() {
318 $this->isRunningClear = true;
319 $this->__construct($this->inputValues['aDatay'], $this->inputValues['aDatax']);
320 $this->isRunningClear = false;
321 }
322
[284]323 function Stroke($img,$xscale,$yscale) {
[2]324
[284]325 $numpoints = count($this->coords[0]);
326 if( isset($this->coords[1]) ) {
327 if( count($this->coords[1])!=$numpoints ) {
328 JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);
329 //"Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])."Number of Y-points:$numpoints");
330 }
331 else {
332 $exist_x = true;
333 }
334 }
335 else {
336 $exist_x = false;
337 }
[2]338
339
[284]340 $numbars=count($this->coords[0]);
[2]341
[284]342 // Use GetMinVal() instead of scale[0] directly since in the case
343 // of log scale we get a correct value. Log scales will have negative
344 // values for values < 1 while still not representing negative numbers.
345 if( $yscale->GetMinVal() >= 0 )
346 $zp=$yscale->scale_abs[0];
347 else {
348 $zp=$yscale->Translate(0);
349 }
[2]350
[284]351 if( $this->abswidth > -1 ) {
352 $abswidth=$this->abswidth;
353 }
354 else {
355 $abswidth=round($this->width*$xscale->scale_factor,0);
356 }
[2]357
[284]358 // Count pontetial pattern array to avoid doing the count for each iteration
359 if( is_array($this->iPattern) ) {
360 $np = count($this->iPattern);
361 }
[2]362
[284]363 $grad = null;
364 for($i=0; $i < $numbars; ++$i) {
[2]365
[284]366 // If value is NULL, or 0 then don't draw a bar at all
367 if ($this->coords[0][$i] === null || $this->coords[0][$i] === '' )
368 continue;
[2]369
[284]370 if( $exist_x ) {
371 $x=$this->coords[1][$i];
372 }
373 else {
374 $x=$i;
375 }
[2]376
[284]377 $x=$xscale->Translate($x);
[2]378
[284]379 // Comment Note: This confuses the positioning when using acc together with
380 // grouped bars. Workaround for fixing #191
381 /*
382 if( !$xscale->textscale ) {
383 if($this->align=="center")
384 $x -= $abswidth/2;
385 elseif($this->align=="right")
386 $x -= $abswidth;
387 }
388 */
389 // Stroke fill color and fill gradient
390 $pts=array(
391 $x,$zp,
392 $x,$yscale->Translate($this->coords[0][$i]),
393 $x+$abswidth,$yscale->Translate($this->coords[0][$i]),
394 $x+$abswidth,$zp);
395 if( $this->grad ) {
396 if( $grad === null ) {
397 $grad = new Gradient($img);
398 }
399 if( is_array($this->grad_fromcolor) ) {
400 // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array
401 // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be
402 // an array to specify both (from, to style) for each individual bar. The way to know the difference is
403 // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB
404 // triple.
405 $ng = count($this->grad_fromcolor);
406 if( $ng === 3 ) {
407 if( is_numeric($this->grad_fromcolor[0]) && $this->grad_fromcolor[0] > 0 && $this->grad_fromcolor[0] < 256 ) {
408 // RGB Triple
409 $fromcolor = $this->grad_fromcolor;
410 $tocolor = $this->grad_tocolor;
411 $style = $this->grad_style;
412 }
413 else {
414 $fromcolor = $this->grad_fromcolor[$i % $ng][0];
415 $tocolor = $this->grad_fromcolor[$i % $ng][1];
416 $style = $this->grad_fromcolor[$i % $ng][2];
417 }
418 }
419 else {
420 $fromcolor = $this->grad_fromcolor[$i % $ng][0];
421 $tocolor = $this->grad_fromcolor[$i % $ng][1];
422 $style = $this->grad_fromcolor[$i % $ng][2];
423 }
424 $grad->FilledRectangle($pts[2],$pts[3],
425 $pts[6],$pts[7],
426 $fromcolor,$tocolor,$style);
427 }
428 else {
429 $grad->FilledRectangle($pts[2],$pts[3],
430 $pts[6],$pts[7],
431 $this->grad_fromcolor,$this->grad_tocolor,$this->grad_style);
432 }
433 }
434 elseif( !empty($this->fill_color) ) {
435 if(is_array($this->fill_color)) {
436 $img->PushColor($this->fill_color[$i % count($this->fill_color)]);
437 } else {
438 $img->PushColor($this->fill_color);
439 }
440 $img->FilledPolygon($pts);
441 $img->PopColor();
442 }
[2]443
[284]444/////////////////////////kokorahen rectangle polygon//////////////////////
[2]445
[284]446 // Remember value of this bar
447 $val=$this->coords[0][$i];
[2]448
[284]449 if( !empty($val) && !is_numeric($val) ) {
450 JpGraphError::RaiseL(2004,$i,$val);
451 //'All values for a barplot must be numeric. You have specified value['.$i.'] == \''.$val.'\'');
452 }
[2]453
[284]454 // Determine the shadow
455 if( $this->bar_shadow && $val != 0) {
[2]456
[284]457 $ssh = $this->bar_shadow_hsize;
458 $ssv = $this->bar_shadow_vsize;
459 // Create points to create a "upper-right" shadow
460 if( $val > 0 ) {
461 $sp[0]=$pts[6]; $sp[1]=$pts[7];
462 $sp[2]=$pts[4]; $sp[3]=$pts[5];
463 $sp[4]=$pts[2]; $sp[5]=$pts[3];
464 $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv;
465 $sp[8]=$pts[4]+$ssh; $sp[9]=$pts[5]-$ssv;
466 $sp[10]=$pts[6]+$ssh; $sp[11]=$pts[7]-$ssv;
467 }
468 elseif( $val < 0 ) {
469 $sp[0]=$pts[4]; $sp[1]=$pts[5];
470 $sp[2]=$pts[6]; $sp[3]=$pts[7];
471 $sp[4]=$pts[0]; $sp[5]=$pts[1];
472 $sp[6]=$pts[0]+$ssh; $sp[7]=$pts[1]-$ssv;
473 $sp[8]=$pts[6]+$ssh; $sp[9]=$pts[7]-$ssv;
474 $sp[10]=$pts[4]+$ssh; $sp[11]=$pts[5]-$ssv;
475 }
476 if( is_array($this->bar_shadow_color) ) {
477 $numcolors = count($this->bar_shadow_color);
478 if( $numcolors == 0 ) {
479 JpGraphError::RaiseL(2005);//('You have specified an empty array for shadow colors in the bar plot.');
480 }
481 $img->PushColor($this->bar_shadow_color[$i % $numcolors]);
482 }
483 else {
484 $img->PushColor($this->bar_shadow_color);
485 }
486 $img->FilledPolygon($sp);
487 $img->PopColor();
488
489 } elseif( $this->bar_3d && $val != 0) {
490 // Determine the 3D
491
492 $ssh = $this->bar_3d_hsize;
493 $ssv = $this->bar_3d_vsize;
494
495 // Create points to create a "upper-right" shadow
496 if( $val > 0 ) {
497 $sp1[0]=$pts[6]; $sp1[1]=$pts[7];
498 $sp1[2]=$pts[4]; $sp1[3]=$pts[5];
499 $sp1[4]=$pts[4]+$ssh; $sp1[5]=$pts[5]-$ssv;
500 $sp1[6]=$pts[6]+$ssh; $sp1[7]=$pts[7]-$ssv;
501
502 $sp2[0]=$pts[4]; $sp2[1]=$pts[5];
503 $sp2[2]=$pts[2]; $sp2[3]=$pts[3];
504 $sp2[4]=$pts[2]+$ssh; $sp2[5]=$pts[3]-$ssv;
505 $sp2[6]=$pts[4]+$ssh; $sp2[7]=$pts[5]-$ssv;
506
507 }
508 elseif( $val < 0 ) {
509 $sp1[0]=$pts[4]; $sp1[1]=$pts[5];
510 $sp1[2]=$pts[6]; $sp1[3]=$pts[7];
511 $sp1[4]=$pts[6]+$ssh; $sp1[5]=$pts[7]-$ssv;
512 $sp1[6]=$pts[4]+$ssh; $sp1[7]=$pts[5]-$ssv;
513
514 $sp2[0]=$pts[6]; $sp2[1]=$pts[7];
515 $sp2[2]=$pts[0]; $sp2[3]=$pts[1];
516 $sp2[4]=$pts[0]+$ssh; $sp2[5]=$pts[1]-$ssv;
517 $sp2[6]=$pts[6]+$ssh; $sp2[7]=$pts[7]-$ssv;
518 }
519
520 $base_color = $this->fill_color;
521
522 $img->PushColor($base_color . ':0.7');
523 $img->FilledPolygon($sp1);
524 $img->PopColor();
525
526 $img->PushColor($base_color . ':1.1');
527 $img->FilledPolygon($sp2);
528 $img->PopColor();
529 }
530
531 // Stroke the pattern
532 if( is_array($this->iPattern) ) {
533 $f = new RectPatternFactory();
534 if( is_array($this->iPatternColor) ) {
535 $pcolor = $this->iPatternColor[$i % $np];
536 }
537 else {
538 $pcolor = $this->iPatternColor;
539 }
540 $prect = $f->Create($this->iPattern[$i % $np],$pcolor,1);
541 $prect->SetDensity($this->iPatternDensity[$i % $np]);
542
543 if( $val < 0 ) {
544 $rx = $pts[0];
545 $ry = $pts[1];
546 }
547 else {
548 $rx = $pts[2];
549 $ry = $pts[3];
550 }
551 $width = abs($pts[4]-$pts[0])+1;
552 $height = abs($pts[1]-$pts[3])+1;
553 $prect->SetPos(new Rectangle($rx,$ry,$width,$height));
554 $prect->Stroke($img);
555 }
556 else {
557 if( $this->iPattern > -1 ) {
558 $f = new RectPatternFactory();
559 $prect = $f->Create($this->iPattern,$this->iPatternColor,1);
560 $prect->SetDensity($this->iPatternDensity);
561 if( $val < 0 ) {
562 $rx = $pts[0];
563 $ry = $pts[1];
564 }
565 else {
566 $rx = $pts[2];
567 $ry = $pts[3];
568 }
569 $width = abs($pts[4]-$pts[0])+1;
570 $height = abs($pts[1]-$pts[3])+1;
571 $prect->SetPos(new Rectangle($rx,$ry,$width,$height));
572 $prect->Stroke($img);
573 }
574 }
575
576 // Stroke the outline of the bar
577 if( is_array($this->color) ) {
578 $img->SetColor($this->color[$i % count($this->color)]);
579 }
580 else {
581 $img->SetColor($this->color);
582 }
583
584 $pts[] = $pts[0];
585 $pts[] = $pts[1];
586
587 if( $this->weight > 0 ) {
588 $img->SetLineWeight($this->weight);
589 $img->Polygon($pts);
590 }
591
592 // Determine how to best position the values of the individual bars
593 $x=$pts[2]+($pts[4]-$pts[2])/2;
594 $this->value->SetMargin(5);
595
596 if( $this->valuepos=='top' ) {
597 $y=$pts[3];
598 if( $img->a === 90 ) {
599 if( $val < 0 ) {
600 $this->value->SetAlign('right','center');
601 }
602 else {
603 $this->value->SetAlign('left','center');
604 }
605
606 }
607 else {
608 if( $val < 0 ) {
609 $this->value->SetMargin(-5);
610 $y=$pts[1];
611 $this->value->SetAlign('center','bottom');
612 }
613 else {
614 $this->value->SetAlign('center','bottom');
615 }
616
617 }
618 $this->value->Stroke($img,$val,$x,$y);
619 }
620 elseif( $this->valuepos=='max' ) {
621 $y=$pts[3];
622 if( $img->a === 90 ) {
623 if( $val < 0 )
624 $this->value->SetAlign('left','center');
625 else
626 $this->value->SetAlign('right','center');
627 }
628 else {
629 if( $val < 0 ) {
630 $this->value->SetAlign('center','bottom');
631 }
632 else {
633 $this->value->SetAlign('center','top');
634 }
635 }
636 $this->value->SetMargin(-5);
637 $this->value->Stroke($img,$val,$x,$y);
638 }
639 elseif( $this->valuepos=='center' ) {
640 $y = ($pts[3] + $pts[1])/2;
641 $this->value->SetAlign('center','center');
642 $this->value->SetMargin(0);
643 $this->value->Stroke($img,$val,$x,$y);
644 }
645 elseif( $this->valuepos=='bottom' || $this->valuepos=='min' ) {
646 $y=$pts[1];
647 if( $img->a === 90 ) {
648 if( $val < 0 )
649 $this->value->SetAlign('right','center');
650 else
651 $this->value->SetAlign('left','center');
652 }
653 $this->value->SetMargin(3);
654 $this->value->Stroke($img,$val,$x,$y);
655 }
656 else {
657 JpGraphError::RaiseL(2006,$this->valuepos);
658 //'Unknown position for values on bars :'.$this->valuepos);
659 }
660 // Create the client side image map
661 $rpts = $img->ArrRotate($pts);
662 $csimcoord=round($rpts[0]).", ".round($rpts[1]);
663 for( $j=1; $j < 4; ++$j){
664 $csimcoord .= ", ".round($rpts[2*$j]).", ".round($rpts[2*$j+1]);
665 }
666 if( !empty($this->csimtargets[$i]) ) {
667 $this->csimareas .= '<area shape="poly" coords="'.$csimcoord.'" ';
668 $this->csimareas .= " href=\"".htmlentities($this->csimtargets[$i])."\"";
669
670 if( !empty($this->csimwintargets[$i]) ) {
671 $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
672 }
673
674 $sval='';
675 if( !empty($this->csimalts[$i]) ) {
676 $sval=sprintf($this->csimalts[$i],$this->coords[0][$i]);
677 $this->csimareas .= " title=\"$sval\" alt=\"$sval\" ";
678 }
679 $this->csimareas .= " />\n";
680 }
681 }
682 return true;
[2]683 }
684} // Class
685
686//===================================================
687// CLASS GroupBarPlot
688// Description: Produce grouped bar plots
689//===================================================
690class GroupBarPlot extends BarPlot {
[284]691 public $plots;
692 private $nbrplots=0;
693 //---------------
694 // CONSTRUCTOR
695 function __construct($plots) {
696 $this->width=0.7;
697 $this->plots = $plots;
698 $this->nbrplots = count($plots);
699 if( $this->nbrplots < 1 ) {
700 JpGraphError::RaiseL(2007);//('Cannot create GroupBarPlot from empty plot array.');
701 }
702 for($i=0; $i < $this->nbrplots; ++$i ) {
703 if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) {
704 JpGraphError::RaiseL(2008,$i);//("Group bar plot element nbr $i is undefined or empty.");
705 }
706 }
707 $this->numpoints = $plots[0]->numpoints;
708 $this->width=0.7;
[2]709 }
710
[284]711 //---------------
712 // PUBLIC METHODS
[2]713 function Legend($graph) {
[284]714 $n = count($this->plots);
715 for($i=0; $i < $n; ++$i) {
716 $c = get_class($this->plots[$i]);
717 if( !($this->plots[$i] instanceof BarPlot) ) {
718 JpGraphError::RaiseL(2009,$c);
719 //('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.')');
720 }
721 $this->plots[$i]->DoLegend($graph);
722 }
[2]723 }
[284]724
[2]725 function Min() {
[284]726 list($xmin,$ymin) = $this->plots[0]->Min();
727 $n = count($this->plots);
728 for($i=0; $i < $n; ++$i) {
729 list($xm,$ym) = $this->plots[$i]->Min();
[346]730 $xmin = min($xmin,$xm);
[284]731 $ymin = min($ymin,$ym);
732 }
733 return array($xmin,$ymin);
[2]734 }
[284]735
[2]736 function Max() {
[284]737 list($xmax,$ymax) = $this->plots[0]->Max();
738 $n = count($this->plots);
739 for($i=0; $i < $n; ++$i) {
740 list($xm,$ym) = $this->plots[$i]->Max();
741 $xmax = max($xmax,$xm);
742 $ymax = max($ymax,$ym);
743 }
744 return array($xmax,$ymax);
[2]745 }
[284]746
[2]747 function GetCSIMareas() {
[284]748 $n = count($this->plots);
749 $csimareas='';
750 for($i=0; $i < $n; ++$i) {
751 $csimareas .= $this->plots[$i]->csimareas;
752 }
753 return $csimareas;
[2]754 }
[284]755
[2]756 // Stroke all the bars next to each other
[284]757 function Stroke($img,$xscale,$yscale) {
758 $tmp=$xscale->off;
759 $n = count($this->plots);
760 $subwidth = $this->width/$this->nbrplots ;
[2]761
[284]762 for( $i=0; $i < $n; ++$i ) {
763 $this->plots[$i]->ymin=$this->ybase;
764 $this->plots[$i]->SetWidth($subwidth);
765
766 // If the client have used SetTextTickInterval() then
767 // major_step will be > 1 and the positioning will fail.
768 // If we assume it is always one the positioning will work
769 // fine with a text scale but this will not work with
770 // arbitrary linear scale
771 $xscale->off = $tmp+$i*round($xscale->scale_factor* $subwidth);
772 $this->plots[$i]->Stroke($img,$xscale,$yscale);
773 }
774 $xscale->off=$tmp;
[2]775 }
776} // Class
777
778//===================================================
779// CLASS AccBarPlot
780// Description: Produce accumulated bar plots
781//===================================================
782class AccBarPlot extends BarPlot {
[284]783 public $plots=null;
784 private $nbrplots=0;
785 //---------------
786 // CONSTRUCTOR
787 function __construct($plots) {
788 $this->plots = $plots;
789 $this->nbrplots = count($plots);
790 if( $this->nbrplots < 1 ) {
791 JpGraphError::RaiseL(2010);//('Cannot create AccBarPlot from empty plot array.');
792 }
793 for($i=0; $i < $this->nbrplots; ++$i ) {
794 if( empty($this->plots[$i]) || !isset($this->plots[$i]) ) {
795 JpGraphError::RaiseL(2011,$i);//("Acc bar plot element nbr $i is undefined or empty.");
796 }
797 }
[2]798
[284]799 // We can only allow individual plost which do not have specified X-positions
800 for($i=0; $i < $this->nbrplots; ++$i ) {
801 if( !empty($this->plots[$i]->coords[1]) ) {
802 JpGraphError::RaiseL(2015);
803 //'Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-positions.');
804 }
805 }
806
807 // Use 0 weight by default which means that the individual bar
808 // weights will be used per part n the accumulated bar
809 $this->SetWeight(0);
810
811 $this->numpoints = $plots[0]->numpoints;
812 $this->value = new DisplayValue();
[2]813 }
814
[284]815 //---------------
816 // PUBLIC METHODS
[2]817 function Legend($graph) {
[284]818 $n = count($this->plots);
819 for( $i=$n-1; $i >= 0; --$i ) {
820 $c = get_class($this->plots[$i]);
821 if( !($this->plots[$i] instanceof BarPlot) ) {
822 JpGraphError::RaiseL(2012,$c);
823 //('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.')');
824 }
825 $this->plots[$i]->DoLegend($graph);
826 }
[2]827 }
828
829 function Max() {
[284]830 list($xmax) = $this->plots[0]->Max();
831 $nmax=0;
832 for($i=0; $i < count($this->plots); ++$i) {
833 $n = count($this->plots[$i]->coords[0]);
834 $nmax = max($nmax,$n);
835 list($x) = $this->plots[$i]->Max();
836 $xmax = max($xmax,$x);
837 }
838 for( $i = 0; $i < $nmax; $i++ ) {
839 // Get y-value for bar $i by adding the
840 // individual bars from all the plots added.
841 // It would be wrong to just add the
842 // individual plots max y-value since that
843 // would in most cases give to large y-value.
844 $y=0;
845 if( !isset($this->plots[0]->coords[0][$i]) ) {
846 JpGraphError::RaiseL(2014);
847 }
848 if( $this->plots[0]->coords[0][$i] > 0 )
849 $y=$this->plots[0]->coords[0][$i];
850 for( $j = 1; $j < $this->nbrplots; $j++ ) {
851 if( !isset($this->plots[$j]->coords[0][$i]) ) {
852 JpGraphError::RaiseL(2014);
853 }
854 if( $this->plots[$j]->coords[0][$i] > 0 )
855 $y += $this->plots[$j]->coords[0][$i];
856 }
857 $ymax[$i] = $y;
858 }
859 $ymax = max($ymax);
[2]860
[284]861 // Bar always start at baseline
862 if( $ymax <= $this->ybase )
863 $ymax = $this->ybase;
864 return array($xmax,$ymax);
[2]865 }
866
867 function Min() {
[284]868 $nmax=0;
869 list($xmin,$ysetmin) = $this->plots[0]->Min();
870 for($i=0; $i < count($this->plots); ++$i) {
871 $n = count($this->plots[$i]->coords[0]);
872 $nmax = max($nmax,$n);
873 list($x,$y) = $this->plots[$i]->Min();
874 $xmin = Min($xmin,$x);
875 $ysetmin = Min($y,$ysetmin);
876 }
877 for( $i = 0; $i < $nmax; $i++ ) {
878 // Get y-value for bar $i by adding the
879 // individual bars from all the plots added.
880 // It would be wrong to just add the
881 // individual plots max y-value since that
882 // would in most cases give to large y-value.
883 $y=0;
884 if( $this->plots[0]->coords[0][$i] < 0 )
885 $y=$this->plots[0]->coords[0][$i];
886 for( $j = 1; $j < $this->nbrplots; $j++ ) {
887 if( $this->plots[$j]->coords[0][$i] < 0 )
888 $y += $this->plots[ $j ]->coords[0][$i];
889 }
890 $ymin[$i] = $y;
891 }
892 $ymin = Min($ysetmin,Min($ymin));
893 // Bar always start at baseline
894 if( $ymin >= $this->ybase )
895 $ymin = $this->ybase;
896 return array($xmin,$ymin);
[2]897 }
898
899 // Stroke acc bar plot
900 function Stroke($img,$xscale,$yscale) {
[284]901 $pattern=NULL;
902 $img->SetLineWeight($this->weight);
903 $grad=null;
904 for($i=0; $i < $this->numpoints-1; $i++) {
905 $accy = 0;
906 $accy_neg = 0;
907 for($j=0; $j < $this->nbrplots; ++$j ) {
908 $img->SetColor($this->plots[$j]->color);
[2]909
[284]910 if ( $this->plots[$j]->coords[0][$i] >= 0) {
911 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy);
912 $accyt=$yscale->Translate($accy);
913 $accy+=$this->plots[$j]->coords[0][$i];
914 }
915 else {
916 //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) {
917 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg);
918 $accyt=$yscale->Translate($accy_neg);
919 $accy_neg+=$this->plots[$j]->coords[0][$i];
920 }
[2]921
[284]922 $xt=$xscale->Translate($i);
[2]923
[284]924 if( $this->abswidth > -1 ) {
925 $abswidth=$this->abswidth;
926 }
927 else {
928 $abswidth=round($this->width*$xscale->scale_factor,0);
929 }
[2]930
[284]931 $pts=array($xt,$accyt,$xt,$yt,$xt+$abswidth,$yt,$xt+$abswidth,$accyt);
[2]932
[284]933 if( $this->bar_shadow ) {
934 $ssh = $this->bar_shadow_hsize;
935 $ssv = $this->bar_shadow_vsize;
[2]936
[284]937 // We must also differ if we are a positive or negative bar.
938 if( $j === 0 ) {
939 // This gets extra complicated since we have to
940 // see all plots to see if we are negative. It could
941 // for example be that all plots are 0 until the very
942 // last one. We therefore need to save the initial setup
943 // for both the negative and positive case
[2]944
[284]945 // In case the final bar is positive
946 $sp[0]=$pts[6]+1; $sp[1]=$pts[7];
947 $sp[2]=$pts[6]+$ssh; $sp[3]=$pts[7]-$ssv;
[2]948
[284]949 // In case the final bar is negative
950 $nsp[0]=$pts[0]; $nsp[1]=$pts[1];
951 $nsp[2]=$pts[0]+$ssh; $nsp[3]=$pts[1]-$ssv;
952 $nsp[4]=$pts[6]+$ssh; $nsp[5]=$pts[7]-$ssv;
953 $nsp[10]=$pts[6]+1; $nsp[11]=$pts[7];
954 }
[2]955
[284]956 if( $j === $this->nbrplots-1 ) {
957 // If this is the last plot of the bar and
958 // the total value is larger than 0 then we
959 // add the shadow.
960 if( is_array($this->bar_shadow_color) ) {
961 $numcolors = count($this->bar_shadow_color);
962 if( $numcolors == 0 ) {
963 JpGraphError::RaiseL(2013);//('You have specified an empty array for shadow colors in the bar plot.');
964 }
965 $img->PushColor($this->bar_shadow_color[$i % $numcolors]);
966 }
967 else {
968 $img->PushColor($this->bar_shadow_color);
969 }
[2]970
[284]971 if( $accy > 0 ) {
972 $sp[4]=$pts[4]+$ssh; $sp[5]=$pts[5]-$ssv;
973 $sp[6]=$pts[2]+$ssh; $sp[7]=$pts[3]-$ssv;
974 $sp[8]=$pts[2]; $sp[9]=$pts[3]-1;
975 $sp[10]=$pts[4]+1; $sp[11]=$pts[5];
976 $img->FilledPolygon($sp,4);
977 }
978 elseif( $accy_neg < 0 ) {
979 $nsp[6]=$pts[4]+$ssh; $nsp[7]=$pts[5]-$ssv;
980 $nsp[8]=$pts[4]+1; $nsp[9]=$pts[5];
981 $img->FilledPolygon($nsp,4);
982 }
983 $img->PopColor();
984 }
985 }
[2]986
987
[284]988 // If value is NULL or 0, then don't draw a bar at all
989 if ($this->plots[$j]->coords[0][$i] == 0 ) continue;
[2]990
[284]991 if( $this->plots[$j]->grad ) {
992 if( $grad === null ) {
993 $grad = new Gradient($img);
994 }
995 if( is_array($this->plots[$j]->grad_fromcolor) ) {
996 // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array
997 // then we have two choices. It can either a) be a single color specified as an RGB triple or it can be
998 // an array to specify both (from, to style) for each individual bar. The way to know the difference is
999 // to investgate the first element. If this element is an integer [0,255] then we assume it is an RGB
1000 // triple.
1001 $ng = count($this->plots[$j]->grad_fromcolor);
1002 if( $ng === 3 ) {
1003 if( is_numeric($this->plots[$j]->grad_fromcolor[0]) && $this->plots[$j]->grad_fromcolor[0] > 0 &&
1004 $this->plots[$j]->grad_fromcolor[0] < 256 ) {
1005 // RGB Triple
1006 $fromcolor = $this->plots[$j]->grad_fromcolor;
1007 $tocolor = $this->plots[$j]->grad_tocolor;
1008 $style = $this->plots[$j]->grad_style;
1009 }
1010 else {
1011 $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0];
1012 $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1];
1013 $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2];
1014 }
1015 }
1016 else {
1017 $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0];
1018 $tocolor = $this->plots[$j]->grad_fromcolor[$i % $ng][1];
1019 $style = $this->plots[$j]->grad_fromcolor[$i % $ng][2];
1020 }
1021 $grad->FilledRectangle($pts[2],$pts[3],
1022 $pts[6],$pts[7],
1023 $fromcolor,$tocolor,$style);
1024 }
1025 else {
1026 $grad->FilledRectangle($pts[2],$pts[3],
1027 $pts[6],$pts[7],
1028 $this->plots[$j]->grad_fromcolor,
1029 $this->plots[$j]->grad_tocolor,
1030 $this->plots[$j]->grad_style);
1031 }
1032 } else {
1033 if (is_array($this->plots[$j]->fill_color) ) {
1034 $numcolors = count($this->plots[$j]->fill_color);
1035 $fillcolor = $this->plots[$j]->fill_color[$i % $numcolors];
1036 // If the bar is specified to be non filled then the fill color is false
1037 if( $fillcolor !== false ) {
1038 $img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]);
1039 }
1040 }
1041 else {
1042 $fillcolor = $this->plots[$j]->fill_color;
1043 if( $fillcolor !== false ) {
1044 $img->SetColor($this->plots[$j]->fill_color);
1045 }
1046 }
1047 if( $fillcolor !== false ) {
1048 $img->FilledPolygon($pts);
1049 }
1050 }
[2]1051
[284]1052 $img->SetColor($this->plots[$j]->color);
[2]1053
[284]1054 // Stroke the pattern
1055 if( $this->plots[$j]->iPattern > -1 ) {
1056 if( $pattern===NULL ) {
1057 $pattern = new RectPatternFactory();
1058 }
[2]1059
[284]1060 $prect = $pattern->Create($this->plots[$j]->iPattern,$this->plots[$j]->iPatternColor,1);
1061 $prect->SetDensity($this->plots[$j]->iPatternDensity);
1062 if( $this->plots[$j]->coords[0][$i] < 0 ) {
1063 $rx = $pts[0];
1064 $ry = $pts[1];
1065 }
1066 else {
1067 $rx = $pts[2];
1068 $ry = $pts[3];
1069 }
1070 $width = abs($pts[4]-$pts[0])+1;
1071 $height = abs($pts[1]-$pts[3])+1;
1072 $prect->SetPos(new Rectangle($rx,$ry,$width,$height));
1073 $prect->Stroke($img);
1074 }
[2]1075
1076
[284]1077 // CSIM array
[2]1078
[284]1079 if( $i < count($this->plots[$j]->csimtargets) ) {
1080 // Create the client side image map
1081 $rpts = $img->ArrRotate($pts);
1082 $csimcoord=round($rpts[0]).", ".round($rpts[1]);
1083 for( $k=1; $k < 4; ++$k){
1084 $csimcoord .= ", ".round($rpts[2*$k]).", ".round($rpts[2*$k+1]);
1085 }
1086 if( ! empty($this->plots[$j]->csimtargets[$i]) ) {
1087 $this->csimareas.= '<area shape="poly" coords="'.$csimcoord.'" ';
1088 $this->csimareas.= " href=\"".$this->plots[$j]->csimtargets[$i]."\" ";
[2]1089
[284]1090 if( ! empty($this->plots[$j]->csimwintargets[$i]) ) {
1091 $this->csimareas.= " target=\"".$this->plots[$j]->csimwintargets[$i]."\" ";
1092 }
[2]1093
[284]1094 $sval='';
1095 if( !empty($this->plots[$j]->csimalts[$i]) ) {
1096 $sval=sprintf($this->plots[$j]->csimalts[$i],$this->plots[$j]->coords[0][$i]);
1097 $this->csimareas .= " title=\"$sval\" ";
1098 }
1099 $this->csimareas .= " alt=\"$sval\" />\n";
1100 }
1101 }
1102
1103 $pts[] = $pts[0];
1104 $pts[] = $pts[1];
1105 $img->SetLineWeight($this->plots[$j]->weight);
1106 $img->Polygon($pts);
1107 $img->SetLineWeight(1);
1108 }
1109
1110 // Daw potential bar around the entire accbar bar
1111 if( $this->weight > 0 ) {
1112 $y=$yscale->Translate(0);
1113 $img->SetColor($this->color);
1114 $img->SetLineWeight($this->weight);
1115 $img->Rectangle($pts[0],$y,$pts[6],$pts[5]);
1116 }
1117
1118 // Draw labels for each acc.bar
1119
1120 $x=$pts[2]+($pts[4]-$pts[2])/2;
1121 if($this->bar_shadow) $x += $ssh;
1122
1123 // First stroke the accumulated value for the entire bar
1124 // This value is always placed at the top/bottom of the bars
1125 if( $accy + $accy_neg < 0 ) {
1126 $y=$yscale->Translate($accy_neg);
1127 }
1128 else {
1129 $y=$yscale->Translate($accy);
1130 }
1131 $this->value->Stroke($img,$accy + $accy_neg,$x,$y);
1132
1133 $accy = 0;
1134 $accy_neg = 0;
1135 for($j=0; $j < $this->nbrplots; ++$j ) {
1136
1137 // We don't print 0 values in an accumulated bar plot
1138 if( $this->plots[$j]->coords[0][$i] == 0 ) continue;
1139
1140 if ($this->plots[$j]->coords[0][$i] > 0) {
1141 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy);
1142 $accyt=$yscale->Translate($accy);
1143 if( $this->plots[$j]->valuepos=='center' ) {
1144 $y = $accyt-($accyt-$yt)/2;
1145 }
1146 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1147 $y = $accyt;
1148 }
1149 else { // top or max
1150 $y = $accyt-($accyt-$yt);
1151 }
1152 $accy+=$this->plots[$j]->coords[0][$i];
1153 if( $this->plots[$j]->valuepos=='center' ) {
1154 $this->plots[$j]->value->SetAlign("center","center");
1155 $this->plots[$j]->value->SetMargin(0);
1156 }
1157 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1158 $this->plots[$j]->value->SetAlign('center','bottom');
1159 $this->plots[$j]->value->SetMargin(2);
1160 }
1161 else {
1162 $this->plots[$j]->value->SetAlign('center','top');
1163 $this->plots[$j]->value->SetMargin(1);
1164 }
1165 } else {
1166 $yt=$yscale->Translate($this->plots[$j]->coords[0][$i]+$accy_neg);
1167 $accyt=$yscale->Translate($accy_neg);
1168 $accy_neg+=$this->plots[$j]->coords[0][$i];
1169 if( $this->plots[$j]->valuepos=='center' ) {
1170 $y = $accyt-($accyt-$yt)/2;
1171 }
1172 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1173 $y = $accyt;
1174 }
1175 else {
1176 $y = $accyt-($accyt-$yt);
1177 }
1178 if( $this->plots[$j]->valuepos=='center' ) {
1179 $this->plots[$j]->value->SetAlign("center","center");
1180 $this->plots[$j]->value->SetMargin(0);
1181 }
1182 elseif( $this->plots[$j]->valuepos=='bottom' ) {
1183 $this->plots[$j]->value->SetAlign('center',$j==0 ? 'bottom':'top');
1184 $this->plots[$j]->value->SetMargin(-2);
1185 }
1186 else {
1187 $this->plots[$j]->value->SetAlign('center','bottom');
1188 $this->plots[$j]->value->SetMargin(-1);
1189 }
1190 }
1191 $this->plots[$j]->value->Stroke($img,$this->plots[$j]->coords[0][$i],round($x),round($y));
1192 }
1193
1194 }
1195 return true;
[2]1196 }
1197} // Class
1198
1199/* EOF */
1200?>
Note: See TracBrowser for help on using the repository browser.