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