[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /*======================================================================= 3 // File: JPGRAPH_GANTT.PHP 4 // Description: JpGraph Gantt plot extension 5 // Created: 2001-11-12 6 // Author: Johan Persson (johanp@aditus.nu) 7 // Ver: $Id: jpgraph_gantt.php 18250 2005-05-07 14:13:43Z ralfbecker $ 8 // 9 // License: This code is released under GPL 2.0 10 // 11 //======================================================================== 12 */ 13 14 // Scale Header types 15 DEFINE("GANTT_HDAY",1); 16 DEFINE("GANTT_HWEEK",2); 17 DEFINE("GANTT_HMONTH",4); 18 DEFINE("GANTT_HYEAR",8); 19 20 // Bar patterns 21 DEFINE("GANTT_RDIAG",BAND_RDIAG); // Right diagonal lines 22 DEFINE("GANTT_LDIAG",BAND_LDIAG); // Left diagonal lines 23 DEFINE("GANTT_SOLID",BAND_SOLID); // Solid one color 24 DEFINE("GANTT_VLINE",BAND_VLINE); // Vertical lines 25 DEFINE("GANTT_HLINE",BAND_HLINE); // Horizontal lines 26 DEFINE("GANTT_3DPLANE",BAND_3DPLANE); // "3D" Plane 27 DEFINE("GANTT_HVCROSS",BAND_HVCROSS); // Vertical/Hor crosses 28 DEFINE("GANTT_DIAGCROSS",BAND_DIAGCROSS); // Diagonal crosses 29 30 // Conversion constant 31 DEFINE("SECPERDAY",3600*24); 32 33 // Locales 34 DEFINE("LOCALE_EN",0); 35 DEFINE("LOCALE_SE",1); 36 DEFINE("LOCALE_DE",2); 37 38 // Layout of bars 39 DEFINE("GANTT_EVEN",1); 40 DEFINE("GANTT_FROMTOP",2); 41 42 // Styles for week header 43 DEFINE("WEEKSTYLE_WNBR",0); 44 DEFINE("WEEKSTYLE_FIRSTDAY",1); 45 DEFINE("WEEKSTYLE_FIRSTDAY2",1); 46 47 // Styles for month header 48 DEFINE("MONTHSTYLE_SHORTNAME",0); 49 DEFINE("MONTHSTYLE_LONGNAME",1); 50 DEFINE("MONTHSTYLE_LONGNAMEYEAR2",2); 51 DEFINE("MONTHSTYLE_SHORTNAMEYEAR2",3); 52 DEFINE("MONTHSTYLE_LONGNAMEYEAR4",4); 53 DEFINE("MONTHSTYLE_SHORTNAMEYEAR4",5); 54 55 //=================================================== 56 // CLASS DateLocale 57 // Description: Hold localized text used in dates 58 // ToDOo: Rewrite this to use the real local locale 59 // instead. 60 //=================================================== 61 class DateLocale { 62 var $iLocale=0; // Default to english 63 var $iDayAbb = array( 64 array("M","T","W","T","F","S","S"), // English locale 65 array("M","T","O","T","F","L","S"), // Swedish locale 66 array("M","D","M","D","F","S","S")); // German locale 67 var $iShortDay = array( 68 array("Mon","Tue","Wed","Thu","Fri","Sat","Sun"), 69 array("Mån","Tis","Ons","Tor","Fre","Lör","Sön"), 70 array("Mon","Die","Mit","Don","Fre","Sam","Son")); 71 var $iShortMonth = array( 72 array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"), 73 array("Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"), 74 array("Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez")); 75 var $iMonthName = array( 76 array("January","February","Mars","April","May","June","July","August","September","October","November","December"), 77 array("Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"), 78 array("Januar","Februar","März","April","Mai","Juni","July","August","September","Oktober","November","Dezember")); 79 80 //--------------- 81 // CONSTRUCTOR 82 function DateLocale() { 83 // Empty 84 } 85 86 //--------------- 87 // PUBLIC METHODS 88 function Set($aLocale) { 89 if( $aLocale < LOCALE_EN || $aLocale > LOCALE_DE ) 90 JpGraphError::Raise("<b>JpGraph Error:</b> Unsupported locale ($aLocale)"); 91 $this->iLocale = $aLocale; 92 } 93 94 function GetDayAbb() { 95 return $this->iDayAbb[$this->iLocale]; 96 } 97 98 function GetShortDay() { 99 return $this->iShortDay[$this->iLocale]; 100 } 101 102 function GetShortMonth($aMonth=null) { 103 return $this->iShortMonth[$this->iLocale]; 104 } 105 106 function GetShortMonthName($aNbr) { 107 return $this->iShortMonth[$this->iLocale][$aNbr]; 108 } 109 110 function GetLongMonthName($aNbr) { 111 return $this->iMonthName[$this->iLocale][$aNbr]; 112 } 113 114 function GetMonth() { 115 return $this->iMonthName[$this->iLocale]; 116 } 117 } 118 119 //=================================================== 120 // CLASS GanttGraph 121 // Description: Main class to handle gantt graphs 122 //=================================================== 123 class GanttGraph extends Graph { 124 var $scale; // Public accessible 125 var $iObj=array(); // Gantt objects 126 var $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels 127 var $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label 128 var $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN 129 130 //--------------- 131 // CONSTRUCTOR 132 // Create a new gantt graph 133 function GanttGraph($aWidth=-1,$aHeight=-1,$aCachedName="",$aTimeOut=0,$aInline=true) { 134 Graph::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline); 135 $this->scale = new GanttScale($this->img); 136 $this->img->SetMargin($aWidth/17,$aWidth/17,$aHeight/7,$aHeight/10); 137 138 $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY); 139 $this->SetBox(); 140 } 141 142 //--------------- 143 // PUBLIC METHODS 144 // Set what headers should be shown 145 function ShowHeaders($aFlg) { 146 $this->scale->ShowHeaders($aFlg); 147 } 148 149 // Specify the fraction of the font height that should be added 150 // as vertical margin 151 function SetLabelVMarginFactor($aVal) { 152 $this->iLabelVMarginFactor = $aVal; 153 } 154 155 // Add a new Gantt object 156 function Add(&$aObject) { 157 if( is_array($aObject) ) { 158 for($i=0; $i<count($aObject); ++$i) 159 $this->iObj[] = $aObject[$i]; 160 } 161 else 162 $this->iObj[] = $aObject; 163 } 164 165 // Override inherit method from Graph and give a warning message 166 function SetScale() { 167 JpGraphError::Raise("<b>JpGraph Error:</b> SetScale() is not meaningfull with Gantt charts."); 168 // Empty 169 } 170 171 // Specify the date range for Gantt graphs (if this is not set it will be 172 // automtically determined from the input data) 173 function SetDateRange($aStart,$aEnd) { 174 $this->scale->SetRange($aStart,$aEnd); 175 } 176 177 // Get the maximum width of the titles for the bars 178 function GetMaxLabelWidth() { 179 $m=0; 180 if( $this->iObj != null ) { 181 $m = $this->iObj[0]->title->GetWidth($this->img); 182 for($i=1; $i<count($this->iObj); ++$i) { 183 if( $this->iObj[$i]->title->HasTabs() ) { 184 list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true); 185 $m=max($m,$tot); 186 } 187 else 188 $m=max($m,$this->iObj[$i]->title->GetWidth($this->img)); 189 } 190 } 191 return $m; 192 } 193 194 // Get the maximum height of the titles for the bars 195 function GetMaxLabelHeight() { 196 $m=0; 197 if( $this->iObj != null ) { 198 $m = $this->iObj[0]->title->GetHeight($this->img); 199 for($i=1; $i<count($this->iObj); ++$i) { 200 $m=max($m,$this->iObj[$i]->title->GetHeight($this->img)); 201 } 202 } 203 return $m; 204 } 205 206 function GetMaxBarAbsHeight() { 207 $m=0; 208 if( $this->iObj != null ) { 209 $m = $this->iObj[0]->GetAbsHeight($this->img); 210 for($i=1; $i<count($this->iObj); ++$i) { 211 $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img)); 212 } 213 } 214 return $m; 215 } 216 217 // Get the maximum used line number (vertical position) for bars 218 function GetBarMaxLineNumber() { 219 $m=0; 220 if( $this->iObj != null ) { 221 $m = $this->iObj[0]->GetLineNbr(); 222 for($i=1; $i<count($this->iObj); ++$i) { 223 $m=max($m,$this->iObj[$i]->GetLineNbr()); 224 } 225 } 226 return $m; 227 } 228 229 // Get the minumum and maximum used dates for all bars 230 function GetBarMinMax() { 231 $max=$this->scale->NormalizeDate($this->iObj[0]->GetMaxDate()); 232 $min=$this->scale->NormalizeDate($this->iObj[0]->GetMinDate()); 233 for($i=1; $i<count($this->iObj); ++$i) { 234 $max=Max($max,$this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate())); 235 $min=Min($min,$this->scale->NormalizeDate($this->iObj[$i]->GetMinDate())); 236 } 237 $minDate = date("Y-m-d",$min); 238 $min = strtotime($minDate); 239 $maxDate = date("Y-m-d",$max); 240 $max = strtotime($maxDate); 241 return array($min,$max); 242 } 243 244 // Stroke the gantt chart 245 function Stroke($aStrokeFileName="") { 246 247 // Should we autoscale dates? 248 if( !$this->scale->IsRangeSet() ) { 249 list($min,$max) = $this->GetBarMinMax(); 250 $this->scale->SetRange($min,$max); 251 } 252 253 if( $this->img->img == null ) { 254 // The predefined left, right, top, bottom margins. 255 // Note that the top margin might incease depending on 256 // the title. 257 $lm=30;$rm=30;$tm=20;$bm=30; 258 if( BRAND_TIMING ) $bm += 10; 259 260 // First find out the height 261 $n=$this->GetBarMaxLineNumber()+1; 262 $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); 263 $height=$n*((1+$this->iLabelVMarginFactor)*$m); 264 265 // Add the height of the scale titles 266 $h=$this->scale->GetHeaderHeight(); 267 $height += $h; 268 269 // Calculate the top margin needed for title and subtitle 270 if( $this->title->t != "" ) { 271 $tm += $this->title->GetFontHeight($this->img); 272 } 273 if( $this->subtitle->t != "" ) { 274 $tm += $this->subtitle->GetFontHeight($this->img); 275 } 276 277 // ...and then take the bottom and top plot margins into account 278 $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin; 279 280 // Now find the minimum width for the chart required 281 $fw=$this->scale->day->GetFontWidth($this->img)+4; 282 $nd=$this->scale->GetNumberOfDays(); 283 if( !$this->scale->IsDisplayDay() ) { 284 // If we don't display the individual days we can shrink the 285 // scale a little bit. This is a little bit pragmatic at the 286 // moment and should be re-written to take into account 287 // a) What scales exactly are shown and 288 // b) what format do they use so we know how wide we need to 289 // make each scale text space at minimum. 290 $fw /= 2; 291 if( !$this->scale->IsDisplayWeek() ) { 292 $fw /= 1.8; 293 } 294 } 295 296 // Now determine the width for the activity titles column 297 // This is complicated by the fact that the titles may have 298 // tabs. In that case we also need to calculate the individual 299 // tab positions based on the width of the individual columns 300 301 $titlewidth = $this->GetMaxLabelWidth(); 302 303 // Now get the total width taking 304 // titlewidth, left and rigt margin, dayfont size 305 // into account 306 $width = $titlewidth + $nd*$fw + $lm+$rm; 307 308 $this->img->CreateImgCanvas($width,$height); 309 $this->img->SetMargin($lm,$rm,$tm,$bm); 310 } 311 312 // Should we start from the top or just spread the bars out even over the 313 // available height 314 $this->scale->SetVertLayout($this->iLayout); 315 if( $this->iLayout == GANTT_FROMTOP ) { 316 $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight()); 317 $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor)); 318 } 319 // If it hasn't been set find out the maximum line number 320 if( $this->scale->iVertLines == -1 ) 321 $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; 322 323 $maxwidth=max($this->GetMaxLabelWidth(),$this->scale->tableTitle->GetWidth($this->img)); 324 $this->scale->SetLabelWidth($maxwidth*(1+$this->iLabelHMarginFactor)); 325 $this->StrokePlotArea(); 326 $this->scale->Stroke(); 327 $this->StrokePlotBox(); 328 329 for($i=0; $i<count($this->iObj); ++$i) { 330 $this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2)); 331 $this->iObj[$i]->Stroke($this->img,$this->scale); 332 } 333 334 $this->StrokeTitles(); 335 $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); 336 } 337 } 338 339 //=================================================== 340 // CLASS TextProperty 341 // Description: Holds properties for a text 342 //=================================================== 343 class TextProperty { 344 var $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10; 345 var $iColor="black"; 346 var $iShow=true; 347 var $iText=""; 348 var $iHAlign="left",$iVAlign="bottom"; 349 350 //--------------- 351 // CONSTRUCTOR 352 function TextProperty($aTxt="") { 353 $this->iText = $aTxt; 354 } 355 356 //--------------- 357 // PUBLIC METHODS 358 function Set($aTxt) { 359 $this->iText = $aTxt; 360 } 361 362 // Set text color 363 function SetColor($aColor) { 364 $this->iColor = $aColor; 365 } 366 367 function HasTabs() { 368 return substr_count($this->iText,"\t") > 0; 369 } 370 371 // Get number of tabs in string 372 function GetNbrTabs() { 373 substr_count($this->iText,"\t"); 374 } 375 376 // Set alignment 377 function Align($aHAlign,$aVAlign="bottom") { 378 $this->iHAlign=$aHAlign; 379 $this->iVAlign=$aVAlign; 380 } 381 382 // Specify font 383 function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { 384 $this->iFFamily = $aFFamily; 385 $this->iFStyle = $aFStyle; 386 $this->iFSize = $aFSize; 387 } 388 389 // Get width of text. If text contains several columns separated by 390 // tabs then return both the total width as well as an array with a 391 // width for each column. 392 function GetWidth($aImg,$aUseTabs=false,$aTabExtraMargin=1.1) { 393 if( strlen($this->iText)== 0 ) return; 394 $tmp = split("\t",$this->iText); 395 $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); 396 if( count($tmp) <= 1 || !$aUseTabs ) { 397 return $aImg->GetTextWidth($this->iText); 398 } 399 else { 400 $tot=0; 401 for($i=0; $i<count($tmp); ++$i) { 402 $res[$i] = $aImg->GetTextWidth($tmp[$i]); 403 $tot += $res[$i]*$aTabExtraMargin; 404 } 405 return array($tot,$res); 406 } 407 } 408 409 // Get total height of text 410 function GetHeight($aImg) { 411 $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); 412 return $aImg->GetFontHeight(); 413 } 414 415 // Unhide/hide the text 416 function Show($aShow) { 417 $this->iShow=$aShow; 418 } 419 420 // Stroke text at (x,y) coordinates. If the text contains tabs then the 421 // x parameter should be an array of positions to be used for each successive 422 // tab mark. If no array is supplied then the tabs will be ignored. 423 function Stroke($aImg,$aX,$aY) { 424 if( $this->iShow ) { 425 $aImg->SetColor($this->iColor); 426 $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); 427 $aImg->SetTextAlign($this->iHAlign,$this->iVAlign); 428 if( $this->GetNbrTabs() <= 1 || !is_array($aX) ) { 429 // Get rid of any "\t" characters and stroke string 430 $aImg->StrokeText($aX,$aY,str_replace("\t"," ",$this->iText)); 431 } 432 else { 433 $tmp = split("\t",$this->iText); 434 $n = min(count($tmp),count($aX)); 435 for($i=0; $i<$n; ++$i) { 436 $aImg->StrokeText($aX[$i],$aY,$tmp[$i]); 437 } 438 } 439 } 440 } 441 } 442 443 //=================================================== 444 // CLASS HeaderProperty 445 // Description: Data encapsulating class to hold property 446 // for each type of the scale headers 447 //=================================================== 448 class HeaderProperty { 449 var $iTitleVertMargin=3,$iFFamily=FF_FONT0,$iFStyle=FS_NORMAL,$iFSize=8; 450 var $iFrameColor="black",$iFrameWeight=1; 451 var $iShowLabels=true,$iShowGrid=true; 452 var $iBackgroundColor="white"; 453 var $iWeekendBackgroundColor="lightgray",$iSundayTextColor="red"; // these are only used with day scale 454 var $iTextColor="black"; 455 var $iLabelFormStr="%d"; 456 var $grid,$iStyle=0; 457 458 //--------------- 459 // CONSTRUCTOR 460 function HeaderProperty() { 461 $this->grid = new LineProperty(); 462 } 463 464 //--------------- 465 // PUBLIC METHODS 466 function Show($aShow) { 467 $this->iShowLabels = $aShow; 468 } 469 470 function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) { 471 $this->iFFamily = $aFFamily; 472 $this->iFStyle = $aFStyle; 473 $this->iFSize = $aFSize; 474 } 475 476 function SetFontColor($aColor) { 477 $this->iTextColor = $aColor; 478 } 479 480 function GetFontHeight($aImg) { 481 $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); 482 return $aImg->GetFontHeight(); 483 } 484 485 function GetFontWidth($aImg) { 486 $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize); 487 return $aImg->GetFontWidth(); 488 } 489 490 function SetStyle($aStyle) { 491 $this->iStyle = $aStyle; 492 } 493 494 function SetBackgroundColor($aColor) { 495 $this->iBackgroundColor=$aColor; 496 } 497 498 function SetFrameWeight($aWeight) { 499 $this->iFrameWeight=$aWeight; 500 } 501 502 function SetFrameColor($aColor) { 503 $this->iFrameColor=$aColor; 504 } 505 506 // Only used by day scale 507 function SetWeekendColor($aColor) { 508 $this->iWeekendBackgroundColor=$aColor; 509 } 510 511 // Only used by day scale 512 function SetSundayFontColor($aColor) { 513 $this->iSundayTextColor=$aColor; 514 } 515 516 function SetTitleVertMargin($aMargin) { 517 $this->iTitleVertMargin=$aMargin; 518 } 519 520 function SetLabelFormatString($aStr) { 521 $this->iLabelFormStr=$aStr; 522 } 523 } 524 525 //=================================================== 526 // CLASS GanttScale 527 // Description: Responsible for calculating and showing 528 // the scale in a gantt chart. This includes providing methods for 529 // converting dates to position in the chart as well as stroking the 530 // date headers (days, week, etc). 531 //=================================================== 532 class GanttScale { 533 var $day,$week,$month,$year; 534 var $divider,$dividerh,$tableTitle; 535 var $iStartDate=-1,$iEndDate=-1; 536 // Number of gantt bar position (n.b not necessariliy the same as the number of bars) 537 // we could have on bar in position 1, and one bar in position 5 then there are two 538 // bars but the number of bar positions is 5 539 var $iVertLines=-1; 540 // The width of the labels (defaults to the widest of all labels) 541 var $iLabelWidth; 542 // Out image to stroke the scale to 543 var $iImg; 544 var $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black"; 545 var $iTableHeaderFrameWeight=1; 546 var $iAvailableHeight=-1,$iVertSpacing=-1,$iVertHeaderSize=-1; 547 var $iDateLocale; 548 var $iVertLayout=GANTT_EVEN; 549 var $iTopPlotMargin=10,$iBottomPlotMargin=15; 550 var $iUsePlotWeekendBackground=true; 551 552 //--------------- 553 // CONSTRUCTOR 554 function GanttScale(&$aImg) { 555 $this->iImg = &$aImg; 556 $this->iDateLocale = new DateLocale(); 557 $this->day = new HeaderProperty(); 558 $this->day->grid->SetColor("gray"); 559 560 $this->week = new HeaderProperty(); 561 $this->week->SetLabelFormatString("w%d"); 562 $this->week->SetFont(FF_FONT1); 563 564 $this->month = new HeaderProperty(); 565 $this->month->SetFont(FF_FONT1,FS_BOLD); 566 567 $this->year = new HeaderProperty(); 568 $this->year->SetFont(FF_FONT1,FS_BOLD); 569 570 $this->divider=new LineProperty(); 571 $this->dividerh=new LineProperty(); 572 $this->tableTitle=new TextProperty(); 573 } 574 575 //--------------- 576 // PUBLIC METHODS 577 // Specify what headers should be visible 578 function ShowHeaders($aFlg) { 579 $this->day->Show($aFlg & GANTT_HDAY); 580 $this->week->Show($aFlg & GANTT_HWEEK); 581 $this->month->Show($aFlg & GANTT_HMONTH); 582 $this->year->Show($aFlg & GANTT_HYEAR); 583 584 // Make some default settings of gridlines whihc makes sense 585 if( $aFlg & GANTT_HWEEK ) { 586 $this->month->grid->Show(false); 587 $this->year->grid->Show(false); 588 } 589 } 590 591 // Should the weekend background stretch all the way down in the plotarea 592 function UseWeekendBackground($aShow) { 593 $this->iUsePlotWeekendBackground = $aShow; 594 } 595 596 // Have a range been specified? 597 function IsRangeSet() { 598 return $this->iStartDate!=-1 && $this->iEndDate!=-1; 599 } 600 601 // Should the layout be from top or even? 602 function SetVertLayout($aLayout) { 603 $this->iVertLayout = $aLayout; 604 } 605 606 // Which locale should be used? 607 function SetDateLocale($aLocale) { 608 $this->iDateLocale->Set($aLocale); 609 } 610 611 // Number of days we are showing 612 function GetNumberOfDays() { 613 return round(($this->iEndDate-$this->iStartDate)/SECPERDAY)+1; 614 } 615 616 // The widthj of the actual plot area 617 function GetPlotWidth() { 618 $img=$this->iImg; 619 return $img->width - $img->left_margin - $img->right_margin; 620 } 621 622 // Specify the width of the titles(labels) for the activities 623 // (This is by default set to the minimum width enought for the 624 // widest title) 625 function SetLabelWidth($aLabelWidth) { 626 $this->iLabelWidth=$aLabelWidth; 627 } 628 629 // Do we show day scale? 630 function IsDisplayDay() { 631 return $this->day->iShowLabels; 632 } 633 634 // Do we show week scale? 635 function IsDisplayWeek() { 636 return $this->week->iShowLabels; 637 } 638 639 // Do we show month scale? 640 function IsDisplayMonth() { 641 return $this->month->iShowLabels; 642 } 643 644 // Do we show year scale? 645 function IsDisplayYear() { 646 return $this->year->iShowLabels; 647 } 648 649 // Specify spacing (in percent of bar height) between activity bars 650 function SetVertSpacing($aSpacing) { 651 $this->iVertSpacing = $aSpacing; 652 } 653 654 // Specify scale min and max date either as timestamp or as date strings 655 // Always round to the nearest week boundary 656 function SetRange($aMin,$aMax) { 657 $this->iStartDate = $this->NormalizeDate($aMin); 658 $this->iEndDate = $this->NormalizeDate($aMax); 659 660 // Get day in week Sun=0 661 $ds=strftime("%w",$this->iStartDate); 662 $de=strftime("%w",$this->iEndDate); 663 664 if( $ds==0 ) $ds=7; 665 if( $de==0 ) $de=7; 666 667 // We want to start on Monday 668 $this->iStartDate -= SECPERDAY*($ds-1); 669 670 // We want to end on a Sunday 671 $this->iEndDate += SECPERDAY*(7-$de); 672 } 673 674 // Specify background for the table title area (upper left corner of the table) 675 function SetTableTitleBackground($aColor) { 676 $this->iTableHeaderBackgroundColor = $aColor; 677 } 678 679 /////////////////////////////////////// 680 // PRIVATE Methods 681 682 // Determine the height of all the scale headers combined 683 function GetHeaderHeight() { 684 $img=$this->iImg; 685 $height=1; 686 if( $this->day->iShowLabels ) { 687 $height += $this->day->GetFontHeight($img); 688 $height += $this->day->iTitleVertMargin; 689 } 690 if( $this->week->iShowLabels ) { 691 $height += $this->week->GetFontHeight($img); 692 $height += $this->week->iTitleVertMargin; 693 } 694 if( $this->month->iShowLabels ) { 695 $height += $this->month->GetFontHeight($img); 696 $height += $this->month->iTitleVertMargin; 697 } 698 if( $this->year->iShowLabels ) { 699 $height += $this->year->GetFontHeight($img); 700 $height += $this->year->iTitleVertMargin; 701 } 702 return $height; 703 } 704 705 // Get width (in pisels) for a single day 706 function GetDayWidth() { 707 return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays(); 708 } 709 710 // Nuber of days in a year 711 function GetNumDaysInYear($aYear) { 712 if( $this->IsLeap($aYear) ) 713 return 366; 714 else 715 return 365; 716 } 717 718 // Get day number in year 719 function GetDayNbrInYear($aDate) { 720 return 0+strftime("%j",$aDate); 721 } 722 723 // Get week number 724 function GetWeekNbr($aDate) { 725 // We can't use the internal strftime() since it gets the weeknumber 726 // wrong since it doesn't follow ISO. 727 // Even worse is that this works differently if we are on a Windows 728 // or UNIX box (it even differs between UNIX boxes how strftime() 729 // is natively implemented) 730 // 731 // Credit to Nicolas Hoizey <nhoizey@phpheaven.net> for this elegant 732 // version of Week Nbr calculation. 733 734 $day = $this->NormalizeDate($aDate); 735 736 /*------------------------------------------------------------------------- 737 According to ISO-8601 : 738 "Week 01 of a year is per definition the first week that has the Thursday in this year, 739 which is equivalent to the week that contains the fourth day of January. 740 In other words, the first week of a new year is the week that has the majority of its 741 days in the new year." 742 743 Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!! 744 745 day of year = date("z", $day) + 1 746 offset to thursday = 3 - (date("w", $day) + 6) % 7 747 first thursday of year = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7 748 week number = (thursday's day of year - first thursday's day of year) / 7 + 1 749 ---------------------------------------------------------------------------*/ 750 751 $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7); // take week's thursday 752 $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7; 753 754 return $week; 755 } 756 757 // Is year a leap year? 758 function IsLeap($aYear) { 759 // Is the year a leap year? 760 //$year = 0+date("Y",$aDate); 761 if( $aYear % 4 == 0) 762 if( !($aYear % 100 == 0) || ($aYear % 400 == 0) ) 763 return true; 764 return false; 765 } 766 767 // Get current year 768 function GetYear($aDate) { 769 return 0+Date("Y",$aDate); 770 } 771 772 // Return number of days in a year 773 function GetNumDaysInMonth($aMonth,$aYear) { 774 $days=array(31,28,31,30,31,30,31,31,30,31,30,31); 775 $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31); 776 if( $this->IsLeap($aYear)) 777 return $daysl[$aMonth]; 778 else 779 return $days[$aMonth]; 780 } 781 782 // Get day in month 783 function GetMonthDayNbr($aDate) { 784 return 0+strftime("%d",$aDate); 785 } 786 787 // Get day in year 788 function GetYearDayNbr($aDate) { 789 return 0+strftime("%j",$aDate); 790 } 791 792 // Get month number 793 function GetMonthNbr($aDate) { 794 return 0+strftime("%m",$aDate); 795 } 796 797 // Translate a date to screen coordinates (horizontal scale) 798 function TranslateDate($aDate) { 799 $aDate = $this->NormalizeDate($aDate); 800 $img=$this->iImg; 801 //print date('d-m-Y H:i:s',$aDate).'--'.date('d-m-Y H:i:s',$this->iEndDate)."<br>"; 802 if( $aDate < $this->iStartDate || $aDate > $this->iEndDate ) 803 JpGraphError::Raise("<b>JpGraph Error:</b> Date is outside specified scale range."); 804 return ($aDate-$this->iStartDate)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;; 805 } 806 807 // Get screen coordinatesz for the vertical position for a bar 808 function TranslateVertPos($aPos) { 809 $img=$this->iImg; 810 $ph=$this->iAvailableHeight; 811 if( $aPos > $this->iVertLines ) 812 JpGraphError::Raise("<b>JpGraph Error:</b> Illegal vertical position $aPos"); 813 if( $this->iVertLayout == GANTT_EVEN ) { 814 // Position the top bar at 1 vert spacing from the scale 815 return round($img->top_margin + $this->iVertHeaderSize + ($aPos+1)*$this->iVertSpacing); 816 } 817 else { 818 // position the top bar at 1/2 a vert spacing from the scale 819 return round($img->top_margin + $this->iVertHeaderSize + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing); 820 } 821 } 822 823 // What is the vertical spacing? 824 function GetVertSpacing() { 825 return $this->iVertSpacing; 826 } 827 828 // Convert a date to timestamp 829 function NormalizeDate($aDate) { 830 if( is_string($aDate) ) 831 return strtotime($aDate); 832 elseif( is_int($aDate) || is_float($aDate) ) 833 return $aDate; 834 else 835 JpGraphError::Raise("<b>JpGraph Error:</b> Unknown date format in GanttScale ($aDate)."); 836 } 837 838 // Stroke the day scale (including gridlines) 839 function StrokeDays($aYCoord) { 840 $wdays=$this->iDateLocale->GetDayAbb(); 841 $img=$this->iImg; 842 $daywidth=$this->GetDayWidth(); 843 $xt=$img->left_margin+$this->iLabelWidth; 844 $yt=$aYCoord+$img->top_margin; 845 if( $this->day->iShowLabels ) { 846 $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize); 847 $xb=$img->width-$img->right_margin; 848 $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight; 849 $img->SetColor($this->day->iBackgroundColor); 850 $img->FilledRectangle($xt,$yt,$xb,$yb); 851 852 $img->SetColor($this->day->grid->iColor); 853 $x = $xt; 854 $img->SetTextAlign("center"); 855 for($i=0; $i<$this->GetNumberOfDays(); ++$i, $x+=$daywidth) { 856 $day=$i%7; 857 if( $day==5 ) { 858 $img->PushColor($this->day->iWeekendBackgroundColor); 859 if( $this->iUsePlotWeekendBackground ) 860 $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+2*$daywidth,$img->height-$img->bottom_margin); 861 else 862 $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+2*$daywidth,$yb-$this->day->iFrameWeight); 863 $img->PopColor(); 864 } 865 if( $day==6 ) 866 $img->PushColor($this->day->iSundayTextColor); 867 else 868 $img->PushColor($this->day->iTextColor); 869 $img->StrokeText(round($x+$daywidth/2+1), 870 round($yb-$this->day->iTitleVertMargin), 871 $wdays[$i%7]); 872 $img->PopColor(); 873 $img->Line($x,$yt,$x,$yb); 874 $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); 875 } 876 $img->SetColor($this->day->iFrameColor); 877 $img->SetLineWeight($this->day->iFrameWeight); 878 $img->Rectangle($xt,$yt,$xb,$yb); 879 return $yb - $img->top_margin; 880 } 881 return $aYCoord; 882 } 883 884 // Stroke week header and grid 885 function StrokeWeeks($aYCoord) { 886 $wdays=$this->iDateLocale->GetDayAbb(); 887 $img=$this->iImg; 888 $weekwidth=$this->GetDayWidth()*7; 889 $xt=$img->left_margin+$this->iLabelWidth; 890 $yt=$aYCoord+$img->top_margin; 891 $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize); 892 $xb=$img->width-$img->right_margin; 893 $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight; 894 895 $week = $this->iStartDate; 896 $weeknbr=$this->GetWeekNbr($week); 897 if( $this->week->iShowLabels ) { 898 $img->SetColor($this->week->iBackgroundColor); 899 $img->FilledRectangle($xt,$yt,$xb,$yb); 900 $img->SetColor($this->week->grid->iColor); 901 $x = $xt; 902 if( $this->week->iStyle==WEEKSTYLE_WNBR ) { 903 $img->SetTextAlign("center"); 904 $txtOffset = $weekwidth/2+1; 905 } 906 elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY || $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ) { 907 $img->SetTextAlign("left"); 908 $txtOffset = 2; 909 } 910 else 911 JpGraphError::Raise("<b>JpGraph Error:</b>Unknown formatting style for week."); 912 913 for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) { 914 $img->PushColor($this->week->iTextColor); 915 916 if( $this->week->iStyle==WEEKSTYLE_WNBR ) 917 $txt = sprintf($this->week->iLabelFormStr,$weeknbr); 918 elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY ) 919 $txt = date("j/n",$week); 920 elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ) { 921 $monthnbr = date("n",$week)-1; 922 $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr); 923 $txt = Date("j",$week)." ".$shortmonth; 924 } 925 926 $img->StrokeText(round($x+$txtOffset),round($yb-$this->week->iTitleVertMargin),$txt); 927 928 $week += 7*SECPERDAY; 929 $weeknbr = $this->GetWeekNbr($week); 930 $img->PopColor(); 931 $img->Line($x,$yt,$x,$yb); 932 $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); 933 } 934 $img->SetColor($this->week->iFrameColor); 935 $img->SetLineWeight($this->week->iFrameWeight); 936 $img->Rectangle($xt,$yt,$xb,$yb); 937 return $yb-$img->top_margin; 938 } 939 return $aYCoord; 940 } 941 942 // Format the mont scale header string 943 function GetMonthLabel($aMonthNbr,$year) { 944 $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr); 945 $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr); 946 switch($this->month->iStyle) { 947 case MONTHSTYLE_SHORTNAME: 948 $m=$sn; 949 break; 950 case MONTHSTYLE_LONGNAME: 951 $m=$ln; 952 break; 953 case MONTHSTYLE_SHORTNAMEYEAR2: 954 $m=$sn." '".substr("".$year,2); 955 break; 956 case MONTHSTYLE_SHORTNAMEYEAR4: 957 $m=$sn." ".$year; 958 break; 959 case MONTHSTYLE_LONGNAMEYEAR2: 960 $m=$ln." '".substr("".$year,2); 961 break; 962 case MONTHSTYLE_LONGNAMEYEAR4: 963 $m=$ln." ".$year; 964 break; 965 } 966 return $m; 967 } 968 969 // Stroke month scale and gridlines 970 function StrokeMonths($aYCoord) { 971 if( $this->month->iShowLabels ) { 972 $monthnbr = $this->GetMonthNbr($this->iStartDate)-1; 973 $img=$this->iImg; 974 975 $xt=$img->left_margin+$this->iLabelWidth; 976 $yt=$aYCoord+$img->top_margin; 977 $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize); 978 $xb=$img->width-$img->right_margin; 979 $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight; 980 981 $img->SetColor($this->month->iBackgroundColor); 982 $img->FilledRectangle($xt,$yt,$xb,$yb); 983 984 $img->SetLineWeight($this->month->grid->iWeight); 985 $img->SetColor($this->month->iTextColor); 986 $year = 0+strftime("%Y",$this->iStartDate); 987 $img->SetTextAlign("center"); 988 $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1); 989 // Is it enough space to stroke the first month? 990 $monthName = $this->GetMonthLabel($monthnbr,$year); 991 if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) { 992 $img->SetColor($this->month->iTextColor); 993 $img->StrokeText(round($xt+$monthwidth/2+1), 994 round($yb-$this->month->iTitleVertMargin), 995 $monthName); 996 } 997 $x = $xt + $monthwidth; 998 while( $x < $xb ) { 999 $img->SetColor($this->month->grid->iColor); 1000 $img->Line($x,$yt,$x,$yb); 1001 $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); 1002 $monthnbr++; 1003 if( $monthnbr==12 ) { 1004 $monthnbr=0; 1005 $year++; 1006 } 1007 $monthName = $this->GetMonthLabel($monthnbr,$year); 1008 $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year); 1009 if( $x + $monthwidth < $xb ) 1010 $w = $monthwidth; 1011 else 1012 $w = $xb-$x; 1013 if( $w >= 1.2*$img->GetTextWidth($monthName) ) { 1014 $img->SetColor($this->month->iTextColor); 1015 $img->StrokeText(round($x+$w/2+1), 1016 round($yb-$this->month->iTitleVertMargin),$monthName); 1017 } 1018 $x += $monthwidth; 1019 } 1020 $img->SetColor($this->month->iFrameColor); 1021 $img->SetLineWeight($this->month->iFrameWeight); 1022 $img->Rectangle($xt,$yt,$xb,$yb); 1023 return $yb-$img->top_margin; 1024 } 1025 return $aYCoord; 1026 } 1027 1028 // Stroke year scale and gridlines 1029 function StrokeYears($aYCoord) { 1030 if( $this->year->iShowLabels ) { 1031 $year = $this->GetYear($this->iStartDate); 1032 $img=$this->iImg; 1033 1034 $xt=$img->left_margin+$this->iLabelWidth; 1035 $yt=$aYCoord+$img->top_margin; 1036 $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize); 1037 $xb=$img->width-$img->right_margin; 1038 $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight; 1039 1040 $img->SetColor($this->year->iBackgroundColor); 1041 $img->FilledRectangle($xt,$yt,$xb,$yb); 1042 $img->SetLineWeight($this->year->grid->iWeight); 1043 $img->SetTextAlign("center"); 1044 if( $year == $this->GetYear($this->iEndDate) ) 1045 $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1); 1046 else 1047 $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1); 1048 1049 // The space for a year must be at least 20% bigger than the actual text 1050 // so we allow 10% margin on each side 1051 if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) { 1052 $img->SetColor($this->year->iTextColor); 1053 $img->StrokeText(round($xt+$yearwidth/2+1), 1054 round($yb-$this->year->iTitleVertMargin), 1055 $year); 1056 } 1057 $x = $xt + $yearwidth; 1058 while( $x < $xb ) { 1059 $img->SetColor($this->year->grid->iColor); 1060 $img->Line($x,$yt,$x,$yb); 1061 $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin); 1062 $year += 1; 1063 $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year); 1064 if( $x + $yearwidth < $xb ) 1065 $w = $yearwidth; 1066 else 1067 $w = $xb-$x; 1068 if( $w >= 1.2*$img->GetTextWidth("".$year) ) { 1069 $img->SetColor($this->year->iTextColor); 1070 $img->StrokeText(round($x+$w/2+1), 1071 round($yb-$this->year->iTitleVertMargin), 1072 $year); 1073 } 1074 $x += $yearwidth; 1075 } 1076 $img->SetColor($this->year->iFrameColor); 1077 $img->SetLineWeight($this->year->iFrameWeight); 1078 $img->Rectangle($xt,$yt,$xb,$yb); 1079 return $yb-$img->top_margin; 1080 } 1081 return $aYCoord; 1082 } 1083 1084 // Stroke table title (upper left corner) 1085 function StrokeTableHeaders($aYBottom) { 1086 $img=$this->iImg; 1087 $xt=$img->left_margin; 1088 $yt=$img->top_margin; 1089 $xb=$xt+$this->iLabelWidth; 1090 $yb=$aYBottom+$img->top_margin; 1091 1092 $img->SetColor($this->iTableHeaderBackgroundColor); 1093 $img->FilledRectangle($xt,$yt,$xb,$yb); 1094 $this->tableTitle->Align("center","center"); 1095 $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+($yb-$yt)/2); 1096 $img->SetColor($this->iTableHeaderFrameColor); 1097 $img->SetLineWeight($this->iTableHeaderFrameWeight); 1098 $img->Rectangle($xt,$yt,$xb,$yb); 1099 1100 // Draw the vertical dividing line 1101 $this->divider->Stroke($img,$xb,$yt,$xb,$img->height-$img->bottom_margin); 1102 1103 // Draw the horizontal dividing line 1104 $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb); 1105 } 1106 1107 // Main entry point to stroke scale 1108 function Stroke() { 1109 if( !$this->IsRangeSet() ) 1110 JpGraphError::Raise("<b>JpGraph Error:</b> Gantt scale has not been specified."); 1111 $img=$this->iImg; 1112 1113 // Stroke all headers. Aa argument we supply the offset from the 1114 // top which depends on any previous headers 1115 $offy=$this->StrokeYears(0); 1116 $offm=$this->StrokeMonths($offy); 1117 $offw=$this->StrokeWeeks($offm); 1118 $offd=$this->StrokeDays($offw); 1119 1120 // We stroke again in case days also have gridlines that may have 1121 // overwritten the weeks gridline (or month/year). It may seem that we should have logic 1122 // in the days routine instead but this is much easier and wont make to much 1123 // of an performance impact. 1124 $this->StrokeWeeks($offm); 1125 $this->StrokeMonths($offy); 1126 $this->StrokeYears(0); 1127 $this->StrokeTableHeaders($offd); 1128 1129 // Now we can calculate the correct scaling factor for each vertical position 1130 $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd; 1131 $this->iVertHeaderSize = $offd; 1132 if( $this->iVertSpacing == -1 ) 1133 $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines; 1134 } 1135 } 1136 1137 //=================================================== 1138 // CLASS GanttPlotObject 1139 // The common signature for a Gantt object 1140 //=================================================== 1141 class GanttPlotObject { 1142 var $iVPos=0; // Vertical position 1143 var $iLabelLeftMargin=2; // Title margin 1144 var $iStart=""; // Start date 1145 var $title,$caption; 1146 var $iCaptionMargin=5; 1147 1148 function GanttPlotObject() { 1149 $this->title = new TextProperty(); 1150 $this->title->Align("left","center"); 1151 $this->caption = new TextProperty(); 1152 } 1153 1154 function GetMinDate() { 1155 return $this->iStart; 1156 } 1157 1158 function GetMaxDate() { 1159 return $this->iStart; 1160 } 1161 1162 function SetCaptionMargin($aMarg) { 1163 $this->iCaptionMargin=$aMarg; 1164 } 1165 1166 # function GetLineNbr() { 1167 # return 0; 1168 # } 1169 1170 function GetAbsHeight($aImg) { 1171 return 0; 1172 } 1173 1174 function GetLineNbr() { 1175 return $this->iVPos; 1176 } 1177 1178 function SetLabelLeftMargin($aOff) { 1179 $this->iLabelLeftMargin=$aOff; 1180 } 1181 } 1182 1183 //=================================================== 1184 // CLASS Progress 1185 // Holds parameters for the progress indicator 1186 // displyed within a bar 1187 //=================================================== 1188 class Progress { 1189 var $iProgress=-1, $iColor="black", $iPattern=GANTT_SOLID; 1190 var $iDensity=98, $iHeight=0.65; 1191 1192 function Set($aProg) { 1193 if( $aProg < 0.0 || $aProg > 1.0 ) 1194 JpGraphError::Raise("<b>JpGraph Error:</b> Progress value must in range [0, 1]"); 1195 $this->iProgress = $aProg; 1196 } 1197 1198 function SetPattern($aPattern,$aColor="blue",$aDensity=98) { 1199 $this->iPattern = $aPattern; 1200 $this->iColor = $aColor; 1201 $this->iDensity = $aDensity; 1202 } 1203 1204 function SetHeight($aHeight) { 1205 $this->iHeight = $aHeight; 1206 } 1207 } 1208 1209 //=================================================== 1210 // CLASS GanttBar 1211 // Responsible for formatting individual gantt bars 1212 //=================================================== 1213 class GanttBar extends GanttPlotObject { 1214 var $iEnd; 1215 var $iHeightFactor=0.5; 1216 var $iFillColor="white",$iFrameColor="blue"; 1217 var $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black"; 1218 var $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95; 1219 var $leftMark,$rightMark; 1220 var $progress; 1221 1222 //--------------- 1223 // CONSTRUCTOR 1224 function GanttBar($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) { 1225 parent::GanttPlotObject(); 1226 $this->iStart = $aStart; 1227 // Is the end date given as a date or as number of days added to start date? 1228 if( is_string($aEnd) ) 1229 $this->iEnd = strtotime($aEnd)+SECPERDAY; 1230 // check for unix timestamp 1231 elseif($aEnd > 1000000) 1232 $this->iEnd = $aEnd; 1233 elseif(is_int($aEnd) || is_float($aEnd) ) 1234 $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY); 1235 $this->iVPos = $aPos; 1236 $this->iHeightFactor = $aHeightFactor; 1237 $this->title->Set($aLabel); 1238 $this->caption = new TextProperty($aCaption); 1239 $this->caption->Align("left","center"); 1240 $this->leftMark =new PlotMark(); 1241 $this->leftMark->Hide(); 1242 $this->rightMark=new PlotMark(); 1243 $this->rightMark->Hide(); 1244 $this->progress = new Progress(); 1245 } 1246 1247 //--------------- 1248 // PUBLIC METHODS 1249 function SetShadow($aShadow=true,$aColor="gray") { 1250 $this->iShadow=$aShadow; 1251 $this->iShadowColor=$aColor; 1252 } 1253 1254 function GetMaxDate() { 1255 return $this->iEnd; 1256 } 1257 1258 function SetHeight($aHeight) { 1259 $this->iHeightFactor = $aHeight; 1260 } 1261 1262 function SetColor($aColor) { 1263 $this->iFrameColor = $aColor; 1264 } 1265 1266 function SetFillColor($aColor) { 1267 $this->iFillColor = $aColor; 1268 } 1269 1270 function GetAbsHeight($aImg) { 1271 if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) { 1272 $m=-1; 1273 if( is_int($this->iHeightFactor) ) 1274 $m = $this->iHeightFactor; 1275 if( $this->leftMark->show ) 1276 $m = max($m,$this->leftMark->width*2); 1277 if( $this->rightMark->show ) 1278 $m = max($m,$this->rightMark->width*2); 1279 return $m; 1280 } 1281 else 1282 return -1; 1283 } 1284 1285 function SetPattern($aPattern,$aColor="blue",$aDensity=95) { 1286 $this->iPattern = $aPattern; 1287 $this->iPatternColor = $aColor; 1288 $this->iPatternDensity = $aDensity; 1289 } 1290 1291 function Stroke($aImg,$aScale) { 1292 $factory = new RectPatternFactory(); 1293 $prect = $factory->Create($this->iPattern,$this->iPatternColor); 1294 $prect->SetDensity($this->iPatternDensity); 1295 1296 // If height factor is specified as a float between 0,1 then we take it as meaning 1297 // percetage of the scale width between horizontal line. 1298 // If it is an integer > 1 we take it to mean the absolute height in pixels 1299 if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1) 1300 $vs = $aScale->GetVertSpacing()*$this->iHeightFactor; 1301 elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor<200) 1302 $vs = $this->iHeightFactor; 1303 else 1304 JpGraphError::Raise("<b>JpGraph Error:</b>Specified height (".$this->iHeightFactor.") for gantt bar is out of range."); 1305 1306 $xt = $aScale->TranslateDate($aScale->NormalizeDate($this->iStart)); 1307 $xb = $aScale->TranslateDate($aScale->NormalizeDate($this->iEnd)); 1308 $yt = $aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2); 1309 $yb = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2); 1310 1311 $prect->ShowFrame(false); 1312 $prect->SetBackground($this->iFillColor); 1313 if( $this->iShadow ) { 1314 $aImg->SetColor($this->iFrameColor); 1315 $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor); 1316 $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2)); 1317 $prect->Stroke($aImg); 1318 } 1319 else { 1320 $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1)); 1321 $prect->Stroke($aImg); 1322 $aImg->SetColor($this->iFrameColor); 1323 $aImg->Rectangle($xt,$yt,$xb,$yb); 1324 } 1325 if( $this->progress->iProgress > 0 ) { 1326 $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor); 1327 $prog->SetDensity($this->progress->iDensity); 1328 $barheight = ($yb-$yt+1); 1329 if( $this->iShadow ) 1330 $barheight -= $this->iShadowWidth; 1331 $progressheight = floor($barheight*$this->progress->iHeight); 1332 $marg = ceil(($barheight-$progressheight)/2); 1333 $pos = new Rectangle($xt, 1334 $yt + $marg, 1335 ($xb-$xt+1)*$this->progress->iProgress, 1336 $barheight-2*$marg); 1337 $prog->SetPos($pos); 1338 $prog->Stroke($aImg); 1339 } 1340 1341 $middle = round($yt+($yb-$yt)/2); 1342 $this->title->Stroke($aImg,$aImg->left_margin+$this->iLabelLeftMargin,$middle); 1343 $this->leftMark->Stroke($aImg,$xt,$middle); 1344 $this->rightMark->Stroke($aImg,$xb,$middle); 1345 $margin = $this->iCaptionMargin; 1346 if( $this->rightMark->show ) 1347 $margin += $this->rightMark->GetWidth(); 1348 1349 $this->caption->Stroke($aImg,$xb+$margin,$middle); 1350 } 1351 } 1352 1353 //=================================================== 1354 // CLASS MileStone 1355 // Responsible for formatting individual milestones 1356 //=================================================== 1357 class MileStone extends GanttPlotObject { 1358 var $mark; 1359 1360 //--------------- 1361 // CONSTRUCTOR 1362 function MileStone($aVPos,$aLabel,$aDate,$aCaption="") { 1363 GanttPlotObject::GanttPlotObject(); 1364 $this->caption->Set($aCaption); 1365 $this->caption->Align("left","center"); 1366 $this->caption->SetFont(FF_FONT1,FS_BOLD); 1367 $this->title->Set($aLabel); 1368 $this->title->SetColor("darkred"); 1369 $this->mark = new PlotMark(); 1370 $this->mark->SetWidth(10); 1371 $this->mark->SetType(MARK_DIAMOND); 1372 $this->mark->SetColor("darkred"); 1373 $this->mark->SetFillColor("darkred"); 1374 $this->iVPos = $aVPos; 1375 $this->iStart = $aDate; 1376 } 1377 1378 //--------------- 1379 // PUBLIC METHODS 1380 1381 function GetAbsHeight($aImg) { 1382 return max($this->title->GetHeight($aImg),$this->mark->GetWidth()); 1383 } 1384 1385 function Stroke($aImg,$aScale) { 1386 // Put the mark in the middle at the middle of the day 1387 $x = $aScale->TranslateDate($aScale->NormalizeDate($this->iStart)+SECPERDAY/2); 1388 $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2); 1389 1390 $this->mark->Stroke($aImg,$x,$y); 1391 $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y); 1392 $x=$aImg->left_margin+$this->iLabelLeftMargin; 1393 $this->title->Stroke($aImg,$x,$y); 1394 } 1395 } 1396 1397 1398 //=================================================== 1399 // CLASS GanttVLine 1400 // Responsible for formatting individual milestones 1401 //=================================================== 1402 1403 class GanttVLine extends GanttPlotObject { 1404 1405 var $iLine,$title_margin=3; 1406 var $iDayOffset=0; // Defult to left edge of day 1407 1408 //--------------- 1409 // CONSTRUCTOR 1410 function GanttVLine($aDate,$aTitle="",$aColor="black",$aWeight=3,$aStyle="dashed") { 1411 GanttPlotObject::GanttPlotObject(); 1412 $this->iLine = new LineProperty(); 1413 $this->iLine->SetColor($aColor); 1414 $this->iLine->SetWeight($aWeight); 1415 $this->iLine->SetStyle($aStyle); 1416 $this->iStart = $aDate; 1417 $this->title->Set($aTitle); 1418 } 1419 1420 //--------------- 1421 // PUBLIC METHODS 1422 1423 function SetDayOffset($aOff=0.5) { 1424 if( $aOff < 0.0 || $aOff > 1.0 ) 1425 JpGraphError::Raise("<b>JpGraph Error:</b> Offset for vertical line must be in range [0,1]"); 1426 $this->iDayOffset = $aOff; 1427 } 1428 1429 function SetTitleMargin($aMarg) { 1430 $this->title_margin = $aMarg; 1431 } 1432 1433 function Stroke($aImg,$aScale) { 1434 $x = $aScale->TranslateDate($aScale->NormalizeDate($this->iStart)+$this->iDayOffset*SECPERDAY); 1435 $y1 = $aScale->iVertHeaderSize+$aImg->top_margin; 1436 $y2 = $aImg->height - $aImg->bottom_margin; 1437 $this->iLine->Stroke($aImg,$x,$y1,$x,$y2); 1438 $this->title->Align("center","top"); 1439 $this->title->Stroke($aImg,$x,$y2+$this->title_margin); 1440 } 1441 } 1442 1443 // <EOF> 1444 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |