| [ PHPXref.com ] | [ Generated: Sun Jul 20 20:16:32 2008 ] | [ Simple Groupware 0.25 ] |
| [ Index ] [ Variables ] [ Functions ] [ Classes ] [ Constants ] [ Statistics ] | ||
[Summary view] [Print] [Text view]
1 <?php 2 /*======================================================================= 3 // File: JPGRAPH_LINE.PHP 4 // Description: Line plot extension for JpGraph 5 // Created: 2001-01-08 6 // Author: Johan Persson (johanp@aditus.nu) 7 // Ver: $Id: jpgraph_line.php 455 2006-02-04 12:01:03Z ljp $ 8 // 9 // Copyright (c) Aditus Consulting. All rights reserved. 10 //======================================================================== 11 */ 12 13 require_once ('jpgraph_plotmark.inc'); 14 15 // constants for the (filled) area 16 DEFINE("LP_AREA_FILLED", true); 17 DEFINE("LP_AREA_NOT_FILLED", false); 18 DEFINE("LP_AREA_BORDER",false); 19 DEFINE("LP_AREA_NO_BORDER",true); 20 21 //=================================================== 22 // CLASS LinePlot 23 // Description: 24 //=================================================== 25 class LinePlot extends Plot{ 26 var $filled=false; 27 var $fill_color='blue'; 28 var $mark=null; 29 var $step_style=false, $center=false; 30 var $line_style=1; // Default to solid 31 var $filledAreas = array(); // array of arrays(with min,max,col,filled in them) 32 var $barcenter=false; // When we mix line and bar. Should we center the line in the bar. 33 var $fillFromMin = false ; 34 var $fillgrad=false,$fillgrad_fromcolor='navy',$fillgrad_tocolor='silver',$fillgrad_numcolors=100; 35 var $iFastStroke=false; 36 37 //--------------- 38 // CONSTRUCTOR 39 function LinePlot(&$datay,$datax=false) { 40 $this->Plot($datay,$datax); 41 $this->mark = new PlotMark(); 42 } 43 //--------------- 44 // PUBLIC METHODS 45 46 // Set style, filled or open 47 function SetFilled($aFlag=true) { 48 JpGraphError::RaiseL(10001);//('LinePlot::SetFilled() is deprecated. Use SetFillColor()'); 49 } 50 51 function SetBarCenter($aFlag=true) { 52 $this->barcenter=$aFlag; 53 } 54 55 function SetStyle($aStyle) { 56 $this->line_style=$aStyle; 57 } 58 59 function SetStepStyle($aFlag=true) { 60 $this->step_style = $aFlag; 61 } 62 63 function SetColor($aColor) { 64 parent::SetColor($aColor); 65 } 66 67 function SetFillFromYMin($f=true) { 68 $this->fillFromMin = $f ; 69 } 70 71 function SetFillColor($aColor,$aFilled=true) { 72 $this->fill_color=$aColor; 73 $this->filled=$aFilled; 74 } 75 76 function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) { 77 $this->fillgrad_fromcolor = $aFromColor; 78 $this->fillgrad_tocolor = $aToColor; 79 $this->fillgrad_numcolors = $aNumColors; 80 $this->filled = $aFilled; 81 $this->fillgrad = true; 82 } 83 84 function Legend(&$graph) { 85 if( $this->legend!="" ) { 86 if( $this->filled && !$this->fillgrad ) { 87 $graph->legend->Add($this->legend, 88 $this->fill_color,$this->mark,0, 89 $this->legendcsimtarget,$this->legendcsimalt); 90 } 91 elseif( $this->fillgrad ) { 92 $color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor); 93 // In order to differentiate between gradients and cooors specified as an RGB triple 94 $graph->legend->Add($this->legend,$color,"",-2 /* -GRAD_HOR */, 95 $this->legendcsimtarget,$this->legendcsimalt); 96 } 97 else { 98 $graph->legend->Add($this->legend, 99 $this->color,$this->mark,$this->line_style, 100 $this->legendcsimtarget,$this->legendcsimalt); 101 } 102 } 103 } 104 105 function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) { 106 if($aMin > $aMax) { 107 // swap 108 $tmp = $aMin; 109 $aMin = $aMax; 110 $aMax = $tmp; 111 } 112 $this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder); 113 } 114 115 // Gets called before any axis are stroked 116 function PreStrokeAdjust(&$graph) { 117 118 // If another plot type have already adjusted the 119 // offset we don't touch it. 120 // (We check for empty in case the scale is a log scale 121 // and hence doesn't contain any xlabel_offset) 122 if( empty($graph->xaxis->scale->ticks->xlabel_offset) || 123 $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { 124 if( $this->center ) { 125 ++$this->numpoints; 126 $a=0.5; $b=0.5; 127 } else { 128 $a=0; $b=0; 129 } 130 $graph->xaxis->scale->ticks->SetXLabelOffset($a); 131 $graph->SetTextScaleOff($b); 132 //$graph->xaxis->scale->ticks->SupressMinorTickMarks(); 133 } 134 } 135 136 function SetFastStroke($aFlg=true) { 137 $this->iFastStroke = $aFlg; 138 } 139 140 function FastStroke(&$img,&$xscale,&$yscale,$aStartPoint=0,$exist_x=true) { 141 // An optimized stroke for many data points with no extra 142 // features but 60% faster. You can't have values or line styles, or null 143 // values in plots. 144 $numpoints=count($this->coords[0]); 145 if( $this->barcenter ) 146 $textadj = 0.5-$xscale->text_scale_off; 147 else 148 $textadj = 0; 149 150 $img->SetColor($this->color); 151 $img->SetLineWeight($this->weight); 152 $pnts=$aStartPoint; 153 while( $pnts < $numpoints ) { 154 if( $exist_x ) $x=$this->coords[1][$pnts]; 155 else $x=$pnts+$textadj; 156 $xt = $xscale->Translate($x); 157 $y=$this->coords[0][$pnts]; 158 $yt = $yscale->Translate($y); 159 if( is_numeric($y) ) { 160 $cord[] = $xt; 161 $cord[] = $yt; 162 } 163 elseif( $y == '-' && $pnts > 0 ) { 164 // Just ignore 165 } 166 else { 167 JpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()'); 168 return; 169 } 170 ++$pnts; 171 } // WHILE 172 173 $img->Polygon($cord,false,true); 174 175 } 176 177 function Stroke(&$img,&$xscale,&$yscale) { 178 $idx=0; 179 $numpoints=count($this->coords[0]); 180 if( isset($this->coords[1]) ) { 181 if( count($this->coords[1])!=$numpoints ) 182 JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints); 183 //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints"); 184 else 185 $exist_x = true; 186 } 187 else 188 $exist_x = false; 189 190 if( $this->barcenter ) 191 $textadj = 0.5-$xscale->text_scale_off; 192 else 193 $textadj = 0; 194 195 // Find the first numeric data point 196 $startpoint=0; 197 while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) ) 198 ++$startpoint; 199 200 // Bail out if no data points 201 if( $startpoint == $numpoints ) 202 return; 203 204 if( $this->iFastStroke ) { 205 $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x); 206 return; 207 } 208 209 if( $exist_x ) 210 $xs=$this->coords[1][$startpoint]; 211 else 212 $xs= $textadj+$startpoint; 213 214 $img->SetStartPoint($xscale->Translate($xs), 215 $yscale->Translate($this->coords[0][$startpoint])); 216 217 if( $this->filled ) { 218 $min = $yscale->GetMinVal(); 219 if( $min > 0 || $this->fillFromMin ) 220 $fillmin = $yscale->scale_abs[0];//Translate($min); 221 else 222 $fillmin = $yscale->Translate(0); 223 224 $cord[$idx++] = $xscale->Translate($xs); 225 $cord[$idx++] = $fillmin; 226 } 227 $xt = $xscale->Translate($xs); 228 $yt = $yscale->Translate($this->coords[0][$startpoint]); 229 $cord[$idx++] = $xt; 230 $cord[$idx++] = $yt; 231 $yt_old = $yt; 232 $xt_old = $xt; 233 $y_old = $this->coords[0][$startpoint]; 234 235 $this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt); 236 237 $img->SetColor($this->color); 238 $img->SetLineWeight($this->weight); 239 $img->SetLineStyle($this->line_style); 240 $pnts=$startpoint+1; 241 $firstnonumeric = false; 242 while( $pnts < $numpoints ) { 243 244 if( $exist_x ) $x=$this->coords[1][$pnts]; 245 else $x=$pnts+$textadj; 246 $xt = $xscale->Translate($x); 247 $yt = $yscale->Translate($this->coords[0][$pnts]); 248 249 $y=$this->coords[0][$pnts]; 250 if( $this->step_style ) { 251 // To handle null values within step style we need to record the 252 // first non numeric value so we know from where to start if the 253 // non value is '-'. 254 if( is_numeric($y) ) { 255 $firstnonumeric = false; 256 if( is_numeric($y_old) ) { 257 $img->StyleLine($xt_old,$yt_old,$xt,$yt_old); 258 $img->StyleLine($xt,$yt_old,$xt,$yt); 259 } 260 elseif( $y_old == '-' ) { 261 $img->StyleLine($xt_first,$yt_first,$xt,$yt_first); 262 $img->StyleLine($xt,$yt_first,$xt,$yt); 263 } 264 else { 265 $yt_old = $yt; 266 $xt_old = $xt; 267 } 268 $cord[$idx++] = $xt; 269 $cord[$idx++] = $yt_old; 270 $cord[$idx++] = $xt; 271 $cord[$idx++] = $yt; 272 } 273 elseif( $firstnonumeric==false ) { 274 $firstnonumeric = true; 275 $yt_first = $yt_old; 276 $xt_first = $xt_old; 277 } 278 } 279 else { 280 $tmp1=$y; 281 $prev=$this->coords[0][$pnts-1]; 282 if( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x'; 283 if( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x'; 284 285 if( is_numeric($y) || (is_string($y) && $y != '-') ) { 286 if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) { 287 $img->StyleLineTo($xt,$yt); 288 } 289 else { 290 $img->SetStartPoint($xt,$yt); 291 } 292 } 293 if( $this->filled && $tmp1 !== '-' ) { 294 if( $tmp1 === 'x' ) { 295 $cord[$idx++] = $cord[$idx-3]; 296 $cord[$idx++] = $fillmin; 297 } 298 elseif( $prev === 'x' ) { 299 $cord[$idx++] = $xt; 300 $cord[$idx++] = $fillmin; 301 $cord[$idx++] = $xt; 302 $cord[$idx++] = $yt; 303 } 304 else { 305 $cord[$idx++] = $xt; 306 $cord[$idx++] = $yt; 307 } 308 } 309 else { 310 if( is_numeric($tmp1) && (is_numeric($prev) || $prev === '-' ) ) { 311 $cord[$idx++] = $xt; 312 $cord[$idx++] = $yt; 313 } 314 } 315 } 316 $yt_old = $yt; 317 $xt_old = $xt; 318 $y_old = $y; 319 320 $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); 321 322 ++$pnts; 323 } 324 325 if( $this->filled ) { 326 $cord[$idx++] = $xt; 327 if( $min > 0 || $this->fillFromMin ) 328 $cord[$idx++] = $yscale->Translate($min); 329 else 330 $cord[$idx++] = $yscale->Translate(0); 331 if( $this->fillgrad ) { 332 $img->SetLineWeight(1); 333 $grad = new Gradient($img); 334 $grad->SetNumColors($this->fillgrad_numcolors); 335 $grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor); 336 $img->SetLineWeight($this->weight); 337 } 338 else { 339 $img->SetColor($this->fill_color); 340 $img->FilledPolygon($cord); 341 } 342 if( $this->line_weight > 0 ) { 343 $img->SetColor($this->color); 344 $img->Polygon($cord); 345 } 346 } 347 348 if(!empty($this->filledAreas)) { 349 350 $minY = $yscale->Translate($yscale->GetMinVal()); 351 $factor = ($this->step_style ? 4 : 2); 352 353 for($i = 0; $i < sizeof($this->filledAreas); ++$i) { 354 // go through all filled area elements ordered by insertion 355 // fill polygon array 356 $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor]; 357 $areaCoords[] = $minY; 358 359 $areaCoords = 360 array_merge($areaCoords, 361 array_slice($cord, 362 $this->filledAreas[$i][0] * $factor, 363 ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor)); 364 $areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x 365 $areaCoords[] = $minY; // last y 366 367 if($this->filledAreas[$i][3]) { 368 $img->SetColor($this->filledAreas[$i][2]); 369 $img->FilledPolygon($areaCoords); 370 $img->SetColor($this->color); 371 } 372 // Check if we should draw the frame. 373 // If not we still re-draw the line since it might have been 374 // partially overwritten by the filled area and it doesn't look 375 // very good. 376 // TODO: The behaviour is undefined if the line does not have 377 // any line at the position of the area. 378 if( $this->filledAreas[$i][4] ) 379 $img->Polygon($areaCoords); 380 else 381 $img->Polygon($cord); 382 383 $areaCoords = array(); 384 } 385 } 386 387 if( $this->mark->type == -1 || $this->mark->show == false ) 388 return; 389 390 for( $pnts=0; $pnts<$numpoints; ++$pnts) { 391 392 if( $exist_x ) $x=$this->coords[1][$pnts]; 393 else $x=$pnts+$textadj; 394 $xt = $xscale->Translate($x); 395 $yt = $yscale->Translate($this->coords[0][$pnts]); 396 397 if( is_numeric($this->coords[0][$pnts]) ) { 398 if( !empty($this->csimtargets[$pnts]) ) { 399 $this->mark->SetCSIMTarget($this->csimtargets[$pnts]); 400 $this->mark->SetCSIMAlt($this->csimalts[$pnts]); 401 } 402 if( $exist_x ) 403 $x=$this->coords[1][$pnts]; 404 else 405 $x=$pnts; 406 $this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x); 407 $this->mark->Stroke($img,$xt,$yt); 408 $this->csimareas .= $this->mark->GetCSIMAreas(); 409 $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt); 410 } 411 } 412 413 } 414 } // Class 415 416 //=================================================== 417 // CLASS AccLinePlot 418 // Description: 419 //=================================================== 420 class AccLinePlot extends Plot { 421 var $plots=null,$nbrplots=0,$numpoints=0; 422 var $iStartEndZero=true; 423 //--------------- 424 // CONSTRUCTOR 425 function AccLinePlot($plots) { 426 $this->plots = $plots; 427 $this->nbrplots = count($plots); 428 $this->numpoints = $plots[0]->numpoints; 429 430 for($i=0; $i < $this->nbrplots; ++$i ) { 431 $this->LineInterpolate($this->plots[$i]->coords[0]); 432 } 433 } 434 435 //--------------- 436 // PUBLIC METHODS 437 function Legend(&$graph) { 438 $n=count($this->plots); 439 for($i=0; $i < $n; ++$i ) 440 $this->plots[$i]->DoLegend($graph); 441 } 442 443 function Max() { 444 list($xmax) = $this->plots[0]->Max(); 445 $nmax=0; 446 $n = count($this->plots); 447 for($i=0; $i < $n; ++$i) { 448 $nc = count($this->plots[$i]->coords[0]); 449 $nmax = max($nmax,$nc); 450 list($x) = $this->plots[$i]->Max(); 451 $xmax = Max($xmax,$x); 452 } 453 for( $i = 0; $i < $nmax; $i++ ) { 454 // Get y-value for line $i by adding the 455 // individual bars from all the plots added. 456 // It would be wrong to just add the 457 // individual plots max y-value since that 458 // would in most cases give to large y-value. 459 $y=$this->plots[0]->coords[0][$i]; 460 for( $j = 1; $j < $this->nbrplots; $j++ ) { 461 $y += $this->plots[ $j ]->coords[0][$i]; 462 } 463 $ymax[$i] = $y; 464 } 465 $ymax = max($ymax); 466 return array($xmax,$ymax); 467 } 468 469 function Min() { 470 $nmax=0; 471 list($xmin,$ysetmin) = $this->plots[0]->Min(); 472 $n = count($this->plots); 473 for($i=0; $i < $n; ++$i) { 474 $nc = count($this->plots[$i]->coords[0]); 475 $nmax = max($nmax,$nc); 476 list($x,$y) = $this->plots[$i]->Min(); 477 $xmin = Min($xmin,$x); 478 $ysetmin = Min($y,$ysetmin); 479 } 480 for( $i = 0; $i < $nmax; $i++ ) { 481 // Get y-value for line $i by adding the 482 // individual bars from all the plots added. 483 // It would be wrong to just add the 484 // individual plots min y-value since that 485 // would in most cases give to small y-value. 486 $y=$this->plots[0]->coords[0][$i]; 487 for( $j = 1; $j < $this->nbrplots; $j++ ) { 488 $y += $this->plots[ $j ]->coords[0][$i]; 489 } 490 $ymin[$i] = $y; 491 } 492 $ymin = Min($ysetmin,Min($ymin)); 493 return array($xmin,$ymin); 494 } 495 496 // Gets called before any axis are stroked 497 function PreStrokeAdjust(&$graph) { 498 499 // If another plot type have already adjusted the 500 // offset we don't touch it. 501 // (We check for empty in case the scale is a log scale 502 // and hence doesn't contain any xlabel_offset) 503 504 if( empty($graph->xaxis->scale->ticks->xlabel_offset) || 505 $graph->xaxis->scale->ticks->xlabel_offset == 0 ) { 506 if( $this->center ) { 507 ++$this->numpoints; 508 $a=0.5; $b=0.5; 509 } else { 510 $a=0; $b=0; 511 } 512 $graph->xaxis->scale->ticks->SetXLabelOffset($a); 513 $graph->SetTextScaleOff($b); 514 $graph->xaxis->scale->ticks->SupressMinorTickMarks(); 515 } 516 517 } 518 519 function SetInterpolateMode($aIntMode) { 520 $this->iStartEndZero=$aIntMode; 521 } 522 523 // Replace all '-' with an interpolated value. We use straightforward 524 // linear interpolation. If the data starts with one or several '-' they 525 // will be replaced by the the first valid data point 526 function LineInterpolate(&$aData) { 527 528 $n=count($aData); 529 $i=0; 530 531 // If first point is undefined we will set it to the same as the first 532 // valid data 533 if( $aData[$i]==='-' ) { 534 // Find the first valid data 535 while( $i < $n && $aData[$i]==='-' ) { 536 ++$i; 537 } 538 if( $i < $n ) { 539 for($j=0; $j < $i; ++$j ) { 540 if( $this->iStartEndZero ) 541 $aData[$i] = 0; 542 else 543 $aData[$j] = $aData[$i]; 544 } 545 } 546 else { 547 // All '-' => Error 548 return false; 549 } 550 } 551 552 while($i < $n) { 553 while( $i < $n && $aData[$i] !== '-' ) { 554 ++$i; 555 } 556 if( $i < $n ) { 557 $pstart=$i-1; 558 559 // Now see how long this segment of '-' are 560 while( $i < $n && $aData[$i] === '-' ) 561 ++$i; 562 if( $i < $n ) { 563 $pend=$i; 564 $size=$pend-$pstart; 565 $k=($aData[$pend]-$aData[$pstart])/$size; 566 // Replace the segment of '-' with a linear interpolated value. 567 for($j=1; $j < $size; ++$j ) { 568 $aData[$pstart+$j] = $aData[$pstart] + $j*$k ; 569 } 570 } 571 else { 572 // There are no valid end point. The '-' goes all the way to the end 573 // In that case we just set all the remaining values the the same as the 574 // last valid data point. 575 for( $j=$pstart+1; $j < $n; ++$j ) 576 if( $this->iStartEndZero ) 577 $aData[$j] = 0; 578 else 579 $aData[$j] = $aData[$pstart] ; 580 } 581 } 582 } 583 return true; 584 } 585 586 // To avoid duplicate of line drawing code here we just 587 // change the y-values for each plot and then restore it 588 // after we have made the stroke. We must do this copy since 589 // it wouldn't be possible to create an acc line plot 590 // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl)); 591 // since this method would have a side effect. 592 function Stroke(&$img,&$xscale,&$yscale) { 593 $img->SetLineWeight($this->weight); 594 $this->numpoints = count($this->plots[0]->coords[0]); 595 // Allocate array 596 $coords[$this->nbrplots][$this->numpoints]=0; 597 for($i=0; $i<$this->numpoints; $i++) { 598 $coords[0][$i]=$this->plots[0]->coords[0][$i]; 599 $accy=$coords[0][$i]; 600 for($j=1; $j<$this->nbrplots; ++$j ) { 601 $coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy; 602 $accy = $coords[$j][$i]; 603 } 604 } 605 for($j=$this->nbrplots-1; $j>=0; --$j) { 606 $p=$this->plots[$j]; 607 for( $i=0; $i<$this->numpoints; ++$i) { 608 $tmp[$i]=$p->coords[0][$i]; 609 $p->coords[0][$i]=$coords[$j][$i]; 610 } 611 $p->Stroke($img,$xscale,$yscale); 612 for( $i=0; $i<$this->numpoints; ++$i) 613 $p->coords[0][$i]=$tmp[$i]; 614 $p->coords[0][]=$tmp; 615 } 616 } 617 } // Class 618 619 /* EOF */ 620 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| [ Powered by PHPXref - Served by Debian GNU/Linux ] |