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

Last change on this file since 250 was 2, checked in by root, 15 years ago

importo il progetto

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