Ignore:
Timestamp:
Apr 13, 2019, 8:05:15 PM (5 years ago)
Author:
roby
Message:
 
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/client/modules/Elezioni/grafici/jpgraph_gantt.php

    r2 r265  
    11<?php
    22/*=======================================================================
    3 // File:        JPGRAPH_GANTT.PHP
    4 // Description: JpGraph Gantt plot extension
    5 // Created:     2001-11-12
    6 // Ver:         $Id: jpgraph_gantt.php 1091 2009-01-18 22:57:40Z ljp $
    7 //
    8 // Copyright (c) Aditus Consulting. All rights reserved.
    9 //========================================================================
    10 */
    11 
    12 require_once('jpgraph_plotband.php'); 
    13 require_once('jpgraph_iconplot.php'); 
     3 // File:        JPGRAPH_GANTT.PHP
     4 // Description: JpGraph Gantt plot extension
     5 // Created:     2001-11-12
     6 // Ver:         $Id: jpgraph_gantt.php 1809 2009-09-09 13:07:33Z ljp $
     7 //
     8 // Copyright (c) Asial Corporation. All rights reserved.
     9 //========================================================================
     10 */
     11
     12require_once('jpgraph_plotband.php');
     13require_once('jpgraph_iconplot.php');
    1414require_once('jpgraph_plotmark.inc.php');
    1515
    1616// Maximum size for Automatic Gantt chart
    17 define('MAX_GANTTIMG_SIZE_W',4000);
     17define('MAX_GANTTIMG_SIZE_W',8000);
    1818define('MAX_GANTTIMG_SIZE_H',5000);
    1919
     
    2727
    2828// Bar patterns
    29 define("GANTT_RDIAG",BAND_RDIAG);       // Right diagonal lines
     29define("GANTT_RDIAG",BAND_RDIAG); // Right diagonal lines
    3030define("GANTT_LDIAG",BAND_LDIAG); // Left diagonal lines
    3131define("GANTT_SOLID",BAND_SOLID); // Solid one color
     
    4040
    4141// Locales. ONLY KEPT FOR BACKWARDS COMPATIBILITY
    42 // You should use the proper locale strings directly 
    43 // from now on. 
     42// You should use the proper locale strings directly
     43// from now on.
    4444define("LOCALE_EN","en_UK");
    4545define("LOCALE_SV","sv_SE");
     
    5050
    5151// Style for minute header
    52 define("MINUTESTYLE_MM",0);             // 15
    53 define("MINUTESTYLE_CUSTOM",2);         // Custom format
     52define("MINUTESTYLE_MM",0);  // 15
     53define("MINUTESTYLE_CUSTOM",2);  // Custom format
    5454
    5555
    5656// Style for hour header
    57 define("HOURSTYLE_HM24",0);             // 13:10
    58 define("HOURSTYLE_HMAMPM",1);           // 1:10pm
    59 define("HOURSTYLE_H24",2);              // 13
    60 define("HOURSTYLE_HAMPM",3);            // 1pm
    61 define("HOURSTYLE_CUSTOM",4);           // User defined
     57define("HOURSTYLE_HM24",0);  // 13:10
     58define("HOURSTYLE_HMAMPM",1);  // 1:10pm
     59define("HOURSTYLE_H24",2);  // 13
     60define("HOURSTYLE_HAMPM",3);  // 1pm
     61define("HOURSTYLE_CUSTOM",4);  // User defined
    6262
    6363// Style for day header
    64 define("DAYSTYLE_ONELETTER",0);         // "M"
    65 define("DAYSTYLE_LONG",1);              // "Monday"
    66 define("DAYSTYLE_LONGDAYDATE1",2);      // "Monday 23 Jun"
    67 define("DAYSTYLE_LONGDAYDATE2",3);      // "Monday 23 Jun 2003"
    68 define("DAYSTYLE_SHORT",4);             // "Mon"
    69 define("DAYSTYLE_SHORTDAYDATE1",5);     // "Mon 23/6"
    70 define("DAYSTYLE_SHORTDAYDATE2",6);     // "Mon 23 Jun"
    71 define("DAYSTYLE_SHORTDAYDATE3",7);     // "Mon 23"
    72 define("DAYSTYLE_SHORTDATE1",8);        // "23/6"
    73 define("DAYSTYLE_SHORTDATE2",9);        // "23 Jun"
    74 define("DAYSTYLE_SHORTDATE3",10);       // "Mon 23"
    75 define("DAYSTYLE_SHORTDATE4",11);       // "23"
    76 define("DAYSTYLE_CUSTOM",12);           // "M"
     64define("DAYSTYLE_ONELETTER",0);  // "M"
     65define("DAYSTYLE_LONG",1);  // "Monday"
     66define("DAYSTYLE_LONGDAYDATE1",2); // "Monday 23 Jun"
     67define("DAYSTYLE_LONGDAYDATE2",3); // "Monday 23 Jun 2003"
     68define("DAYSTYLE_SHORT",4);  // "Mon"
     69define("DAYSTYLE_SHORTDAYDATE1",5); // "Mon 23/6"
     70define("DAYSTYLE_SHORTDAYDATE2",6); // "Mon 23 Jun"
     71define("DAYSTYLE_SHORTDAYDATE3",7); // "Mon 23"
     72define("DAYSTYLE_SHORTDATE1",8); // "23/6"
     73define("DAYSTYLE_SHORTDATE2",9); // "23 Jun"
     74define("DAYSTYLE_SHORTDATE3",10); // "Mon 23"
     75define("DAYSTYLE_SHORTDATE4",11); // "23"
     76define("DAYSTYLE_CUSTOM",12);  // "M"
    7777
    7878// Styles for week header
     
    128128if (!function_exists('array_fill')) {
    129129    function array_fill($iStart, $iLen, $vValue) {
    130         $aResult = array();
    131         for ($iCount = $iStart; $iCount < $iLen + $iStart; $iCount++) {
    132             $aResult[$iCount] = $vValue;
    133         }
    134         return $aResult;
     130        $aResult = array();
     131        for ($iCount = $iStart; $iCount < $iLen + $iStart; $iCount++) {
     132            $aResult[$iCount] = $vValue;
     133        }
     134        return $aResult;
    135135    }
    136136}
     
    138138//===================================================
    139139// CLASS GanttActivityInfo
    140 // Description: 
     140// Description:
    141141//===================================================
    142142class GanttActivityInfo {
     
    153153    private $iHeaderAlign='center';
    154154
    155     function GanttActivityInfo() {
    156         $this->vgrid = new LineProperty();
     155    function __construct() {
     156        $this->vgrid = new LineProperty();
    157157    }
    158158
    159159    function Hide($aF=true) {
    160         $this->iShow=!$aF;
     160        $this->iShow=!$aF;
    161161    }
    162162
    163163    function Show($aF=true) {
    164         $this->iShow=$aF;
     164        $this->iShow=$aF;
    165165    }
    166166
    167167    // Specify font
    168168    function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) {
    169         $this->iFFamily = $aFFamily;
    170         $this->iFStyle  = $aFStyle;
    171         $this->iFSize    = $aFSize;
     169        $this->iFFamily = $aFFamily;
     170        $this->iFStyle = $aFStyle;
     171        $this->iFSize = $aFSize;
    172172    }
    173173
    174174    function SetStyle($aStyle) {
    175         $this->iStyle = $aStyle;
     175        $this->iStyle = $aStyle;
    176176    }
    177177
    178178    function SetColumnMargin($aLeft,$aRight) {
    179         $this->iLeftColMargin = $aLeft;
    180         $this->iRightColMargin = $aRight;
     179        $this->iLeftColMargin = $aLeft;
     180        $this->iRightColMargin = $aRight;
    181181    }
    182182
    183183    function SetFontColor($aFontColor) {
    184         $this->iFontColor = $aFontColor;
     184        $this->iFontColor = $aFontColor;
    185185    }
    186186
    187187    function SetColor($aColor) {
    188         $this->iColor = $aColor;
     188        $this->iColor = $aColor;
    189189    }
    190190
    191191    function SetBackgroundColor($aColor) {
    192         $this->iBackgroundColor = $aColor;
     192        $this->iBackgroundColor = $aColor;
    193193    }
    194194
    195195    function SetColTitles($aTitles,$aWidth=null) {
    196         $this->iTitles = $aTitles;
    197         $this->iWidth = $aWidth;
     196        $this->iTitles = $aTitles;
     197        $this->iWidth = $aWidth;
    198198    }
    199199
    200200    function SetMinColWidth($aWidths) {
    201         $n = min(count($this->iTitles),count($aWidths));
    202         for($i=0; $i < $n; ++$i ) {
    203             if( !empty($aWidths[$i]) ) {
    204                 if( empty($this->iWidth[$i]) ) {
    205                     $this->iWidth[$i] = $aWidths[$i];
    206                 }
    207                 else {
    208                     $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]);
    209                 }
    210             }
    211         }
     201        $n = min(count($this->iTitles),count($aWidths));
     202        for($i=0; $i < $n; ++$i ) {
     203            if( !empty($aWidths[$i]) ) {
     204                if( empty($this->iWidth[$i]) ) {
     205                    $this->iWidth[$i] = $aWidths[$i];
     206                }
     207                else {
     208                    $this->iWidth[$i] = max($this->iWidth[$i],$aWidths[$i]);
     209                }
     210            }
     211        }
    212212    }
    213213
    214214    function GetWidth($aImg) {
    215         $txt = new TextProperty();
    216         $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    217         $n = count($this->iTitles) ;
    218         $rm=$this->iRightColMargin;
    219         $w = 0;
    220         for($h=0, $i=0; $i < $n; ++$i ) {
    221             $w += $this->iLeftColMargin;
    222             $txt->Set($this->iTitles[$i]);
    223             if( !empty($this->iWidth[$i]) ) {
    224                 $w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]);
    225             }
    226             else {
    227                 $w1 = $txt->GetWidth($aImg)+$rm;
    228             }
    229             $this->iWidth[$i] = $w1;
    230             $w += $w1;
    231             $h = max($h,$txt->GetHeight($aImg));
    232         }
    233         $this->iHeight = $h+$this->iTopHeaderMargin;
     215        $txt = new TextProperty();
     216        $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     217        $n = count($this->iTitles) ;
     218        $rm=$this->iRightColMargin;
     219        $w = 0;
     220        for($h=0, $i=0; $i < $n; ++$i ) {
     221            $w += $this->iLeftColMargin;
     222            $txt->Set($this->iTitles[$i]);
     223            if( !empty($this->iWidth[$i]) ) {
     224                $w1 = max($txt->GetWidth($aImg)+$rm,$this->iWidth[$i]);
     225            }
     226            else {
     227                $w1 = $txt->GetWidth($aImg)+$rm;
     228            }
     229            $this->iWidth[$i] = $w1;
     230            $w += $w1;
     231            $h = max($h,$txt->GetHeight($aImg));
     232        }
     233        $this->iHeight = $h+$this->iTopHeaderMargin;
    234234        $txt='';
    235         return $w;
    236     }
    237    
     235        return $w;
     236    }
     237
    238238    function GetColStart($aImg,&$aStart,$aAddLeftMargin=false) {
    239         $n = count($this->iTitles) ;
    240         $adj = $aAddLeftMargin ? $this->iLeftColMargin : 0;
    241         $aStart=array($aImg->left_margin+$adj);
    242         for( $i=1; $i < $n; ++$i ) {
    243             $aStart[$i] = $aStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1];
    244         }
    245     }
    246    
     239        $n = count($this->iTitles) ;
     240        $adj = $aAddLeftMargin ? $this->iLeftColMargin : 0;
     241        $aStart=array($aImg->left_margin+$adj);
     242        for( $i=1; $i < $n; ++$i ) {
     243            $aStart[$i] = $aStart[$i-1]+$this->iLeftColMargin+$this->iWidth[$i-1];
     244        }
     245    }
     246
    247247    // Adjust headers left, right or centered
    248248    function SetHeaderAlign($aAlign) {
    249         $this->iHeaderAlign=$aAlign;
     249        $this->iHeaderAlign=$aAlign;
    250250    }
    251251
    252252    function Stroke($aImg,$aXLeft,$aYTop,$aXRight,$aYBottom,$aUseTextHeight=false) {
    253253
    254         if( !$this->iShow ) return;
    255 
    256         $txt = new TextProperty();
    257         $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    258         $txt->SetColor($this->iFontColor);
    259         $txt->SetAlign($this->iHeaderAlign,'top');
    260         $n=count($this->iTitles);
    261 
    262         if( $n == 0 )
    263             return;
    264        
    265         $x = $aXLeft;
    266         $h = $this->iHeight;
    267         $yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ;
    268 
    269         if( $h < 0 ) {
    270             JpGraphError::RaiseL(6001);
    271 //('Internal error. Height for ActivityTitles is < 0');
    272         }
    273 
    274         $aImg->SetLineWeight(1);
    275         // Set background color
    276         $aImg->SetColor($this->iBackgroundColor);
    277         $aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1);
    278 
    279         if( $this->iStyle == 1 ) {
    280             // Make a 3D effect
    281             $aImg->SetColor('white');
    282             $aImg->Line($aXLeft,$yTop+1,
    283                         $aXRight,$yTop+1);
    284         }
    285        
    286         for($i=0; $i < $n; ++$i ) {
    287             if( $this->iStyle == 1 ) {
    288                 // Make a 3D effect
    289                 $aImg->SetColor('white');
    290                 $aImg->Line($x+1,$yTop,$x+1,$aYBottom);
    291             }
    292             $x += $this->iLeftColMargin;
    293             $txt->Set($this->iTitles[$i]);
    294            
    295             // Adjust the text anchor position according to the choosen alignment
    296             $xp = $x;
    297             if( $this->iHeaderAlign == 'center' ) {
    298                 $xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2;
    299             }
    300             elseif( $this->iHeaderAlign == 'right' ) {
    301                 $xp = $x +$this->iWidth[$i]-$this->iRightColMargin;
    302             }
    303                    
    304             $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin);
    305             $x += $this->iWidth[$i];
    306             if( $i < $n-1 ) {
    307                 $aImg->SetColor($this->iColor);
    308                 $aImg->Line($x,$yTop,$x,$aYBottom);
    309             }
    310         }
    311 
    312         $aImg->SetColor($this->iColor);
    313         $aImg->Line($aXLeft,$yTop, $aXRight,$yTop);
    314 
    315         // Stroke vertical column dividers
    316         $cols=array();
    317         $this->GetColStart($aImg,$cols);
    318         $n=count($cols);
    319         for( $i=1; $i < $n; ++$i ) {
    320             $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i],
    321                                     $aImg->height - $aImg->bottom_margin);
    322         }
     254        if( !$this->iShow ) return;
     255
     256        $txt = new TextProperty();
     257        $txt->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     258        $txt->SetColor($this->iFontColor);
     259        $txt->SetAlign($this->iHeaderAlign,'top');
     260        $n=count($this->iTitles);
     261
     262        if( $n == 0 )
     263        return;
     264
     265        $x = $aXLeft;
     266        $h = $this->iHeight;
     267        $yTop = $aUseTextHeight ? $aYBottom-$h-$this->iTopColMargin-$this->iBottomColMargin : $aYTop ;
     268
     269        if( $h < 0 ) {
     270            JpGraphError::RaiseL(6001);
     271            //('Internal error. Height for ActivityTitles is < 0');
     272        }
     273
     274        $aImg->SetLineWeight(1);
     275        // Set background color
     276        $aImg->SetColor($this->iBackgroundColor);
     277        $aImg->FilledRectangle($aXLeft,$yTop,$aXRight,$aYBottom-1);
     278
     279        if( $this->iStyle == 1 ) {
     280            // Make a 3D effect
     281            $aImg->SetColor('white');
     282            $aImg->Line($aXLeft,$yTop+1,$aXRight,$yTop+1);
     283        }
     284
     285        for($i=0; $i < $n; ++$i ) {
     286            if( $this->iStyle == 1 ) {
     287                // Make a 3D effect
     288                $aImg->SetColor('white');
     289                $aImg->Line($x+1,$yTop,$x+1,$aYBottom);
     290            }
     291            $x += $this->iLeftColMargin;
     292            $txt->Set($this->iTitles[$i]);
     293
     294            // Adjust the text anchor position according to the choosen alignment
     295            $xp = $x;
     296            if( $this->iHeaderAlign == 'center' ) {
     297                $xp = (($x-$this->iLeftColMargin)+($x+$this->iWidth[$i]))/2;
     298            }
     299            elseif( $this->iHeaderAlign == 'right' ) {
     300                $xp = $x +$this->iWidth[$i]-$this->iRightColMargin;
     301            }
     302
     303            $txt->Stroke($aImg,$xp,$yTop+$this->iTopHeaderMargin);
     304            $x += $this->iWidth[$i];
     305            if( $i < $n-1 ) {
     306                $aImg->SetColor($this->iColor);
     307                $aImg->Line($x,$yTop,$x,$aYBottom);
     308            }
     309        }
     310
     311        $aImg->SetColor($this->iColor);
     312        $aImg->Line($aXLeft,$yTop, $aXRight,$yTop);
     313
     314        // Stroke vertical column dividers
     315        $cols=array();
     316        $this->GetColStart($aImg,$cols);
     317        $n=count($cols);
     318        for( $i=1; $i < $n; ++$i ) {
     319            $this->vgrid->Stroke($aImg,$cols[$i],$aYBottom,$cols[$i],
     320            $aImg->height - $aImg->bottom_margin);
     321        }
    323322    }
    324323}
     
    330329//===================================================
    331330class GanttGraph extends Graph {
    332     public $scale;              // Public accessible
     331    public $scale;  // Public accessible
    333332    public $hgrid=null;
    334     private $iObj=array();                              // Gantt objects
    335     private $iLabelHMarginFactor=0.2;   // 10% margin on each side of the labels
    336     private $iLabelVMarginFactor=0.4;   // 40% margin on top and bottom of label
    337     private $iLayout=GANTT_FROMTOP;     // Could also be GANTT_EVEN
     333    private $iObj=array();    // Gantt objects
     334    private $iLabelHMarginFactor=0.2; // 10% margin on each side of the labels
     335    private $iLabelVMarginFactor=0.4; // 40% margin on top and bottom of label
     336    private $iLayout=GANTT_FROMTOP; // Could also be GANTT_EVEN
    338337    private $iSimpleFont = FF_FONT1,$iSimpleFontSize=11;
    339338    private $iSimpleStyle=GANTT_RDIAG,$iSimpleColor='yellow',$iSimpleBkgColor='red';
    340339    private $iSimpleProgressBkgColor='gray',$iSimpleProgressColor='darkgreen';
    341340    private $iSimpleProgressStyle=GANTT_SOLID;
    342 //---------------
    343 // CONSTRUCTOR 
     341    private $iZoomFactor = 1.0;
     342    //---------------
     343    // CONSTRUCTOR
    344344    // Create a new gantt graph
    345     function GanttGraph($aWidth=0,$aHeight=0,$aCachedName="",$aTimeOut=0,$aInline=true) {
    346 
    347         // Backward compatibility
    348         if( $aWidth == -1 ) $aWidth=0;
    349         if( $aHeight == -1 ) $aHeight=0;
    350 
    351         if( $aWidth<  0 || $aHeight < 0 ) {
    352             JpgraphError::RaiseL(6002);
    353 //("You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.");
    354         }
    355         Graph::Graph($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline);         
    356         $this->scale = new GanttScale($this->img);
    357 
    358         // Default margins
    359         $this->img->SetMargin(15,17,25,15);
    360 
    361         $this->hgrid = new HorizontalGridLine();
    362                
    363         $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY);
    364         $this->SetBox();
    365     }
    366        
    367 //---------------
    368 // PUBLIC METHODS
    369 
    370     // 
     345    function __construct($aWidth=0,$aHeight=0,$aCachedName="",$aTimeOut=0,$aInline=true) {
     346
     347        // Backward compatibility
     348        if( $aWidth == -1 ) $aWidth=0;
     349        if( $aHeight == -1 ) $aHeight=0;
     350
     351        if( $aWidth<  0 || $aHeight < 0 ) {
     352            JpgraphError::RaiseL(6002);
     353            //("You can't specify negative sizes for Gantt graph dimensions. Use 0 to indicate that you want the library to automatically determine a dimension.");
     354        }
     355        parent::__construct($aWidth,$aHeight,$aCachedName,$aTimeOut,$aInline);
     356        $this->scale = new GanttScale($this->img);
     357
     358        // Default margins
     359        $this->img->SetMargin(15,17,25,15);
     360
     361        $this->hgrid = new HorizontalGridLine();
     362
     363        $this->scale->ShowHeaders(GANTT_HWEEK|GANTT_HDAY);
     364        $this->SetBox();
     365    }
     366
     367    //---------------
     368    // PUBLIC METHODS
     369
     370    //
    371371
    372372    function SetSimpleFont($aFont,$aSize) {
    373         $this->iSimpleFont = $aFont;
    374         $this->iSimpleFontSize = $aSize;
     373        $this->iSimpleFont = $aFont;
     374        $this->iSimpleFontSize = $aSize;
    375375    }
    376376
    377377    function SetSimpleStyle($aBand,$aColor,$aBkgColor) {
    378         $this->iSimpleStyle = $aBand;
    379         $this->iSimpleColor = $aColor;
    380         $this->iSimpleBkgColor = $aBkgColor;
     378        $this->iSimpleStyle = $aBand;
     379        $this->iSimpleColor = $aColor;
     380        $this->iSimpleBkgColor = $aBkgColor;
    381381    }
    382382
    383383    // A utility function to help create basic Gantt charts
    384384    function CreateSimple($data,$constrains=array(),$progress=array()) {
    385         $num = count($data);
    386         for( $i=0; $i < $num; ++$i) {
    387             switch( $data[$i][1] ) {
    388                 case ACTYPE_GROUP:
    389                     // Create a slightly smaller height bar since the
    390                     // "wings" at the end will make it look taller
    391                     $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8);
    392                     $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize);             
    393                     $a->rightMark->Show();
    394                     $a->rightMark->SetType(MARK_RIGHTTRIANGLE);
    395                     $a->rightMark->SetWidth(8);
    396                     $a->rightMark->SetColor('black');
    397                     $a->rightMark->SetFillColor('black');
    398            
    399                     $a->leftMark->Show();
    400                     $a->leftMark->SetType(MARK_LEFTTRIANGLE);
    401                     $a->leftMark->SetWidth(8);
    402                     $a->leftMark->SetColor('black');
    403                     $a->leftMark->SetFillColor('black');
    404            
    405                     $a->SetPattern(BAND_SOLID,'black');
    406                     $csimpos = 6;
    407                     break;
    408                
    409                 case ACTYPE_NORMAL:
    410                     $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10);
    411                     $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);
    412                     $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor);
    413                     $a->SetFillColor($this->iSimpleBkgColor);
    414                     // Check if this activity should have a constrain line
    415                     $n = count($constrains);
    416                     for( $j=0; $j < $n; ++$j ) {
    417                         if( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) {
    418                             JpGraphError::RaiseL(6003,$j);
    419 //("Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)");   
    420                         }
    421                         if( $constrains[$j][0]==$data[$i][0] ) {
    422                             $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID);   
    423                         }
    424                     }
    425 
    426                     // Check if this activity have a progress bar
    427                     $n = count($progress);
    428                     for( $j=0; $j < $n; ++$j ) {
    429                        
    430                         if( empty($progress[$j]) || (count($progress[$j]) != 2) ) {
    431                             JpGraphError::RaiseL(6004,$j);
    432 //("Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)");     
    433                         }
    434                         if( $progress[$j][0]==$data[$i][0] ) {
    435                             $a->progress->Set($progress[$j][1]);
    436                             $a->progress->SetPattern($this->iSimpleProgressStyle,
    437                                                      $this->iSimpleProgressColor);
    438                             $a->progress->SetFillColor($this->iSimpleProgressBkgColor);
    439                             //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]);
    440                             break;
    441                         }
    442                     }
    443                     $csimpos = 6;
    444                     break;
    445 
    446                 case ACTYPE_MILESTONE:
    447                     $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]);
    448                     $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);
    449                     $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);
    450                     $csimpos = 5;
    451                     break;
    452                 default:
    453                     die('Unknown activity type');
    454                     break;
    455             }
    456 
    457             // Setup caption
    458             $a->caption->Set($data[$i][$csimpos-1]);
    459 
    460             // Check if this activity should have a CSIM target ?
    461             if( !empty($data[$i][$csimpos]) ) {
    462                 $a->SetCSIMTarget($data[$i][$csimpos]);
    463                 $a->SetCSIMAlt($data[$i][$csimpos+1]);
    464             }
    465             if( !empty($data[$i][$csimpos+2]) ) {
    466                 $a->title->SetCSIMTarget($data[$i][$csimpos+2]);
    467                 $a->title->SetCSIMAlt($data[$i][$csimpos+3]);
    468             }
    469 
    470             $this->Add($a);
    471         }
    472     }
    473 
    474        
     385        $num = count($data);
     386        for( $i=0; $i < $num; ++$i) {
     387            switch( $data[$i][1] ) {
     388                case ACTYPE_GROUP:
     389                    // Create a slightly smaller height bar since the
     390                    // "wings" at the end will make it look taller
     391                    $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',8);
     392                    $a->title->SetFont($this->iSimpleFont,FS_BOLD,$this->iSimpleFontSize);
     393                    $a->rightMark->Show();
     394                    $a->rightMark->SetType(MARK_RIGHTTRIANGLE);
     395                    $a->rightMark->SetWidth(8);
     396                    $a->rightMark->SetColor('black');
     397                    $a->rightMark->SetFillColor('black');
     398
     399                    $a->leftMark->Show();
     400                    $a->leftMark->SetType(MARK_LEFTTRIANGLE);
     401                    $a->leftMark->SetWidth(8);
     402                    $a->leftMark->SetColor('black');
     403                    $a->leftMark->SetFillColor('black');
     404
     405                    $a->SetPattern(BAND_SOLID,'black');
     406                    $csimpos = 6;
     407                    break;
     408
     409                case ACTYPE_NORMAL:
     410                    $a = new GanttBar($data[$i][0],$data[$i][2],$data[$i][3],$data[$i][4],'',10);
     411                    $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);
     412                    $a->SetPattern($this->iSimpleStyle,$this->iSimpleColor);
     413                    $a->SetFillColor($this->iSimpleBkgColor);
     414                    // Check if this activity should have a constrain line
     415                    $n = count($constrains);
     416                    for( $j=0; $j < $n; ++$j ) {
     417                        if( empty($constrains[$j]) || (count($constrains[$j]) != 3) ) {
     418                            JpGraphError::RaiseL(6003,$j);
     419                            //("Invalid format for Constrain parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Constrain-To,Constrain-Type)");
     420                        }
     421                        if( $constrains[$j][0]==$data[$i][0] ) {
     422                            $a->SetConstrain($constrains[$j][1],$constrains[$j][2],'black',ARROW_S2,ARROWT_SOLID);
     423                        }
     424                    }
     425
     426                    // Check if this activity have a progress bar
     427                    $n = count($progress);
     428                    for( $j=0; $j < $n; ++$j ) {
     429
     430                        if( empty($progress[$j]) || (count($progress[$j]) != 2) ) {
     431                            JpGraphError::RaiseL(6004,$j);
     432                            //("Invalid format for Progress parameter at index=$j in CreateSimple(). Parameter must start with index 0 and contain arrays of (Row,Progress)");
     433                        }
     434                        if( $progress[$j][0]==$data[$i][0] ) {
     435                            $a->progress->Set($progress[$j][1]);
     436                            $a->progress->SetPattern($this->iSimpleProgressStyle,
     437                            $this->iSimpleProgressColor);
     438                            $a->progress->SetFillColor($this->iSimpleProgressBkgColor);
     439                            //$a->progress->SetPattern($progress[$j][2],$progress[$j][3]);
     440                            break;
     441                        }
     442                    }
     443                    $csimpos = 6;
     444                    break;
     445
     446                case ACTYPE_MILESTONE:
     447                    $a = new MileStone($data[$i][0],$data[$i][2],$data[$i][3]);
     448                    $a->title->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);
     449                    $a->caption->SetFont($this->iSimpleFont,FS_NORMAL,$this->iSimpleFontSize);
     450                    $csimpos = 5;
     451                    break;
     452                default:
     453                    die('Unknown activity type');
     454                    break;
     455            }
     456
     457            // Setup caption
     458            $a->caption->Set($data[$i][$csimpos-1]);
     459
     460            // Check if this activity should have a CSIM targetï¿œ?
     461            if( !empty($data[$i][$csimpos]) ) {
     462                $a->SetCSIMTarget($data[$i][$csimpos]);
     463                $a->SetCSIMAlt($data[$i][$csimpos+1]);
     464            }
     465            if( !empty($data[$i][$csimpos+2]) ) {
     466                $a->title->SetCSIMTarget($data[$i][$csimpos+2]);
     467                $a->title->SetCSIMAlt($data[$i][$csimpos+3]);
     468            }
     469
     470            $this->Add($a);
     471        }
     472    }
     473
     474    // Set user specified scale zoom factor when auto sizing is used
     475    function SetZoomFactor($aZoom) {
     476        $this->iZoomFactor = $aZoom;
     477    }
     478
     479
    475480    // Set what headers should be shown
    476481    function ShowHeaders($aFlg) {
    477         $this->scale->ShowHeaders($aFlg);
    478     }
    479        
    480     // Specify the fraction of the font height that should be added 
     482        $this->scale->ShowHeaders($aFlg);
     483    }
     484
     485    // Specify the fraction of the font height that should be added
    481486    // as vertical margin
    482487    function SetLabelVMarginFactor($aVal) {
    483         $this->iLabelVMarginFactor = $aVal;
     488        $this->iLabelVMarginFactor = $aVal;
    484489    }
    485490
    486491    // Synonym to the method above
    487492    function SetVMarginFactor($aVal) {
    488         $this->iLabelVMarginFactor = $aVal;
    489     }
    490        
    491        
     493        $this->iLabelVMarginFactor = $aVal;
     494    }
     495
     496
    492497    // Add a new Gantt object
    493498    function Add($aObject) {
    494         if( is_array($aObject) && count($aObject) > 0 ) {
    495             $cl = $aObject[0];
    496             if( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) {
    497                 $this->AddIcon($aObject);
    498             }
    499             else {
    500                 $n = count($aObject);
    501                 for($i=0; $i < $n; ++$i)
    502                     $this->iObj[] = $aObject[$i];
    503             }
     499        if( is_array($aObject) && count($aObject) > 0 ) {
     500            $cl = $aObject[0];
     501            if( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) {
     502                $this->AddIcon($aObject);
     503            }
     504            elseif( class_exists('Text',false) && ($cl instanceof Text) ) {
     505                $this->AddText($aObject);
     506            }
     507            else {
     508                $n = count($aObject);
     509                for($i=0; $i < $n; ++$i)
     510                $this->iObj[] = $aObject[$i];
     511            }
     512        }
     513        else {
     514            if( class_exists('IconPlot',false) && ($aObject instanceof IconPlot) ) {
     515                $this->AddIcon($aObject);
     516            }
     517            elseif( class_exists('Text',false) && ($aObject instanceof Text) ) {
     518                $this->AddText($aObject);
     519            }
     520            else {
     521                $this->iObj[] = $aObject;
     522            }
     523        }
     524    }
     525
     526        function StrokeTexts() {
     527        // Stroke any user added text objects
     528        if( $this->texts != null ) {
     529                $n = count($this->texts);
     530            for($i=0; $i < $n; ++$i) {
     531                if( $this->texts[$i]->iScalePosX !== null && $this->texts[$i]->iScalePosY !== null ) {
     532                        $x = $this->scale->TranslateDate($this->texts[$i]->iScalePosX);
     533                        $y = $this->scale->TranslateVertPos($this->texts[$i]->iScalePosY);
     534                        $y -= $this->scale->GetVertSpacing()/2;
     535                }
     536                else {
     537                        $x = $y = null;
     538                }
     539                $this->texts[$i]->Stroke($this->img,$x,$y);
     540            }
     541        }
    504542        }
    505         else {
    506             if( class_exists('IconPlot',false) && ($aObject instanceof IconPlot) ) {
    507                 $this->AddIcon($aObject);
    508             }
    509             else {         
    510                 $this->iObj[] = $aObject;
    511             }
    512         }
    513     }
    514543
    515544    // Override inherit method from Graph and give a warning message
    516545    function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) {
    517         JpGraphError::RaiseL(6005);
    518 //("SetScale() is not meaningfull with Gantt charts.");
     546        JpGraphError::RaiseL(6005);
     547        //("SetScale() is not meaningfull with Gantt charts.");
    519548    }
    520549
     
    522551    // automtically determined from the input data)
    523552    function SetDateRange($aStart,$aEnd) {
    524         // Adjust the start and end so that the indicate the
    525         // begining and end of respective start and end days
    526         if( strpos($aStart,':') === false )
    527             $aStart = date('Y-m-d 00:00',strtotime($aStart));
    528         if( strpos($aEnd,':') === false )
    529             $aEnd = date('Y-m-d 23:59',strtotime($aEnd));
    530         $this->scale->SetRange($aStart,$aEnd);
    531     }
    532        
     553        // Adjust the start and end so that the indicate the
     554        // begining and end of respective start and end days
     555        if( strpos($aStart,':') === false )
     556        $aStart = date('Y-m-d 00:00',strtotime($aStart));
     557        if( strpos($aEnd,':') === false )
     558        $aEnd = date('Y-m-d 23:59',strtotime($aEnd));
     559        $this->scale->SetRange($aStart,$aEnd);
     560    }
     561
    533562    // Get the maximum width of the activity titles columns for the bars
    534563    // The name is lightly misleading since we from now on can have
     
    536565    // it only supported a single label, hence the name.
    537566    function GetMaxLabelWidth() {
    538         $m=10;
    539         if( $this->iObj != null ) {
    540             $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin;
    541             $n = count($this->iObj);
    542             for($i=0; $i < $n; ++$i) {
    543                 if( !empty($this->iObj[$i]->title) ) {
    544                     if( $this->iObj[$i]->title->HasTabs() ) {
    545                         list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true);
    546                         $m=max($m,$tot);
    547                     }
    548                     else
    549                         $m=max($m,$this->iObj[$i]->title->GetWidth($this->img));
    550                 }
    551             }
    552         }
    553         return $m;
    554     }
    555        
     567        $m=10;
     568        if( $this->iObj != null ) {
     569            $marg = $this->scale->actinfo->iLeftColMargin+$this->scale->actinfo->iRightColMargin;
     570            $n = count($this->iObj);
     571            for($i=0; $i < $n; ++$i) {
     572                if( !empty($this->iObj[$i]->title) ) {
     573                    if( $this->iObj[$i]->title->HasTabs() ) {
     574                        list($tot,$w) = $this->iObj[$i]->title->GetWidth($this->img,true);
     575                        $m=max($m,$tot);
     576                    }
     577                    else
     578                    $m=max($m,$this->iObj[$i]->title->GetWidth($this->img));
     579                }
     580            }
     581        }
     582        return $m;
     583    }
     584
    556585    // Get the maximum height of the titles for the bars
    557586    function GetMaxLabelHeight() {
    558         $m=10;
    559         if( $this->iObj != null ) {
    560             $n = count($this->iObj);
    561             for($i=0; $i < $n; ++$i) {
    562                 if( !empty($this->iObj[$i]->title) ) {
    563                     $m=max($m,$this->iObj[$i]->title->GetHeight($this->img));
    564                 }
    565             }
    566         }
    567         return $m;
     587        $m=10;
     588        if( $this->iObj != null ) {
     589            $n = count($this->iObj);
     590            // We can not include the title of GnttVLine since that title is stroked at the bottom
     591            // of the Gantt bar and not in the activity title columns
     592            for($i=0; $i < $n; ++$i) {
     593                if( !empty($this->iObj[$i]->title) && !($this->iObj[$i] instanceof GanttVLine) ) {
     594                    $m=max($m,$this->iObj[$i]->title->GetHeight($this->img));
     595                }
     596            }
     597        }
     598        return $m;
    568599    }
    569600
    570601    function GetMaxBarAbsHeight() {
    571         $m=0;
    572         if( $this->iObj != null ) {
    573             $m = $this->iObj[0]->GetAbsHeight($this->img);
    574             $n = count($this->iObj);
    575             for($i=1; $i < $n; ++$i) {
    576                 $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img));
    577             }
    578         }
    579         return $m;             
    580     }
    581        
     602        $m=0;
     603        if( $this->iObj != null ) {
     604            $m = $this->iObj[0]->GetAbsHeight($this->img);
     605            $n = count($this->iObj);
     606            for($i=1; $i < $n; ++$i) {
     607                $m=max($m,$this->iObj[$i]->GetAbsHeight($this->img));
     608            }
     609        }
     610        return $m;
     611    }
     612
    582613    // Get the maximum used line number (vertical position) for bars
    583614    function GetBarMaxLineNumber() {
    584         $m=1;
    585         if( $this->iObj != null ) {
    586             $m = $this->iObj[0]->GetLineNbr();
    587             $n = count($this->iObj);
    588             for($i=1; $i < $n; ++$i) {
    589                 $m=max($m,$this->iObj[$i]->GetLineNbr());
    590             }
    591         }
    592         return $m;
    593     }
    594        
     615        $m=1;
     616        if( $this->iObj != null ) {
     617            $m = $this->iObj[0]->GetLineNbr();
     618            $n = count($this->iObj);
     619            for($i=1; $i < $n; ++$i) {
     620                $m=max($m,$this->iObj[$i]->GetLineNbr());
     621            }
     622        }
     623        return $m;
     624    }
     625
    595626    // Get the minumum and maximum used dates for all bars
    596627    function GetBarMinMax() {
    597         $start = 0 ;
    598         $n = count($this->iObj);
    599         while( $start < $n && $this->iObj[$start]->GetMaxDate() === false )
    600             ++$start;
    601         if( $start >= $n ) {
    602             JpgraphError::RaiseL(6006);
    603 //('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]');
    604         }
    605 
    606         $max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate());
    607         $min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate());
    608 
    609         for($i=$start+1; $i < $n; ++$i) {
    610             $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate());
    611             if( $rmax != false )
    612                 $max=Max($max,$rmax);
    613             $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate());
    614             if( $rmin != false )
    615                 $min=Min($min,$rmin);
    616         }
    617         $minDate = date("Y-m-d",$min);
    618         $min = strtotime($minDate);
    619         $maxDate = date("Y-m-d 23:59",$max);
    620         $max = strtotime($maxDate);     
    621         return array($min,$max);
     628        $start = 0 ;
     629        $n = count($this->iObj);
     630        while( $start < $n && $this->iObj[$start]->GetMaxDate() === false )
     631        ++$start;
     632        if( $start >= $n ) {
     633            JpgraphError::RaiseL(6006);
     634            //('Cannot autoscale Gantt chart. No dated activities exist. [GetBarMinMax() start >= n]');
     635        }
     636
     637        $max=$this->scale->NormalizeDate($this->iObj[$start]->GetMaxDate());
     638        $min=$this->scale->NormalizeDate($this->iObj[$start]->GetMinDate());
     639
     640        for($i=$start+1; $i < $n; ++$i) {
     641            $rmax = $this->scale->NormalizeDate($this->iObj[$i]->GetMaxDate());
     642            if( $rmax != false )
     643            $max=Max($max,$rmax);
     644            $rmin = $this->scale->NormalizeDate($this->iObj[$i]->GetMinDate());
     645            if( $rmin != false )
     646            $min=Min($min,$rmin);
     647        }
     648        $minDate = date("Y-m-d",$min);
     649        $min = strtotime($minDate);
     650        $maxDate = date("Y-m-d 23:59",$max);
     651        $max = strtotime($maxDate);
     652        return array($min,$max);
    622653    }
    623654
     
    628659    function AutoSize() {
    629660
    630         if( $this->img->img == null ) {
    631             // The predefined left, right, top, bottom margins.
    632             // Note that the top margin might incease depending on
    633             // the title.
    634             $lm = $this->img->left_margin;
    635             $rm = $this->img->right_margin;
    636             $rm += 2 ;
    637             $tm = $this->img->top_margin;
    638             $bm = $this->img->bottom_margin;
    639             $bm += 1;
    640             if( BRAND_TIMING ) $bm += 10;
    641                        
    642             // First find out the height                       
    643             $n=$this->GetBarMaxLineNumber()+1;
    644             $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight());
    645             $height=$n*((1+$this->iLabelVMarginFactor)*$m);                     
    646                        
    647             // Add the height of the scale titles                       
    648             $h=$this->scale->GetHeaderHeight();
    649             $height += $h;
    650 
    651             // Calculate the top margin needed for title and subtitle
    652             if( $this->title->t != "" ) {
    653                 $tm += $this->title->GetFontHeight($this->img);
    654             }
    655             if( $this->subtitle->t != "" ) {
    656                 $tm += $this->subtitle->GetFontHeight($this->img);
    657             }
    658 
    659             // ...and then take the bottom and top plot margins into account
    660             $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin;
    661             // Now find the minimum width for the chart required
    662 
    663             // If day scale or smaller is shown then we use the day font width
    664             // as the base size unit.
    665             // If only weeks or above is displayed we use a modified unit to
    666             // get a smaller image.
    667             if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) {
    668                 // Add 2 pixel margin on each side
    669                 $fw=$this->scale->day->GetFontWidth($this->img)+4;
    670             }
    671             elseif( $this->scale->IsDisplayWeek() ) {
    672                 $fw = 8;
    673             }
    674             elseif( $this->scale->IsDisplayMonth() ) {
    675                 $fw = 4;
    676             }
    677             else {
    678                 $fw = 2;
    679             }
    680 
    681             $nd=$this->scale->GetNumberOfDays();
    682 
    683             if( $this->scale->IsDisplayDay() ) {
    684                 // If the days are displayed we also need to figure out
    685                 // how much space each day's title will require.
    686                 switch( $this->scale->day->iStyle ) {
    687                     case DAYSTYLE_LONG :
    688                         $txt = "Monday";
    689                         break;
    690                     case DAYSTYLE_LONGDAYDATE1 :
    691                         $txt =  "Monday 23 Jun";
    692                         break;
    693                     case DAYSTYLE_LONGDAYDATE2 :
    694                         $txt =  "Monday 23 Jun 2003";
    695                         break;
    696                     case DAYSTYLE_SHORT :
    697                         $txt =  "Mon";
    698                         break;
    699                     case DAYSTYLE_SHORTDAYDATE1 :
     661        if( $this->img->img == null ) {
     662            // The predefined left, right, top, bottom margins.
     663            // Note that the top margin might incease depending on
     664            // the title.
     665           $hadj = $vadj = 0;
     666           if( $this->doshadow ) {
     667                        $hadj = $this->shadow_width;
     668                $vadj = $this->shadow_width+5;
     669            }
     670
     671            $lm = $this->img->left_margin;
     672            $rm = $this->img->right_margin +$hadj;
     673            $rm += 2 ;
     674            $tm = $this->img->top_margin;
     675            $bm = $this->img->bottom_margin + $vadj;
     676            $bm += 2;
     677
     678            // If there are any added GanttVLine we must make sure that the
     679            // bottom margin is wide enough to hold a title.
     680            $n = count($this->iObj);
     681                for($i=0; $i < $n; ++$i) {
     682                if( $this->iObj[$i] instanceof GanttVLine ) {
     683                                        $bm = max($bm,$this->iObj[$i]->title->GetHeight($this->img)+10);
     684                }
     685                }
     686
     687            // First find out the height
     688            $n=$this->GetBarMaxLineNumber()+1;
     689            $m=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight());
     690            $height=$n*((1+$this->iLabelVMarginFactor)*$m);
     691
     692            // Add the height of the scale titles
     693            $h=$this->scale->GetHeaderHeight();
     694            $height += $h;
     695
     696            // Calculate the top margin needed for title and subtitle
     697            if( $this->title->t != "" ) {
     698                $tm += $this->title->GetFontHeight($this->img);
     699            }
     700            if( $this->subtitle->t != "" ) {
     701                $tm += $this->subtitle->GetFontHeight($this->img);
     702            }
     703
     704            // ...and then take the bottom and top plot margins into account
     705            $height += $tm + $bm + $this->scale->iTopPlotMargin + $this->scale->iBottomPlotMargin;
     706            // Now find the minimum width for the chart required
     707
     708            // If day scale or smaller is shown then we use the day font width
     709            // as the base size unit.
     710            // If only weeks or above is displayed we use a modified unit to
     711            // get a smaller image.
     712            if( $this->scale->IsDisplayHour() || $this->scale->IsDisplayMinute() ) {
     713                // Add 2 pixel margin on each side
     714                $fw=$this->scale->day->GetFontWidth($this->img)+4;
     715            }
     716            elseif( $this->scale->IsDisplayWeek() ) {
     717                $fw = 8;
     718            }
     719            elseif( $this->scale->IsDisplayMonth() ) {
     720                $fw = 4;
     721            }
     722            else {
     723                $fw = 2;
     724            }
     725
     726            $nd=$this->scale->GetNumberOfDays();
     727
     728            if( $this->scale->IsDisplayDay() ) {
     729                // If the days are displayed we also need to figure out
     730                // how much space each day's title will require.
     731                switch( $this->scale->day->iStyle ) {
     732                    case DAYSTYLE_LONG :
     733                        $txt = "Monday";
     734                        break;
     735                    case DAYSTYLE_LONGDAYDATE1 :
     736                        $txt =  "Monday 23 Jun";
     737                        break;
     738                    case DAYSTYLE_LONGDAYDATE2 :
     739                        $txt =  "Monday 23 Jun 2003";
     740                        break;
     741                    case DAYSTYLE_SHORT :
     742                        $txt =  "Mon";
     743                        break;
     744                    case DAYSTYLE_SHORTDAYDATE1 :
    700745                        $txt =  "Mon 23/6";
    701                         break;
    702                     case DAYSTYLE_SHORTDAYDATE2 :
    703                         $txt =  "Mon 23 Jun";
    704                         break;
    705                     case DAYSTYLE_SHORTDAYDATE3 :
    706                         $txt =  "Mon 23";
    707                         break;
    708                     case DAYSTYLE_SHORTDATE1 :
     746                        break;
     747                    case DAYSTYLE_SHORTDAYDATE2 :
     748                        $txt =  "Mon 23 Jun";
     749                        break;
     750                    case DAYSTYLE_SHORTDAYDATE3 :
     751                        $txt =  "Mon 23";
     752                        break;
     753                    case DAYSTYLE_SHORTDATE1 :
    709754                        $txt =  "23/6";
    710                         break;
    711                     case DAYSTYLE_SHORTDATE2 :
    712                         $txt =  "23 Jun";
    713                         break;
    714                     case DAYSTYLE_SHORTDATE3 :
    715                         $txt =  "Mon 23";
    716                         break;
    717                     case DAYSTYLE_SHORTDATE4 :
    718                         $txt =  "88";
    719                         break;
    720                     case DAYSTYLE_CUSTOM :
    721                         $txt = date($this->scale->day->iLabelFormStr,
    722                                     strtotime('2003-12-20 18:00'));
    723                         break;
    724                     case DAYSTYLE_ONELETTER :
    725                     default:
    726                         $txt = "M";
    727                         break;
    728                 }
    729                 $fw = $this->scale->day->GetStrWidth($this->img,$txt)+6;
    730             }
    731 
    732             // If we have hours enabled we must make sure that each day has enough
    733             // space to fit the number of hours to be displayed.
    734             if( $this->scale->IsDisplayHour() ) {
    735                 // Depending on what format the user has choose we need different amount
    736                 // of space. We therefore create a typical string for the choosen format
    737                 // and determine the length of that string.
    738                 switch( $this->scale->hour->iStyle ) {
    739                     case HOURSTYLE_HMAMPM:
    740                         $txt = '12:00pm';
    741                         break;
    742                     case HOURSTYLE_H24:
    743                         // 13
    744                         $txt = '24';
    745                         break;
    746                     case HOURSTYLE_HAMPM:
    747                         $txt = '12pm';
    748                         break;
    749                     case HOURSTYLE_CUSTOM:
    750                         $txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00'));
    751                         break;
    752                     case HOURSTYLE_HM24:
    753                     default:
    754                         $txt = '24:00';
    755                         break;
    756                 }
    757 
    758                 $hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6;
    759                 $mw = $hfw;
    760                 if( $this->scale->IsDisplayMinute() ) {
    761                     // Depending on what format the user has choose we need different amount
    762                     // of space. We therefore create a typical string for the choosen format
    763                     // and determine the length of that string.
    764                     switch( $this->scale->minute->iStyle ) {
    765                         case HOURSTYLE_CUSTOM:
    766                             $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55'));
    767                             break;
    768                         case MINUTESTYLE_MM:
    769                         default:
    770                             $txt2 = '15';
    771                             break;
    772                     }
    773                    
    774                     $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6;
    775                     $n2 = ceil(60 / $this->scale->minute->GetIntervall() );
    776                     $mw = $n2 * $mfw;
    777                 }
    778                 $hfw = $hfw < $mw ? $mw : $hfw ;   
    779                 $n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) );
    780                 $hw = $n * $hfw;
    781                 $fw = $fw < $hw ? $hw : $fw ;
    782             }
    783 
    784             // We need to repeat this code block here as well.
    785             // THIS iS NOT A MISTAKE !
    786             // We really need it since we need to adjust for minutes both in the case
    787             // where hour scale is shown and when it is not shown.
    788 
    789             if( $this->scale->IsDisplayMinute() ) {
    790                 // Depending on what format the user has choose we need different amount
    791                 // of space. We therefore create a typical string for the choosen format
    792                 // and determine the length of that string.
    793                 switch( $this->scale->minute->iStyle ) {
    794                     case HOURSTYLE_CUSTOM:
    795                         $txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55'));
    796                         break;
    797                     case MINUTESTYLE_MM:
    798                     default:
    799                         $txt = '15';
    800                         break;
    801                 }
    802                
    803                 $mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6;
    804                 $n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) );
    805                 $mw = $n * $mfw;
    806                 $fw = $fw < $mw ? $mw : $fw ;
    807             }
    808 
    809             // If we display week we must make sure that 7*$fw is enough
    810             // to fit up to 10 characters of the week font (if the week is enabled)
    811             if( $this->scale->IsDisplayWeek() ) {
    812                 // Depending on what format the user has choose we need different amount
    813                 // of space
    814                 $fsw = strlen($this->scale->week->iLabelFormStr);
    815                 if( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
    816                     $fsw += 8;
    817                 }
    818                 elseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) {
    819                     $fsw += 7;
    820                 }
    821                 else {
    822                     $fsw += 4;
    823                 }
    824                    
    825                 $ww = $fsw*$this->scale->week->GetFontWidth($this->img);
    826                 if( 7*$fw < $ww ) {
    827                     $fw = ceil($ww/7);
    828                 }
    829             }
    830 
    831             if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() &&
    832                 !( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||
    833                     $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) {
    834                 // If we don't display the individual days we can shrink the
    835                 // scale a little bit. This is a little bit pragmatic at the
    836                 // moment and should be re-written to take into account
    837                 // a) What scales exactly are shown and
    838                 // b) what format do they use so we know how wide we need to
    839                 // make each scale text space at minimum.
    840                 $fw /= 2;
    841                 if( !$this->scale->IsDisplayWeek() ) {
    842                     $fw /= 1.8;
    843                 }
    844             }
    845 
    846             $cw = $this->GetMaxActInfoColWidth() ;
    847             $this->scale->actinfo->SetMinColWidth($cw);
    848             if( $this->img->width <= 0 ) {
    849                 // Now determine the width for the activity titles column
    850 
    851                 // Firdst find out the maximum width of each object column
    852                 $titlewidth = max(max($this->GetMaxLabelWidth(),
    853                                       $this->scale->tableTitle->GetWidth($this->img)),
    854                                   $this->scale->actinfo->GetWidth($this->img));
    855 
    856                 // Add the width of the vertivcal divider line
    857                 $titlewidth += $this->scale->divider->iWeight*2;
    858 
    859 
    860                 // Now get the total width taking
    861                 // titlewidth, left and rigt margin, dayfont size
    862                 // into account
    863                 $width = $titlewidth + $nd*$fw + $lm+$rm;
    864             }
    865             else {
    866                 $width = $this->img->width;
    867             }
    868 
    869             $width = round($width);
    870             $height = round($height);
    871             // Make a sanity check on image size
    872             if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) {
    873                 JpgraphError::RaiseL(6007,$width,$height);
    874 //("Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.");
    875             }
    876             $this->img->CreateImgCanvas($width,$height);                       
    877             $this->img->SetMargin($lm,$rm,$tm,$bm);
    878         }
     755                        break;
     756                    case DAYSTYLE_SHORTDATE2 :
     757                        $txt =  "23 Jun";
     758                        break;
     759                    case DAYSTYLE_SHORTDATE3 :
     760                        $txt =  "Mon 23";
     761                        break;
     762                    case DAYSTYLE_SHORTDATE4 :
     763                        $txt =  "88";
     764                        break;
     765                    case DAYSTYLE_CUSTOM :
     766                        $txt = date($this->scale->day->iLabelFormStr,strtotime('2003-12-20 18:00'));
     767                        break;
     768                    case DAYSTYLE_ONELETTER :
     769                    default:
     770                        $txt = "M";
     771                        break;
     772                }
     773                $fw = $this->scale->day->GetStrWidth($this->img,$txt)+6;
     774            }
     775
     776            // If we have hours enabled we must make sure that each day has enough
     777            // space to fit the number of hours to be displayed.
     778            if( $this->scale->IsDisplayHour() ) {
     779                // Depending on what format the user has choose we need different amount
     780                // of space. We therefore create a typical string for the choosen format
     781                // and determine the length of that string.
     782                switch( $this->scale->hour->iStyle ) {
     783                    case HOURSTYLE_HMAMPM:
     784                        $txt = '12:00pm';
     785                        break;
     786                    case HOURSTYLE_H24:
     787                        // 13
     788                        $txt = '24';
     789                        break;
     790                    case HOURSTYLE_HAMPM:
     791                        $txt = '12pm';
     792                        break;
     793                    case HOURSTYLE_CUSTOM:
     794                        $txt = date($this->scale->hour->iLabelFormStr,strtotime('2003-12-20 18:00'));
     795                        break;
     796                    case HOURSTYLE_HM24:
     797                    default:
     798                        $txt = '24:00';
     799                        break;
     800                }
     801
     802                $hfw = $this->scale->hour->GetStrWidth($this->img,$txt)+6;
     803                $mw = $hfw;
     804                if( $this->scale->IsDisplayMinute() ) {
     805                    // Depending on what format the user has choose we need different amount
     806                    // of space. We therefore create a typical string for the choosen format
     807                    // and determine the length of that string.
     808                    switch( $this->scale->minute->iStyle ) {
     809                        case HOURSTYLE_CUSTOM:
     810                            $txt2 = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55'));
     811                            break;
     812                        case MINUTESTYLE_MM:
     813                        default:
     814                            $txt2 = '15';
     815                            break;
     816                    }
     817
     818                    $mfw = $this->scale->minute->GetStrWidth($this->img,$txt2)+6;
     819                    $n2 = ceil(60 / $this->scale->minute->GetIntervall() );
     820                    $mw = $n2 * $mfw;
     821                }
     822                $hfw = $hfw < $mw ? $mw : $hfw ;
     823                $n = ceil(24*60 / $this->scale->TimeToMinutes($this->scale->hour->GetIntervall()) );
     824                $hw = $n * $hfw;
     825                $fw = $fw < $hw ? $hw : $fw ;
     826            }
     827
     828            // We need to repeat this code block here as well.
     829            // THIS iS NOT A MISTAKE !
     830            // We really need it since we need to adjust for minutes both in the case
     831            // where hour scale is shown and when it is not shown.
     832
     833            if( $this->scale->IsDisplayMinute() ) {
     834                // Depending on what format the user has choose we need different amount
     835                // of space. We therefore create a typical string for the choosen format
     836                // and determine the length of that string.
     837                switch( $this->scale->minute->iStyle ) {
     838                    case HOURSTYLE_CUSTOM:
     839                        $txt = date($this->scale->minute->iLabelFormStr,strtotime('2005-05-15 18:55'));
     840                        break;
     841                    case MINUTESTYLE_MM:
     842                    default:
     843                        $txt = '15';
     844                        break;
     845                }
     846
     847                $mfw = $this->scale->minute->GetStrWidth($this->img,$txt)+6;
     848                $n = ceil(60 / $this->scale->TimeToMinutes($this->scale->minute->GetIntervall()) );
     849                $mw = $n * $mfw;
     850                $fw = $fw < $mw ? $mw : $fw ;
     851            }
     852
     853            // If we display week we must make sure that 7*$fw is enough
     854            // to fit up to 10 characters of the week font (if the week is enabled)
     855            if( $this->scale->IsDisplayWeek() ) {
     856                // Depending on what format the user has choose we need different amount
     857                // of space
     858                $fsw = strlen($this->scale->week->iLabelFormStr);
     859                if( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
     860                    $fsw += 8;
     861                }
     862                elseif( $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ) {
     863                    $fsw += 7;
     864                }
     865                else {
     866                    $fsw += 4;
     867                }
     868
     869                $ww = $fsw*$this->scale->week->GetFontWidth($this->img);
     870                if( 7*$fw < $ww ) {
     871                    $fw = ceil($ww/7);
     872                }
     873            }
     874
     875            if( !$this->scale->IsDisplayDay() && !$this->scale->IsDisplayHour() &&
     876                !( ($this->scale->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||
     877                        $this->scale->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR) && $this->scale->IsDisplayWeek() ) ) {
     878                // If we don't display the individual days we can shrink the
     879                // scale a little bit. This is a little bit pragmatic at the
     880                // moment and should be re-written to take into account
     881                // a) What scales exactly are shown and
     882                // b) what format do they use so we know how wide we need to
     883                // make each scale text space at minimum.
     884                $fw /= 2;
     885                if( !$this->scale->IsDisplayWeek() ) {
     886                    $fw /= 1.8;
     887                }
     888            }
     889
     890            $cw = $this->GetMaxActInfoColWidth() ;
     891            $this->scale->actinfo->SetMinColWidth($cw);
     892            if( $this->img->width <= 0 ) {
     893                // Now determine the width for the activity titles column
     894
     895                // Firdst find out the maximum width of each object column
     896                $titlewidth = max(max($this->GetMaxLabelWidth(),
     897                $this->scale->tableTitle->GetWidth($this->img)),
     898                $this->scale->actinfo->GetWidth($this->img));
     899
     900                // Add the width of the vertivcal divider line
     901                $titlewidth += $this->scale->divider->iWeight*2;
     902
     903                                // Adjust the width by the user specified zoom factor
     904                                $fw *= $this->iZoomFactor;
     905
     906                // Now get the total width taking
     907                // titlewidth, left and rigt margin, dayfont size
     908                // into account
     909                $width = $titlewidth + $nd*$fw + $lm+$rm;
     910            }
     911            else {
     912                $width = $this->img->width;
     913            }
     914
     915            $width = round($width);
     916            $height = round($height);
     917            // Make a sanity check on image size
     918            if( $width > MAX_GANTTIMG_SIZE_W || $height > MAX_GANTTIMG_SIZE_H ) {
     919                JpgraphError::RaiseL(6007,$width,$height);
     920                //("Sanity check for automatic Gantt chart size failed. Either the width (=$width) or height (=$height) is larger than MAX_GANTTIMG_SIZE. This could potentially be caused by a wrong date in one of the activities.");
     921            }
     922            $this->img->CreateImgCanvas($width,$height);
     923            $this->img->SetMargin($lm,$rm,$tm,$bm);
     924        }
    879925    }
    880926
     
    884930    // must walk through all the objects, sigh...
    885931    function GetMaxActInfoColWidth() {
    886         $n = count($this->iObj);
    887         if( $n == 0 ) return;
    888         $w = array();
    889         $m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin;
    890        
    891         for( $i=0; $i < $n; ++$i ) {
    892             $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m);
    893             $nn = count($tmp);
    894             for( $j=0; $j < $nn; ++$j ) {
    895                 if( empty($w[$j]) )
    896                     $w[$j] = $tmp[$j];
    897                 else
    898                     $w[$j] = max($w[$j],$tmp[$j]);
    899             }
    900         }
    901         return $w;
     932        $n = count($this->iObj);
     933        if( $n == 0 ) return;
     934        $w = array();
     935        $m = $this->scale->actinfo->iLeftColMargin + $this->scale->actinfo->iRightColMargin;
     936
     937        for( $i=0; $i < $n; ++$i ) {
     938            $tmp = $this->iObj[$i]->title->GetColWidth($this->img,$m);
     939            $nn = count($tmp);
     940            for( $j=0; $j < $nn; ++$j ) {
     941                if( empty($w[$j]) )
     942                $w[$j] = $tmp[$j];
     943                else
     944                $w[$j] = max($w[$j],$tmp[$j]);
     945            }
     946        }
     947        return $w;
    902948    }
    903949
    904950    // Stroke the gantt chart
    905     function Stroke($aStrokeFileName="") {     
    906 
    907         // If the filename is the predefined value = '_csim_special_'
    908         // we assume that the call to stroke only needs to do enough
    909         // to correctly generate the CSIM maps.
    910         // We use this variable to skip things we don't strictly need
    911         // to do to generate the image map to improve performance
    912         // a best we can. Therefor you will see a lot of tests !$_csim in the
    913         // code below.
    914         $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
    915 
    916         // Should we autoscale dates?
    917 
    918         if( !$this->scale->IsRangeSet() ) {
    919             list($min,$max) = $this->GetBarMinMax();
    920             $this->scale->SetRange($min,$max);
    921         }
    922 
    923         $this->scale->AdjustStartEndDay();
    924 
    925         // Check if we should autoscale the image
    926         $this->AutoSize();
    927 
    928         // Should we start from the top or just spread the bars out even over the
    929         // available height
    930         $this->scale->SetVertLayout($this->iLayout);                   
    931         if( $this->iLayout == GANTT_FROMTOP ) {
    932             $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight());
    933             $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor));
    934         }
    935         // If it hasn't been set find out the maximum line number
    936         if( $this->scale->iVertLines == -1 )
    937             $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1; 
    938                
    939         $maxwidth=max($this->scale->actinfo->GetWidth($this->img),
    940                       max($this->GetMaxLabelWidth(),
    941                       $this->scale->tableTitle->GetWidth($this->img)));
    942 
    943         $this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor));
    944 
    945         if( !$_csim ) {
    946             $this->StrokePlotArea();
    947             if( $this->iIconDepth == DEPTH_BACK ) {
    948                 $this->StrokeIcons();
    949             }
    950         }
    951 
    952         $this->scale->Stroke();
    953 
    954         if( !$_csim ) {
    955             // Due to a minor off by 1 bug we need to temporarily adjust the margin
    956             $this->img->right_margin--;
    957             $this->StrokePlotBox();
    958             $this->img->right_margin++;
    959         }
    960 
    961         // Stroke Grid line
    962         $this->hgrid->Stroke($this->img,$this->scale);
    963 
    964         $n = count($this->iObj);
    965         for($i=0; $i < $n; ++$i) {
    966             //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2));
    967             $this->iObj[$i]->Stroke($this->img,$this->scale);
    968         }
    969 
    970         $this->StrokeTitles();
    971 
    972         if( !$_csim ) {
    973             $this->StrokeConstrains();
    974             $this->footer->Stroke($this->img);
    975 
    976 
    977             if( $this->iIconDepth == DEPTH_FRONT) {
    978                 $this->StrokeIcons();
    979             }
    980 
    981             // Should we do any final image transformation
    982             if( $this->iImgTrans ) {
    983                 if( !class_exists('ImgTrans',false) ) {
    984                     require_once('jpgraph_imgtrans.php');
    985                 }
    986            
    987                 $tform = new ImgTrans($this->img->img);
    988                 $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
    989                                                  $this->iImgTransDirection,$this->iImgTransHighQ,
    990                                                  $this->iImgTransMinSize,$this->iImgTransFillColor,
    991                                                  $this->iImgTransBorder);
    992             }
    993            
    994            
    995             // If the filename is given as the special "__handle"
    996             // then the image handler is returned and the image is NOT
    997             // streamed back
    998             if( $aStrokeFileName == _IMG_HANDLER ) {
    999                 return $this->img->img;
    1000             }
    1001             else {
    1002                 // Finally stream the generated picture                                 
    1003                 $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,
    1004                                            $aStrokeFileName);           
    1005             }
    1006         }
     951    function Stroke($aStrokeFileName="") {
     952
     953        // If the filename is the predefined value = '_csim_special_'
     954        // we assume that the call to stroke only needs to do enough
     955        // to correctly generate the CSIM maps.
     956        // We use this variable to skip things we don't strictly need
     957        // to do to generate the image map to improve performance
     958        // a best we can. Therefor you will see a lot of tests !$_csim in the
     959        // code below.
     960        $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
     961
     962        // Should we autoscale dates?
     963
     964        if( !$this->scale->IsRangeSet() ) {
     965            list($min,$max) = $this->GetBarMinMax();
     966            $this->scale->SetRange($min,$max);
     967        }
     968
     969        $this->scale->AdjustStartEndDay();
     970
     971        // Check if we should autoscale the image
     972        $this->AutoSize();
     973
     974        // Should we start from the top or just spread the bars out even over the
     975        // available height
     976        $this->scale->SetVertLayout($this->iLayout);
     977        if( $this->iLayout == GANTT_FROMTOP ) {
     978            $maxheight=max($this->GetMaxLabelHeight(),$this->GetMaxBarAbsHeight());
     979            $this->scale->SetVertSpacing($maxheight*(1+$this->iLabelVMarginFactor));
     980        }
     981        // If it hasn't been set find out the maximum line number
     982        if( $this->scale->iVertLines == -1 )
     983                $this->scale->iVertLines = $this->GetBarMaxLineNumber()+1;
     984
     985        $maxwidth=max($this->scale->actinfo->GetWidth($this->img),
     986        max($this->GetMaxLabelWidth(),
     987        $this->scale->tableTitle->GetWidth($this->img)));
     988
     989        $this->scale->SetLabelWidth($maxwidth+$this->scale->divider->iWeight);//*(1+$this->iLabelHMarginFactor));
     990
     991        if( !$_csim ) {
     992            $this->StrokePlotArea();
     993            if( $this->iIconDepth == DEPTH_BACK ) {
     994                $this->StrokeIcons();
     995            }
     996        }
     997
     998        $this->scale->Stroke();
     999
     1000        if( !$_csim ) {
     1001            // Due to a minor off by 1 bug we need to temporarily adjust the margin
     1002            $this->img->right_margin--;
     1003            $this->StrokePlotBox();
     1004            $this->img->right_margin++;
     1005        }
     1006
     1007        // Stroke Grid line
     1008        $this->hgrid->Stroke($this->img,$this->scale);
     1009
     1010        $n = count($this->iObj);
     1011        for($i=0; $i < $n; ++$i) {
     1012            //$this->iObj[$i]->SetLabelLeftMargin(round($maxwidth*$this->iLabelHMarginFactor/2));
     1013            $this->iObj[$i]->Stroke($this->img,$this->scale);
     1014        }
     1015
     1016        $this->StrokeTitles();
     1017
     1018        if( !$_csim ) {
     1019            $this->StrokeConstrains();
     1020            $this->footer->Stroke($this->img);
     1021
     1022
     1023            if( $this->iIconDepth == DEPTH_FRONT) {
     1024                $this->StrokeIcons();
     1025            }
     1026
     1027            // Stroke all added user texts
     1028            $this->StrokeTexts();
     1029
     1030            // Should we do any final image transformation
     1031            if( $this->iImgTrans ) {
     1032                if( !class_exists('ImgTrans',false) ) {
     1033                    require_once('jpgraph_imgtrans.php');
     1034                }
     1035
     1036                $tform = new ImgTrans($this->img->img);
     1037                $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
     1038                $this->iImgTransDirection,$this->iImgTransHighQ,
     1039                $this->iImgTransMinSize,$this->iImgTransFillColor,
     1040                $this->iImgTransBorder);
     1041            }
     1042
     1043
     1044            // If the filename is given as the special "__handle"
     1045            // then the image handler is returned and the image is NOT
     1046            // streamed back
     1047            if( $aStrokeFileName == _IMG_HANDLER ) {
     1048                return $this->img->img;
     1049            }
     1050            else {
     1051                // Finally stream the generated picture
     1052                $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,
     1053                $aStrokeFileName);
     1054            }
     1055        }
    10071056    }
    10081057
    10091058    function StrokeConstrains() {
    1010         $n = count($this->iObj);
    1011 
    1012         // Stroke all constrains
    1013         for($i=0; $i < $n; ++$i) {
    1014 
    1015             // Some gantt objects may not have constraints associated with them
    1016             // for example we can add IconPlots which doesn't have this property.
    1017             if( empty($this->iObj[$i]->constraints) ) continue;
    1018 
    1019             $numConstrains = count($this->iObj[$i]->constraints);
    1020 
    1021             for( $k = 0; $k < $numConstrains; $k++ ) {
    1022                 $vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow;
    1023                 if( $vpos >= 0 ) {
    1024                     $c1 = $this->iObj[$i]->iConstrainPos;
    1025 
    1026                     // Find out which object is on the target row
    1027                     $targetobj = -1;
    1028                     for( $j=0; $j < $n && $targetobj == -1; ++$j ) {
    1029                         if( $this->iObj[$j]->iVPos == $vpos ) {
    1030                             $targetobj = $j;
    1031                         }
    1032                     }
    1033                     if( $targetobj == -1 ) {
    1034                         JpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos);
    1035 //('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.');
    1036                     }
    1037                     $c2 = $this->iObj[$targetobj]->iConstrainPos;
    1038                     if( count($c1) == 4 && count($c2 ) == 4) {
    1039                         switch( $this->iObj[$i]->constraints[$k]->iConstrainType ) {
    1040                             case CONSTRAIN_ENDSTART:
    1041                                 if( $c1[1] < $c2[1] ) {
    1042                                     $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]);
    1043                                 }
    1044                                 else {
    1045                                     $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]);
    1046                                 }
    1047                                 $link->SetPath(3);
    1048                                 break;
    1049                             case CONSTRAIN_STARTEND:
    1050                                 if( $c1[1] < $c2[1] ) {
    1051                                     $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]);
    1052                                 }
    1053                                 else {
    1054                                     $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]);
    1055                                 }
    1056                                 $link->SetPath(0);
    1057                                 break;
    1058                             case CONSTRAIN_ENDEND:
    1059                                 if( $c1[1] < $c2[1] ) {
    1060                                     $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]);
    1061                                 }
    1062                                 else {
    1063                                     $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]);
    1064                                 }
    1065                                 $link->SetPath(1);
    1066                                 break;
    1067                             case CONSTRAIN_STARTSTART:
    1068                                 if( $c1[1] < $c2[1] ) {
    1069                                     $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]);
    1070                                 }
    1071                                 else {
    1072                                     $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]);
    1073                                 }
    1074                                 $link->SetPath(3);
    1075                                 break;
    1076                             default:
    1077                                 JpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos);
    1078 //('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos);
    1079                                 break;
    1080                         }
    1081 
    1082                         $link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor);
    1083                         $link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize,
    1084                                         $this->iObj[$i]->constraints[$k]->iConstrainArrowType);
    1085  
    1086                         $link->Stroke($this->img);
    1087                     }
    1088                 }
    1089             }
    1090         }
     1059        $n = count($this->iObj);
     1060
     1061        // Stroke all constrains
     1062        for($i=0; $i < $n; ++$i) {
     1063
     1064            // Some gantt objects may not have constraints associated with them
     1065            // for example we can add IconPlots which doesn't have this property.
     1066            if( empty($this->iObj[$i]->constraints) ) continue;
     1067
     1068            $numConstrains = count($this->iObj[$i]->constraints);
     1069
     1070            for( $k = 0; $k < $numConstrains; $k++ ) {
     1071                $vpos = $this->iObj[$i]->constraints[$k]->iConstrainRow;
     1072                if( $vpos >= 0 ) {
     1073                    $c1 = $this->iObj[$i]->iConstrainPos;
     1074
     1075                    // Find out which object is on the target row
     1076                    $targetobj = -1;
     1077                    for( $j=0; $j < $n && $targetobj == -1; ++$j ) {
     1078                        if( $this->iObj[$j]->iVPos == $vpos ) {
     1079                            $targetobj = $j;
     1080                        }
     1081                    }
     1082                    if( $targetobj == -1 ) {
     1083                        JpGraphError::RaiseL(6008,$this->iObj[$i]->iVPos,$vpos);
     1084                        //('You have specifed a constrain from row='.$this->iObj[$i]->iVPos.' to row='.$vpos.' which does not have any activity.');
     1085                    }
     1086                    $c2 = $this->iObj[$targetobj]->iConstrainPos;
     1087                    if( count($c1) == 4 && count($c2 ) == 4) {
     1088                        switch( $this->iObj[$i]->constraints[$k]->iConstrainType ) {
     1089                            case CONSTRAIN_ENDSTART:
     1090                                if( $c1[1] < $c2[1] ) {
     1091                                    $link = new GanttLink($c1[2],$c1[3],$c2[0],$c2[1]);
     1092                                }
     1093                                else {
     1094                                    $link = new GanttLink($c1[2],$c1[1],$c2[0],$c2[3]);
     1095                                }
     1096                                $link->SetPath(3);
     1097                                break;
     1098                            case CONSTRAIN_STARTEND:
     1099                                if( $c1[1] < $c2[1] ) {
     1100                                    $link = new GanttLink($c1[0],$c1[3],$c2[2],$c2[1]);
     1101                                }
     1102                                else {
     1103                                    $link = new GanttLink($c1[0],$c1[1],$c2[2],$c2[3]);
     1104                                }
     1105                                $link->SetPath(0);
     1106                                break;
     1107                            case CONSTRAIN_ENDEND:
     1108                                if( $c1[1] < $c2[1] ) {
     1109                                    $link = new GanttLink($c1[2],$c1[3],$c2[2],$c2[1]);
     1110                                }
     1111                                else {
     1112                                    $link = new GanttLink($c1[2],$c1[1],$c2[2],$c2[3]);
     1113                                }
     1114                                $link->SetPath(1);
     1115                                break;
     1116                            case CONSTRAIN_STARTSTART:
     1117                                if( $c1[1] < $c2[1] ) {
     1118                                    $link = new GanttLink($c1[0],$c1[3],$c2[0],$c2[1]);
     1119                                }
     1120                                else {
     1121                                    $link = new GanttLink($c1[0],$c1[1],$c2[0],$c2[3]);
     1122                                }
     1123                                $link->SetPath(3);
     1124                                break;
     1125                            default:
     1126                                JpGraphError::RaiseL(6009,$this->iObj[$i]->iVPos,$vpos);
     1127                                //('Unknown constrain type specified from row='.$this->iObj[$i]->iVPos.' to row='.$vpos);
     1128                                break;
     1129                        }
     1130
     1131                        $link->SetColor($this->iObj[$i]->constraints[$k]->iConstrainColor);
     1132                        $link->SetArrow($this->iObj[$i]->constraints[$k]->iConstrainArrowSize,
     1133                        $this->iObj[$i]->constraints[$k]->iConstrainArrowType);
     1134
     1135                        $link->Stroke($this->img);
     1136                    }
     1137                }
     1138            }
     1139        }
    10911140    }
    10921141
    10931142    function GetCSIMAreas() {
    1094         if( !$this->iHasStroked )
    1095             $this->Stroke(_CSIM_SPECIALFILE);
    1096  
    1097         $csim = $this->title->GetCSIMAreas();
    1098         $csim .= $this->subtitle->GetCSIMAreas();
    1099         $csim .= $this->subsubtitle->GetCSIMAreas();
    1100 
    1101         $n = count($this->iObj);
    1102         for( $i=$n-1; $i >= 0; --$i )
    1103             $csim .= $this->iObj[$i]->GetCSIMArea();
    1104         return $csim;
     1143        if( !$this->iHasStroked )
     1144        $this->Stroke(_CSIM_SPECIALFILE);
     1145
     1146        $csim = $this->title->GetCSIMAreas();
     1147        $csim .= $this->subtitle->GetCSIMAreas();
     1148        $csim .= $this->subsubtitle->GetCSIMAreas();
     1149
     1150        $n = count($this->iObj);
     1151        for( $i=$n-1; $i >= 0; --$i )
     1152        $csim .= $this->iObj[$i]->GetCSIMArea();
     1153        return $csim;
    11051154    }
    11061155}
     
    11281177
    11291178    function GetLen() {
    1130         return $this->iLen ;
     1179        return $this->iLen ;
    11311180    }
    11321181
    11331182    function GetImg($aIdx) {
    1134         if( $aIdx < 0 || $aIdx >= $this->iLen ) {
    1135             JpGraphError::RaiseL(6010,$aIdx);
    1136 //('Illegal icon index for Gantt builtin icon ['.$aIdx.']');
    1137         }
    1138         return Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1]));   
    1139     }
    1140 
    1141     function PredefIcons() {
    1142         //==========================================================
    1143         // warning.png
    1144         //==========================================================
    1145         $this->iBuiltinIcon[0][0]= 1043 ;
    1146         $this->iBuiltinIcon[0][1]=
    1147             'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'.
    1148             'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'.
    1149             '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'.
    1150             '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'.
    1151             'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'.
    1152             'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'.
    1153             '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'.
    1154             'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'.
    1155             'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'.
    1156             'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'.
    1157             'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'.
    1158             'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'.
    1159             'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'.
    1160             'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ;
    1161 
    1162         //==========================================================
    1163         // edit.png
    1164         //==========================================================
    1165         $this->iBuiltinIcon[1][0]= 959 ;
    1166         $this->iBuiltinIcon[1][1]=
    1167             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'.
    1168             'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'.
    1169             'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'.
    1170             'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'.
    1171             'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'.
    1172             'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'.
    1173             'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'.
    1174             'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'.
    1175             'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'.
    1176             'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'.
    1177             'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'.
    1178             'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'.
    1179             'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ;
    1180 
    1181         //==========================================================
    1182         // endconstrain.png
    1183         //==========================================================
    1184         $this->iBuiltinIcon[2][0]= 666 ;
    1185         $this->iBuiltinIcon[2][1]=
    1186             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
    1187             'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'.
    1188             'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'.
    1189             'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'.
    1190             'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'.
    1191             '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'.
    1192             '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'.
    1193             'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'.
    1194             'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ;
    1195 
    1196         //==========================================================
    1197         // mail.png
    1198         //==========================================================
    1199         $this->iBuiltinIcon[3][0]= 1122 ;
    1200         $this->iBuiltinIcon[3][1]=
    1201             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
    1202             'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'.
    1203             'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'.
    1204             'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'.
    1205             'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'.
    1206             '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'.
    1207             '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'.
    1208             'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'.
    1209             'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'.
    1210             '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'.
    1211             'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'.
    1212             'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'.
    1213             'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'.
    1214             'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'.
    1215             'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ;
    1216 
    1217         //==========================================================
    1218         // startconstrain.png
    1219         //==========================================================
    1220         $this->iBuiltinIcon[4][0]= 725 ;
    1221         $this->iBuiltinIcon[4][1]=
    1222             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
    1223             'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'.
    1224             'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'.
    1225             'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'.
    1226             'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'.
    1227             '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'.
    1228             'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'.
    1229             'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'.
    1230             '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'.
    1231             'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ;
    1232 
    1233         //==========================================================
    1234         // calc.png
    1235         //==========================================================
    1236         $this->iBuiltinIcon[5][0]= 589 ;
    1237         $this->iBuiltinIcon[5][1]=
    1238             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'.
    1239             'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'.
    1240             'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'.
    1241             '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'.
    1242             'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'.
    1243             'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'.
    1244             'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'.
    1245             'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ;
    1246 
    1247         //==========================================================
    1248         // mag.png
    1249         //==========================================================
    1250         $this->iBuiltinIcon[6][0]= 1415 ;
    1251         $this->iBuiltinIcon[6][1]=
    1252             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
    1253             'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'.
    1254             '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'.
    1255             'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'.
    1256             'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'.
    1257             'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'.
    1258             '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'.
    1259             'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'.
    1260             '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'.
    1261             'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'.
    1262             'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'.
    1263             'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'.
    1264             'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'.
    1265             'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'.
    1266             'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'.
    1267             'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'.
    1268             'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'.
    1269             'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'.
    1270             'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ;
    1271 
    1272         //==========================================================
    1273         // lock.png
    1274         //==========================================================
    1275         $this->iBuiltinIcon[7][0]= 963 ;
    1276         $this->iBuiltinIcon[7][1]=
    1277             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
    1278             'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'.
    1279             'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'.
    1280             'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'.
    1281             'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'.
    1282             'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'.
    1283             'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'.
    1284             'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'.
    1285             'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'.
    1286             'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'.
    1287             'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'.
    1288             '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'.
    1289             'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ;
    1290 
    1291         //==========================================================
    1292         // stop.png
    1293         //==========================================================
    1294         $this->iBuiltinIcon[8][0]= 889 ;
    1295         $this->iBuiltinIcon[8][1]=
    1296             'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
    1297             'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'.
    1298             'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'.
    1299             'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'.
    1300             'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'.
    1301             'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'.
    1302             'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'.
    1303             'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'.
    1304             'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'.
    1305             'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'.
    1306             'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'.
    1307             'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ;
    1308 
    1309         //==========================================================
    1310         // error.png
    1311         //==========================================================
    1312         $this->iBuiltinIcon[9][0]= 541 ;
    1313         $this->iBuiltinIcon[9][1]=
    1314             'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'.
    1315             'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'.
    1316             'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'.
    1317             '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'.
    1318             'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'.
    1319             'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'.
    1320             'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'.
    1321             'iOsCHgAAAABJRU5ErkJggg==' ;
    1322 
    1323         //==========================================================
    1324         // openfolder.png
    1325         //==========================================================
    1326         $this->iBuiltinIcon[10][0]= 2040 ;
    1327         $this->iBuiltinIcon[10][1]=
    1328             'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'.
    1329             'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'.
    1330             'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'.
    1331             'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'.
    1332             'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'.
    1333             'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'.
    1334             '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'.
    1335             'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'.
    1336             '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'.
    1337             'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'.
    1338             'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'.
    1339             'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'.
    1340             'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'.
    1341             'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'.
    1342             'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'.
    1343             'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'.
    1344             'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'.
    1345             'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'.
    1346             'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'.
    1347             'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'.
    1348             'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'.
    1349             'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'.
    1350             'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'.
    1351             'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'.
    1352             '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'.
    1353             '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'.
    1354             'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'.
    1355             'dBntAAAAAElFTkSuQmCC' ;
    1356 
    1357         //==========================================================
    1358         // folder.png
    1359         //==========================================================
     1183        if( $aIdx < 0 || $aIdx >= $this->iLen ) {
     1184            JpGraphError::RaiseL(6010,$aIdx);
     1185            //('Illegal icon index for Gantt builtin icon ['.$aIdx.']');
     1186        }
     1187        return Image::CreateFromString(base64_decode($this->iBuiltinIcon[$aIdx][1]));
     1188    }
     1189
     1190    function __construct() {
     1191        //==========================================================
     1192        // warning.png
     1193        //==========================================================
     1194        $this->iBuiltinIcon[0][0]= 1043 ;
     1195        $this->iBuiltinIcon[0][1]=
     1196     'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAA'.
     1197     'B3RJTUUH0wgKFSgilWPhUQAAA6BJREFUeNrtl91rHFUYh5/3zMx+Z5JNUoOamCZNaqTZ6IWIkqRiQWmi1IDetHfeiCiltgXBP8AL'.
     1198     '0SIUxf/AvfRSBS9EKILFFqyIH9CEmFZtPqrBJLs7c+b1YneT3WTTbNsUFPLCcAbmzPt73o9zzgzs2Z793231UOdv3w9k9Z2uzOdA'.
     1199     '5+2+79yNeL7Hl7hw7oeixRMZ6PJM26W18DNAm/Vh7lR8fqh97NmMF11es1iFpMATqdirwMNA/J4DpIzkr5YsAF1PO6gIMYHRdPwl'.
     1200     'oO2elmB+qH3sm7XozbkgYvy8SzYnZPtcblyM6I+5z3jQ+0vJfgpEu56BfI9vUkbyi2HZd1QJoeWRiAjBd4SDCW8SSAOy6wBHMzF7'.
     1201     'YdV2A+ROuvRPLfHoiSU0EMY/cDAIhxJeGngKaN1VgHyPL7NBxI1K9P4QxBzw3K1zJ/zkG8B9uwaQ7/HNsRZv9kohBGD0o7JqMYS/'.
     1202     '/ynPidQw/LrBiPBcS/yFCT95DvB2BWAy4575PaQbQKW+tPd3GCItu2odKI++YxiKu0d26oWmAD7paZU/rLz37VqIijD2YbnzNBBE'.
     1203     'IBHf8K8qjL7vYhCGErEU8CTg3xXAeMp96GrJEqkyXkm9Bhui1xfsunjdGhcYLq+IzjsGmBt5YH/cmJkFq6gIqlon3u4LxdKGuCIo'.
     1204     'Qu41g0E41po+2R33Xt5uz9kRIB2UTle7PnfKrROP1HD4sRjZlq0lzhwoZ6rDNeTi3nEg1si/7FT7kYQbXS6E5E65tA5uRF9tutq0'.
     1205     'K/VwAF+/FbIYWt6+tjQM/AqUms7A4Wy6d7YSfSNxgMmzi0ycWWworio4QJvj4LpuL5BqugTnXzzqJsJwurrlNhJXFaavW67NRw3F'.
     1206     'q+aJcCQVe9fzvJGmAY7/dPH0gi0f64OveGxa+usCuQMeZ0+kt8BVrX+qPO9Bzx0MgqBvs+a2PfDdYIf+WAjXU1ub4tqNaPPzRs8A'.
     1207     'blrli+WVn79cXn0cWKl+tGx7HLc7pu3CSmnfitL+l1UihAhwjFkPQev4K/fSABjBM8JCaFuurJU+rgW41SroA8aNMVNAFtgHJCsn'.
     1208     'XGy/58QVxAC9MccJtZ5kIzNlW440WrJ2ea4YPA9cAooA7i0A/gS+iqLoOpB1HOegqrYB3UBmJrAtQAJwpwPr1Ry92wVlgZsiYlW1'.
     1209     'uX1gU36dymgqYxJIJJNJT1W9QqHgNwFQBGYqo94OwHZQUuPD7ACglSvc+5n5T9m/wfJJX4U9qzEAAAAASUVORK5CYII=' ;
     1210
     1211        //==========================================================
     1212        // edit.png
     1213        //==========================================================
     1214        $this->iBuiltinIcon[1][0]= 959 ;
     1215        $this->iBuiltinIcon[1][1]=
     1216     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAFgAWABY9j+ZuwAAAAlwSFlz'.
     1217     'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDAwbIEXOA6AAAAM8SURBVHicpdRPaBxlHMbx76ZvsmOTmm1dsEqQSIIsEmGVBAQjivEQ'.
     1218     'PAUJngpWsAWlBw8egpQepKwplN4ULEG9CjkEyUFKlSJrWTG0IU51pCsdYW2ncUPjdtp9Z+f3vuNhu8nKbmhaf5cZeGc+PO8zf1Lc'.
     1219     'm0KhkACICCKCMeaBjiLC0tLSnjNvPmuOHRpH0TZTU1M8zBi9wakzn7OFTs5sw8YYACYmJrre7HkeuVyu69qPF77hlT1XmZ0eQ03O'.
     1220     'wOLJTvhBx1rLz18VmJ0eY+jVd2FxDkKXnvYLHgb97OgLzE4ON9Hzc1B1QaQzsed5O0Lta3Ec89OnR5h5McfQ+Mw2qgQUnfBOPbZ3'.
     1221     'bK3l+xOvMT0+3ERLp5FNF6UEjcL32+DdVmGt5WLhDYYPZrbRqreFumXwql0S3w9tnDvLWD5PZigPpdOwuYpSCo3C8wU3UHxQdHbf'.
     1222     'cZIkNM6dxcnlUM4k1eUFMlUPpUADbpkttFarHe6oYqeOr6yt4RzMQHYUcUsQVtGicHDwKprViuLDkkOtVnsHCHZVRVy/zcj1i5Af'.
     1223     'h8AjdIts+hUcGcYPK3iBtKM3gD/uAzf/AdY2mmmVgy6X8YNNKmGIvyloPcB8SUin07RQ4EZHFdsdG0wkJEnEaHAJxvKEpSLeaokV'.
     1224     'r4zWmhUZYLlY4b1D03y5eIEWCtS7vsciAgiIxkQRabWOrlQor66y4pUphoJb1jiO4uO5o0S3q6RSqVbiOmC7VCEgAhLSaDQ48dH7'.
     1225     'vD46REY0iysegSjKQciRt99ib7qXwX0O+pG4teM6YKHLB9JMq4mTmF9/+AKA4wvLZByH7OgYL7+UY2qvw/7Bfg5kHiXjJFyv3CGO'.
     1226     'Y1rof+BW4t/XLiPG0DCGr79d4XzRxRnIMn98huXSTYyJ6et1UNYQhRvcinpJq86H3wGPPPM0iBDd+QffD1g4eZjLvuG7S1Wef26E'.
     1227     'J7L7eSx7gAHVg7V3MSbi6m/r93baBd6qQjerAJg/9Ql/XrvG0ON1+vv7GH3qSfY5fahUnSTpwZgIEQesaVXRPbHRG/xyJSAxMYlp'.
     1228     'EOm71HUINiY7mGb95l/8jZCyQmJjMDGJjUmsdCROtZ0n/P/Z8v4Fs2MTUUf7vYoAAAAASUVORK5CYII=' ;
     1229
     1230        //==========================================================
     1231        // endconstrain.png
     1232        //==========================================================
     1233        $this->iBuiltinIcon[2][0]= 666 ;
     1234        $this->iBuiltinIcon[2][1]=
     1235     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
     1236     'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ALEREILkh0+eQAAAIXSURBVHictZU9aFNRFMd/N81HX77aptJUWmp1LHRpIcWhg5sIDlUQ'.
     1237     'LAXB4t7RRUpwEhy7iQ46CCIoSHcl0CFaoVARU2MFMYktadLXJNok7x2HtCExvuYFmnO4w/3gx+Gc/z1HKRTdMEdXqHbB/sgc/sic'.
     1238     'nDoYAI8XwDa8o1RMLT+2hAsigtTvbIGVqhX46szUifBGswUeCPgAGB7QeLk0X4Ork+HOxo1VgSqGASjMqkn8W4r4vVtEgI/RRQEL'.
     1239     'vaoGD85cl5V3nySR/S1mxWxab7f35PnntNyMJeRr9kCMqiHTy09EoeToLwggx6ymiMOD/VwcD7Oa/MHkcIiQx026WGYto5P/U+ZZ'.
     1240     '7gD0QwDuT5z9N3LrVPi0Xs543eQPKkRzaS54eviJIp4tMFQFMllAWN2qcRZHBnixNM8NYD162xq8u7ePSQ+GX2Pjwxc2dB2cLtB8'.
     1241     '7GgamCb0anBYBeChMtl8855CarclxU1gvViiUK4w2OMkNDnGeJ8bt9fH90yOnOkCwLFTwhzykhvtYzOWoBBbY//R3dbaNTYhf2RO'.
     1242     'QpeuUMzv188MlwuHy0H13HnE48UzMcL0WAtUHX8OxZHoG1URiFw7rnLLCswuSPD1ulze/iWjT2PSf+dBXRFtVVGIvzqph0pQL7VE'.
     1243     'avXYaXXxPwsnt0imdttCocMmZBdK7YU9D8wuNOW0nXc6QWzPsSa5naZ1beb9BbGB6dxGtMnXAAAAAElFTkSuQmCC' ;
     1244
     1245        //==========================================================
     1246        // mail.png
     1247        //==========================================================
     1248        $this->iBuiltinIcon[3][0]= 1122 ;
     1249        $this->iBuiltinIcon[3][1]=
     1250     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
     1251     'AAALEAAACxABrSO9dQAAAAd0SU1FB9AJHAMfFvL9OU8AAAPfSURBVHictZRdaBRXFMd/987H7tbNx8aYtGCrEexDsOBDaKHFxirb'.
     1252     'h0qhsiY0ykppKq1osI99C4H2WSiFFMHWUhXBrjRi0uCmtSEUGgP1QWqhWjGkoW7M1kTX3WRn5p4+TJJNGolQ6IXDnDtz+N0z/3PP'.
     1253     'UWBIpdpYa23b9g09PZ2kUrOrvmUyGVKp1Ao/mUyi56YnVgWfO/P1CihAd/dJMpmaNROIRq8BkM1m0bH6TasC3j6QXgFdXI+DR6PR'.
     1254     'JX/Pno8B+KLnMKqlpUU8z8MYs2RBEDzWf9J+0RcRbMdxGBsbw/fmCXwPMUEYID4iAVp8wIRmDIHMo4yHSIBSASKC+CWE0C/PF9jU'.
     1255     '3B6Cp+4M07C5FUtKGNvGwQJctPgIsgD2wRhEIqAMGB+UQYkHJgYYZD7P1HwVlmWhHcfhyk83KeRGUW4t6CgoG5SNUS4KBWgQDUov'.
     1256     '7AGlwYASBVqH0Bk49dXpCviVV3dw/tI1Bvr7kMIIlh0NYUpjlF0BAYvcxSXmEVLKceHSCJm+PnbueBHbtkNwTXUNBzo6aGpq4sSZ'.
     1257     'GwT5H7BsF6Wdf1GWHQAoM0upeI9PT1yioS7B7tdaSdSuw7KsUGMAy7HYsmUztTW1nMwM0txssX1rlHjjS5jy/Uq2YkK/eJuLl6/z'.
     1258     'x+1xkslW6mrixGIODx8EFSlEBC0+tmXT0NhA2763iEUjnLv4C8XpUbSbAB1mKkGJ3J83Od77HW5EszvZSqK2iljMIeJaRGNuJePF'.
     1259     '6mspY7BJ1DXwQnCd2fxGRq5OUCz8xt72dyhMZcn++Cu3xu9SKhdp2b4ZHWnAtTSxmIWlhcIjlksR3lNBYzlxZsb7+f7ne+xtSzOd'.
     1260     'u83szH1OnThOPp/n+a0beeP1l4mvq+PU2Qyd+5PY1RuwlAqLYFaBfbTbyPSdfgaH77A//QF4f1O/vpr6RJyq+C5Kc/M8FbFxXItY'.
     1261     'xOHDrvfo/fxLDnbsJBp5BowBReVWYAzabeTh5ABDw7cWoNNL3YYYNtSv57lnn6Z+Qx01VeuIuBa2DV1HD3H63BAPZu4u1WGpeLHq'.
     1262     'Rh7+NcjA0O+0p4+CNwXigwnbWlQQdpuEpli+n+PIkcOc//YKuckJJFh2K2anrjFw+QZt6S6kPImIF/b+cqAJD1LihWAxC61twBTo'.
     1263     'fPcQF/oGsVW5ovHQlavs2/8+uYnRVSOUgHAmmAClBIOBwKC0gPjhIRgEIX2wg7NnwpZW3d3d4vs+vu8TBMGK51rvPM9b8hdteZxd'.
     1264     'LBbVR8feJDs0Rlv6GFKeXJ21rNRXESxMPR+CBUl0nN7PjtO+dye7Up/8v1I88bf/ixT/AO1/hZsqW+C6AAAAAElFTkSuQmCC' ;
     1265
     1266        //==========================================================
     1267        // startconstrain.png
     1268        //==========================================================
     1269        $this->iBuiltinIcon[4][0]= 725 ;
     1270        $this->iBuiltinIcon[4][1]=
     1271     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
     1272     'AAALDgAACw4BQL7hQQAAAAd0SU1FB9ALEREICJp5fBkAAAJSSURBVHic3dS9a1NRGMfx77kxtS+xqS9FG6p1ER3qVJpBQUUc3CRU'.
     1273     'BwURVLB1EAuKIP0THJQiiNRJBK3iJl18AyeltRZa0bbaJMbUNmlNSm5e7s25j0NqpSSmyag/OMM9POdzDuflwn8djz8gClVRrVEV'.
     1274     'ur4Bl1FTNSzLrSS6vbml0jUUwSXj8Qfk3PkLtLW2AeBIybmrgz3+gFzpucjlE4f4btuFTuWuCF5XDr3a3UPf6cM8GQvxzbsRAJdh'.
     1275     'ScfxSywml5j7mVypN0eGEJ0tebIre+zxB6Tv7jPReS2hREpOvpmUXU+H5eC913JnNCSRVE60pUVbWoZjprR39Yq70bdqj4pW7PEH'.
     1276     '5FpvL9e79jOTTHM7ssDL6CJZ08LbvAGnrpZg2mI2Z/MlZfN8IkxuSwu4V9+WIrj7zFlOHfXzKrLIi2SGh5ECKjnNVNxkQEc55vOw'.
     1277     'rb6O8JLFdHyJ+ayFElUeHvjwkfteL/V7fKTSkFvIQE4DoLI2Mz/muTkTApcBKIwaN8pwIUrKw+ajWwDknAO0d/r4zFaMuRS63sWm'.
     1278     'RoOdm+vRIriUYjKexrQV+t1o0YEVwfZSVJmD/dIABJuO0LG3lRFx0GOfiAELE9OgCrfU0XnIp5FwGLEy5WEAOxlR5uN+ARhP7GN3'.
     1279     '5w7Gv4bQI2+xpt4jjv2nWBmIlcExE2vDAHYioszBZXw6CPE4ADoWVHmd/tuwlZR9eXYyoszBfpiNQqaAOU5+TXRN+DeeenADPT9b'.
     1280     'EVgKVsutKPl0TGWGhwofoquaoKK4apsq/tH/e/kFwBMXLgAEKK4AAAAASUVORK5CYII=' ;
     1281
     1282        //==========================================================
     1283        // calc.png
     1284        //==========================================================
     1285        $this->iBuiltinIcon[5][0]= 589 ;
     1286        $this->iBuiltinIcon[5][1]=
     1287     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAA4AIwBbgMF12wAAAAlwSFlz'.
     1288     'AAALEQAACxEBf2RfkQAAAAd0SU1FB9AHBxQeFsqn0wQAAAHKSURBVHicnZWff+RAGIef3U/gcOEgUAgUCgcLhYXCwsHBQeGgUDgs'.
     1289     'FgMHB4VA/4Bg4XChWFgIFIqBwkJhsRAYeOGF+TQHmWSTTbKd9pU37/x45jvfTDITXEynAbdWKVQB0NazcVm0alcL4rJaRVzm+w/e'.
     1290     '3iwAkzbYRcnnYgI04GCvsxxSPabYaEdt2Ra6D0atcvvvDmyrMWBX1zPq2ircP/Tk98DiJtjV/fim6ziOCL6dDHZNhxQ3arIMsox4'.
     1291     'vejleL2Ay9+jaw6A+4OSICG2cacGKhsGxg+CxeqAQS0Y7BYJvowq7iGMOhXHEfzpvpQkA9bLKgOgWKt+4Lo1mM9hs9m17QNsJ70P'.
     1292     'Fjc/O52joogoX8MZKiBiAFxd9Z1vcj9wfSpUlDRNMcYQxzFpmnJ0FPH8nDe1MQaWSz9woQpWSZKEojDkeaWoKAyr1tlu+s48wfVx'.
     1293     'u7n5i7jthmGIiEGcT+36PP+gFeJrxWLhb0UA/lb4ggGs1T0rZs0zwM/ZjNfilcIY5tutPxgOW3F6dUX464LrKILLiw+A7WErrl+2'.
     1294     'rABG1EL/BilZP8DjU2uR4U+2E49P1Z8QJmNXUzl24A9GBT0IruCfi86d9x+D12RGzt+pNAAAAABJRU5ErkJggg==' ;
     1295
     1296        //==========================================================
     1297        // mag.png
     1298        //==========================================================
     1299        $this->iBuiltinIcon[6][0]= 1415 ;
     1300        $this->iBuiltinIcon[6][1]=
     1301     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlz'.
     1302     'AAALDAAACwwBP0AiyAAAAAd0SU1FB9ALDxEWDY6Ul+UAAAUESURBVHicdZVrbFRFGIafsyyF0nalV1R6WiggaAptlzsr1OgEogmC'.
     1303     '0IgoBAsBgkIrBAPEhBj/AP6xRTCUFEwRI4jcgsitXMrFCJptJWvBNpXYbbXtbtttt6e7e86ec/yxadlCfZPJZDIz73zzzjfvR2VL'.
     1304     'F7U+hf0HD2JduIzTFy6SlJRkPtkcDgdCCE65OxFC8NPV6wghyM7OptankJ2dzbSC5QghEEIgCSHog9PpNAF27dlN6miZuPgElB4/'.
     1305     'nmY3O7ZtByA1NVUCkGWZweD1eklJScESTbqxuIjrd+/x6uIl5M19hSy7nfGOeUxf+g7VjU1sKi7C4/GYsiyz7tAJAD4/cRaA1tZW'.
     1306     'AHIPnECUVGD1+/3U19ebG4uLeHf1akamjsIwoVnVCOvQEdLoVILYYmMo3PIxSBJflpSaDX5FAmju1QAYv/8k/s8+wLVxOU0jR2LZ'.
     1307     '8sMFAApWrCApbRRDrRZirBYSLBKaoRPQw3SFernf2sav7T0Ubt4KwL4FMwF4Vu8FoHBCKgCzDhwHwLIhZ7y5a89u4m2JhA0wTdDC'.
     1308     'OrphEjJMNElCHxKDEjaobmvlfo/Krj27CQQCJsCGJW8C0KXqAMxMiosQA8hZWcTFx9OsaniDKh1qmG7VoFsL0x0K06kbeAMhWpRe'.
     1309     '/KpG+gwHAKUnz7Dz3BUMw6DK18nuw99wt0Nh6VdHI8RJicmETQgFg7SFwjSrGv+oKp6ghldV6dZ0ugJBlF6FmCESQ2w2AIqXLsan'.
     1310     'BrFYLJTnTCBrdBqveeopWZiPFaBHUegJhegMqGgxEkHDwB/UaQ9rdIV06v0+TD2EEQjQFtAY0dsNgNvt5sialQAIIXh7wQKuVf6J'.
     1311     'gTsSccPDWlQstClBGjr9eHpVWvUQncEwdYEedF8noQ4vmYmpZMTH0nTvDn25vLbrNmu7bvfnsYEbAMnhcPDgwQPzUo2LJusw/mhp'.
     1312     'QwlHNO0KBAnoIfxtrcQMT2De1Mm891wyUzNlUlJSpIyMDBobGzlzr5rFM/Koq6vrP8ASGxsLwPmKcvIShjPGZiPOakE3VFB8hHwd'.
     1313     'vJAxhrk5L7Ly+RQuH/sWgPdXrwFg/6HDFBUsIj09nehfbAWwPWOT9n5RYhqGwarNWxkRM5TRCfF4U1PQsDDJFk9uYhwXvzvKjm3b'.
     1314     'KSsro3DJInNW5RXp7u2bAKSlpeH1esnPz6eqqgqLpmmcr3Fht9ulfaV7mZk1Bs+lM6T1djM9fhg5egDPpTNMy5TZsW07kydPYdWM'.
     1315     'aXx96ixOp9O8cfUa80srmDpjOgAulytiQqZpMnvObLbt/JTtHxXj9/tRVdU0DGOAufRpevPDTeac0hJyc3NxOOawfv161lVWS6eX'.
     1316     'z+9/UOCxu1VWVvaTRGv16NFfjB2bNeAQp9NpTpmSM4DcbrdL0WsGDKLRR+52uwe1yP8jb2lpYfikyY9t80n03UCWZeaXVjw1f+zs'.
     1317     'Oen+/d+pqanhzp2fKSsrw+l0mi6XiyPl5ZGITdN8fAVJwjRNJEmi1qfw1kw7siyTnJxMe3s71dXV3GpoZO64DG41NPJylvxU5D/e'.
     1318     'qJKsfWQD9IkaZ2RmUvr9aV4aGYcQgjfO3aWoYBF5eXm4ewIsu/CbdPz1aWb0/p1bNoOrQxlUiuiaFo3c3FyEEOx9+C9CCD6paaTW'.
     1319     'p/TXyYkTJ0Xe59jf7QOyAKDWp/QXxcFQ61P4pT3ShBBcvnUHIQTjxmX19/8BCeVg+/GPpskAAAAASUVORK5CYII=' ;
     1320
     1321        //==========================================================
     1322        // lock.png
     1323        //==========================================================
     1324        $this->iBuiltinIcon[7][0]= 963 ;
     1325        $this->iBuiltinIcon[7][1]=
     1326     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
     1327     'AAALCwAACwsBbQSEtwAAAAd0SU1FB9AKAw0XDmwMOwIAAANASURBVHic7ZXfS1t3GMY/3+PprI7aisvo2YU6h6ATA8JW4rrlsF4U'.
     1328     'qiAsF9mhl0N2cYTRy9G/wptAYWPD9iJtRy5asDe7cYFmyjaXOLaMImOrmkRrjL9yTmIS3120JybWQgfb3R74wuc8Lzw858vLOUpE'.
     1329     'OK6pqSm2trbY39+nu7tbPHYch7m5OcLhMIA67kWj0aMQEWk6tm17rNm2LSIie3t7ksvlJJ1OSyqVkls3Z8SyLMnlcqTTaVKpFLdu'.
     1330     'zmBZVj1HeY2VUti2TSQSQSml2bZdi0QirK2tMT09zerqKtlslqGhISYnJ4nHv2N+foFsNquOe9FotLlxOBwmk8lgWRbhcFgymYxY'.
     1331     'liUi0mqaJoAuIi2macrdO7fFsizx3to0Te7euV1vrXtXEgqFmJmZYWVlhXK5LB4/U9kwDL784kYV0A3DYHd3m4sXRymXywKoRi8U'.
     1332     'Ch01DgQCJBIJLMsiEAhIIpHw2uLz+eqtYrEYIqKZpimxWEyCwaCMjY01zYPBIJpXqVQqsby8TLVabWKA/v5+RkZGMAyDrq4ulFKH'.
     1333     'HsfjcWZnZ+ns7KTRqwcnk0mKxSKFQqGJlVKtruuSTCYB6O3trW9UI/v9/iZPB/j8s2HOnX0FgHfeXpeffnzK+fWf+fijvhLs0PtG'.
     1334     'D/n1OJ9+MsrlSwb3733DwMCAt1EyPj6uACYmJp56168NU6nUqFSE9nZdPE7+WqC/r4NKTagcCJVqDaUUB5VDAA4Pa9x7sMLlSwan'.
     1335     'WjRmv13D7/erpaWlo604qOp88OF7LC48rPNosMq5Th+Dgxd4/XyA1rbzADi7j8jnf2P++wdcvSr8MJ/i8eomAKlUqn41OsDAQDeD'.
     1336     'g++yuPCwzm/2vU8+n2a7sMFfj79mp7BBuVzioFSiXHJx3SKuW2Rzy0Up9dxnQVvODALQerqNRn4ZKe0Mvtc6TpzpmqbxalcY9Ato'.
     1337     '2v06t515C73YQftZB9GLnDrt4LoujuPgOA4Ui+C6yOpXJwZrJ7r/gv4P/u+D9W7fLxTz+1ScQxrZ3atRLaVxdjbY2d184R6/sLHe'.
     1338     'opHP7/Do90Ua+WWUyezzZHObP/7cfX54/dowE1d66s8TV3oE+Mfn+L/zb4XmHPjRG9YjAAAAAElFTkSuQmCC' ;
     1339
     1340        //==========================================================
     1341        // stop.png
     1342        //==========================================================
     1343        $this->iBuiltinIcon[8][0]= 889 ;
     1344        $this->iBuiltinIcon[8][1]=
     1345     'iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
     1346     'AAALDwAACw8BkvkDpQAAAAd0SU1FB9AJDwEvNyD6M/0AAAL2SURBVHic1ZTLaxVnGIefb2bO5OScHJN4oWrFNqcUJYoUEgU3/Qf6'.
     1347     'F7gwCkIrvdBLUtqqiLhSg9bgBduFSHZdiG5ctkJ3xRDbUFwUmghNzBDanPGMkzOX79LFJGPMOSd204U/+Bbzvd/78F4H/ieJdoad'.
     1348     'pZKxRFszAI/DcP0HazXY22v+HB01kee1PA/v3zfnjx4xgGnHcNZe7OvuNj+cOEF1ZATv5nUA4jhBSgmADCVWo8Ge2Of9wb18P/G7'.
     1349     'oUXmYi30zqlTVEdGWLh1g2D6MYlKkXGE0Vl8aa2GEB149+4xXSzyoOIw/mimiZV/DPb25pFOj13A9gOMEChhUEqhVYqWKUk9QAUp'.
     1350     'sT/P4s8PmKlUmNhQaIJbkDVqBbpw6wZ2zUc4Nm+ePku5p4eOrgpueQOFUoVCVxcD4+N07dpF9+5tVJeWGPBjhvr7WF1zC8ASgtcP'.
     1351     'H8a7eZ1odh4sh50nzwCw9ZNh3M4Stutiu0X2nB/LyjZ6lcIbVTpdQU/jWVPzLADM8+ZGBRdtC7wrF/O7bR99iu26VL86iU4SAH4b'.
     1352     'Po5d6AQhstMSvGyI4wS5FJBKSRwnzF8byx/u+PjzzMF1mfryQ1K/jnCahqp1xEopjFLoNEFJSRJHzF799gWHqa+/QKcSUXBI609f'.
     1353     'Al5W4teQSiHDOipNUKnMI13RvnOXAIEKQixvGWya98SC560MFwPiqEG86JM8q79Q06lvhnOndy5/B6GPCUOMUu3BQgg8z0M3GmBZ'.
     1354     'iGJn3v2VmsqnfzNx7FDueODuj8ROCFpjtG5TCmOYv32bJ09msP0ISydMfnAUgF8/O45RAA6WTPjlvXcB+Gn7FuRf/zAnNX6x3ARe'.
     1355     'PSdmqL+P/YHkwMGDOGWDZTlQcNBRhPEComgB/YeHfq2InF1kLlXUOkpMbio1bd7aATRD/X0M1lPeSlM2vt2X1XBZjZnpLG2tmZO6'.
     1356     'LbQVOIcP+HG2UauH3xgwBqOz9Cc3l1tC24Fz+MvUDroeGNb5if9H/1dM/wLPCYMw9fryKgAAAABJRU5ErkJggg==' ;
     1357
     1358        //==========================================================
     1359        // error.png
     1360        //==========================================================
     1361        $this->iBuiltinIcon[9][0]= 541 ;
     1362        $this->iBuiltinIcon[9][1]=
     1363     'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaVBMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'.
     1364     'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpYiYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'.
     1365     'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxIAAAsSAdLdfvwAAAAHdElNRQfTCAkUMSj9wWSOAAABLUlEQVR4'.
     1366     '2s2U3ZKCMAxGjfzJanFAXFkUle/9H9JUKA1gKTN7Yy6YMjl+kNPK5rlZVSuxf1ZRnlZxFYAm93NnIKvR+MEHUgqBXx93wZGIUrSe'.
     1367     'h+ctEgbpiMo3iQ4kioHCGxir/ZYUbr7AgPXs9bX0BCYM8vN/cPe8oQYzom3tVsSBMVHEoOJ5dm5F1RsIe9CtqGgRacCAkUvRtevT'.
     1368     'e2pd6vOWF+gCuc/brcuhyARakBU9FgK5bUBWdHEH8tHpDsZnRTZQGzdLVvQ3CzyYZiTAmSIODEwzFCAdJopuvbpeZDisJ4pKEcjD'.
     1369     'ijWPJhU1MjCo9dkYfiUVjQNTDKY6CVbR6A0niUSZjRwFanR0l9i/TyvGnFdqwStq5axMfDbyBksld/FUumvxS/Bd9VyJvQDWiiMx'.
     1370     'iOsCHgAAAABJRU5ErkJggg==' ;
     1371
     1372        //==========================================================
     1373        // openfolder.png
     1374        //==========================================================
     1375        $this->iBuiltinIcon[10][0]= 2040 ;
     1376        $this->iBuiltinIcon[10][1]=
     1377     'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAZiS0dEANAAtwClFht71AAAAAlwSFlz'.
     1378     'AAALEAAACxABrSO9dQAAAAd0SU1FB9AKDQ4RIXMeaLcAAAd1SURBVHicxZd7jBXVHcc/58zcvTNzH8vusqw8FsTsKiCUUh5WBZXG'.
     1379     'GkOptmqwNWsWLKXFGlEpzZI0AWNKSy0WhDS22gJKtWlTsSRqzYIuLGB2WVvDIwQMZQMsy2OFfdzde+/OnHP6x907vJaFpjb9JZM5'.
     1380     'c85Mfp/f9/s7Jxn4P4e41gtSyp78WGvtfdEAcqDFYUOH9HS0NhGk9tPb/ilSyp789UUB2AMuqhQy3Uzm7HGkE6W3dTNZMRI3EcWO'.
     1381     'jf9ClLmWBT3dzW8jUsevWHCG3UpWl+IkHSxnbDh/Mcz12NevBcuWXTmf6TjnXvJ88gDmVB3pw3+nt3UzHa1NqMzBS2zqPLGFjtMN'.
     1382     'ZNr3XdW+qyqwZcFk76HX/tHWfuQvyO4W7qhaHwL8efkMRlRUpPv7rqD0RrJ+FgAjLy1a20OIxZJEEuNCRfIApj+om4bGM3u2/sYU'.
     1383     '9J41d8973f3Dhg1pISTV1dXXBRNJxPGFCzhou+DCQrScZOkktNaeDZjamgeZ9MgiYmVDccvHhjAzJw0NTh8/alyZMaVJicp0iTHj'.
     1384     'JpgNv38tjWUhhGROdbUL9W5/MH5XCkjlcibi+KIop5LVHLKEu8A/f4r286doa9pGrGwYAAsfqbbH3b8MgO/Nqgy6WvdbbXHMkEFJ'.
     1385     '4xUOMVEvaTZu3BgmvF4Yk4hz9rO/Ulr5cE9owae/rcGxohSOuiWkC2IjcIqKyPZm+OmCH7GhoZEF077EEzVVweAbJ+riEeO0Ey8y'.
     1386     'UubqOHn0AOgMwvf59txnBrSp9dgxKmf/+kIP1NY8SFk0jh5ajmNHAWg5b2E5EexojGHjbiVRMoRMNs0LC+Yz46vTuH3enN7BI8fr'.
     1387     'qFdo0BoVZNC9aVSQ4fNjBzEmQJiARxb+/AqYPMAVB5FsPU5v37g9OxgLhe14ZM5/ju052E6MNZvf5pmHHuLmmWOkEysxUtpGAtme'.
     1388     'dtHTflJkezqQto3jFRnLssyf1jydxiiM7zNnye/c3ZsqLu2BN5fcMfzrv/hby1tPzmRUoihcTJ87CwQI2yLtDcIqsIjYUf51qBlf'.
     1389     'OnScOSrdQUOMURkiXsLUzJnvbGhoBGDHH5cGyZLhOpYoNl5hqYnYEXOu5fDl9eYAHntx98n8hFHZcPHUuTSxSASAeK/CGIOxJJ0f'.
     1390     'bOGNPU280dgkq6Y2yu8vfjCIlwwzr+/ZQ/PHO0gOLuO5qsftDQ2NbN+4OCgqG6WTxWVaq6zpF+DiSHWnicdylp3r6aZTWthIOrNp'.
     1391     'ktHcvBu0sHX1Sm6ozB3B42d90zZA9bQp7PvgPSzXZfnqX/HS4DKKK2+x69Y/HURs26iBAN5ccsfw7774UcumF37C6f07KSt2OHji'.
     1392     'DEUJD0tISjyPrrSPlAKvN0JP/U4O1NfjuhG2rvklN1SOpfXwftpbTqAyKRrff5fb7rs9V1R7m4wlz2ihA3HpmXflUWyOH2umpLiY'.
     1393     'ui3v8M+6bWzfsRNbSgqkxaCkiy0simMuEWEhpcRzIhQWOIAh6tiAwS4owInFiTou5dOnMnl2NR++ujBwXEc9terD6M43nrj6LgAB'.
     1394     'QnDPA9/irtkP8JRS7Hr/3T6YekDQ1pEiEXOwpUVJzCVlZZFS4mZtkpEo9ChAkDp/jtLMBACy6S4RiQghLyv5cgBRPnKUOX6smUGF'.
     1395     'hSil0MYw9d77mPy1e5mnFE3batm3czvb6nYgEJztSFGU9LCRlMRdUjIH0+lnEMIwPNXD3NumoVJnrMCJaiciMUZfvQnz4QcBSvV1'.
     1396     'vjE5GK358t0zmXDnDB79saLpo20c+aSRD+t25JTp7GZQwsEWFiVxl6hlUf/WO9z32CxmL1rOe6u/I2KuwGhzLQCB7/sYY9Bah3el'.
     1397     'FKbvrrVm4vS7GH/7ncx+chEHGz7myCeNbPtoO0JI2jq78WIRLGkzsqs7V5SfFV5EovXACoiqqsfNpk2vo5VCWtYFBfoU0VoTBAFa'.
     1398     'a7TRaK2p+MoURk+cxMzq+Rzbv49DDbuo27UTW9h0dedssPxuK+kIfN8XxhgDYPVXf2Fh4XKtFIl4AiklAlBKAYRKKK36wHIweTCt'.
     1399     'NfHiEkaOn8j0+7/BmDFjaT30GbHywSxcuZkpFfFg+m1jjZ/NmnVvNfRvwd69e8WBA/uNFAIh4JVXXmHsmDHE4vEQQgjQ2lxQIm9N'.
     1400     'nz35q3BEOZOHzaG2thaA4mRU+L29It+IV21CpbRQfeMFC35gRB/M2rVrubnyZmLxWJhECBEmz/eHyo/7lMlH3LFFujsthNFCCGOu'.
     1401     '+WNyeUgpjSVzMKtWraKyshLPdcPEeYWCIEBdpIxSivr6eta8vI7d6+cGnhdV06pe1QP+F/QXWmuRL+jZZ58LlVmxYgUVFRV4rhtu'.
     1402     '4TzMxXAA6XRaRAtsYUkx8I/JtSJQOlSwpmZpCLN8+fPcdNNoHMfB9/0QJgRoP295TlR7UVv8xxZcHMuWIZ9/Hn35vG3JEGZpzVJG'.
     1403     'jx5N1IlitKahsZE1L69j69qHgx+urFX/lQL9JYdLlfnZihUhzOLFi8N3Ml1dthOxVH/f/8/CtqSJ2JaJ2JZ59J7RPsC/AViJsQS/'.
     1404     'dBntAAAAAElFTkSuQmCC' ;
     1405
     1406        //==========================================================
     1407        // folder.png
     1408        //==========================================================
    13601409        $this->iBuiltinIcon[11][0]= 1824 ;
    1361         $this->iBuiltinIcon[11][1]=
    1362             'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
    1363             'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'.
    1364             '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'.
    1365             'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'.
    1366             '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'.
    1367             'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'.
    1368             'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'.
    1369             '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'.
    1370             'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'.
    1371             'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'.
    1372             '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'.
    1373             '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'.
    1374             'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'.
    1375             'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'.
    1376             'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'.
    1377             'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'.
    1378             'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'.
    1379             'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'.
    1380             'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'.
    1381             'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'.
    1382             'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'.
    1383             'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'.
    1384             'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'.
    1385             'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'.
    1386             'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ;
    1387 
    1388         //==========================================================
    1389         // file_important.png
    1390         //==========================================================
    1391         $this->iBuiltinIcon[12][0]= 1785 ;
    1392         $this->iBuiltinIcon[12][1]=
    1393             'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
    1394             'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'.
    1395             'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'.
    1396             'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'.
    1397             '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'.
    1398             's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'.
    1399             'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'.
    1400             'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'.
    1401             'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'.
    1402             '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'.
    1403             '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'.
    1404             'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'.
    1405             'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'.
    1406             'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'.
    1407             'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'.
    1408             't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'.
    1409             '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'.
    1410             'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'.
    1411             'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'.
    1412             'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'.
    1413             '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'.
    1414             'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'.
    1415             'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'.
    1416             '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ;
    1417 
    1418         $this->iLen = count($this->iBuiltinIcon);
     1410        $this->iBuiltinIcon[11][1]=
     1411     'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
     1412     'AAALEAAACxABrSO9dQAAAAd0SU1FB9ECAQgFFyd9cRUAAAadSURBVHiczdhvbBP3Hcfx9/2xfefEOA5JoCNNnIT8AdtZmYBETJsI'.
     1413     '6+jQOlQihT1AYgytqzZpD1atfyYqlT1h0lRpT7aRJ4NQpRvZGELVuo5Ua9jEJDIETQsNQyPBsUJMWGPnj//e+e72wNg4xElMR6ed'.
     1414     'ZNln3933dZ/f93f6yfB/sgmrHdDV1WXlPg8NDZUDScD8LFFFEZZlWYZhWMFg0Orq6sq/gDJAfFy1iiZy9OjrVnj4JzQ1rMWqfxm/'.
     1415     '309jYyNtbW0kEgnu3bvH4cOH88c/jqSKQl4/XGkd+eVtAN46up1LH92ktqYS++ZX8Pv9NDQ0sGnTJlKpFOFwmO7u7vy5IyMjeVRd'.
     1416     'XV1+WEOh0IrY4pDnq6wXX/sTiCJaMkFZdRNqxefoe7VtCSqXVDqdZnZ2ltraWkzTpKqqijt3JpFlG7dvj7NzZ1f++qFQyA3EClHL'.
     1417     'Ql743nFkhxPDtJAd5eTaYSVUfX09lZWVlJWVIUnSg7sVQMBCUcu4ceMGe/bsIRQK1QAzOcyykIM9P0KyudAyCWyqG8nhwqa4SkLt'.
     1418     '3r0bVVVxu924XC40TUOWZUQxe97CwgIdHR2LMHIxSCaVInVvFElxE0vMY1Pd2NUKJMWNTXHlUfF//4vETJCelwbpFm3MjP2dt37x'.
     1419     'AlN+PzU1NViWRSwW4+7du3g8HjweD4qi5EFAJzAExIpCANbooxhplfB0FJvTg6xWIqsVRVF6MopkU3FXPcnkJxGU0VEAdF2noqKC'.
     1420     'W3/8DpnqLjzep2lubsblcjE8PExHR8fboVDID9xYFpLBDpJF0jDQIncQpWlkm31FlFLtp9PfyuW/vYQj1kPSuRW/38+lj27S2Q7v'.
     1421     '/aWXUBVUffVNtm3blivVCEwsC5Eyc5iiApEpDEAXMqQdldhSiWVQHjJagud+8Fuexck/zv+K82dfoSbSCsDe75/km+4GVPd6+l5t'.
     1422     '4zJHcqVUYN2yEEtZQDCSJCueRAYsPY49HsFIZVG6p25JUumFafT4DKJN4amtT7Nz38sk5+5A70HMtEYyMkFiZhxzjQ/poXrLQrRU'.
     1423     'DFGEeFpAlkQkm4pRiCpIKodKzk0T/2QMh+piPjxKZPwiSkUtu/b9mNnJEWS7E8nhAmvpM60oJDkXJxqNozxRRUxPIesispBBlsXV'.
     1424     'UaKEFo8gzoaJhz8s2lOmrpUG+WBhJ9/60g+Z+fDXTAXfxllRjl1VkO0OFATsYhYliiK21ZKKhhHnFveUqSdKgwAEOp7F2v51vvw8'.
     1425     'XH7/N1wd/BlTweuUV65BdtgfoLTSkipsdD3tRi0VYpommUwGwzDwdT5HYEc3giAwcvH3jLz3BlPB67jWeZBEKYsSBWwpHZtNKo4q'.
     1426     'aHTDsJeeiGEYWJaFZVmYpommaRiGQdPnv0bb1m8gSRL/vPIOV979aR4lmAJ2p4qCgCxksNuKJ6VNpx4NYhgGpmkuQhmGQTqdxjAM'.
     1427     'qr2d7HtxEEEQuH1tkKvvvkF44tqDnrIcKJKAPf1g+LAUElq8dIiu60sApmnm93Pfzc7OYhgGrie+wFe++ztcLhcT1wf54PzPCU9c'.
     1428     'w7XWjWS3IdsdOAUBWZAxrRJnTQ6SG5bce2FCpmkughmGQSqVYm5uDtnj44sH38TtdhP6+Dwf//V4ttHXrkGURZJaic8RgHQ6jWma'.
     1429     'SJKUL5RLKNfIOczDKF3XSSaTRCIRhLJWntp3nGfWrSMxc5OLf3iNP4+68T9Ub9nF76lTpxgfHycajZJKpdA0LZ9GbjYV7hcDWZaF'.
     1430     'pmnMz88Ti8UYunSLmu1HFi2aVkxkaGjINTY2ttDb24vX6+XQoUNs3ryZ8vJyIDu1BUFYkkxhgxeiWlpaOHPmDE1NTdTX1xe98eWG'.
     1431     'JnF/9dQZCoXUYDA4AOD1ejlw4ACtra2Ul5fniwmCkEcUJiUIAoFAgL6+Pnw+H21tbfT39z8SxCS7hHsfWH9/8dL4MKqnp4eWlhac'.
     1432     'TmcekEvMNE2am5s5ceIEgUCA9vZ2Tp48ic/nY3j4UsmQHCYOjJHtpeBKqL1799Lc3IzT6UTXdRobGxkYGKC9vZ3W1tZ8Ko86NJ8a'.
     1433     'tXHjRo4dO8bp06fZsmULGzZsoL+/n0AggNfr5ezZs/8VpGTU5OSkc//+/acBfD4f1dXV7Nq1i4aGBs6dO4fP5+Pq1SuPBbIiyjTN'.
     1434     'RUnV1dUNXLhwAa/Xy44dO4jFYgBEo9FFF1r134BPuYlk16LrAYXsAlmtq6sbKDwoFAp9m+ykuP5ZQVZF3f8tCdwCov8LyHIoAANI'.
     1435     'AXf/A1TI0XCDh7OWAAAAAElFTkSuQmCC' ;
     1436
     1437        //==========================================================
     1438        // file_important.png
     1439        //==========================================================
     1440        $this->iBuiltinIcon[12][0]= 1785 ;
     1441        $this->iBuiltinIcon[12][1]=
     1442     'iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAYAAAA6RwvCAAAABGdBTUEAALGPC/xhBQAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlz'.
     1443     'AAALDwAACw8BkvkDpQAAAAd0SU1FB9ECDAcjDeD3lKsAAAZ2SURBVHicrZhPaFzHHcc/897s7lutJCsr2VHsOHWMk0MPbsBUrcnF'.
     1444     'OFRdSo6FNhdB6SGHlpDmYtJCDyoxyKe6EBxKQkt7KKL0T6ABo0NbciqigtC6PhWKI2NFqqxdSd7V2/dmftPDvPd212t55dCBYfbN'.
     1445     'zpvfZ77z+/1mdhUjytWrV93Hf/24eD5z9gwiMlDjOKbb7dLtdhER2u02u7u73Lp1CxEZBw4AeZwdNQqkMd9wbziFGINJUt6rRbz5'.
     1446     '1ptUq1XK5TJBEAAUMHt7e+zu7gKwvLzMysoKwAng/uNg9CgQgFKlgg1DUJ67Vqtx6tQpZmdniaIIpRTOOZRSdDoddnZ2aLfbLC8v'.
     1447     's7S0xJUrV7ZGwQSj1PhhfRodVdDlMrpc5vup5Z2fvMPdu3fZ29vDWjvwztjYGPV6nVqtRqVS4dKlSywtLQFsAdOH2XwsCEApg3jl'.
     1448     'w98Rak2gvYjNZpNms0mSJDjnHgkDMDc3dySYQ0Ea8w139YUX0OUKulzyg7UmCEO+l1huvHuDra0t9vf3h1TJYSqVypFhHquIrlQI'.
     1449     'S5qv/uIDAC7/4bcEQYAKvK+0Wq1DVQGIoog7d+4cCeaRII35hrt+8SsEOkRlUaEyR0UpFIrXHxyMVKVUKnHv3r0jwRwaNelBjBjL'.
     1450     'Sz/7KYuLiwAsLi7y4z/9kY9e+TpkCuSqjI+Po7XuAWeKXLt2DWNMUZMkwRjDhQsXWFtbK6JpCCT3jfQgxomPtPX19YHWicM5x3c2'.
     1451     '73Pj3Ru8/aO3mZqaolKpoHVvyuvXr/Ppnf/Q7uzz380NPtu4y/qnG+ztd1hfX2dtbQ3gIvDnRyqSxl1UoPjyz98D4PTp0wPtq39Z'.
     1452     '4fdzLxegrVaLVqvF5OQkYRgWqpRKJZ77wvNsbW1RG5tgfKLOTH2G7Z1twqBQrgrMDvhInjfSOCY5iIv+hYWFgRZArEWsZWF941Bf'.
     1453     'SdMUgMnJCWpjVU4cn+HUyePM1Gc4+fRUPkzBI5w1jbukcczLv/5l0XfmzJmBFuCba38r/CRXpT+CrDUoZ0jjB4RYonJAOYRobJKT'.
     1454     'z5zgqfqxAbsFSH6mpHFM2qdGXh4VnoViD6mSJF2cTQeqDqBaKVHWmonJCWpZjhkC6anR5WsffTgwaHV1FaUUq6urA/2v3f5k4LnV'.
     1455     'arG9tUn3oI2YBCcWHYAxMVYs1qZEZY2SFB2aYZDGfMN9d7uJiWPSeFiNo5Rclc3NTXZbO6RpF7EJVixYA9agwwDnUiqlEPdQ3imi'.
     1456     'Jo27BGHIt/7x9yEjc3Nzh27Na7c/4TdffKl4bja3ae5MUIu0T/HOEIaOpJt4gwoSsVTK4SBIY77hFtY3ABBjBiZ90rKwvsH77/+K'.
     1457     't37wOhO1iPpTk4SBw1mLsz6CnKQ4l3qV+kE+t9XHlNZOk+bUJLVIE1VCcIJWQmJ6qjj30NbcXLkZMt8YPig+Z3n1G5fZ39/j/vY2'.
     1458     '9ckqZT2Ochbn0p4qNkU/dDfUADdXbh4HXgRO4zNdEU0XL1784PLly5w9e7Z4SazFOfGrEotDcOKrcoJPmrYIXf/Zop3QNd1skuGt'.
     1459     'cUAb2MgAxvHZTgFUq1Wmp6eZnZ0F8JlTjDduDThBnDeECEoJtbGIp6enqEblzCcEZ1PECU4yVRiOGgd0gc+AB0CZvkv1sWPHOHfu'.
     1460     'HOfPn8da41cpkkltEBEPJhYnBkTQJcdYVKGkgRxCfBsq5xXNgAa2Bn+hjTOgHEKBP8pzRUxykIH4ifLJRTJAl+UMBJzPHQ6bfe/f'.
     1461     'cWIzPxlUpD+zugzIZtVk1d8znBAqRxgoQuVQgSJQ3h9C5QhDRYgjUILCAzlnEdsHYTKfMTEBcP7F54YUGVmc2GLlIn6ve6v0ahSt'.
     1462     '8X25TzjJ+rIx1grKpQPWR4LkGVVsMgghvS0qjPdvm5OeceOTWA5Evo2mFzkjQfL7hZPUy5yvvF/uPFQL3+nbDmsLCEmT3sTmCTNr'.
     1463     'rogT6yFsOix3ftw7OwQhkvSU6CuinhCk0+kAkFoBazEEICHaHHiPVmU0gnUp4EAc1mYrF0EBVpwPi34VrBkwPxKk3W5ju/e5/c+d'.
     1464     'bGUHIAIuydTIE5zfc5Wr4lJcahHnHTP3CVGm78DrgY38N+DEibp7dmYKdAQmBh1hjEFjis+9CTWYGK21H6PxPyOI0DobYwzZF/z7'.
     1465     '7jadTvJtYG0kCD7lfwl49ijgT1gc0AH+dZSJA/xB+Mz/GSIvFoj/B7H1mAd8CO/zAAAAAElFTkSuQmCC' ;
     1466
     1467        $this->iLen = count($this->iBuiltinIcon);
    14191468    }
    14201469}
     
    14271476//===================================================
    14281477// CLASS IconImage
    1429 // Description: Holds properties for an icon image 
     1478// Description: Holds properties for an icon image
    14301479//===================================================
    14311480class IconImage {
     
    14351484    private $iScale=1.0;
    14361485
    1437     function IconImage($aIcon,$aScale=1) {
    1438         GLOBAL $_gPredefIcons ;
    1439         if( is_string($aIcon) ) {
    1440             $this->iGDImage = Graph::LoadBkgImage('',$aIcon);
    1441         }
    1442         elseif( is_integer($aIcon) ) {
    1443             // Builtin image
    1444             $this->iGDImage = $_gPredefIcons->GetImg($aIcon);
    1445         }
    1446         else {
    1447             JpGraphError::RaiseL(6011);
    1448 //('Argument to IconImage must be string or integer');
    1449         }
    1450         $this->iScale = $aScale;
    1451         $this->iWidth = Image::GetWidth($this->iGDImage);
    1452         $this->iHeight = Image::GetHeight($this->iGDImage);
     1486    function __construct($aIcon,$aScale=1) {
     1487        GLOBAL $_gPredefIcons ;
     1488        if( is_string($aIcon) ) {
     1489            $this->iGDImage = Graph::LoadBkgImage('',$aIcon);
     1490        }
     1491        elseif( is_integer($aIcon) ) {
     1492            // Builtin image
     1493            $this->iGDImage = $_gPredefIcons->GetImg($aIcon);
     1494        }
     1495        else {
     1496            JpGraphError::RaiseL(6011);
     1497            //('Argument to IconImage must be string or integer');
     1498        }
     1499        $this->iScale = $aScale;
     1500        $this->iWidth = Image::GetWidth($this->iGDImage);
     1501        $this->iHeight = Image::GetHeight($this->iGDImage);
    14531502    }
    14541503
    14551504    function GetWidth() {
    1456         return round($this->iScale*$this->iWidth);
     1505        return round($this->iScale*$this->iWidth);
    14571506    }
    14581507
    14591508    function GetHeight() {
    1460         return round($this->iScale*$this->iHeight);
     1509        return round($this->iScale*$this->iHeight);
    14611510    }
    14621511
    14631512    function SetAlign($aX='left',$aY='center') {
    1464 
    1465         $this->ixalign = $aX;
    1466         $this->iyalign = $aY;
    1467 
     1513        $this->ixalign = $aX;
     1514        $this->iyalign = $aY;
    14681515    }
    14691516
    14701517    function Stroke($aImg,$x,$y) {
    14711518
    1472         if( $this->ixalign == 'right' ) {
    1473             $x -= $this->iWidth;
    1474         }
    1475         elseif( $this->ixalign == 'center' ) {
    1476             $x -= round($this->iWidth/2*$this->iScale);
    1477         }
    1478 
    1479         if( $this->iyalign == 'bottom' ) {
    1480             $y -= $this->iHeight;
    1481         }
    1482         elseif( $this->iyalign == 'center' ) {
    1483             $y -= round($this->iHeight/2*$this->iScale);
    1484         }
    1485 
    1486         $aImg->Copy($this->iGDImage,
    1487                     $x,$y,0,0,
    1488                     round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale),
    1489                     $this->iWidth,$this->iHeight);
     1519        if( $this->ixalign == 'right' ) {
     1520            $x -= $this->iWidth;
     1521        }
     1522        elseif( $this->ixalign == 'center' ) {
     1523            $x -= round($this->iWidth/2*$this->iScale);
     1524        }
     1525
     1526        if( $this->iyalign == 'bottom' ) {
     1527            $y -= $this->iHeight;
     1528        }
     1529        elseif( $this->iyalign == 'center' ) {
     1530            $y -= round($this->iHeight/2*$this->iScale);
     1531        }
     1532
     1533        $aImg->Copy($this->iGDImage,
     1534                                $x,$y,0,0,
     1535                                round($this->iWidth*$this->iScale),round($this->iHeight*$this->iScale),
     1536                                $this->iWidth,$this->iHeight);
    14901537    }
    14911538}
     
    15001547    public $csimtarget='',$csimwintarget='',$csimalt='';
    15011548    private $iFFamily=FF_FONT1,$iFStyle=FS_NORMAL,$iFSize=10;
     1549    private $iFontArray=array();
    15021550    private $iColor="black";
    15031551    private $iText="";
    15041552    private $iHAlign="left",$iVAlign="bottom";
    1505        
    1506 //---------------
    1507 // CONSTRUCTOR 
    1508     function TextProperty($aTxt='') {
    1509         $this->iText = $aTxt;
    1510     }           
    1511        
    1512 //---------------
    1513 // PUBLIC METHODS       
     1553
     1554    //---------------
     1555    // CONSTRUCTOR
     1556    function __construct($aTxt='') {
     1557        $this->iText = $aTxt;
     1558    }
     1559
     1560    //---------------
     1561    // PUBLIC METHODS
    15141562    function Set($aTxt) {
    1515         $this->iText = $aTxt;
     1563        $this->iText = $aTxt;
    15161564    }
    15171565
    15181566    function SetCSIMTarget($aTarget,$aAltText='',$aWinTarget='') {
    1519         if( is_string($aTarget) )
    1520             $aTarget = array($aTarget);
    1521         $this->csimtarget=$aTarget;
    1522 
    1523         if( is_string($aWinTarget) )
    1524             $aWinTarget = array($aWinTarget);
    1525         $this->csimwintarget=$aWinTarget;
    1526 
    1527         if( is_string($aAltText) )
    1528             $aAltText = array($aAltText);
     1567        if( is_string($aTarget) )
     1568        $aTarget = array($aTarget);
     1569        $this->csimtarget=$aTarget;
     1570
     1571        if( is_string($aWinTarget) )
     1572        $aWinTarget = array($aWinTarget);
     1573        $this->csimwintarget=$aWinTarget;
     1574
     1575        if( is_string($aAltText) )
     1576        $aAltText = array($aAltText);
    15291577        $this->csimalt=$aAltText;
    1530        
    1531     }
    1532    
     1578
     1579    }
     1580
    15331581    function SetCSIMAlt($aAltText) {
    1534         if( is_string($aAltText) )
    1535             $aAltText = array($aAltText);
     1582        if( is_string($aAltText) )
     1583        $aAltText = array($aAltText);
    15361584        $this->csimalt=$aAltText;
    15371585    }
     
    15391587    // Set text color
    15401588    function SetColor($aColor) {
    1541         $this->iColor = $aColor;
    1542     }
    1543        
     1589        $this->iColor = $aColor;
     1590    }
     1591
    15441592    function HasTabs() {
    1545         if( is_string($this->iText) ) {
    1546             return substr_count($this->iText,"\t") > 0;
    1547         }
    1548         elseif( is_array($this->iText) ) {
    1549             return false;
    1550         }
    1551     }
    1552        
     1593        if( is_string($this->iText) ) {
     1594            return substr_count($this->iText,"\t") > 0;
     1595        }
     1596        elseif( is_array($this->iText) ) {
     1597            return false;
     1598        }
     1599    }
     1600
    15531601    // Get number of tabs in string
    15541602    function GetNbrTabs() {
    1555         if( is_string($this->iText) ) {
    1556             return substr_count($this->iText,"\t") ;
    1557         }
    1558         else{
    1559             return 0;
    1560         }
    1561     }
    1562        
     1603        if( is_string($this->iText) ) {
     1604            return substr_count($this->iText,"\t") ;
     1605        }
     1606        else{
     1607            return 0;
     1608        }
     1609    }
     1610
    15631611    // Set alignment
    15641612    function Align($aHAlign,$aVAlign="bottom") {
    1565         $this->iHAlign=$aHAlign;
    1566         $this->iVAlign=$aVAlign;
    1567     }
    1568        
     1613        $this->iHAlign=$aHAlign;
     1614        $this->iVAlign=$aVAlign;
     1615    }
     1616
    15691617    // Synonym
    15701618    function SetAlign($aHAlign,$aVAlign="bottom") {
    1571         $this->iHAlign=$aHAlign;
    1572         $this->iVAlign=$aVAlign;
    1573     }
    1574        
     1619        $this->iHAlign=$aHAlign;
     1620        $this->iVAlign=$aVAlign;
     1621    }
     1622
    15751623    // Specify font
    15761624    function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) {
    1577         $this->iFFamily = $aFFamily;
    1578         $this->iFStyle   = $aFStyle;
    1579         $this->iFSize    = $aFSize;
    1580     }
     1625        $this->iFFamily = $aFFamily;
     1626        $this->iFStyle  = $aFStyle;
     1627        $this->iFSize  = $aFSize;
     1628    }
     1629
     1630    function SetColumnFonts($aFontArray) {
     1631        if( !is_array($aFontArray) || count($aFontArray[0]) != 3 ) {
     1632            JpGraphError::RaiseL(6033);
     1633            // 'Array of fonts must contain arrays with 3 elements, i.e. (Family, Style, Size)'
     1634        }
     1635        $this->iFontArray = $aFontArray;
     1636    }
     1637
    15811638
    15821639    function IsColumns() {
    1583         return is_array($this->iText) ;
    1584     }
    1585        
     1640        return is_array($this->iText) ;
     1641    }
     1642
    15861643    // Get width of text. If text contains several columns separated by
    1587     // tabs then return both the total width as well as an array with a 
     1644    // tabs then return both the total width as well as an array with a
    15881645    // width for each column.
    15891646    function GetWidth($aImg,$aUseTabs=false,$aTabExtraMargin=1.1) {
    1590         $extra_margin=4;
    1591         $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    1592         if( is_string($this->iText) ) {
    1593             if( strlen($this->iText) == 0 ) return 0;
    1594             $tmp = split("\t",$this->iText);
    1595             if( count($tmp) <= 1 || !$aUseTabs ) {
    1596                 $w = $aImg->GetTextWidth($this->iText);
    1597                 return $w + 2*$extra_margin;
    1598             }
    1599             else {
    1600                 $tot=0;
    1601                 $n = count($tmp);
    1602                 for($i=0; $i < $n; ++$i) {
    1603                     $res[$i] = $aImg->GetTextWidth($tmp[$i]);
    1604                     $tot += $res[$i]*$aTabExtraMargin;
    1605                 }
    1606                 return array(round($tot),$res);
    1607             }
    1608         }
    1609         elseif( is_object($this->iText) ) {
    1610             // A single icon
    1611             return $this->iText->GetWidth()+2*$extra_margin;
    1612         }
    1613         elseif( is_array($this->iText) ) {
    1614             // Must be an array of texts. In this case we return the sum of the
    1615             // length + a fixed margin of 4 pixels on each text string
    1616             $n = count($this->iText);
    1617             for( $i=0, $w=0; $i < $n; ++$i ) {
    1618                 $tmp = $this->iText[$i];
    1619                 if( is_string($tmp) ) {
    1620                     $w += $aImg->GetTextWidth($tmp)+$extra_margin;
    1621                 }
    1622                 else {
    1623                     if( is_object($tmp) === false ) {
    1624                         JpGraphError::RaiseL(6012);
    1625                     }
    1626                     $w += $tmp->GetWidth()+$extra_margin;
    1627                 }
    1628             }
    1629             return $w;
    1630         }
    1631         else {
    1632             JpGraphError::RaiseL(6012);
    1633         }
     1647        $extra_margin=4;
     1648        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1649        if( is_string($this->iText) ) {
     1650            if( strlen($this->iText) == 0 ) return 0;
     1651            $tmp = preg_split('/\t/',$this->iText);
     1652            if( count($tmp) <= 1 || !$aUseTabs ) {
     1653                $w = $aImg->GetTextWidth($this->iText);
     1654                return $w + 2*$extra_margin;
     1655            }
     1656            else {
     1657                $tot=0;
     1658                $n = count($tmp);
     1659                for($i=0; $i < $n; ++$i) {
     1660                    $res[$i] = $aImg->GetTextWidth($tmp[$i]);
     1661                    $tot += $res[$i]*$aTabExtraMargin;
     1662                }
     1663                return array(round($tot),$res);
     1664            }
     1665        }
     1666        elseif( is_object($this->iText) ) {
     1667            // A single icon
     1668            return $this->iText->GetWidth()+2*$extra_margin;
     1669        }
     1670        elseif( is_array($this->iText) ) {
     1671            // Must be an array of texts. In this case we return the sum of the
     1672            // length + a fixed margin of 4 pixels on each text string
     1673            $n = count($this->iText);
     1674            $nf = count($this->iFontArray);
     1675            for( $i=0, $w=0; $i < $n; ++$i ) {
     1676                if( $i < $nf ) {
     1677                    $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]);
     1678                }
     1679                else {
     1680                    $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1681                }
     1682                $tmp = $this->iText[$i];
     1683                if( is_string($tmp) ) {
     1684                    $w += $aImg->GetTextWidth($tmp)+$extra_margin;
     1685                }
     1686                else {
     1687                    if( is_object($tmp) === false ) {
     1688                        JpGraphError::RaiseL(6012);
     1689                    }
     1690                    $w += $tmp->GetWidth()+$extra_margin;
     1691                }
     1692            }
     1693            return $w;
     1694        }
     1695        else {
     1696            JpGraphError::RaiseL(6012);
     1697        }
    16341698    }
    16351699
     
    16381702    // column as an array of one
    16391703    function GetColWidth($aImg,$aMargin=0) {
    1640         $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    1641         if( is_array($this->iText) ) {
    1642             $n = count($this->iText);
    1643             for( $i=0, $w=array(); $i < $n; ++$i ) {
    1644                 $tmp = $this->iText[$i];
    1645                 if( is_string($tmp) ) {
    1646                     $w[$i] = $aImg->GetTextWidth($this->iText[$i])+$aMargin;
    1647                 }
    1648                 else {
    1649                     if( is_object($tmp) === false ) {
    1650                         JpGraphError::RaiseL(6012);
    1651                     }
    1652                     $w[$i] = $tmp->GetWidth()+$aMargin;
    1653                 }
    1654             }
    1655             return $w; 
    1656         }
    1657         else {
    1658             return array($this->GetWidth($aImg));
    1659         }
    1660     }
    1661        
     1704        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1705        if( is_array($this->iText) ) {
     1706            $n = count($this->iText);
     1707            $nf = count($this->iFontArray);
     1708            for( $i=0, $w=array(); $i < $n; ++$i ) {
     1709                $tmp = $this->iText[$i];
     1710                if( is_string($tmp) ) {
     1711                    if( $i < $nf ) {
     1712                        $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]);
     1713                    }
     1714                    else {
     1715                        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1716                    }
     1717                    $w[$i] = $aImg->GetTextWidth($tmp)+$aMargin;
     1718                }
     1719                else {
     1720                    if( is_object($tmp) === false ) {
     1721                        JpGraphError::RaiseL(6012);
     1722                    }
     1723                    $w[$i] = $tmp->GetWidth()+$aMargin;
     1724                }
     1725            }
     1726            return $w;
     1727        }
     1728        else {
     1729            return array($this->GetWidth($aImg));
     1730        }
     1731    }
     1732
    16621733    // Get total height of text
    16631734    function GetHeight($aImg) {
    1664         $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    1665         return $aImg->GetFontHeight();
    1666     }
    1667        
    1668     // Unhide/hide the text     
     1735        $nf = count($this->iFontArray);
     1736        $maxheight = -1;
     1737
     1738        if( $nf > 0 ) {
     1739            // We have to find out the largest font and take that one as the
     1740            // height of the row
     1741            for($i=0; $i < $nf; ++$i ) {
     1742                $aImg->SetFont($this->iFontArray[$i][0],$this->iFontArray[$i][1],$this->iFontArray[$i][2]);
     1743                $height = $aImg->GetFontHeight();
     1744                $maxheight = max($height,$maxheight);
     1745            }
     1746        }
     1747
     1748        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1749        $height = $aImg->GetFontHeight();
     1750        $maxheight = max($height,$maxheight);
     1751        return $maxheight;
     1752    }
     1753
     1754    // Unhide/hide the text
    16691755    function Show($aShow=true) {
    1670         $this->iShow=$aShow;
    1671     }
    1672        
     1756        $this->iShow=$aShow;
     1757    }
     1758
    16731759    // Stroke text at (x,y) coordinates. If the text contains tabs then the
    16741760    // x parameter should be an array of positions to be used for each successive
    16751761    // tab mark. If no array is supplied then the tabs will be ignored.
    16761762    function Stroke($aImg,$aX,$aY) {
    1677         if( $this->iShow ) {
    1678             $aImg->SetColor($this->iColor);
    1679             $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    1680             $aImg->SetTextAlign($this->iHAlign,$this->iVAlign);                 
    1681             if( $this->GetNbrTabs() <= 1 ) {
    1682                 if( is_string($this->iText) ) {
    1683                     // Get rid of any "\t" characters and stroke string
    1684                     if( is_array($aX) ) $aX=$aX[0];
    1685                     if( is_array($aY) ) $aY=$aY[0];
    1686                     $aImg->StrokeText($aX,$aY,str_replace("\t"," ",$this->iText));
    1687                 }
    1688                 elseif( is_array($this->iText) && ($n = count($this->iText)) > 0 ) {
    1689                     $ax = is_array($aX) ;
    1690                     $ay = is_array($aY) ;
    1691                     if( $ax && $ay ) {
    1692                         // Nothing; both are already arrays
    1693                     }
    1694                     elseif( $ax ) {
    1695                         $aY = array_fill(0,$n,$aY);
    1696                     }
    1697                     elseif( $ay ) {
    1698                         $aX = array_fill(0,$n,$aX);
    1699                     }
    1700                     else {
    1701                         $aX = array_fill(0,$n,$aX);
    1702                         $aY = array_fill(0,$n,$aY);
    1703                     }
    1704                     $n = min($n, count($aX) ) ;
    1705                     $n = min($n, count($aY) ) ;
    1706                     for($i=0; $i < $n; ++$i ) {
    1707                         $tmp = $this->iText[$i];
    1708                         if( is_object($tmp) ) {
    1709                             $tmp->Stroke($aImg,$aX[$i],$aY[$i]);
    1710                         }
    1711                         else
    1712                             $aImg->StrokeText($aX[$i],$aY[$i],str_replace("\t"," ",$tmp));
    1713                     }
    1714                 }
    1715             }
    1716             else {
    1717                 $tmp = split("\t",$this->iText);
    1718                 $n = min(count($tmp),count($aX));
    1719                 for($i=0; $i < $n; ++$i) {
    1720                     $aImg->StrokeText($aX[$i],$aY,$tmp[$i]);
    1721                 }       
    1722             }
    1723         }
     1763        if( $this->iShow ) {
     1764            $aImg->SetColor($this->iColor);
     1765            $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1766            $aImg->SetTextAlign($this->iHAlign,$this->iVAlign);
     1767            if( $this->GetNbrTabs() < 1 ) {
     1768                if( is_string($this->iText) ) {
     1769                    if( is_array($aX) ) $aX=$aX[0];
     1770                    if( is_array($aY) ) $aY=$aY[0];
     1771                    $aImg->StrokeText($aX,$aY,$this->iText);
     1772                }
     1773                elseif( is_array($this->iText) && ($n = count($this->iText)) > 0 ) {
     1774                    $ax = is_array($aX) ;
     1775                    $ay = is_array($aY) ;
     1776                    if( $ax && $ay ) {
     1777                        // Nothing; both are already arrays
     1778                    }
     1779                    elseif( $ax ) {
     1780                        $aY = array_fill(0,$n,$aY);
     1781                    }
     1782                    elseif( $ay ) {
     1783                        $aX = array_fill(0,$n,$aX);
     1784                    }
     1785                    else {
     1786                        $aX = array_fill(0,$n,$aX);
     1787                        $aY = array_fill(0,$n,$aY);
     1788                    }
     1789                    $n = min($n, count($aX) ) ;
     1790                    $n = min($n, count($aY) ) ;
     1791                    for($i=0; $i < $n; ++$i ) {
     1792                        $tmp = $this->iText[$i];
     1793                        if( is_object($tmp) ) {
     1794                            $tmp->Stroke($aImg,$aX[$i],$aY[$i]);
     1795                        }
     1796                        else {
     1797                            if( $i < count($this->iFontArray) ) {
     1798                                $font = $this->iFontArray[$i];
     1799                                $aImg->SetFont($font[0],$font[1],$font[2]);
     1800                            }
     1801                            else {
     1802                                $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1803                            }
     1804                                $aImg->StrokeText($aX[$i],$aY[$i],str_replace("\t"," ",$tmp));
     1805                        }
     1806                    }
     1807                }
     1808            }
     1809            else {
     1810                $tmp = preg_split('/\t/',$this->iText);
     1811                $n = min(count($tmp),count($aX));
     1812                for($i=0; $i < $n; ++$i) {
     1813                    if( $i < count($this->iFontArray) ) {
     1814                        $font = $this->iFontArray[$i];
     1815                        $aImg->SetFont($font[0],$font[1],$font[2]);
     1816                    }
     1817                    else {
     1818                        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1819                    }
     1820                    $aImg->StrokeText($aX[$i],$aY,$tmp[$i]);
     1821                }
     1822            }
     1823        }
    17241824    }
    17251825}
     
    17271827//===================================================
    17281828// CLASS HeaderProperty
    1729 // Description: Data encapsulating class to hold property 
     1829// Description: Data encapsulating class to hold property
    17301830// for each type of the scale headers
    17311831//===================================================
     
    17421842    public $iIntervall = 1;
    17431843
    1744 //---------------
    1745 // CONSTRUCTOR 
    1746     function HeaderProperty() {
    1747         $this->grid = new LineProperty();
    1748     }
    1749 
    1750 //---------------
    1751 // PUBLIC METHODS               
     1844    //---------------
     1845    // CONSTRUCTOR
     1846    function __construct() {
     1847        $this->grid = new LineProperty();
     1848    }
     1849
     1850    //---------------
     1851    // PUBLIC METHODS
    17521852    function Show($aShow=true) {
    1753         $this->iShowLabels = $aShow;
     1853        $this->iShowLabels = $aShow;
    17541854    }
    17551855
    17561856    function SetIntervall($aInt) {
    1757         $this->iIntervall = $aInt;
     1857        $this->iIntervall = $aInt;
     1858    }
     1859
     1860    function SetInterval($aInt) {
     1861        $this->iIntervall = $aInt;
    17581862    }
    17591863
    17601864    function GetIntervall() {
    1761         return $this->iIntervall ;
    1762     }
    1763        
     1865        return $this->iIntervall ;
     1866    }
     1867
    17641868    function SetFont($aFFamily,$aFStyle=FS_NORMAL,$aFSize=10) {
    1765         $this->iFFamily = $aFFamily;
    1766         $this->iFStyle  = $aFStyle;
    1767         $this->iFSize    = $aFSize;
     1869        $this->iFFamily = $aFFamily;
     1870        $this->iFStyle = $aFStyle;
     1871        $this->iFSize = $aFSize;
    17681872    }
    17691873
    17701874    function SetFontColor($aColor) {
    1771         $this->iTextColor = $aColor;
    1772     }
    1773        
     1875        $this->iTextColor = $aColor;
     1876    }
     1877
    17741878    function GetFontHeight($aImg) {
    1775         $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    1776         return $aImg->GetFontHeight();
     1879        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1880        return $aImg->GetFontHeight();
    17771881    }
    17781882
    17791883    function GetFontWidth($aImg) {
    1780         $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    1781         return $aImg->GetFontWidth();
     1884        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1885        return $aImg->GetFontWidth();
    17821886    }
    17831887
    17841888    function GetStrWidth($aImg,$aStr) {
    1785         $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
    1786         return $aImg->GetTextWidth($aStr);
    1787     }
    1788        
     1889        $aImg->SetFont($this->iFFamily,$this->iFStyle,$this->iFSize);
     1890        return $aImg->GetTextWidth($aStr);
     1891    }
     1892
    17891893    function SetStyle($aStyle) {
    1790         $this->iStyle = $aStyle;
    1791     }
    1792        
     1894        $this->iStyle = $aStyle;
     1895    }
     1896
    17931897    function SetBackgroundColor($aColor) {
    1794         $this->iBackgroundColor=$aColor;
     1898        $this->iBackgroundColor=$aColor;
    17951899    }
    17961900
    17971901    function SetFrameWeight($aWeight) {
    1798         $this->iFrameWeight=$aWeight;
     1902        $this->iFrameWeight=$aWeight;
    17991903    }
    18001904
    18011905    function SetFrameColor($aColor) {
    1802         $this->iFrameColor=$aColor;
    1803     }
    1804        
     1906        $this->iFrameColor=$aColor;
     1907    }
     1908
    18051909    // Only used by day scale
    18061910    function SetWeekendColor($aColor) {
    1807         $this->iWeekendBackgroundColor=$aColor;
    1808     }
    1809        
     1911        $this->iWeekendBackgroundColor=$aColor;
     1912    }
     1913
    18101914    // Only used by day scale
    18111915    function SetSundayFontColor($aColor) {
    1812         $this->iSundayTextColor=$aColor;
    1813     }
    1814        
     1916        $this->iSundayTextColor=$aColor;
     1917    }
     1918
    18151919    function SetTitleVertMargin($aMargin) {
    1816         $this->iTitleVertMargin=$aMargin;
    1817     }
    1818        
     1920        $this->iTitleVertMargin=$aMargin;
     1921    }
     1922
    18191923    function SetLabelFormatString($aStr) {
    1820         $this->iLabelFormStr=$aStr;
     1924        $this->iLabelFormStr=$aStr;
    18211925    }
    18221926
    18231927    function SetFormatString($aStr) {
    1824         $this->SetLabelFormatString($aStr);
     1928        $this->SetLabelFormatString($aStr);
    18251929    }
    18261930
     
    18441948    public $actinfo;
    18451949    public $iTopPlotMargin=10,$iBottomPlotMargin=15;
    1846     public $iVertLines=-1;     
     1950    public $iVertLines=-1;
    18471951    public $iVertHeaderSize=-1;
    18481952    // The width of the labels (defaults to the widest of all labels)
    1849     private $iLabelWidth;       
     1953    private $iLabelWidth;
    18501954    // Out image to stroke the scale to
    1851     private $iImg;     
     1955    private $iImg;
    18521956    private $iTableHeaderBackgroundColor="white",$iTableHeaderFrameColor="black";
    18531957    private $iTableHeaderFrameWeight=1;
     
    18561960    private $iVertLayout=GANTT_EVEN;
    18571961    private $iUsePlotWeekendBackground=true;
    1858     private $iWeekStart = 1;    // Default to have weekends start on Monday
    1859        
    1860 //---------------
    1861 // CONSTRUCTOR 
    1862     function GanttScale($aImg) {
    1863         $this->iImg = $aImg;           
    1864         $this->iDateLocale = new DateLocale();
    1865 
    1866         $this->minute = new HeaderProperty();
    1867         $this->minute->SetIntervall(15);
    1868         $this->minute->SetLabelFormatString('i');
    1869         $this->minute->SetFont(FF_FONT0);
    1870         $this->minute->grid->SetColor("gray");
    1871 
    1872         $this->hour = new HeaderProperty();
    1873         $this->hour->SetFont(FF_FONT0);
    1874         $this->hour->SetIntervall(6);
    1875         $this->hour->SetStyle(HOURSTYLE_HM24);
    1876         $this->hour->SetLabelFormatString('H:i');
    1877         $this->hour->grid->SetColor("gray");
    1878 
    1879         $this->day = new HeaderProperty();
    1880         $this->day->grid->SetColor("gray");
    1881         $this->day->SetLabelFormatString('l');
    1882 
    1883         $this->week = new HeaderProperty();
    1884         $this->week->SetLabelFormatString("w%d");
    1885         $this->week->SetFont(FF_FONT1);
    1886 
    1887         $this->month = new HeaderProperty();
    1888         $this->month->SetFont(FF_FONT1,FS_BOLD);
    1889 
    1890         $this->year = new HeaderProperty();
    1891         $this->year->SetFont(FF_FONT1,FS_BOLD);         
    1892                
    1893         $this->divider=new LineProperty();
    1894         $this->dividerh=new LineProperty();             
    1895         $this->dividerh->SetWeight(2);
    1896         $this->divider->SetWeight(6);
    1897         $this->divider->SetColor('gray');
    1898         $this->divider->SetStyle('fancy');
    1899 
    1900         $this->tableTitle=new TextProperty();
    1901         $this->tableTitle->Show(false);
    1902         $this->actinfo = new GanttActivityInfo();
    1903     }
    1904        
    1905 //---------------
    1906 // PUBLIC METHODS       
     1962    private $iWeekStart = 1; // Default to have weekends start on Monday
     1963
     1964    //---------------
     1965    // CONSTRUCTOR
     1966    function __construct($aImg) {
     1967        $this->iImg = $aImg;
     1968        $this->iDateLocale = new DateLocale();
     1969
     1970        $this->minute = new HeaderProperty();
     1971        $this->minute->SetIntervall(15);
     1972        $this->minute->SetLabelFormatString('i');
     1973        $this->minute->SetFont(FF_FONT0);
     1974        $this->minute->grid->SetColor("gray");
     1975
     1976        $this->hour = new HeaderProperty();
     1977        $this->hour->SetFont(FF_FONT0);
     1978        $this->hour->SetIntervall(6);
     1979        $this->hour->SetStyle(HOURSTYLE_HM24);
     1980        $this->hour->SetLabelFormatString('H:i');
     1981        $this->hour->grid->SetColor("gray");
     1982
     1983        $this->day = new HeaderProperty();
     1984        $this->day->grid->SetColor("gray");
     1985        $this->day->SetLabelFormatString('l');
     1986
     1987        $this->week = new HeaderProperty();
     1988        $this->week->SetLabelFormatString("w%d");
     1989        $this->week->SetFont(FF_FONT1);
     1990
     1991        $this->month = new HeaderProperty();
     1992        $this->month->SetFont(FF_FONT1,FS_BOLD);
     1993
     1994        $this->year = new HeaderProperty();
     1995        $this->year->SetFont(FF_FONT1,FS_BOLD);
     1996
     1997        $this->divider=new LineProperty();
     1998        $this->dividerh=new LineProperty();
     1999        $this->dividerh->SetWeight(2);
     2000        $this->divider->SetWeight(6);
     2001        $this->divider->SetColor('gray');
     2002        $this->divider->SetStyle('fancy');
     2003
     2004        $this->tableTitle=new TextProperty();
     2005        $this->tableTitle->Show(false);
     2006        $this->actinfo = new GanttActivityInfo();
     2007    }
     2008
     2009    //---------------
     2010    // PUBLIC METHODS
    19072011    // Specify what headers should be visible
    19082012    function ShowHeaders($aFlg) {
    1909         $this->day->Show($aFlg & GANTT_HDAY);
    1910         $this->week->Show($aFlg & GANTT_HWEEK);
    1911         $this->month->Show($aFlg & GANTT_HMONTH);
    1912         $this->year->Show($aFlg & GANTT_HYEAR);
    1913         $this->hour->Show($aFlg & GANTT_HHOUR);
    1914         $this->minute->Show($aFlg & GANTT_HMIN);
    1915 
    1916         // Make some default settings of gridlines whihc makes sense
    1917         if( $aFlg & GANTT_HWEEK ) {
    1918             $this->month->grid->Show(false);
    1919             $this->year->grid->Show(false);
    1920         }
    1921         if( $aFlg & GANTT_HHOUR ) {
    1922             $this->day->grid->SetColor("black");
    1923         }
    1924     }
    1925        
     2013        $this->day->Show($aFlg & GANTT_HDAY);
     2014        $this->week->Show($aFlg & GANTT_HWEEK);
     2015        $this->month->Show($aFlg & GANTT_HMONTH);
     2016        $this->year->Show($aFlg & GANTT_HYEAR);
     2017        $this->hour->Show($aFlg & GANTT_HHOUR);
     2018        $this->minute->Show($aFlg & GANTT_HMIN);
     2019
     2020        // Make some default settings of gridlines whihc makes sense
     2021        if( $aFlg & GANTT_HWEEK ) {
     2022            $this->month->grid->Show(false);
     2023            $this->year->grid->Show(false);
     2024        }
     2025        if( $aFlg & GANTT_HHOUR ) {
     2026            $this->day->grid->SetColor("black");
     2027        }
     2028    }
     2029
    19262030    // Should the weekend background stretch all the way down in the plotarea
    19272031    function UseWeekendBackground($aShow) {
    1928         $this->iUsePlotWeekendBackground = $aShow;
    1929     }
    1930        
     2032        $this->iUsePlotWeekendBackground = $aShow;
     2033    }
     2034
    19312035    // Have a range been specified?
    19322036    function IsRangeSet() {
    1933         return $this->iStartDate!=-1 && $this->iEndDate!=-1;
    1934     }
    1935        
     2037        return $this->iStartDate!=-1 && $this->iEndDate!=-1;
     2038    }
     2039
    19362040    // Should the layout be from top or even?
    19372041    function SetVertLayout($aLayout) {
    1938         $this->iVertLayout = $aLayout;
    1939     }
    1940        
     2042        $this->iVertLayout = $aLayout;
     2043    }
     2044
    19412045    // Which locale should be used?
    19422046    function SetDateLocale($aLocale) {
    1943         $this->iDateLocale->Set($aLocale);
    1944     }
    1945        
     2047        $this->iDateLocale->Set($aLocale);
     2048    }
     2049
    19462050    // Number of days we are showing
    19472051    function GetNumberOfDays() {
    1948         return round(($this->iEndDate-$this->iStartDate)/SECPERDAY);
    1949     }
    1950        
     2052        return round(($this->iEndDate-$this->iStartDate)/SECPERDAY);
     2053    }
     2054
    19512055    // The width of the actual plot area
    19522056    function GetPlotWidth() {
    1953         $img=$this->iImg;
    1954         return $img->width - $img->left_margin - $img->right_margin;
     2057        $img=$this->iImg;
     2058        return $img->width - $img->left_margin - $img->right_margin;
    19552059    }
    19562060
     
    19592063    // widest title)
    19602064    function SetLabelWidth($aLabelWidth) {
    1961         $this->iLabelWidth=$aLabelWidth;
    1962     }
    1963 
    1964         // Which day should the week start?
    1965         // 0==Sun, 1==Monday, 2==Tuesday etc
     2065        $this->iLabelWidth=$aLabelWidth;
     2066    }
     2067
     2068    // Which day should the week start?
     2069    // 0==Sun, 1==Monday, 2==Tuesday etc
    19662070    function SetWeekStart($aStartDay) {
    1967         $this->iWeekStart = $aStartDay % 7;
    1968        
    1969         //Recalculate the startday since this will change the week start
    1970         $this->SetRange($this->iStartDate,$this->iEndDate);
     2071        $this->iWeekStart = $aStartDay % 7;
     2072
     2073        //Recalculate the startday since this will change the week start
     2074        $this->SetRange($this->iStartDate,$this->iEndDate);
    19712075    }
    19722076
    19732077    // Do we show min scale?
    19742078    function IsDisplayMinute() {
    1975         return $this->minute->iShowLabels;
     2079        return $this->minute->iShowLabels;
    19762080    }
    19772081
    19782082    // Do we show day scale?
    19792083    function IsDisplayHour() {
    1980         return $this->hour->iShowLabels;
    1981     }
    1982 
    1983        
     2084        return $this->hour->iShowLabels;
     2085    }
     2086
     2087
    19842088    // Do we show day scale?
    19852089    function IsDisplayDay() {
    1986         return $this->day->iShowLabels;
    1987     }
    1988        
     2090        return $this->day->iShowLabels;
     2091    }
     2092
    19892093    // Do we show week scale?
    19902094    function IsDisplayWeek() {
    1991         return $this->week->iShowLabels;
    1992     }
    1993        
     2095        return $this->week->iShowLabels;
     2096    }
     2097
    19942098    // Do we show month scale?
    19952099    function IsDisplayMonth() {
    1996         return $this->month->iShowLabels;
    1997     }
    1998        
     2100        return $this->month->iShowLabels;
     2101    }
     2102
    19992103    // Do we show year scale?
    20002104    function IsDisplayYear() {
    2001         return $this->year->iShowLabels;
     2105        return $this->year->iShowLabels;
    20022106    }
    20032107
    20042108    // Specify spacing (in percent of bar height) between activity bars
    20052109    function SetVertSpacing($aSpacing) {
    2006         $this->iVertSpacing = $aSpacing;
     2110        $this->iVertSpacing = $aSpacing;
    20072111    }
    20082112
     
    20102114    // Always round to the nearest week boundary
    20112115    function SetRange($aMin,$aMax) {
    2012         $this->iStartDate = $this->NormalizeDate($aMin);
    2013         $this->iEndDate = $this->NormalizeDate($aMax); 
     2116        $this->iStartDate = $this->NormalizeDate($aMin);
     2117        $this->iEndDate = $this->NormalizeDate($aMax);
    20142118    }
    20152119
     
    20192123    function AdjustStartEndDay() {
    20202124
    2021         if( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) {
    2022             // Don't adjust
    2023             return;
    2024         }
    2025 
    2026         // Get day in week for start and ending date (Sun==0)
    2027         $ds=strftime("%w",$this->iStartDate);
    2028         $de=strftime("%w",$this->iEndDate);     
    2029        
    2030         // We want to start on iWeekStart day. But first we subtract a week
    2031         // if the startdate is "behind" the day the week start at.
    2032         // This way we ensure that the given start date is always included
    2033         // in the range. If we don't do this the nearest correct weekday in the week
    2034         // to start at might be later than the start date.
    2035         if( $ds < $this->iWeekStart )
    2036             $d = strtotime('-7 day',$this->iStartDate);
    2037         else
    2038             $d = $this->iStartDate;
    2039         $adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ );
    2040         $this->iStartDate = $adjdate;
    2041        
    2042         // We want to end on the last day of the week
    2043         $preferredEndDay = ($this->iWeekStart+6)%7;
    2044         if( $preferredEndDay != $de ) {
    2045             // Solve equivalence eq:    $de + x ~ $preferredDay (mod 7)
    2046             $adj = (7+($preferredEndDay - $de)) % 7;
    2047             $adjdate = strtotime("+$adj day",$this->iEndDate);
    2048             $this->iEndDate = $adjdate;
    2049         }       
    2050     }
    2051 
    2052     // Specify background for the table title area (upper left corner of the table)     
     2125        if( !($this->IsDisplayYear() ||$this->IsDisplayMonth() || $this->IsDisplayWeek()) ) {
     2126            // Don't adjust
     2127            return;
     2128        }
     2129
     2130        // Get day in week for start and ending date (Sun==0)
     2131        $ds=strftime("%w",$this->iStartDate);
     2132        $de=strftime("%w",$this->iEndDate);
     2133
     2134        // We want to start on iWeekStart day. But first we subtract a week
     2135        // if the startdate is "behind" the day the week start at.
     2136        // This way we ensure that the given start date is always included
     2137        // in the range. If we don't do this the nearest correct weekday in the week
     2138        // to start at might be later than the start date.
     2139        if( $ds < $this->iWeekStart )
     2140        $d = strtotime('-7 day',$this->iStartDate);
     2141        else
     2142        $d = $this->iStartDate;
     2143        $adjdate = strtotime(($this->iWeekStart-$ds).' day',$d /*$this->iStartDate*/ );
     2144        $this->iStartDate = $adjdate;
     2145
     2146        // We want to end on the last day of the week
     2147        $preferredEndDay = ($this->iWeekStart+6)%7;
     2148        if( $preferredEndDay != $de ) {
     2149            // Solve equivalence eq:    $de + x ~ $preferredDay (mod 7)
     2150            $adj = (7+($preferredEndDay - $de)) % 7;
     2151            $adjdate = strtotime("+$adj day",$this->iEndDate);
     2152            $this->iEndDate = $adjdate;
     2153        }
     2154    }
     2155
     2156    // Specify background for the table title area (upper left corner of the table)
    20532157    function SetTableTitleBackground($aColor) {
    2054         $this->iTableHeaderBackgroundColor = $aColor;
    2055     }
    2056 
    2057 ///////////////////////////////////////
    2058 // PRIVATE Methods
    2059        
     2158        $this->iTableHeaderBackgroundColor = $aColor;
     2159    }
     2160
     2161    ///////////////////////////////////////
     2162    // PRIVATE Methods
     2163
    20602164    // Determine the height of all the scale headers combined
    20612165    function GetHeaderHeight() {
    2062         $img=$this->iImg;
    2063         $height=1;
    2064         if( $this->minute->iShowLabels ) {
    2065             $height += $this->minute->GetFontHeight($img);
    2066             $height += $this->minute->iTitleVertMargin;
    2067         }
    2068         if( $this->hour->iShowLabels ) {
    2069             $height += $this->hour->GetFontHeight($img);
    2070             $height += $this->hour->iTitleVertMargin;
    2071         }
    2072         if( $this->day->iShowLabels ) {
    2073             $height += $this->day->GetFontHeight($img);
    2074             $height += $this->day->iTitleVertMargin;
    2075         }
    2076         if( $this->week->iShowLabels ) {
    2077             $height += $this->week->GetFontHeight($img);
    2078             $height += $this->week->iTitleVertMargin;
    2079         }
    2080         if( $this->month->iShowLabels ) {
    2081             $height += $this->month->GetFontHeight($img);
    2082             $height += $this->month->iTitleVertMargin;
    2083         }
    2084         if( $this->year->iShowLabels ) {
    2085             $height += $this->year->GetFontHeight($img);
    2086             $height += $this->year->iTitleVertMargin;
    2087         }
    2088         return $height;
    2089     }
    2090        
     2166        $img=$this->iImg;
     2167        $height=1;
     2168        if( $this->minute->iShowLabels ) {
     2169            $height += $this->minute->GetFontHeight($img);
     2170            $height += $this->minute->iTitleVertMargin;
     2171        }
     2172        if( $this->hour->iShowLabels ) {
     2173            $height += $this->hour->GetFontHeight($img);
     2174            $height += $this->hour->iTitleVertMargin;
     2175        }
     2176        if( $this->day->iShowLabels ) {
     2177            $height += $this->day->GetFontHeight($img);
     2178            $height += $this->day->iTitleVertMargin;
     2179        }
     2180        if( $this->week->iShowLabels ) {
     2181            $height += $this->week->GetFontHeight($img);
     2182            $height += $this->week->iTitleVertMargin;
     2183        }
     2184        if( $this->month->iShowLabels ) {
     2185            $height += $this->month->GetFontHeight($img);
     2186            $height += $this->month->iTitleVertMargin;
     2187        }
     2188        if( $this->year->iShowLabels ) {
     2189            $height += $this->year->GetFontHeight($img);
     2190            $height += $this->year->iTitleVertMargin;
     2191        }
     2192        return $height;
     2193    }
     2194
    20912195    // Get width (in pixels) for a single day
    20922196    function GetDayWidth() {
    2093         return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays();   
     2197        return ($this->GetPlotWidth()-$this->iLabelWidth+1)/$this->GetNumberOfDays();
    20942198    }
    20952199
    20962200    // Get width (in pixels) for a single hour
    20972201    function GetHourWidth() {
    2098         return $this->GetDayWidth() / 24 ;
     2202        return $this->GetDayWidth() / 24 ;
    20992203    }
    21002204
    21012205    function GetMinuteWidth() {
    2102         return $this->GetHourWidth() / 60 ;
     2206        return $this->GetHourWidth() / 60 ;
    21032207    }
    21042208
    21052209    // Nuber of days in a year
    21062210    function GetNumDaysInYear($aYear) {
    2107         if( $this->IsLeap($aYear) )
    2108             return 366;
    2109         else
    2110             return 365;
    2111     }
    2112        
    2113     // Get week number 
     2211        if( $this->IsLeap($aYear) )
     2212        return 366;
     2213        else
     2214        return 365;
     2215    }
     2216
     2217    // Get week number
    21142218    function GetWeekNbr($aDate,$aSunStart=true) {
    2115         // We can't use the internal strftime() since it gets the weeknumber
    2116         // wrong since it doesn't follow ISO on all systems since this is
    2117         // system linrary dependent.
    2118         // Even worse is that this works differently if we are on a Windows
    2119         // or UNIX box (it even differs between UNIX boxes how strftime()
    2120         // is natively implemented)
    2121         //
    2122         // Credit to Nicolas Hoizey <nhoizey@phpheaven.net> for this elegant
    2123         // version of Week Nbr calculation.
    2124 
    2125         $day = $this->NormalizeDate($aDate);
    2126         if( $aSunStart )
    2127             $day += 60*60*24;
    2128                
    2129         /*-------------------------------------------------------------------------
    2130           According to ISO-8601 :
    2131           "Week 01 of a year is per definition the first week that has the Thursday in this year,
    2132           which is equivalent to the week that contains the fourth day of January.
    2133           In other words, the first week of a new year is the week that has the majority of its
    2134           days in the new year."
    2135                  
    2136           Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!!
    2137                  
    2138           day of year             = date("z", $day) + 1
    2139           offset to thursday      = 3 - (date("w", $day) + 6) % 7
    2140           first thursday of year  = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7
    2141           week number             = (thursday's day of year - first thursday's day of year) / 7 + 1
    2142           ---------------------------------------------------------------------------*/
    2143                  
    2144         $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7);              // take week's thursday
    2145         $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7;
    2146                  
    2147         return $week;
    2148     }
    2149        
     2219        // We can't use the internal strftime() since it gets the weeknumber
     2220        // wrong since it doesn't follow ISO on all systems since this is
     2221        // system linrary dependent.
     2222        // Even worse is that this works differently if we are on a Windows
     2223        // or UNIX box (it even differs between UNIX boxes how strftime()
     2224        // is natively implemented)
     2225        //
     2226        // Credit to Nicolas Hoizey <nhoizey@phpheaven.net> for this elegant
     2227        // version of Week Nbr calculation.
     2228
     2229        $day = $this->NormalizeDate($aDate);
     2230        if( $aSunStart )
     2231        $day += 60*60*24;
     2232
     2233        /*-------------------------------------------------------------------------
     2234         According to ISO-8601 :
     2235         "Week 01 of a year is per definition the first week that has the Thursday in this year,
     2236         which is equivalent to the week that contains the fourth day of January.
     2237         In other words, the first week of a new year is the week that has the majority of its
     2238         days in the new year."
     2239
     2240         Be carefull, with PHP, -3 % 7 = -3, instead of 4 !!!
     2241
     2242         day of year             = date("z", $day) + 1
     2243         offset to thursday      = 3 - (date("w", $day) + 6) % 7
     2244         first thursday of year  = 1 + (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $day)))) % 7
     2245         week number             = (thursday's day of year - first thursday's day of year) / 7 + 1
     2246         ---------------------------------------------------------------------------*/
     2247
     2248        $thursday = $day + 60 * 60 * 24 * (3 - (date("w", $day) + 6) % 7);              // take week's thursday
     2249        $week = 1 + (date("z", $thursday) - (11 - date("w", mktime(0, 0, 0, 1, 1, date("Y", $thursday)))) % 7) / 7;
     2250
     2251        return $week;
     2252    }
     2253
    21502254    // Is year a leap year?
    21512255    function IsLeap($aYear) {
    2152         // Is the year a leap year?
    2153         //$year = 0+date("Y",$aDate);
    2154         if( $aYear % 4 == 0)
    2155             if( !($aYear % 100 == 0) || ($aYear % 400 == 0) )
    2156                 return true;
    2157         return false;
     2256        // Is the year a leap year?
     2257        //$year = 0+date("Y",$aDate);
     2258        if( $aYear % 4 == 0)
     2259        if( !($aYear % 100 == 0) || ($aYear % 400 == 0) )
     2260        return true;
     2261        return false;
    21582262    }
    21592263
    21602264    // Get current year
    21612265    function GetYear($aDate) {
    2162         return 0+Date("Y",$aDate);
    2163     }
    2164        
     2266        return 0+Date("Y",$aDate);
     2267    }
     2268
    21652269    // Return number of days in a year
    21662270    function GetNumDaysInMonth($aMonth,$aYear) {
    2167         $days=array(31,28,31,30,31,30,31,31,30,31,30,31);
    2168         $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31);
    2169         if( $this->IsLeap($aYear))
    2170             return $daysl[$aMonth];
    2171         else
    2172             return $days[$aMonth];
    2173     }
    2174        
     2271        $days=array(31,28,31,30,31,30,31,31,30,31,30,31);
     2272        $daysl=array(31,29,31,30,31,30,31,31,30,31,30,31);
     2273        if( $this->IsLeap($aYear))
     2274        return $daysl[$aMonth];
     2275        else
     2276        return $days[$aMonth];
     2277    }
     2278
    21752279    // Get day in month
    21762280    function GetMonthDayNbr($aDate) {
    2177         return 0+strftime("%d",$aDate);
     2281        return 0+strftime("%d",$aDate);
    21782282    }
    21792283
    21802284    // Get day in year
    21812285    function GetYearDayNbr($aDate) {
    2182         return 0+strftime("%j",$aDate);
    2183     }
    2184        
     2286        return 0+strftime("%j",$aDate);
     2287    }
     2288
    21852289    // Get month number
    21862290    function GetMonthNbr($aDate) {
    2187         return 0+strftime("%m",$aDate);
    2188     }
    2189        
    2190     // Translate a date to screen coordinates   (horizontal scale)
     2291        return 0+strftime("%m",$aDate);
     2292    }
     2293
     2294    // Translate a date to screen coordinates (horizontal scale)
    21912295    function TranslateDate($aDate) {
    2192         //
    2193         // In order to handle the problem with Daylight savings time
    2194         // the scale written with equal number of seconds per day beginning
    2195         // with the start date. This means that we "cement" the state of
    2196         // DST as it is in the start date. If later the scale includes the
    2197         // switchover date (depends on the locale) we need to adjust back
    2198         // if the date we try to translate has a different DST status since
    2199         // we would otherwise be off by one hour.
    2200         $aDate = $this->NormalizeDate($aDate);
    2201         $tmp = localtime($aDate);
    2202         $cloc = $tmp[8];
    2203         $tmp = localtime($this->iStartDate);
    2204         $sloc = $tmp[8];
    2205         $offset = 0;
    2206         if( $sloc != $cloc) {
    2207             if( $sloc )
    2208                 $offset = 3600;
    2209             else
    2210                 $offset = -3600;
    2211         }
    2212         $img=$this->iImg;               
    2213         return ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;;
    2214     }
    2215 
    2216     // Get screen coordinatesz for the vertical position for a bar             
    2217     function TranslateVertPos($aPos) {
    2218         $img=$this->iImg;
    2219         $ph=$this->iAvailableHeight;
    2220         if( $aPos > $this->iVertLines )
    2221             JpGraphError::RaiseL(6015,$aPos);
    2222 // 'Illegal vertical position %d'
    2223         if( $this->iVertLayout == GANTT_EVEN ) {
    2224             // Position the top bar at 1 vert spacing from the scale
    2225             return round($img->top_margin + $this->iVertHeaderSize +  ($aPos+1)*$this->iVertSpacing);
    2226         }
    2227         else {
    2228             // position the top bar at 1/2 a vert spacing from the scale
    2229             return round($img->top_margin + $this->iVertHeaderSize  + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing);           
    2230         }
    2231     }
    2232        
     2296        //
     2297        // In order to handle the problem with Daylight savings time
     2298        // the scale written with equal number of seconds per day beginning
     2299        // with the start date. This means that we "cement" the state of
     2300        // DST as it is in the start date. If later the scale includes the
     2301        // switchover date (depends on the locale) we need to adjust back
     2302        // if the date we try to translate has a different DST status since
     2303        // we would otherwise be off by one hour.
     2304        $aDate = $this->NormalizeDate($aDate);
     2305        $tmp = localtime($aDate);
     2306        $cloc = $tmp[8];
     2307        $tmp = localtime($this->iStartDate);
     2308        $sloc = $tmp[8];
     2309        $offset = 0;
     2310        if( $sloc != $cloc) {
     2311            if( $sloc )
     2312            $offset = 3600;
     2313            else
     2314            $offset = -3600;
     2315        }
     2316        $img=$this->iImg;
     2317        return ($aDate-$this->iStartDate-$offset)/SECPERDAY*$this->GetDayWidth()+$img->left_margin+$this->iLabelWidth;;
     2318    }
     2319
     2320    // Get screen coordinatesz for the vertical position for a bar
     2321    function TranslateVertPos($aPos,$atTop=false) {
     2322        $img=$this->iImg;
     2323        if( $aPos > $this->iVertLines )
     2324                JpGraphError::RaiseL(6015,$aPos);
     2325        // 'Illegal vertical position %d'
     2326        if( $this->iVertLayout == GANTT_EVEN ) {
     2327            // Position the top bar at 1 vert spacing from the scale
     2328            $pos =  round($img->top_margin + $this->iVertHeaderSize +  ($aPos+1)*$this->iVertSpacing);
     2329        }
     2330        else {
     2331            // position the top bar at 1/2 a vert spacing from the scale
     2332            $pos = round($img->top_margin + $this->iVertHeaderSize  + $this->iTopPlotMargin + ($aPos+1)*$this->iVertSpacing);
     2333        }
     2334
     2335        if( $atTop )
     2336            $pos -= $this->iVertSpacing;
     2337
     2338        return $pos;
     2339    }
     2340
    22332341    // What is the vertical spacing?
    22342342    function GetVertSpacing() {
    2235         return $this->iVertSpacing;
    2236     }
    2237                                        
     2343        return $this->iVertSpacing;
     2344    }
     2345
    22382346    // Convert a date to timestamp
    22392347    function NormalizeDate($aDate) {
    2240         if( $aDate === false ) return false;
    2241         if( is_string($aDate) ) {
    2242             $t = strtotime($aDate);
    2243             if( $t === FALSE || $t === -1 ) {
    2244                 JpGraphError::RaiseL(6016,$aDate);
    2245 //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30");
    2246             }
    2247             return $t;
    2248         }
    2249         elseif( is_int($aDate) || is_float($aDate) )
    2250             return $aDate;
    2251         else
    2252             JpGraphError::RaiseL(6017,$aDate);
    2253 //Unknown date format in GanttScale ($aDate).");
    2254     }
    2255 
    2256    
     2348        if( $aDate === false ) return false;
     2349        if( is_string($aDate) ) {
     2350            $t = strtotime($aDate);
     2351            if( $t === FALSE || $t === -1 ) {
     2352                JpGraphError::RaiseL(6016,$aDate);
     2353                //("Date string ($aDate) specified for Gantt activity can not be interpretated. Please make sure it is a valid time string, e.g. 2005-04-23 13:30");
     2354            }
     2355            return $t;
     2356        }
     2357        elseif( is_int($aDate) || is_float($aDate) )
     2358            return $aDate;
     2359        else
     2360            JpGraphError::RaiseL(6017,$aDate);
     2361        //Unknown date format in GanttScale ($aDate).");
     2362    }
     2363
     2364
    22572365    // Convert a time string to minutes
    22582366
    22592367    function TimeToMinutes($aTimeString) {
    2260         // Split in hours and minutes
    2261         $pos=strpos($aTimeString,':');
    2262         $minint=60;
    2263         if( $pos === false ) {
    2264             $hourint = $aTimeString;
    2265             $minint = 0;
    2266         }
    2267         else {
    2268             $hourint = floor(substr($aTimeString,0,$pos));
    2269             $minint = floor(substr($aTimeString,$pos+1));
    2270         }
    2271         $minint += 60 * $hourint;
    2272         return $minint;
    2273     }
    2274 
    2275     // Stroke the day scale (including gridlines)                       
     2368        // Split in hours and minutes
     2369        $pos=strpos($aTimeString,':');
     2370        $minint=60;
     2371        if( $pos === false ) {
     2372            $hourint = $aTimeString;
     2373            $minint = 0;
     2374        }
     2375        else {
     2376            $hourint = floor(substr($aTimeString,0,$pos));
     2377            $minint = floor(substr($aTimeString,$pos+1));
     2378        }
     2379        $minint += 60 * $hourint;
     2380        return $minint;
     2381    }
     2382
     2383    // Stroke the day scale (including gridlines)
    22762384    function StrokeMinutes($aYCoord,$getHeight=false) {
    2277         $img=$this->iImg;       
    2278         $xt=$img->left_margin+$this->iLabelWidth;
    2279         $yt=$aYCoord+$img->top_margin;         
    2280         if( $this->minute->iShowLabels ) {
    2281             $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize);
    2282             $yb = $yt + $img->GetFontHeight() +
    2283                   $this->minute->iTitleVertMargin + $this->minute->iFrameWeight;
    2284             if( $getHeight ) {
    2285                 return $yb - $img->top_margin;
    2286             }
    2287             $xb = $img->width-$img->right_margin+1;
    2288             $img->SetColor($this->minute->iBackgroundColor);
    2289             $img->FilledRectangle($xt,$yt,$xb,$yb);
    2290 
    2291             $x = $xt;   
    2292             $img->SetTextAlign("center");
    2293             $day = date('w',$this->iStartDate);
    2294             $minint = $this->minute->GetIntervall() ;
    2295            
    2296             if( 60 % $minint !== 0 ) {
     2385        $img=$this->iImg;
     2386        $xt=$img->left_margin+$this->iLabelWidth;
     2387        $yt=$aYCoord+$img->top_margin;
     2388        if( $this->minute->iShowLabels ) {
     2389            $img->SetFont($this->minute->iFFamily,$this->minute->iFStyle,$this->minute->iFSize);
     2390            $yb = $yt + $img->GetFontHeight() +
     2391            $this->minute->iTitleVertMargin + $this->minute->iFrameWeight;
     2392            if( $getHeight ) {
     2393                return $yb - $img->top_margin;
     2394            }
     2395            $xb = $img->width-$img->right_margin+1;
     2396            $img->SetColor($this->minute->iBackgroundColor);
     2397            $img->FilledRectangle($xt,$yt,$xb,$yb);
     2398
     2399            $x = $xt;
     2400            $img->SetTextAlign("center");
     2401            $day = date('w',$this->iStartDate);
     2402            $minint = $this->minute->GetIntervall() ;
     2403
     2404            if( 60 % $minint !== 0 ) {
    22972405                JpGraphError::RaiseL(6018,$minint);
    2298 //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.');
    2299             }
    2300 
    2301 
    2302             $n = 60 / $minint;
    2303             $datestamp = $this->iStartDate;
    2304             $width = $this->GetHourWidth() / $n ;
    2305             if( $width < 8 ) {
    2306                 // TO small width to draw minute scale
    2307                 JpGraphError::RaiseL(6019,$width);
    2308 //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.');
    2309             }
    2310 
    2311             $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) );
    2312             $nd = $this->GetNumberOfDays();
    2313             // Convert to intervall to seconds
    2314             $minint *= 60;
    2315             for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) {
    2316                 for( $k=0; $k < $nh; ++$k ) {
    2317                     for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) {   
    2318                         if( $day==6 || $day==0 ) {
    2319                        
    2320                             $img->PushColor($this->day->iWeekendBackgroundColor);
    2321                             if( $this->iUsePlotWeekendBackground )
    2322                                 $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin);                                             
    2323                             else
    2324                                 $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight);
    2325                             $img->PopColor();
    2326 
    2327                         }
    2328 
    2329                         if( $day==0 )
    2330                             $img->SetColor($this->day->iSundayTextColor);
    2331                         else
    2332                             $img->SetColor($this->day->iTextColor);
    2333 
    2334                         switch( $this->minute->iStyle ) {
    2335                             case MINUTESTYLE_CUSTOM:
    2336                                 $txt = date($this->minute->iLabelFormStr,$datestamp);
    2337                                 break;
    2338                             case MINUTESTYLE_MM:
    2339                             default:
    2340                                 // 15
    2341                                 $txt = date('i',$datestamp);
    2342                                 break;
    2343                         }
    2344                         $img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt);
    2345 
    2346                         // FIXME: The rounding problem needs to be solved properly ...
    2347                         //
    2348                         // Fix a rounding problem the wrong way ..
    2349                         // If we also have hour scale then don't draw the firsta or last
    2350                         // gridline since that will be overwritten by the hour scale gridline if such exists.
    2351                         // However, due to the propagation of rounding of the 'x+=width' term in the loop
    2352                         // this might sometimes be one pixel of so we fix this by not drawing it.
    2353                         // The proper way to fix it would be to re-calculate the scale for each step and
    2354                         // not using the additive term.
    2355                         if( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) {
    2356                             $img->SetColor($this->minute->grid->iColor);
    2357                             $img->SetLineWeight($this->minute->grid->iWeight);
    2358                             $img->Line($x,$yt,$x,$yb);
    2359                             $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
    2360                         }
    2361                     }           
    2362                 }       
    2363             }
    2364             $img->SetColor($this->minute->iFrameColor);
    2365             $img->SetLineWeight($this->minute->iFrameWeight);
    2366             $img->Rectangle($xt,$yt,$xb,$yb);
    2367             return $yb - $img->top_margin;
    2368         }
    2369         return $aYCoord;
    2370     }
    2371 
    2372     // Stroke the day scale (including gridlines)                       
     2406                //'Intervall for minutes must divide the hour evenly, e.g. 1,5,10,12,15,20,30 etc You have specified an intervall of '.$minint.' minutes.');
     2407            }
     2408
     2409
     2410            $n = 60 / $minint;
     2411            $datestamp = $this->iStartDate;
     2412            $width = $this->GetHourWidth() / $n ;
     2413            if( $width < 8 ) {
     2414                // TO small width to draw minute scale
     2415                JpGraphError::RaiseL(6019,$width);
     2416                //('The available width ('.$width.') for minutes are to small for this scale to be displayed. Please use auto-sizing or increase the width of the graph.');
     2417            }
     2418
     2419            $nh = ceil(24*60 / $this->TimeToMinutes($this->hour->GetIntervall()) );
     2420            $nd = $this->GetNumberOfDays();
     2421            // Convert to intervall to seconds
     2422            $minint *= 60;
     2423            for($j=0; $j < $nd; ++$j, $day += 1, $day %= 7) {
     2424                for( $k=0; $k < $nh; ++$k ) {
     2425                    for($i=0; $i < $n ;++$i, $x+=$width, $datestamp += $minint ) {
     2426                        if( $day==6 || $day==0 ) {
     2427
     2428                            $img->PushColor($this->day->iWeekendBackgroundColor);
     2429                            if( $this->iUsePlotWeekendBackground )
     2430                            $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin);
     2431                            else
     2432                            $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight);
     2433                            $img->PopColor();
     2434
     2435                        }
     2436
     2437                        if( $day==0 )
     2438                        $img->SetColor($this->day->iSundayTextColor);
     2439                        else
     2440                        $img->SetColor($this->day->iTextColor);
     2441
     2442                        switch( $this->minute->iStyle ) {
     2443                            case MINUTESTYLE_CUSTOM:
     2444                                $txt = date($this->minute->iLabelFormStr,$datestamp);
     2445                                break;
     2446                            case MINUTESTYLE_MM:
     2447                            default:
     2448                                // 15
     2449                                $txt = date('i',$datestamp);
     2450                                break;
     2451                        }
     2452                        $img->StrokeText(round($x+$width/2),round($yb-$this->minute->iTitleVertMargin),$txt);
     2453
     2454                        // Fix a rounding problem the wrong way ..
     2455                        // If we also have hour scale then don't draw the firsta or last
     2456                        // gridline since that will be overwritten by the hour scale gridline if such exists.
     2457                        // However, due to the propagation of rounding of the 'x+=width' term in the loop
     2458                        // this might sometimes be one pixel of so we fix this by not drawing it.
     2459                        // The proper way to fix it would be to re-calculate the scale for each step and
     2460                        // not using the additive term.
     2461                        if( !(($i == $n || $i==0) && $this->hour->iShowLabels && $this->hour->grid->iShow) ) {
     2462                            $img->SetColor($this->minute->grid->iColor);
     2463                            $img->SetLineWeight($this->minute->grid->iWeight);
     2464                            $img->Line($x,$yt,$x,$yb);
     2465                            $this->minute->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
     2466                        }
     2467                    }
     2468                }
     2469            }
     2470            $img->SetColor($this->minute->iFrameColor);
     2471            $img->SetLineWeight($this->minute->iFrameWeight);
     2472            $img->Rectangle($xt,$yt,$xb,$yb);
     2473            return $yb - $img->top_margin;
     2474        }
     2475        return $aYCoord;
     2476    }
     2477
     2478    // Stroke the day scale (including gridlines)
    23732479    function StrokeHours($aYCoord,$getHeight=false) {
    2374         $img=$this->iImg;       
    2375         $xt=$img->left_margin+$this->iLabelWidth;
    2376         $yt=$aYCoord+$img->top_margin;         
    2377         if( $this->hour->iShowLabels ) {
    2378             $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize);
    2379             $yb = $yt + $img->GetFontHeight() +
    2380                   $this->hour->iTitleVertMargin + $this->hour->iFrameWeight;
    2381             if( $getHeight ) {
    2382                 return $yb - $img->top_margin;
    2383             }
    2384             $xb = $img->width-$img->right_margin+1;
    2385             $img->SetColor($this->hour->iBackgroundColor);
    2386             $img->FilledRectangle($xt,$yt,$xb,$yb);
    2387 
    2388             $x = $xt;   
    2389             $img->SetTextAlign("center");
    2390             $tmp = $this->hour->GetIntervall() ;
    2391             $minint = $this->TimeToMinutes($tmp);
    2392             if( 1440 % $minint !== 0 ) {
     2480        $img=$this->iImg;
     2481        $xt=$img->left_margin+$this->iLabelWidth;
     2482        $yt=$aYCoord+$img->top_margin;
     2483        if( $this->hour->iShowLabels ) {
     2484            $img->SetFont($this->hour->iFFamily,$this->hour->iFStyle,$this->hour->iFSize);
     2485            $yb = $yt + $img->GetFontHeight() +
     2486            $this->hour->iTitleVertMargin + $this->hour->iFrameWeight;
     2487            if( $getHeight ) {
     2488                return $yb - $img->top_margin;
     2489            }
     2490            $xb = $img->width-$img->right_margin+1;
     2491            $img->SetColor($this->hour->iBackgroundColor);
     2492            $img->FilledRectangle($xt,$yt,$xb,$yb);
     2493
     2494            $x = $xt;
     2495            $img->SetTextAlign("center");
     2496            $tmp = $this->hour->GetIntervall() ;
     2497            $minint = $this->TimeToMinutes($tmp);
     2498            if( 1440 % $minint !== 0 ) {
    23932499                JpGraphError::RaiseL(6020,$tmp);
    2394 //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp);
    2395             } 
    2396 
    2397             $n = ceil(24*60 / $minint );
    2398             $datestamp = $this->iStartDate;
    2399             $day = date('w',$this->iStartDate);
    2400             $doback = !$this->minute->iShowLabels;
    2401             $width = $this->GetDayWidth() / $n ;
    2402             for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) {
    2403                 for($i=0; $i < $n ;++$i, $x+=$width) {   
    2404                     if( $day==6 || $day==0 ) {
    2405                        
    2406                         $img->PushColor($this->day->iWeekendBackgroundColor);
    2407                         if( $this->iUsePlotWeekendBackground && $doback )
    2408                             $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin);                                         
    2409                         else
    2410                             $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight);
    2411                         $img->PopColor();
    2412 
    2413                     }
    2414 
    2415                     if( $day==0 )
    2416                         $img->SetColor($this->day->iSundayTextColor);
    2417                     else
    2418                         $img->SetColor($this->day->iTextColor);
    2419 
    2420                     switch( $this->hour->iStyle ) {
    2421                         case HOURSTYLE_HMAMPM:
    2422                             // 1:35pm
    2423                             $txt = date('g:ia',$datestamp);
    2424                             break;
    2425                         case HOURSTYLE_H24:
    2426                             // 13
    2427                             $txt = date('H',$datestamp);
    2428                             break;
    2429                         case HOURSTYLE_HAMPM:
    2430                             $txt = date('ga',$datestamp);
    2431                             break;
    2432                         case HOURSTYLE_CUSTOM:
    2433                             $txt = date($this->hour->iLabelFormStr,$datestamp);
    2434                             break;
    2435                         case HOURSTYLE_HM24:
    2436                         default:
    2437                             $txt = date('H:i',$datestamp);
    2438                             break;
    2439                     }
    2440                     $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt);
    2441                     $img->SetColor($this->hour->grid->iColor);
    2442                     $img->SetLineWeight($this->hour->grid->iWeight);
    2443                     $img->Line($x,$yt,$x,$yb);
    2444                     $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
    2445                     //$datestamp += $minint*60
    2446                     $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0,
    2447                                         date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp));
    2448                    
    2449                 }                       
    2450             }
    2451             $img->SetColor($this->hour->iFrameColor);
    2452             $img->SetLineWeight($this->hour->iFrameWeight);
    2453             $img->Rectangle($xt,$yt,$xb,$yb);
    2454             return $yb - $img->top_margin;
    2455         }
    2456         return $aYCoord;
    2457     }
    2458 
    2459 
    2460     // Stroke the day scale (including gridlines)                       
     2500                //('Intervall for hours must divide the day evenly, e.g. 0:30, 1:00, 1:30, 4:00 etc. You have specified an intervall of '.$tmp);
     2501            }
     2502
     2503            $n = ceil(24*60 / $minint );
     2504            $datestamp = $this->iStartDate;
     2505            $day = date('w',$this->iStartDate);
     2506            $doback = !$this->minute->iShowLabels;
     2507            $width = $this->GetDayWidth() / $n ;
     2508            for($j=0; $j < $this->GetNumberOfDays(); ++$j, $day += 1,$day %= 7) {
     2509                for($i=0; $i < $n ;++$i, $x+=$width) {
     2510                    if( $day==6 || $day==0 ) {
     2511
     2512                        $img->PushColor($this->day->iWeekendBackgroundColor);
     2513                        if( $this->iUsePlotWeekendBackground && $doback )
     2514                        $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$img->height-$img->bottom_margin);
     2515                        else
     2516                        $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,$x+$width,$yb-$this->day->iFrameWeight);
     2517                        $img->PopColor();
     2518
     2519                    }
     2520
     2521                    if( $day==0 )
     2522                    $img->SetColor($this->day->iSundayTextColor);
     2523                    else
     2524                    $img->SetColor($this->day->iTextColor);
     2525
     2526                    switch( $this->hour->iStyle ) {
     2527                        case HOURSTYLE_HMAMPM:
     2528                            // 1:35pm
     2529                            $txt = date('g:ia',$datestamp);
     2530                            break;
     2531                        case HOURSTYLE_H24:
     2532                            // 13
     2533                            $txt = date('H',$datestamp);
     2534                            break;
     2535                        case HOURSTYLE_HAMPM:
     2536                            $txt = date('ga',$datestamp);
     2537                            break;
     2538                        case HOURSTYLE_CUSTOM:
     2539                            $txt = date($this->hour->iLabelFormStr,$datestamp);
     2540                            break;
     2541                        case HOURSTYLE_HM24:
     2542                        default:
     2543                            $txt = date('H:i',$datestamp);
     2544                            break;
     2545                    }
     2546                    $img->StrokeText(round($x+$width/2),round($yb-$this->hour->iTitleVertMargin),$txt);
     2547                    $img->SetColor($this->hour->grid->iColor);
     2548                    $img->SetLineWeight($this->hour->grid->iWeight);
     2549                    $img->Line($x,$yt,$x,$yb);
     2550                    $this->hour->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
     2551                    //$datestamp += $minint*60
     2552                    $datestamp = mktime(date('H',$datestamp),date('i',$datestamp)+$minint,0,
     2553                    date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp));
     2554
     2555                }
     2556            }
     2557            $img->SetColor($this->hour->iFrameColor);
     2558            $img->SetLineWeight($this->hour->iFrameWeight);
     2559            $img->Rectangle($xt,$yt,$xb,$yb);
     2560            return $yb - $img->top_margin;
     2561        }
     2562        return $aYCoord;
     2563    }
     2564
     2565
     2566    // Stroke the day scale (including gridlines)
    24612567    function StrokeDays($aYCoord,$getHeight=false) {
    2462         $img=$this->iImg;       
    2463         $daywidth=$this->GetDayWidth();
    2464         $xt=$img->left_margin+$this->iLabelWidth;
    2465         $yt=$aYCoord+$img->top_margin;         
    2466         if( $this->day->iShowLabels ) {
    2467             $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize);
    2468             $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight;
    2469             if( $getHeight ) {
    2470                 return $yb - $img->top_margin;
    2471             }
    2472             $xb=$img->width-$img->right_margin+1;
    2473             $img->SetColor($this->day->iBackgroundColor);
    2474             $img->FilledRectangle($xt,$yt,$xb,$yb);
    2475 
    2476             $x = $xt;   
    2477             $img->SetTextAlign("center");
    2478             $day = date('w',$this->iStartDate);
    2479             $datestamp = $this->iStartDate;
    2480            
    2481             $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels);
    2482 
    2483             setlocale(LC_TIME,$this->iDateLocale->iLocale);
    2484            
    2485             for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) {
    2486                 if( $day==6 || $day==0 ) {
    2487                     $img->SetColor($this->day->iWeekendBackgroundColor);
    2488                     if( $this->iUsePlotWeekendBackground && $doback)
    2489                         $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,
    2490                                               $x+$daywidth,$img->height-$img->bottom_margin);   
    2491                     else
    2492                         $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,
    2493                                               $x+$daywidth,$yb-$this->day->iFrameWeight);
    2494                 }
    2495 
    2496                 $mn = strftime('%m',$datestamp);
    2497                 if( $mn[0]=='0' )
    2498                     $mn = $mn[1];
    2499 
    2500                 switch( $this->day->iStyle ) {
    2501                     case DAYSTYLE_LONG:
    2502                         // "Monday"
    2503                         $txt = strftime('%A',$datestamp);
    2504                         break;
    2505                     case DAYSTYLE_SHORT:
    2506                         // "Mon"
    2507                         $txt = strftime('%a',$datestamp);
    2508                         break;
    2509                     case DAYSTYLE_SHORTDAYDATE1:
    2510                         // "Mon 23/6"
    2511                         $txt = strftime('%a %d/'.$mn,$datestamp);
    2512                         break;
    2513                     case DAYSTYLE_SHORTDAYDATE2:
    2514                         // "Mon 23 Jun"
    2515                         $txt = strftime('%a %d %b',$datestamp);
    2516                         break;
    2517                     case DAYSTYLE_SHORTDAYDATE3:
    2518                         // "Mon 23 Jun 2003"
    2519                         $txt = strftime('%a %d %b %Y',$datestamp);
    2520                         break;
    2521                     case DAYSTYLE_LONGDAYDATE1:
    2522                         // "Monday 23 Jun"
    2523                         $txt = strftime('%A %d %b',$datestamp);
    2524                         break;
    2525                     case DAYSTYLE_LONGDAYDATE2:
    2526                         // "Monday 23 Jun 2003"
    2527                         $txt = strftime('%A %d %b %Y',$datestamp);
    2528                         break;
    2529                     case DAYSTYLE_SHORTDATE1:
    2530                         // "23/6"
    2531                         $txt = strftime('%d/'.$mn,$datestamp);
    2532                         break;                 
    2533                     case DAYSTYLE_SHORTDATE2:
    2534                         // "23 Jun"
    2535                         $txt = strftime('%d %b',$datestamp);
    2536                         break;                 
    2537                     case DAYSTYLE_SHORTDATE3:
    2538                         // "Mon 23"
    2539                         $txt = strftime('%a %d',$datestamp);
    2540                         break; 
    2541                     case DAYSTYLE_SHORTDATE4:
    2542                         // "23"
    2543                         $txt = strftime('%d',$datestamp);
    2544                         break; 
    2545                     case DAYSTYLE_CUSTOM:
    2546                         // Custom format
    2547                         $txt = strftime($this->day->iLabelFormStr,$datestamp);
    2548                         break; 
    2549                     case DAYSTYLE_ONELETTER:
    2550                     default:
    2551                         // "M"
    2552                         $txt = strftime('%A',$datestamp);
    2553                         $txt = strtoupper($txt[0]);
    2554                         break;
    2555                 }
    2556 
    2557                 if( $day==0 )
    2558                     $img->SetColor($this->day->iSundayTextColor);
    2559                 else
    2560                     $img->SetColor($this->day->iTextColor);
    2561                 $img->StrokeText(round($x+$daywidth/2+1),
    2562                                 round($yb-$this->day->iTitleVertMargin),$txt);
    2563                 $img->SetColor($this->day->grid->iColor);
    2564                 $img->SetLineWeight($this->day->grid->iWeight);
    2565                 $img->Line($x,$yt,$x,$yb);
    2566                 $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
    2567                 $datestamp = mktime(0,0,0,date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp));
    2568                 //$datestamp += SECPERDAY;
    2569                
    2570             }                   
    2571             $img->SetColor($this->day->iFrameColor);
    2572             $img->SetLineWeight($this->day->iFrameWeight);
    2573             $img->Rectangle($xt,$yt,$xb,$yb);
    2574             return $yb - $img->top_margin;
    2575         }
    2576         return $aYCoord;
    2577     }
    2578        
     2568        $img=$this->iImg;
     2569        $daywidth=$this->GetDayWidth();
     2570        $xt=$img->left_margin+$this->iLabelWidth;
     2571        $yt=$aYCoord+$img->top_margin;
     2572        if( $this->day->iShowLabels ) {
     2573            $img->SetFont($this->day->iFFamily,$this->day->iFStyle,$this->day->iFSize);
     2574            $yb=$yt + $img->GetFontHeight() + $this->day->iTitleVertMargin + $this->day->iFrameWeight;
     2575            if( $getHeight ) {
     2576                return $yb - $img->top_margin;
     2577            }
     2578            $xb=$img->width-$img->right_margin+1;
     2579            $img->SetColor($this->day->iBackgroundColor);
     2580            $img->FilledRectangle($xt,$yt,$xb,$yb);
     2581
     2582            $x = $xt;
     2583            $img->SetTextAlign("center");
     2584            $day = date('w',$this->iStartDate);
     2585            $datestamp = $this->iStartDate;
     2586
     2587            $doback = !($this->hour->iShowLabels || $this->minute->iShowLabels);
     2588
     2589            setlocale(LC_TIME,$this->iDateLocale->iLocale);
     2590
     2591            for($i=0; $i < $this->GetNumberOfDays(); ++$i, $x+=$daywidth, $day += 1,$day %= 7) {
     2592                if( $day==6 || $day==0 ) {
     2593                    $img->SetColor($this->day->iWeekendBackgroundColor);
     2594                    if( $this->iUsePlotWeekendBackground && $doback)
     2595                        $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,
     2596                                              $x+$daywidth,$img->height-$img->bottom_margin);
     2597                    else
     2598                        $img->FilledRectangle($x,$yt+$this->day->iFrameWeight,
     2599                    $x+$daywidth,$yb-$this->day->iFrameWeight);
     2600                }
     2601
     2602                $mn = strftime('%m',$datestamp);
     2603                if( $mn[0]=='0' )
     2604                    $mn = $mn[1];
     2605
     2606                switch( $this->day->iStyle ) {
     2607                    case DAYSTYLE_LONG:
     2608                        // "Monday"
     2609                        $txt = strftime('%A',$datestamp);
     2610                        break;
     2611                    case DAYSTYLE_SHORT:
     2612                        // "Mon"
     2613                        $txt = strftime('%a',$datestamp);
     2614                        break;
     2615                    case DAYSTYLE_SHORTDAYDATE1:
     2616                        // "Mon 23/6"
     2617                        $txt = strftime('%a %d/'.$mn,$datestamp);
     2618                        break;
     2619                    case DAYSTYLE_SHORTDAYDATE2:
     2620                        // "Mon 23 Jun"
     2621                        $txt = strftime('%a %d %b',$datestamp);
     2622                        break;
     2623                    case DAYSTYLE_SHORTDAYDATE3:
     2624                        // "Mon 23 Jun 2003"
     2625                        $txt = strftime('%a %d %b %Y',$datestamp);
     2626                        break;
     2627                    case DAYSTYLE_LONGDAYDATE1:
     2628                        // "Monday 23 Jun"
     2629                        $txt = strftime('%A %d %b',$datestamp);
     2630                        break;
     2631                    case DAYSTYLE_LONGDAYDATE2:
     2632                        // "Monday 23 Jun 2003"
     2633                        $txt = strftime('%A %d %b %Y',$datestamp);
     2634                        break;
     2635                    case DAYSTYLE_SHORTDATE1:
     2636                        // "23/6"
     2637                        $txt = strftime('%d/'.$mn,$datestamp);
     2638                        break;
     2639                    case DAYSTYLE_SHORTDATE2:
     2640                        // "23 Jun"
     2641                        $txt = strftime('%d %b',$datestamp);
     2642                        break;
     2643                    case DAYSTYLE_SHORTDATE3:
     2644                        // "Mon 23"
     2645                        $txt = strftime('%a %d',$datestamp);
     2646                        break;
     2647                    case DAYSTYLE_SHORTDATE4:
     2648                        // "23"
     2649                        $txt = strftime('%d',$datestamp);
     2650                        break;
     2651                    case DAYSTYLE_CUSTOM:
     2652                        // Custom format
     2653                        $txt = strftime($this->day->iLabelFormStr,$datestamp);
     2654                        break;
     2655                    case DAYSTYLE_ONELETTER:
     2656                    default:
     2657                        // "M"
     2658                        $txt = strftime('%A',$datestamp);
     2659                        $txt = strtoupper($txt[0]);
     2660                        break;
     2661                }
     2662
     2663                if( $day==0 )
     2664                    $img->SetColor($this->day->iSundayTextColor);
     2665                else
     2666                    $img->SetColor($this->day->iTextColor);
     2667                $img->StrokeText(round($x+$daywidth/2+1),
     2668                round($yb-$this->day->iTitleVertMargin),$txt);
     2669                $img->SetColor($this->day->grid->iColor);
     2670                $img->SetLineWeight($this->day->grid->iWeight);
     2671                $img->Line($x,$yt,$x,$yb);
     2672                $this->day->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
     2673                $datestamp = mktime(0,0,0,date("m",$datestamp),date("d",$datestamp)+1,date("Y",$datestamp));
     2674                //$datestamp += SECPERDAY;
     2675
     2676            }
     2677            $img->SetColor($this->day->iFrameColor);
     2678            $img->SetLineWeight($this->day->iFrameWeight);
     2679            $img->Rectangle($xt,$yt,$xb,$yb);
     2680            return $yb - $img->top_margin;
     2681        }
     2682        return $aYCoord;
     2683    }
     2684
    25792685    // Stroke week header and grid
    25802686    function StrokeWeeks($aYCoord,$getHeight=false) {
    2581         if( $this->week->iShowLabels ) {
    2582             $img=$this->iImg;   
    2583             $yt=$aYCoord+$img->top_margin;             
    2584             $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize);
    2585             $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight;
    2586 
    2587             if( $getHeight ) {
    2588                 return $yb - $img->top_margin; 
    2589             }
    2590 
    2591             $xt=$img->left_margin+$this->iLabelWidth;
    2592             $weekwidth=$this->GetDayWidth()*7;
    2593             $wdays=$this->iDateLocale->GetDayAbb();     
    2594             $xb=$img->width-$img->right_margin+1;
    2595             $week = $this->iStartDate;
    2596             $weeknbr=$this->GetWeekNbr($week);
    2597             $img->SetColor($this->week->iBackgroundColor);
    2598             $img->FilledRectangle($xt,$yt,$xb,$yb);
    2599             $img->SetColor($this->week->grid->iColor);
    2600             $x = $xt;
    2601             if( $this->week->iStyle==WEEKSTYLE_WNBR ) {
    2602                 $img->SetTextAlign("center");
    2603                 $txtOffset = $weekwidth/2+1;
    2604             }
    2605             elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY  ||
    2606                     $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ||
    2607                     $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||
    2608                     $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
    2609                 $img->SetTextAlign("left");
    2610                 $txtOffset = 3;
    2611             }
    2612             else
    2613                 JpGraphError::RaiseL(6021);
    2614 //("Unknown formatting style for week.");
    2615                                
    2616             for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) {
    2617                 $img->PushColor($this->week->iTextColor);
    2618                                
    2619                 if( $this->week->iStyle==WEEKSTYLE_WNBR )
    2620                     $txt = sprintf($this->week->iLabelFormStr,$weeknbr);
    2621                 elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY ||
    2622                         $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR )
    2623                     $txt = date("j/n",$week);
    2624                 elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ||
    2625                         $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
    2626                     $monthnbr = date("n",$week)-1;
    2627                     $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr);
    2628                     $txt = Date("j",$week)." ".$shortmonth;
    2629                 }
    2630 
    2631                 if( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||
    2632                     $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
    2633                     $w = sprintf($this->week->iLabelFormStr,$weeknbr);
    2634                     $txt .= ' '.$w;
    2635                 }
    2636                                
    2637                 $img->StrokeText(round($x+$txtOffset),
    2638                                  round($yb-$this->week->iTitleVertMargin),$txt);
    2639                                
    2640                 $week = strtotime('+7 day',$week);
    2641                 $weeknbr = $this->GetWeekNbr($week);
    2642                 $img->PopColor();       
    2643                 $img->SetLineWeight($this->week->grid->iWeight);
    2644                 $img->Line($x,$yt,$x,$yb);
    2645                 $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
    2646             }                   
    2647             $img->SetColor($this->week->iFrameColor);
    2648             $img->SetLineWeight($this->week->iFrameWeight);
    2649             $img->Rectangle($xt,$yt,$xb,$yb);
    2650             return $yb-$img->top_margin;
    2651         }
    2652         return $aYCoord;
    2653     }   
    2654        
     2687        if( $this->week->iShowLabels ) {
     2688            $img=$this->iImg;
     2689            $yt=$aYCoord+$img->top_margin;
     2690            $img->SetFont($this->week->iFFamily,$this->week->iFStyle,$this->week->iFSize);
     2691            $yb=$yt + $img->GetFontHeight() + $this->week->iTitleVertMargin + $this->week->iFrameWeight;
     2692
     2693            if( $getHeight ) {
     2694                return $yb - $img->top_margin;
     2695            }
     2696
     2697            $xt=$img->left_margin+$this->iLabelWidth;
     2698            $weekwidth=$this->GetDayWidth()*7;
     2699            $wdays=$this->iDateLocale->GetDayAbb();
     2700            $xb=$img->width-$img->right_margin+1;
     2701            $week = $this->iStartDate;
     2702            $weeknbr=$this->GetWeekNbr($week);
     2703            $img->SetColor($this->week->iBackgroundColor);
     2704            $img->FilledRectangle($xt,$yt,$xb,$yb);
     2705            $img->SetColor($this->week->grid->iColor);
     2706            $x = $xt;
     2707            if( $this->week->iStyle==WEEKSTYLE_WNBR ) {
     2708                $img->SetTextAlign("center");
     2709                $txtOffset = $weekwidth/2+1;
     2710            }
     2711            elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY  ||
     2712                    $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ||
     2713                    $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||
     2714                    $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
     2715                $img->SetTextAlign("left");
     2716                $txtOffset = 3;
     2717            }
     2718            else {
     2719                JpGraphError::RaiseL(6021);
     2720                //("Unknown formatting style for week.");
     2721            }
     2722
     2723            for($i=0; $i<$this->GetNumberOfDays()/7; ++$i, $x+=$weekwidth) {
     2724                $img->PushColor($this->week->iTextColor);
     2725
     2726                if( $this->week->iStyle==WEEKSTYLE_WNBR )
     2727                    $txt = sprintf($this->week->iLabelFormStr,$weeknbr);
     2728                elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY ||
     2729                        $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR )
     2730                    $txt = date("j/n",$week);
     2731                elseif( $this->week->iStyle==WEEKSTYLE_FIRSTDAY2 ||
     2732                        $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
     2733                    $monthnbr = date("n",$week)-1;
     2734                    $shortmonth = $this->iDateLocale->GetShortMonthName($monthnbr);
     2735                    $txt = Date("j",$week)." ".$shortmonth;
     2736                }
     2737
     2738                if( $this->week->iStyle==WEEKSTYLE_FIRSTDAYWNBR ||
     2739                $this->week->iStyle==WEEKSTYLE_FIRSTDAY2WNBR ) {
     2740                    $w = sprintf($this->week->iLabelFormStr,$weeknbr);
     2741                    $txt .= ' '.$w;
     2742                }
     2743
     2744                $img->StrokeText(round($x+$txtOffset),
     2745                round($yb-$this->week->iTitleVertMargin),$txt);
     2746
     2747                $week = strtotime('+7 day',$week);
     2748                $weeknbr = $this->GetWeekNbr($week);
     2749                $img->PopColor();
     2750                $img->SetLineWeight($this->week->grid->iWeight);
     2751                $img->Line($x,$yt,$x,$yb);
     2752                $this->week->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
     2753            }
     2754            $img->SetColor($this->week->iFrameColor);
     2755            $img->SetLineWeight($this->week->iFrameWeight);
     2756            $img->Rectangle($xt,$yt,$xb,$yb);
     2757            return $yb-$img->top_margin;
     2758        }
     2759        return $aYCoord;
     2760    }
     2761
    26552762    // Format the mont scale header string
    26562763    function GetMonthLabel($aMonthNbr,$year) {
    2657         $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr);
    2658         $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr);
    2659         switch($this->month->iStyle) {
    2660             case MONTHSTYLE_SHORTNAME:
    2661                 $m=$sn;
    2662                 break;
    2663             case MONTHSTYLE_LONGNAME:
    2664                 $m=$ln;
    2665                 break;
    2666             case MONTHSTYLE_SHORTNAMEYEAR2:
    2667                 $m=$sn." '".substr("".$year,2);
    2668                 break;
    2669             case MONTHSTYLE_SHORTNAMEYEAR4:
    2670                 $m=$sn." ".$year;
    2671                 break;
    2672             case MONTHSTYLE_LONGNAMEYEAR2:
    2673                 $m=$ln." '".substr("".$year,2);
    2674                 break;
    2675             case MONTHSTYLE_LONGNAMEYEAR4:
    2676                 $m=$ln." ".$year;
    2677                 break;
    2678             case MONTHSTYLE_FIRSTLETTER:
    2679                 $m=$sn[0];
    2680                 break;
    2681         }
    2682         return $m;
    2683     }
    2684        
     2764        $sn = $this->iDateLocale->GetShortMonthName($aMonthNbr);
     2765        $ln = $this->iDateLocale->GetLongMonthName($aMonthNbr);
     2766        switch($this->month->iStyle) {
     2767            case MONTHSTYLE_SHORTNAME:
     2768                $m=$sn;
     2769                break;
     2770            case MONTHSTYLE_LONGNAME:
     2771                $m=$ln;
     2772                break;
     2773            case MONTHSTYLE_SHORTNAMEYEAR2:
     2774                $m=$sn." '".substr("".$year,2);
     2775                break;
     2776            case MONTHSTYLE_SHORTNAMEYEAR4:
     2777                $m=$sn." ".$year;
     2778                break;
     2779            case MONTHSTYLE_LONGNAMEYEAR2:
     2780                $m=$ln." '".substr("".$year,2);
     2781                break;
     2782            case MONTHSTYLE_LONGNAMEYEAR4:
     2783                $m=$ln." ".$year;
     2784                break;
     2785            case MONTHSTYLE_FIRSTLETTER:
     2786                $m=$sn[0];
     2787                break;
     2788        }
     2789        return $m;
     2790    }
     2791
    26852792    // Stroke month scale and gridlines
    26862793    function StrokeMonths($aYCoord,$getHeight=false) {
    2687         if( $this->month->iShowLabels ) {
    2688             $img=$this->iImg;           
    2689             $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize);
    2690             $yt=$aYCoord+$img->top_margin;             
    2691             $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight;
    2692             if( $getHeight ) {
    2693                 return $yb - $img->top_margin; 
    2694             }
    2695             $monthnbr = $this->GetMonthNbr($this->iStartDate)-1;
    2696             $xt=$img->left_margin+$this->iLabelWidth;
    2697             $xb=$img->width-$img->right_margin+1;
    2698                        
    2699             $img->SetColor($this->month->iBackgroundColor);
    2700             $img->FilledRectangle($xt,$yt,$xb,$yb);
    2701 
    2702             $img->SetLineWeight($this->month->grid->iWeight);
    2703             $img->SetColor($this->month->iTextColor);
    2704             $year = 0+strftime("%Y",$this->iStartDate);
    2705             $img->SetTextAlign("center");
    2706             if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate) 
    2707                 && $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) {
    2708                 $monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1);
    2709             }
    2710             else {
    2711                 $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1);
    2712             }
    2713             // Is it enough space to stroke the first month?
    2714             $monthName = $this->GetMonthLabel($monthnbr,$year);
    2715             if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) {
    2716                 $img->SetColor($this->month->iTextColor);                               
    2717                 $img->StrokeText(round($xt+$monthwidth/2+1),
    2718                                 round($yb-$this->month->iTitleVertMargin),
    2719                                 $monthName);
    2720             }
    2721             $x = $xt + $monthwidth;
    2722             while( $x < $xb ) {
    2723                 $img->SetColor($this->month->grid->iColor);                             
    2724                 $img->Line($x,$yt,$x,$yb);
    2725                 $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
    2726                 $monthnbr++;
    2727                 if( $monthnbr==12 ) {
    2728                     $monthnbr=0;
    2729                     $year++;
    2730                 }
    2731                 $monthName = $this->GetMonthLabel($monthnbr,$year);
    2732                 $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year);                             
    2733                 if( $x + $monthwidth < $xb )
    2734                     $w = $monthwidth;
    2735                 else
    2736                     $w = $xb-$x;
    2737                 if( $w >= 1.2*$img->GetTextWidth($monthName) ) {
    2738                     $img->SetColor($this->month->iTextColor);                           
    2739                     $img->StrokeText(round($x+$w/2+1),
    2740                                      round($yb-$this->month->iTitleVertMargin),$monthName);
    2741                 }
    2742                 $x += $monthwidth;
    2743             }   
    2744             $img->SetColor($this->month->iFrameColor);
    2745             $img->SetLineWeight($this->month->iFrameWeight);
    2746             $img->Rectangle($xt,$yt,$xb,$yb);                   
    2747             return $yb-$img->top_margin;
    2748         }
    2749         return $aYCoord;
     2794        if( $this->month->iShowLabels ) {
     2795            $img=$this->iImg;
     2796            $img->SetFont($this->month->iFFamily,$this->month->iFStyle,$this->month->iFSize);
     2797            $yt=$aYCoord+$img->top_margin;
     2798            $yb=$yt + $img->GetFontHeight() + $this->month->iTitleVertMargin + $this->month->iFrameWeight;
     2799            if( $getHeight ) {
     2800                return $yb - $img->top_margin;
     2801            }
     2802            $monthnbr = $this->GetMonthNbr($this->iStartDate)-1;
     2803            $xt=$img->left_margin+$this->iLabelWidth;
     2804            $xb=$img->width-$img->right_margin+1;
     2805
     2806            $img->SetColor($this->month->iBackgroundColor);
     2807            $img->FilledRectangle($xt,$yt,$xb,$yb);
     2808
     2809            $img->SetLineWeight($this->month->grid->iWeight);
     2810            $img->SetColor($this->month->iTextColor);
     2811            $year = 0+strftime("%Y",$this->iStartDate);
     2812            $img->SetTextAlign("center");
     2813            if( $this->GetMonthNbr($this->iStartDate) == $this->GetMonthNbr($this->iEndDate)
     2814                && $this->GetYear($this->iStartDate)==$this->GetYear($this->iEndDate) ) {
     2815                $monthwidth=$this->GetDayWidth()*($this->GetMonthDayNbr($this->iEndDate) - $this->GetMonthDayNbr($this->iStartDate) + 1);
     2816            }
     2817            else {
     2818                $monthwidth=$this->GetDayWidth()*($this->GetNumDaysInMonth($monthnbr,$year)-$this->GetMonthDayNbr($this->iStartDate)+1);
     2819            }
     2820            // Is it enough space to stroke the first month?
     2821            $monthName = $this->GetMonthLabel($monthnbr,$year);
     2822            if( $monthwidth >= 1.2*$img->GetTextWidth($monthName) ) {
     2823                $img->SetColor($this->month->iTextColor);
     2824                $img->StrokeText(round($xt+$monthwidth/2+1),
     2825                round($yb-$this->month->iTitleVertMargin),
     2826                $monthName);
     2827            }
     2828            $x = $xt + $monthwidth;
     2829            while( $x < $xb ) {
     2830                $img->SetColor($this->month->grid->iColor);
     2831                $img->Line($x,$yt,$x,$yb);
     2832                $this->month->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
     2833                $monthnbr++;
     2834                if( $monthnbr==12 ) {
     2835                    $monthnbr=0;
     2836                    $year++;
     2837                }
     2838                $monthName = $this->GetMonthLabel($monthnbr,$year);
     2839                $monthwidth=$this->GetDayWidth()*$this->GetNumDaysInMonth($monthnbr,$year);
     2840                if( $x + $monthwidth < $xb )
     2841                    $w = $monthwidth;
     2842                else
     2843                    $w = $xb-$x;
     2844                if( $w >= 1.2*$img->GetTextWidth($monthName) ) {
     2845                    $img->SetColor($this->month->iTextColor);
     2846                    $img->StrokeText(round($x+$w/2+1),
     2847                    round($yb-$this->month->iTitleVertMargin),$monthName);
     2848                }
     2849                $x += $monthwidth;
     2850            }
     2851            $img->SetColor($this->month->iFrameColor);
     2852            $img->SetLineWeight($this->month->iFrameWeight);
     2853            $img->Rectangle($xt,$yt,$xb,$yb);
     2854            return $yb-$img->top_margin;
     2855        }
     2856        return $aYCoord;
    27502857    }
    27512858
    27522859    // Stroke year scale and gridlines
    27532860    function StrokeYears($aYCoord,$getHeight=false) {
    2754         if( $this->year->iShowLabels ) {
    2755             $img=$this->iImg;   
    2756             $yt=$aYCoord+$img->top_margin;             
    2757             $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize);
    2758             $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight;
    2759 
    2760             if( $getHeight ) {
    2761                 return $yb - $img->top_margin; 
    2762             }
    2763 
    2764             $xb=$img->width-$img->right_margin+1;
    2765             $xt=$img->left_margin+$this->iLabelWidth;
    2766             $year = $this->GetYear($this->iStartDate);                 
    2767             $img->SetColor($this->year->iBackgroundColor);
    2768             $img->FilledRectangle($xt,$yt,$xb,$yb);
    2769             $img->SetLineWeight($this->year->grid->iWeight);
    2770             $img->SetTextAlign("center");
    2771             if( $year == $this->GetYear($this->iEndDate) )
    2772                 $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1);
    2773             else
    2774                 $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1);
    2775                        
    2776             // The space for a year must be at least 20% bigger than the actual text
    2777             // so we allow 10% margin on each side
    2778             if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) {
    2779                 $img->SetColor($this->year->iTextColor);                               
    2780                 $img->StrokeText(round($xt+$yearwidth/2+1),
    2781                                 round($yb-$this->year->iTitleVertMargin),
    2782                                 $year);
    2783             }
    2784             $x = $xt + $yearwidth;
    2785             while( $x < $xb ) {
    2786                 $img->SetColor($this->year->grid->iColor);                             
    2787                 $img->Line($x,$yt,$x,$yb);
    2788                 $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
    2789                 $year += 1;
    2790                 $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year);                         
    2791                 if( $x + $yearwidth < $xb )
    2792                     $w = $yearwidth;
    2793                 else
    2794                     $w = $xb-$x;
    2795                 if( $w >= 1.2*$img->GetTextWidth("".$year) ) {
    2796                     $img->SetColor($this->year->iTextColor);
    2797                     $img->StrokeText(round($x+$w/2+1),
    2798                                      round($yb-$this->year->iTitleVertMargin),
    2799                                      $year);
    2800                 }
    2801                 $x += $yearwidth;
    2802             }
    2803             $img->SetColor($this->year->iFrameColor);
    2804             $img->SetLineWeight($this->year->iFrameWeight);
    2805             $img->Rectangle($xt,$yt,$xb,$yb);                   
    2806             return $yb-$img->top_margin;
    2807         }
    2808         return $aYCoord;
    2809     }
    2810        
     2861        if( $this->year->iShowLabels ) {
     2862            $img=$this->iImg;
     2863            $yt=$aYCoord+$img->top_margin;
     2864            $img->SetFont($this->year->iFFamily,$this->year->iFStyle,$this->year->iFSize);
     2865            $yb=$yt + $img->GetFontHeight() + $this->year->iTitleVertMargin + $this->year->iFrameWeight;
     2866
     2867            if( $getHeight ) {
     2868                return $yb - $img->top_margin;
     2869            }
     2870
     2871            $xb=$img->width-$img->right_margin+1;
     2872            $xt=$img->left_margin+$this->iLabelWidth;
     2873            $year = $this->GetYear($this->iStartDate);
     2874            $img->SetColor($this->year->iBackgroundColor);
     2875            $img->FilledRectangle($xt,$yt,$xb,$yb);
     2876            $img->SetLineWeight($this->year->grid->iWeight);
     2877            $img->SetTextAlign("center");
     2878            if( $year == $this->GetYear($this->iEndDate) )
     2879                $yearwidth=$this->GetDayWidth()*($this->GetYearDayNbr($this->iEndDate)-$this->GetYearDayNbr($this->iStartDate)+1);
     2880            else
     2881                $yearwidth=$this->GetDayWidth()*($this->GetNumDaysInYear($year)-$this->GetYearDayNbr($this->iStartDate)+1);
     2882
     2883            // The space for a year must be at least 20% bigger than the actual text
     2884            // so we allow 10% margin on each side
     2885            if( $yearwidth >= 1.20*$img->GetTextWidth("".$year) ) {
     2886                $img->SetColor($this->year->iTextColor);
     2887                $img->StrokeText(round($xt+$yearwidth/2+1),
     2888                                round($yb-$this->year->iTitleVertMargin),
     2889                                $year);
     2890            }
     2891            $x = $xt + $yearwidth;
     2892            while( $x < $xb ) {
     2893                $img->SetColor($this->year->grid->iColor);
     2894                $img->Line($x,$yt,$x,$yb);
     2895                $this->year->grid->Stroke($img,$x,$yb,$x,$img->height-$img->bottom_margin);
     2896                $year += 1;
     2897                $yearwidth=$this->GetDayWidth()*$this->GetNumDaysInYear($year);
     2898                if( $x + $yearwidth < $xb )
     2899                    $w = $yearwidth;
     2900                else
     2901                    $w = $xb-$x;
     2902                if( $w >= 1.2*$img->GetTextWidth("".$year) ) {
     2903                    $img->SetColor($this->year->iTextColor);
     2904                    $img->StrokeText(round($x+$w/2+1),
     2905                                     round($yb-$this->year->iTitleVertMargin),
     2906                                     $year);
     2907                }
     2908                $x += $yearwidth;
     2909            }
     2910            $img->SetColor($this->year->iFrameColor);
     2911            $img->SetLineWeight($this->year->iFrameWeight);
     2912            $img->Rectangle($xt,$yt,$xb,$yb);
     2913            return $yb-$img->top_margin;
     2914        }
     2915        return $aYCoord;
     2916    }
     2917
    28112918    // Stroke table title (upper left corner)
    28122919    function StrokeTableHeaders($aYBottom) {
    2813         $img=$this->iImg;
    2814         $xt=$img->left_margin;
    2815         $yt=$img->top_margin;
    2816         $xb=$xt+$this->iLabelWidth;
    2817         $yb=$aYBottom+$img->top_margin;
    2818 
    2819         if( $this->tableTitle->iShow ) {
    2820             $img->SetColor($this->iTableHeaderBackgroundColor);
    2821             $img->FilledRectangle($xt,$yt,$xb,$yb);
    2822             $this->tableTitle->Align("center","top");
    2823             $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2);           
    2824             $img->SetColor($this->iTableHeaderFrameColor);
    2825             $img->SetLineWeight($this->iTableHeaderFrameWeight);
    2826             $img->Rectangle($xt,$yt,$xb,$yb);
    2827         }
    2828 
    2829         $this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow);
    2830 
    2831 
    2832         // Draw the horizontal dividing line           
    2833         $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb);               
    2834                
    2835         // Draw the vertical dividing line
    2836         // We do the width "manually" since we want the line only to grow
    2837         // to the left
    2838         $fancy = $this->divider->iStyle == 'fancy' ;
    2839         if( $fancy ) {
    2840             $this->divider->iStyle = 'solid';
    2841         }
    2842 
    2843         $tmp = $this->divider->iWeight;
    2844         $this->divider->iWeight=1;
    2845         $y = $img->height-$img->bottom_margin;
    2846         for($i=0; $i < $tmp; ++$i ) {
    2847             $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y);
    2848         }
    2849 
    2850         // Should we draw "fancy" divider
    2851         if( $fancy ) {
    2852             $img->SetLineWeight(1);
    2853             $img->SetColor($this->iTableHeaderFrameColor);
    2854             $img->Line($xb,$yt,$xb,$y);
    2855             $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y);
    2856             $img->SetColor('white');
    2857             $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y);
    2858         }
     2920        $img=$this->iImg;
     2921        $xt=$img->left_margin;
     2922        $yt=$img->top_margin;
     2923        $xb=$xt+$this->iLabelWidth;
     2924        $yb=$aYBottom+$img->top_margin;
     2925
     2926        if( $this->tableTitle->iShow ) {
     2927            $img->SetColor($this->iTableHeaderBackgroundColor);
     2928            $img->FilledRectangle($xt,$yt,$xb,$yb);
     2929            $this->tableTitle->Align("center","top");
     2930            $this->tableTitle->Stroke($img,$xt+($xb-$xt)/2+1,$yt+2);
     2931            $img->SetColor($this->iTableHeaderFrameColor);
     2932            $img->SetLineWeight($this->iTableHeaderFrameWeight);
     2933            $img->Rectangle($xt,$yt,$xb,$yb);
     2934        }
     2935
     2936        $this->actinfo->Stroke($img,$xt,$yt,$xb,$yb,$this->tableTitle->iShow);
     2937
     2938
     2939        // Draw the horizontal dividing line
     2940        $this->dividerh->Stroke($img,$xt,$yb,$img->width-$img->right_margin,$yb);
     2941
     2942        // Draw the vertical dividing line
     2943        // We do the width "manually" since we want the line only to grow
     2944        // to the left
     2945        $fancy = $this->divider->iStyle == 'fancy' ;
     2946        if( $fancy ) {
     2947            $this->divider->iStyle = 'solid';
     2948        }
     2949
     2950        $tmp = $this->divider->iWeight;
     2951        $this->divider->iWeight=1;
     2952        $y = $img->height-$img->bottom_margin;
     2953        for($i=0; $i < $tmp; ++$i ) {
     2954            $this->divider->Stroke($img,$xb-$i,$yt,$xb-$i,$y);
     2955        }
     2956
     2957        // Should we draw "fancy" divider
     2958        if( $fancy ) {
     2959            $img->SetLineWeight(1);
     2960            $img->SetColor($this->iTableHeaderFrameColor);
     2961            $img->Line($xb,$yt,$xb,$y);
     2962            $img->Line($xb-$tmp+1,$yt,$xb-$tmp+1,$y);
     2963            $img->SetColor('white');
     2964            $img->Line($xb-$tmp+2,$yt,$xb-$tmp+2,$y);
     2965        }
    28592966    }
    28602967
    28612968    // Main entry point to stroke scale
    28622969    function Stroke() {
    2863         if( !$this->IsRangeSet() )
    2864             JpGraphError::RaiseL(6022);
    2865 //("Gantt scale has not been specified.");
    2866         $img=$this->iImg;
    2867 
    2868         // If minutes are displayed then hour interval must be 1
    2869         if( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) {
    2870             JpGraphError::RaiseL(6023);
    2871 //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).');
    2872         }
    2873                
    2874         // Stroke all headers. As argument we supply the offset from the
    2875         // top which depends on any previous headers
    2876        
    2877         // First find out the height of each header
    2878         $offy=$this->StrokeYears(0,true);
    2879         $offm=$this->StrokeMonths($offy,true);
    2880         $offw=$this->StrokeWeeks($offm,true);
    2881         $offd=$this->StrokeDays($offw,true);
    2882         $offh=$this->StrokeHours($offd,true);
    2883         $offmin=$this->StrokeMinutes($offh,true);
    2884 
    2885 
    2886         // ... then we can stroke them in the "backwards order to ensure that
    2887         // the larger scale gridlines is stroked over the smaller scale gridline
    2888         $this->StrokeMinutes($offh);
    2889         $this->StrokeHours($offd);
    2890         $this->StrokeDays($offw);
    2891         $this->StrokeWeeks($offm);             
    2892         $this->StrokeMonths($offy);             
    2893         $this->StrokeYears(0);
    2894 
    2895         // Now when we now the oaverall size of the scale headers
    2896         // we can stroke the overall table headers
    2897         $this->StrokeTableHeaders($offmin);
    2898                
    2899         // Now we can calculate the correct scaling factor for each vertical position
    2900         $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd;               
    2901         $this->iVertHeaderSize = $offmin;
    2902         if( $this->iVertSpacing == -1 )
    2903             $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines;
    2904     }   
     2970        if( !$this->IsRangeSet() ) {
     2971                JpGraphError::RaiseL(6022);
     2972                //("Gantt scale has not been specified.");
     2973        }
     2974        $img=$this->iImg;
     2975
     2976        // If minutes are displayed then hour interval must be 1
     2977        if( $this->IsDisplayMinute() && $this->hour->GetIntervall() > 1 ) {
     2978            JpGraphError::RaiseL(6023);
     2979            //('If you display both hour and minutes the hour intervall must be 1 (Otherwise it doesn\' make sense to display minutes).');
     2980        }
     2981
     2982        // Stroke all headers. As argument we supply the offset from the
     2983        // top which depends on any previous headers
     2984
     2985        // First find out the height of each header
     2986        $offy=$this->StrokeYears(0,true);
     2987        $offm=$this->StrokeMonths($offy,true);
     2988        $offw=$this->StrokeWeeks($offm,true);
     2989        $offd=$this->StrokeDays($offw,true);
     2990        $offh=$this->StrokeHours($offd,true);
     2991        $offmin=$this->StrokeMinutes($offh,true);
     2992
     2993
     2994        // ... then we can stroke them in the "backwards order to ensure that
     2995        // the larger scale gridlines is stroked over the smaller scale gridline
     2996        $this->StrokeMinutes($offh);
     2997        $this->StrokeHours($offd);
     2998        $this->StrokeDays($offw);
     2999        $this->StrokeWeeks($offm);
     3000        $this->StrokeMonths($offy);
     3001        $this->StrokeYears(0);
     3002
     3003        // Now when we now the oaverall size of the scale headers
     3004        // we can stroke the overall table headers
     3005        $this->StrokeTableHeaders($offmin);
     3006
     3007        // Now we can calculate the correct scaling factor for each vertical position
     3008        $this->iAvailableHeight = $img->height - $img->top_margin - $img->bottom_margin - $offd;
     3009
     3010        $this->iVertHeaderSize = $offmin;
     3011        if( $this->iVertSpacing == -1 )
     3012                $this->iVertSpacing = $this->iAvailableHeight / $this->iVertLines;
     3013    }
    29053014}
    29063015
     
    29173026    public $iConstrainArrowType;
    29183027
    2919 //---------------
    2920 // CONSTRUCTOR
    2921     function GanttConstraint($aRow,$aType,$aColor,$aArrowSize,$aArrowType){
    2922         $this->iConstrainType = $aType;
    2923         $this->iConstrainRow = $aRow;
    2924         $this->iConstrainColor=$aColor;
    2925         $this->iConstrainArrowSize=$aArrowSize;
    2926         $this->iConstrainArrowType=$aArrowType;
     3028    //---------------
     3029    // CONSTRUCTOR
     3030    function __construct($aRow,$aType,$aColor,$aArrowSize,$aArrowType){
     3031        $this->iConstrainType = $aType;
     3032        $this->iConstrainRow = $aRow;
     3033        $this->iConstrainColor=$aColor;
     3034        $this->iConstrainArrowSize=$aArrowSize;
     3035        $this->iConstrainArrowType=$aArrowType;
    29273036    }
    29283037}
     
    29363045    public $title,$caption;
    29373046    public $csimarea='',$csimtarget='',$csimwintarget='',$csimalt='';
    2938     public $constraints = array();   
     3047    public $constraints = array();
    29393048    public $iCaptionMargin=5;
    29403049    public $iConstrainPos=array();
    2941     protected $iStart="";                               // Start date
    2942     public $iVPos=0;                                    // Vertical position
    2943     protected $iLabelLeftMargin=2;      // Title margin
    2944                
    2945     function GanttPlotObject() {
    2946         $this->title = new TextProperty();
    2947         $this->title->Align("left","center");
    2948         $this->caption = new TextProperty();
     3050    protected $iStart="";    // Start date
     3051    public $iVPos=0;     // Vertical position
     3052    protected $iLabelLeftMargin=2; // Title margin
     3053
     3054    function __construct() {
     3055        $this->title = new TextProperty();
     3056        $this->title->Align('left','center');
     3057        $this->caption = new TextProperty();
    29493058    }
    29503059
    29513060    function GetCSIMArea() {
    2952         return $this->csimarea;
     3061        return $this->csimarea;
    29533062    }
    29543063
    29553064    function SetCSIMTarget($aTarget,$aAlt='',$aWinTarget='') {
    2956         if( !is_string($aTarget) ) {
    2957             $tv = substr(var_export($aTarget,true),0,40);
    2958             JpGraphError::RaiseL(6024,$tv);
    2959 //('CSIM Target must be specified as a string.'."\nStart of target is:\n$tv");
    2960         }
    2961         if( !is_string($aAlt) ) {
    2962             $tv = substr(var_export($aAlt,true),0,40);
    2963             JpGraphError::RaiseL(6025,$tv);
    2964 //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv");
    2965         }
     3065        if( !is_string($aTarget) ) {
     3066            $tv = substr(var_export($aTarget,true),0,40);
     3067            JpGraphError::RaiseL(6024,$tv);
     3068            //('CSIM Target must be specified as a string.'."\nStart of target is:\n$tv");
     3069        }
     3070        if( !is_string($aAlt) ) {
     3071            $tv = substr(var_export($aAlt,true),0,40);
     3072            JpGraphError::RaiseL(6025,$tv);
     3073            //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv");
     3074        }
    29663075
    29673076        $this->csimtarget=$aTarget;
     
    29693078        $this->csimalt=$aAlt;
    29703079    }
    2971    
     3080
    29723081    function SetCSIMAlt($aAlt) {
    2973         if( !is_string($aAlt) ) {
    2974             $tv = substr(var_export($aAlt,true),0,40);
    2975             JpGraphError::RaiseL(6025,$tv);
    2976 //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv");
    2977         }
     3082        if( !is_string($aAlt) ) {
     3083            $tv = substr(var_export($aAlt,true),0,40);
     3084            JpGraphError::RaiseL(6025,$tv);
     3085            //('CSIM Alt text must be specified as a string.'."\nStart of alt text is:\n$tv");
     3086        }
    29783087        $this->csimalt=$aAlt;
    29793088    }
    29803089
    29813090    function SetConstrain($aRow,$aType,$aColor='black',$aArrowSize=ARROW_S2,$aArrowType=ARROWT_SOLID) {
    2982         $this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType);
     3091        $this->constraints[] = new GanttConstraint($aRow, $aType, $aColor, $aArrowSize, $aArrowType);
    29833092    }
    29843093
    29853094    function SetConstrainPos($xt,$yt,$xb,$yb) {
    2986         $this->iConstrainPos = array($xt,$yt,$xb,$yb);
    2987     }
    2988 
    2989     /*
    2990     function GetConstrain() {
    2991         return array($this->iConstrainRow,$this->iConstrainType);
    2992     }
    2993     */
    2994        
     3095        $this->iConstrainPos = array($xt,$yt,$xb,$yb);
     3096    }
     3097
    29953098    function GetMinDate() {
    2996         return $this->iStart;
     3099        return $this->iStart;
    29973100    }
    29983101
    29993102    function GetMaxDate() {
    3000         return $this->iStart;
    3001     }
    3002        
     3103        return $this->iStart;
     3104    }
     3105
    30033106    function SetCaptionMargin($aMarg) {
    3004         $this->iCaptionMargin=$aMarg;
     3107        $this->iCaptionMargin=$aMarg;
    30053108    }
    30063109
    30073110    function GetAbsHeight($aImg) {
    3008         return 0;
    3009     }
    3010        
     3111        return 0;
     3112    }
     3113
    30113114    function GetLineNbr() {
    3012         return $this->iVPos;
     3115        return $this->iVPos;
    30133116    }
    30143117
    30153118    function SetLabelLeftMargin($aOff) {
    3016         $this->iLabelLeftMargin=$aOff;
    3017     }           
     3119        $this->iLabelLeftMargin=$aOff;
     3120    }
    30183121
    30193122    function StrokeActInfo($aImg,$aScale,$aYPos) {
    3020         $cols=array();
    3021         $aScale->actinfo->GetColStart($aImg,$cols,true);
    3022         $this->title->Stroke($aImg,$cols,$aYPos);               
     3123        $cols=array();
     3124        $aScale->actinfo->GetColStart($aImg,$cols,true);
     3125        $this->title->Stroke($aImg,$cols,$aYPos);
    30233126    }
    30243127}
     
    30263129//===================================================
    30273130// CLASS Progress
    3028 // Holds parameters for the progress indicator 
     3131// Holds parameters for the progress indicator
    30293132// displyed within a bar
    30303133//===================================================
     
    30333136    public $iPattern=GANTT_SOLID;
    30343137    public $iColor="black", $iFillColor='black';
    3035     public $iDensity=98, $iHeight=0.65; 
    3036        
     3138    public $iDensity=98, $iHeight=0.65;
     3139
    30373140    function Set($aProg) {
    3038         if( $aProg < 0.0 || $aProg > 1.0 )
    3039             JpGraphError::RaiseL(6027);
    3040 //("Progress value must in range [0, 1]");
    3041         $this->iProgress = $aProg;
    3042     }
    3043 
    3044     function SetPattern($aPattern,$aColor="blue",$aDensity=98) {               
    3045         $this->iPattern = $aPattern;
    3046         $this->iColor = $aColor;
    3047         $this->iDensity = $aDensity;
     3141        if( $aProg < 0.0 || $aProg > 1.0 ) {
     3142                JpGraphError::RaiseL(6027);
     3143                //("Progress value must in range [0, 1]");
     3144        }
     3145        $this->iProgress = $aProg;
     3146    }
     3147
     3148    function SetPattern($aPattern,$aColor="blue",$aDensity=98) {
     3149        $this->iPattern = $aPattern;
     3150        $this->iColor = $aColor;
     3151        $this->iDensity = $aDensity;
    30483152    }
    30493153
    30503154    function SetFillColor($aColor) {
    3051         $this->iFillColor = $aColor;
    3052     }
    3053        
     3155        $this->iFillColor = $aColor;
     3156    }
     3157
    30543158    function SetHeight($aHeight) {
    3055         $this->iHeight = $aHeight;
     3159        $this->iHeight = $aHeight;
    30563160    }
    30573161}
     
    30713175    private $iStart=0; // 0=from left margin, 1=just along header
    30723176
    3073     function HorizontalGridLine() {
    3074         $this->line = new LineProperty();
    3075         $this->line->SetColor('gray@0.4');
    3076         $this->line->SetStyle('dashed');
    3077     }
    3078    
     3177    function __construct() {
     3178        $this->line = new LineProperty();
     3179        $this->line->SetColor('gray@0.4');
     3180        $this->line->SetStyle('dashed');
     3181    }
     3182
    30793183    function Show($aShow=true) {
    3080         $this->iShow = $aShow;
     3184        $this->iShow = $aShow;
    30813185    }
    30823186
    30833187    function SetRowFillColor($aColor1,$aColor2='') {
    3084         $this->iRowColor1 = $aColor1;
    3085         $this->iRowColor2 = $aColor2;
     3188        $this->iRowColor1 = $aColor1;
     3189        $this->iRowColor2 = $aColor2;
    30863190    }
    30873191
    30883192    function SetStart($aStart) {
    3089         $this->iStart = $aStart;
     3193        $this->iStart = $aStart;
    30903194    }
    30913195
    30923196    function Stroke($aImg,$aScale) {
    3093        
    3094         if( ! $this->iShow ) return;
    3095 
    3096         // Get horizontal width of line
    3097         /*
    3098         $limst = $aScale->iStartDate;
    3099         $limen = $aScale->iEndDate;
    3100         $xt = round($aScale->TranslateDate($aScale->iStartDate));
    3101         $xb = round($aScale->TranslateDate($limen));
    3102         */
    3103 
    3104         if( $this->iStart === 0 ) {
    3105             $xt = $aImg->left_margin-1;
    3106         }
    3107         else {
    3108             $xt = round($aScale->TranslateDate($aScale->iStartDate))+1;
    3109         }
    3110 
    3111         $xb = $aImg->width-$aImg->right_margin;
    3112 
    3113         $yt = round($aScale->TranslateVertPos(0));
    3114         $yb = round($aScale->TranslateVertPos(1));         
    3115         $height = $yb - $yt;
    3116 
    3117         // Loop around for all lines in the chart
    3118         for($i=0; $i < $aScale->iVertLines; ++$i ) {
    3119             $yb = $yt - $height;
    3120             $this->line->Stroke($aImg,$xt,$yb,$xb,$yb);
    3121             if( $this->iRowColor1 !== '' ) {
    3122                 if( $i % 2 == 0 ) {
    3123                     $aImg->PushColor($this->iRowColor1);
    3124                     $aImg->FilledRectangle($xt,$yt,$xb,$yb);
    3125                     $aImg->PopColor();
    3126                 }
    3127                 elseif( $this->iRowColor2 !== '' ) {
    3128                     $aImg->PushColor($this->iRowColor2);
    3129                     $aImg->FilledRectangle($xt,$yt,$xb,$yb);
    3130                     $aImg->PopColor();
    3131                 }
    3132             }
    3133             $yt = round($aScale->TranslateVertPos($i+1));
    3134         }
    3135         $yb = $yt - $height;
    3136         $this->line->Stroke($aImg,$xt,$yb,$xb,$yb);
     3197
     3198        if( ! $this->iShow ) return;
     3199
     3200        // Get horizontal width of line
     3201        /*
     3202        $limst = $aScale->iStartDate;
     3203        $limen = $aScale->iEndDate;
     3204        $xt = round($aScale->TranslateDate($aScale->iStartDate));
     3205        $xb = round($aScale->TranslateDate($limen));
     3206        */
     3207
     3208        if( $this->iStart === 0 ) {
     3209            $xt = $aImg->left_margin-1;
     3210        }
     3211        else {
     3212            $xt = round($aScale->TranslateDate($aScale->iStartDate))+1;
     3213        }
     3214
     3215        $xb = $aImg->width-$aImg->right_margin;
     3216
     3217        $yt = round($aScale->TranslateVertPos(0));
     3218        $yb = round($aScale->TranslateVertPos(1));
     3219        $height = $yb - $yt;
     3220
     3221        // Loop around for all lines in the chart
     3222        for($i=0; $i < $aScale->iVertLines; ++$i ) {
     3223            $yb = $yt - $height;
     3224            $this->line->Stroke($aImg,$xt,$yb,$xb,$yb);
     3225            if( $this->iRowColor1 !== '' ) {
     3226                if( $i % 2 == 0 ) {
     3227                    $aImg->PushColor($this->iRowColor1);
     3228                    $aImg->FilledRectangle($xt,$yt,$xb,$yb);
     3229                    $aImg->PopColor();
     3230                }
     3231                elseif( $this->iRowColor2 !== '' ) {
     3232                    $aImg->PushColor($this->iRowColor2);
     3233                    $aImg->FilledRectangle($xt,$yt,$xb,$yb);
     3234                    $aImg->PopColor();
     3235                }
     3236            }
     3237            $yt = round($aScale->TranslateVertPos($i+1));
     3238        }
     3239        $yb = $yt - $height;
     3240        $this->line->Stroke($aImg,$xt,$yb,$xb,$yb);
    31373241    }
    31383242}
     
    31513255    private $iShadow=false,$iShadowColor="darkgray",$iShadowWidth=1,$iShadowFrame="black";
    31523256    private $iPattern=GANTT_RDIAG,$iPatternColor="blue",$iPatternDensity=95;
    3153 //---------------
    3154 // CONSTRUCTOR 
    3155     function GanttBar($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) {
    3156         parent::GanttPlotObject();     
    3157         $this->iStart = $aStart;       
    3158         // Is the end date given as a date or as number of days added to start date?
    3159         if( is_string($aEnd) ) {
    3160             // If end date has been specified without a time we will asssume
    3161             // end date is at the end of that date
    3162             if( strpos($aEnd,':') === false )
    3163                 $this->iEnd = strtotime($aEnd)+SECPERDAY-1;
    3164             else
    3165                 $this->iEnd = $aEnd;
    3166         }
    3167         elseif(is_int($aEnd) || is_float($aEnd) )
    3168             $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY);
    3169         $this->iVPos = $aPos;
    3170         $this->iHeightFactor = $aHeightFactor;
    3171         $this->title->Set($aLabel);
    3172         $this->caption = new TextProperty($aCaption);
    3173         $this->caption->Align("left","center");
    3174         $this->leftMark =new PlotMark();
    3175         $this->leftMark->Hide();
    3176         $this->rightMark=new PlotMark();
    3177         $this->rightMark->Hide();
    3178         $this->progress = new Progress();
    3179     }
    3180        
    3181 //---------------
    3182 // PUBLIC METHODS       
     3257    private $iBreakStyle=false, $iBreakLineStyle='dotted',$iBreakLineWeight=1;
     3258    //---------------
     3259    // CONSTRUCTOR
     3260    function __construct($aPos,$aLabel,$aStart,$aEnd,$aCaption="",$aHeightFactor=0.6) {
     3261        parent::__construct();
     3262        $this->iStart = $aStart;
     3263        // Is the end date given as a date or as number of days added to start date?
     3264        if( is_string($aEnd) ) {
     3265            // If end date has been specified without a time we will asssume
     3266            // end date is at the end of that date
     3267            if( strpos($aEnd,':') === false ) {
     3268                $this->iEnd = strtotime($aEnd)+SECPERDAY-1;
     3269            }
     3270            else {
     3271                $this->iEnd = $aEnd;
     3272            }
     3273        }
     3274        elseif(is_int($aEnd) || is_float($aEnd) ) {
     3275                $this->iEnd = strtotime($aStart)+round($aEnd*SECPERDAY);
     3276        }
     3277        $this->iVPos = $aPos;
     3278        $this->iHeightFactor = $aHeightFactor;
     3279        $this->title->Set($aLabel);
     3280        $this->caption = new TextProperty($aCaption);
     3281        $this->caption->Align("left","center");
     3282        $this->leftMark =new PlotMark();
     3283        $this->leftMark->Hide();
     3284        $this->rightMark=new PlotMark();
     3285        $this->rightMark->Hide();
     3286        $this->progress = new Progress();
     3287    }
     3288
     3289    //---------------
     3290    // PUBLIC METHODS
    31833291    function SetShadow($aShadow=true,$aColor="gray") {
    3184         $this->iShadow=$aShadow;
    3185         $this->iShadowColor=$aColor;
    3186     }
    3187    
     3292        $this->iShadow=$aShadow;
     3293        $this->iShadowColor=$aColor;
     3294    }
     3295
     3296    function SetBreakStyle($aFlg=true,$aLineStyle='dotted',$aLineWeight=1) {
     3297        $this->iBreakStyle = $aFlg;
     3298        $this->iBreakLineStyle = $aLineStyle;
     3299        $this->iBreakLineWeight = $aLineWeight;
     3300    }
     3301
    31883302    function GetMaxDate() {
    3189         return $this->iEnd;
    3190     }
    3191        
     3303        return $this->iEnd;
     3304    }
     3305
    31923306    function SetHeight($aHeight) {
    3193         $this->iHeightFactor = $aHeight;
     3307        $this->iHeightFactor = $aHeight;
    31943308    }
    31953309
    31963310    function SetColor($aColor) {
    3197         $this->iFrameColor = $aColor;
     3311        $this->iFrameColor = $aColor;
    31983312    }
    31993313
    32003314    function SetFillColor($aColor) {
    3201         $this->iFillColor = $aColor;
     3315        $this->iFillColor = $aColor;
    32023316    }
    32033317
    32043318    function GetAbsHeight($aImg) {
    3205         if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) {
    3206             $m=-1;
    3207             if( is_int($this->iHeightFactor) )
    3208                 $m = $this->iHeightFactor;
    3209             if( $this->leftMark->show )
    3210                 $m = max($m,$this->leftMark->width*2);
    3211             if( $this->rightMark->show )
    3212                 $m = max($m,$this->rightMark->width*2);
    3213             return $m;
    3214         }
    3215         else
    3216             return -1;
    3217     }
    3218        
    3219     function SetPattern($aPattern,$aColor="blue",$aDensity=95) {               
    3220         $this->iPattern = $aPattern;
    3221         $this->iPatternColor = $aColor;
    3222         $this->iPatternDensity = $aDensity;
     3319        if( is_int($this->iHeightFactor) || $this->leftMark->show || $this->rightMark->show ) {
     3320            $m=-1;
     3321            if( is_int($this->iHeightFactor) )
     3322                $m = $this->iHeightFactor;
     3323            if( $this->leftMark->show )
     3324                $m = max($m,$this->leftMark->width*2);
     3325            if( $this->rightMark->show )
     3326                $m = max($m,$this->rightMark->width*2);
     3327            return $m;
     3328        }
     3329        else
     3330                return -1;
     3331    }
     3332
     3333    function SetPattern($aPattern,$aColor="blue",$aDensity=95) {
     3334        $this->iPattern = $aPattern;
     3335        $this->iPatternColor = $aColor;
     3336        $this->iPatternDensity = $aDensity;
    32233337    }
    32243338
    32253339    function Stroke($aImg,$aScale) {
    3226         $factory = new RectPatternFactory();
    3227         $prect = $factory->Create($this->iPattern,$this->iPatternColor);
    3228         $prect->SetDensity($this->iPatternDensity);
    3229 
    3230         // If height factor is specified as a float between 0,1 then we take it as meaning
    3231         // percetage of the scale width between horizontal line.
    3232         // If it is an integer > 1 we take it to mean the absolute height in pixels
    3233         if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1)
    3234             $vs = $aScale->GetVertSpacing()*$this->iHeightFactor;
    3235         elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 )
    3236             $vs = $this->iHeightFactor;
    3237         else
    3238             JpGraphError::RaiseL(6028,$this->iHeightFactor);
    3239 //("Specified height (".$this->iHeightFactor.") for gantt bar is out of range.");
    3240        
    3241         // Clip date to min max dates to show
    3242         $st = $aScale->NormalizeDate($this->iStart);
    3243         $en = $aScale->NormalizeDate($this->iEnd);
    3244        
    3245 
    3246         $limst = max($st,$aScale->iStartDate);
    3247         $limen = min($en,$aScale->iEndDate);
    3248                        
    3249         $xt = round($aScale->TranslateDate($limst));
    3250         $xb = round($aScale->TranslateDate($limen));
    3251         $yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2));
    3252         $yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2));
    3253         $middle = round($yt+($yb-$yt)/2);
    3254         $this->StrokeActInfo($aImg,$aScale,$middle);
    3255 
    3256         // CSIM for title
    3257         if( ! empty($this->title->csimtarget) ) {
    3258             $colwidth = $this->title->GetColWidth($aImg);
    3259             $colstarts=array();
    3260             $aScale->actinfo->GetColStart($aImg,$colstarts,true);
    3261             $n = min(count($colwidth),count($this->title->csimtarget));
    3262             for( $i=0; $i < $n; ++$i ) {
    3263                 $title_xt = $colstarts[$i];
    3264                 $title_xb = $title_xt + $colwidth[$i];
    3265                 $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb";
    3266 
    3267                 if( ! empty($this->title->csimtarget[$i]) ) {
    3268                     $this->csimarea .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->title->csimtarget[$i]."\"";
    3269                    
    3270                     if( ! empty($this->title->csimwintarget[$i]) ) {
    3271                         $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\" ";
    3272                     }
    3273                    
    3274                     if( ! empty($this->title->csimalt[$i]) ) {
    3275                         $tmp = $this->title->csimalt[$i];
    3276                         $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" ";
    3277                     }
    3278                     $this->csimarea .= " />\n";
    3279                 }
    3280             }
    3281         }
    3282        
    3283         // Check if the bar is totally outside the current scale range
    3284         if( $en <  $aScale->iStartDate || $st > $aScale->iEndDate )
    3285                 return;
    3286                        
    3287 
    3288         // Remember the positions for the bar
    3289         $this->SetConstrainPos($xt,$yt,$xb,$yb);
    3290                
    3291         $prect->ShowFrame(false);
    3292         $prect->SetBackground($this->iFillColor);
    3293         if( $this->iShadow ) {
    3294             $aImg->SetColor($this->iFrameColor);
    3295             $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor);                         
    3296             $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2));                             
    3297             $prect->Stroke($aImg);
    3298         }
    3299         else { 
    3300             $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1));                         
    3301             $prect->Stroke($aImg);
    3302             $aImg->SetColor($this->iFrameColor);
    3303             $aImg->Rectangle($xt,$yt,$xb,$yb);
    3304         }
    3305 
    3306         // CSIM for bar
    3307         if( ! empty($this->csimtarget) ) {
    3308 
    3309             $coords = "$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb";
    3310             $this->csimarea .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtarget."\"";
    3311            
    3312             if( !empty($this->csimwintarget) ) {
    3313                 $this->csimarea .= " target=\"".$this->csimwintarget."\" ";
    3314             }
    3315 
    3316             if( $this->csimalt != '' ) {
    3317                 $tmp = $this->csimalt;
    3318                 $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" ";
    3319             }
    3320             $this->csimarea .= " />\n";
    3321         }
    3322 
    3323         // Draw progress bar inside activity bar
    3324         if( $this->progress->iProgress > 0 ) {
    3325                
    3326             $xtp = $aScale->TranslateDate($st);
    3327             $xbp = $aScale->TranslateDate($en);
    3328             $len = ($xbp-$xtp)*$this->progress->iProgress;
    3329 
    3330             $endpos = $xtp+$len;
    3331             if( $endpos > $xt ) {
    3332 
    3333                 // Take away the length of the progress that is not visible (before the start date)
    3334                 $len -= ($xt-$xtp);
    3335 
    3336                 // Is the the progress bar visible after the start date?
    3337                 if( $xtp < $xt )
    3338                     $xtp = $xt;
    3339                
    3340                 // Make sure that the progess bar doesn't extend over the end date
    3341                 if( $xtp+$len-1 > $xb )
    3342                     $len = $xb - $xtp ;
    3343                
    3344                 $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor);
    3345                 $prog->SetDensity($this->progress->iDensity);
    3346                 $prog->SetBackground($this->progress->iFillColor);
    3347                 $barheight = ($yb-$yt+1);
    3348                 if( $this->iShadow )
    3349                     $barheight -= $this->iShadowWidth;
    3350                 $progressheight = floor($barheight*$this->progress->iHeight);
    3351                 $marg = ceil(($barheight-$progressheight)/2);
    3352                 $pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg);
    3353                 $prog->SetPos($pos);
    3354                 $prog->Stroke($aImg);
    3355             }
    3356         }
    3357        
    3358         // We don't plot the end mark if the bar has been capped
    3359         if( $limst == $st ) {
    3360             $y = $middle;
    3361             // We treat the RIGHT and LEFT triangle mark a little bi
    3362             // special so that these marks are placed right under the
    3363             // bar.
    3364             if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) {
    3365                 $y = $yb ;
    3366             }
    3367             $this->leftMark->Stroke($aImg,$xt,$y);
    3368         }
    3369         if( $limen == $en ) {
    3370             $y = $middle;
    3371             // We treat the RIGHT and LEFT triangle mark a little bi
    3372             // special so that these marks are placed right under the
    3373             // bar.
    3374             if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) {
    3375                 $y = $yb ;
    3376             }
    3377             $this->rightMark->Stroke($aImg,$xb,$y);
    3378            
    3379             $margin = $this->iCaptionMargin;
    3380             if( $this->rightMark->show )
    3381                 $margin += $this->rightMark->GetWidth();
    3382             $this->caption->Stroke($aImg,$xb+$margin,$middle);         
    3383         }
     3340        $factory = new RectPatternFactory();
     3341        $prect = $factory->Create($this->iPattern,$this->iPatternColor);
     3342        $prect->SetDensity($this->iPatternDensity);
     3343
     3344        // If height factor is specified as a float between 0,1 then we take it as meaning
     3345        // percetage of the scale width between horizontal line.
     3346        // If it is an integer > 1 we take it to mean the absolute height in pixels
     3347        if( $this->iHeightFactor > -0.0 && $this->iHeightFactor <= 1.1)
     3348                $vs = $aScale->GetVertSpacing()*$this->iHeightFactor;
     3349        elseif(is_int($this->iHeightFactor) && $this->iHeightFactor>2 && $this->iHeightFactor < 200 )
     3350                $vs = $this->iHeightFactor;
     3351        else {
     3352                JpGraphError::RaiseL(6028,$this->iHeightFactor);
     3353                //      ("Specified height (".$this->iHeightFactor.") for gantt bar is out of range.");
     3354        }
     3355
     3356        // Clip date to min max dates to show
     3357        $st = $aScale->NormalizeDate($this->iStart);
     3358        $en = $aScale->NormalizeDate($this->iEnd);
     3359
     3360        $limst = max($st,$aScale->iStartDate);
     3361        $limen = min($en,$aScale->iEndDate);
     3362
     3363        $xt = round($aScale->TranslateDate($limst));
     3364        $xb = round($aScale->TranslateDate($limen));
     3365        $yt = round($aScale->TranslateVertPos($this->iVPos)-$vs-($aScale->GetVertSpacing()/2-$vs/2));
     3366        $yb = round($aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2-$vs/2));
     3367        $middle = round($yt+($yb-$yt)/2);
     3368        $this->StrokeActInfo($aImg,$aScale,$middle);
     3369
     3370        // CSIM for title
     3371        if( ! empty($this->title->csimtarget) ) {
     3372            $colwidth = $this->title->GetColWidth($aImg);
     3373            $colstarts=array();
     3374            $aScale->actinfo->GetColStart($aImg,$colstarts,true);
     3375            $n = min(count($colwidth),count($this->title->csimtarget));
     3376            for( $i=0; $i < $n; ++$i ) {
     3377                $title_xt = $colstarts[$i];
     3378                $title_xb = $title_xt + $colwidth[$i];
     3379                $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb";
     3380
     3381                if( ! empty($this->title->csimtarget[$i]) ) {
     3382                    $this->csimarea .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->title->csimtarget[$i]."\"";
     3383
     3384                    if( ! empty($this->title->csimwintarget[$i]) ) {
     3385                        $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\" ";
     3386                    }
     3387
     3388                    if( ! empty($this->title->csimalt[$i]) ) {
     3389                        $tmp = $this->title->csimalt[$i];
     3390                        $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" ";
     3391                    }
     3392                    $this->csimarea .= " />\n";
     3393                }
     3394            }
     3395        }
     3396
     3397        // Check if the bar is totally outside the current scale range
     3398        if( $en <  $aScale->iStartDate || $st > $aScale->iEndDate )
     3399                return;
     3400
     3401
     3402        // Remember the positions for the bar
     3403        $this->SetConstrainPos($xt,$yt,$xb,$yb);
     3404
     3405
     3406
     3407        $prect->ShowFrame(false);
     3408        $prect->SetBackground($this->iFillColor);
     3409        if( $this->iBreakStyle ) {
     3410                $aImg->SetColor($this->iFrameColor);
     3411                $olds = $aImg->SetLineStyle($this->iBreakLineStyle);
     3412                $oldw = $aImg->SetLineWeight($this->iBreakLineWeight);
     3413                $aImg->StyleLine($xt,$yt,$xb,$yt);
     3414                $aImg->StyleLine($xt,$yb,$xb,$yb);
     3415                $aImg->SetLineStyle($olds);
     3416                $aImg->SetLineWeight($oldw);
     3417        }
     3418        else {
     3419                if( $this->iShadow ) {
     3420                    $aImg->SetColor($this->iFrameColor);
     3421                    $aImg->ShadowRectangle($xt,$yt,$xb,$yb,$this->iFillColor,$this->iShadowWidth,$this->iShadowColor);
     3422                    $prect->SetPos(new Rectangle($xt+1,$yt+1,$xb-$xt-$this->iShadowWidth-2,$yb-$yt-$this->iShadowWidth-2));
     3423                    $prect->Stroke($aImg);
     3424                }
     3425                else {
     3426                    $prect->SetPos(new Rectangle($xt,$yt,$xb-$xt+1,$yb-$yt+1));
     3427                    $prect->Stroke($aImg);
     3428                    $aImg->SetColor($this->iFrameColor);
     3429                    $aImg->Rectangle($xt,$yt,$xb,$yb);
     3430                }
     3431        }
     3432        // CSIM for bar
     3433        if( ! empty($this->csimtarget) ) {
     3434
     3435            $coords = "$xt,$yt,$xb,$yt,$xb,$yb,$xt,$yb";
     3436            $this->csimarea .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtarget."\"";
     3437
     3438            if( !empty($this->csimwintarget) ) {
     3439                $this->csimarea .= " target=\"".$this->csimwintarget."\" ";
     3440            }
     3441
     3442            if( $this->csimalt != '' ) {
     3443                $tmp = $this->csimalt;
     3444                $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" ";
     3445            }
     3446            $this->csimarea .= " />\n";
     3447        }
     3448
     3449        // Draw progress bar inside activity bar
     3450        if( $this->progress->iProgress > 0 ) {
     3451
     3452            $xtp = $aScale->TranslateDate($st);
     3453            $xbp = $aScale->TranslateDate($en);
     3454            $len = ($xbp-$xtp)*$this->progress->iProgress;
     3455
     3456            $endpos = $xtp+$len;
     3457            if( $endpos > $xt ) {
     3458
     3459                // Take away the length of the progress that is not visible (before the start date)
     3460                $len -= ($xt-$xtp);
     3461
     3462                // Is the the progress bar visible after the start date?
     3463                if( $xtp < $xt )
     3464                $xtp = $xt;
     3465
     3466                // Make sure that the progess bar doesn't extend over the end date
     3467                if( $xtp+$len-1 > $xb )
     3468                $len = $xb - $xtp ;
     3469
     3470                $prog = $factory->Create($this->progress->iPattern,$this->progress->iColor);
     3471                $prog->SetDensity($this->progress->iDensity);
     3472                $prog->SetBackground($this->progress->iFillColor);
     3473                $barheight = ($yb-$yt+1);
     3474                if( $this->iShadow )
     3475                        $barheight -= $this->iShadowWidth;
     3476                $progressheight = floor($barheight*$this->progress->iHeight);
     3477                $marg = ceil(($barheight-$progressheight)/2);
     3478                $pos = new Rectangle($xtp,$yt + $marg, $len,$barheight-2*$marg);
     3479                $prog->SetPos($pos);
     3480                $prog->Stroke($aImg);
     3481            }
     3482        }
     3483
     3484        // We don't plot the end mark if the bar has been capped
     3485        if( $limst == $st ) {
     3486            $y = $middle;
     3487            // We treat the RIGHT and LEFT triangle mark a little bi
     3488            // special so that these marks are placed right under the
     3489            // bar.
     3490            if( $this->leftMark->GetType() == MARK_LEFTTRIANGLE ) {
     3491                $y = $yb ;
     3492            }
     3493            $this->leftMark->Stroke($aImg,$xt,$y);
     3494        }
     3495        if( $limen == $en ) {
     3496            $y = $middle;
     3497            // We treat the RIGHT and LEFT triangle mark a little bi
     3498            // special so that these marks are placed right under the
     3499            // bar.
     3500            if( $this->rightMark->GetType() == MARK_RIGHTTRIANGLE ) {
     3501                $y = $yb ;
     3502            }
     3503            $this->rightMark->Stroke($aImg,$xb,$y);
     3504
     3505            $margin = $this->iCaptionMargin;
     3506            if( $this->rightMark->show )
     3507                $margin += $this->rightMark->GetWidth();
     3508            $this->caption->Stroke($aImg,$xb+$margin,$middle);
     3509        }
    33843510    }
    33853511}
     
    33913517class MileStone extends GanttPlotObject {
    33923518    public $mark;
    3393        
    3394 //---------------
    3395 // CONSTRUCTOR 
    3396     function MileStone($aVPos,$aLabel,$aDate,$aCaption="") {
    3397         GanttPlotObject::GanttPlotObject();
    3398         $this->caption->Set($aCaption);
    3399         $this->caption->Align("left","center");
    3400         $this->caption->SetFont(FF_FONT1,FS_BOLD);
    3401         $this->title->Set($aLabel);
    3402         $this->title->SetColor("darkred");
    3403         $this->mark = new PlotMark();
    3404         $this->mark->SetWidth(10);
    3405         $this->mark->SetType(MARK_DIAMOND);
    3406         $this->mark->SetColor("darkred");
    3407         $this->mark->SetFillColor("darkred");
    3408         $this->iVPos = $aVPos;
    3409         $this->iStart = $aDate;
    3410     }
    3411        
    3412 //---------------
    3413 // PUBLIC METHODS       
    3414        
     3519
     3520    //---------------
     3521    // CONSTRUCTOR
     3522    function __construct($aVPos,$aLabel,$aDate,$aCaption="") {
     3523        GanttPlotObject::__construct();
     3524        $this->caption->Set($aCaption);
     3525        $this->caption->Align("left","center");
     3526        $this->caption->SetFont(FF_FONT1,FS_BOLD);
     3527        $this->title->Set($aLabel);
     3528        $this->title->SetColor("darkred");
     3529        $this->mark = new PlotMark();
     3530        $this->mark->SetWidth(10);
     3531        $this->mark->SetType(MARK_DIAMOND);
     3532        $this->mark->SetColor("darkred");
     3533        $this->mark->SetFillColor("darkred");
     3534        $this->iVPos = $aVPos;
     3535        $this->iStart = $aDate;
     3536    }
     3537
     3538    //---------------
     3539    // PUBLIC METHODS
     3540
    34153541    function GetAbsHeight($aImg) {
    3416         return max($this->title->GetHeight($aImg),$this->mark->GetWidth());
    3417     }
    3418                
     3542        return max($this->title->GetHeight($aImg),$this->mark->GetWidth());
     3543    }
     3544
    34193545    function Stroke($aImg,$aScale) {
    3420         // Put the mark in the middle at the middle of the day
    3421         $d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2;
    3422         $x = $aScale->TranslateDate($d);
    3423         $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2);
    3424 
    3425         $this->StrokeActInfo($aImg,$aScale,$y);
    3426 
    3427         // CSIM for title
    3428         if( ! empty($this->title->csimtarget) ) {
    3429            
    3430             $yt = round($y - $this->title->GetHeight($aImg)/2);
    3431             $yb = round($y + $this->title->GetHeight($aImg)/2);
    3432 
    3433             $colwidth = $this->title->GetColWidth($aImg);
    3434             $colstarts=array();
    3435             $aScale->actinfo->GetColStart($aImg,$colstarts,true);
    3436             $n = min(count($colwidth),count($this->title->csimtarget));
    3437             for( $i=0; $i < $n; ++$i ) {
    3438                 $title_xt = $colstarts[$i];
    3439                 $title_xb = $title_xt + $colwidth[$i];
    3440                 $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb";
    3441                
    3442                 if( !empty($this->title->csimtarget[$i]) ) {
    3443                    
    3444                     $this->csimarea .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->title->csimtarget[$i]."\"";
    3445                    
    3446                     if( !empty($this->title->csimwintarget[$i]) ) {
    3447                         $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\"";
    3448                     }
    3449                    
    3450                     if( ! empty($this->title->csimalt[$i]) ) {
    3451                         $tmp = $this->title->csimalt[$i];
    3452                         $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" ";
    3453                     }
    3454                     $this->csimarea .= " />\n";
    3455                 }
    3456             }
    3457         }
    3458 
    3459         if( $d <  $aScale->iStartDate || $d > $aScale->iEndDate )
    3460                 return;
    3461 
    3462         // Remember the coordinates for any constrains linking to
    3463         // this milestone
    3464         $w = $this->mark->GetWidth()/2;
    3465         $this->SetConstrainPos($x,round($y-$w),$x,round($y+$w));
    3466        
    3467         // Setup CSIM
    3468         if( $this->csimtarget != '' ) {
    3469             $this->mark->SetCSIMTarget( $this->csimtarget );
    3470             $this->mark->SetCSIMAlt( $this->csimalt );
    3471         }
    3472                
    3473         $this->mark->Stroke($aImg,$x,$y);               
    3474         $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y);
    3475 
    3476         $this->csimarea .= $this->mark->GetCSIMAreas();
     3546        // Put the mark in the middle at the middle of the day
     3547        $d = $aScale->NormalizeDate($this->iStart)+SECPERDAY/2;
     3548        $x = $aScale->TranslateDate($d);
     3549        $y = $aScale->TranslateVertPos($this->iVPos)-($aScale->GetVertSpacing()/2);
     3550
     3551        $this->StrokeActInfo($aImg,$aScale,$y);
     3552
     3553        // CSIM for title
     3554        if( ! empty($this->title->csimtarget) ) {
     3555
     3556            $yt = round($y - $this->title->GetHeight($aImg)/2);
     3557            $yb = round($y + $this->title->GetHeight($aImg)/2);
     3558
     3559            $colwidth = $this->title->GetColWidth($aImg);
     3560            $colstarts=array();
     3561            $aScale->actinfo->GetColStart($aImg,$colstarts,true);
     3562            $n = min(count($colwidth),count($this->title->csimtarget));
     3563            for( $i=0; $i < $n; ++$i ) {
     3564                $title_xt = $colstarts[$i];
     3565                $title_xb = $title_xt + $colwidth[$i];
     3566                $coords = "$title_xt,$yt,$title_xb,$yt,$title_xb,$yb,$title_xt,$yb";
     3567
     3568                if( !empty($this->title->csimtarget[$i]) ) {
     3569
     3570                    $this->csimarea .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->title->csimtarget[$i]."\"";
     3571
     3572                    if( !empty($this->title->csimwintarget[$i]) ) {
     3573                        $this->csimarea .= "target=\"".$this->title->csimwintarget[$i]."\"";
     3574                    }
     3575
     3576                    if( ! empty($this->title->csimalt[$i]) ) {
     3577                        $tmp = $this->title->csimalt[$i];
     3578                        $this->csimarea .= " title=\"$tmp\" alt=\"$tmp\" ";
     3579                    }
     3580                    $this->csimarea .= " />\n";
     3581                }
     3582            }
     3583        }
     3584
     3585        if( $d <  $aScale->iStartDate || $d > $aScale->iEndDate )
     3586                return;
     3587
     3588        // Remember the coordinates for any constrains linking to
     3589        // this milestone
     3590        $w = $this->mark->GetWidth()/2;
     3591        $this->SetConstrainPos($x,round($y-$w),$x,round($y+$w));
     3592
     3593        // Setup CSIM
     3594        if( $this->csimtarget != '' ) {
     3595            $this->mark->SetCSIMTarget( $this->csimtarget );
     3596            $this->mark->SetCSIMAlt( $this->csimalt );
     3597        }
     3598
     3599        $this->mark->Stroke($aImg,$x,$y);
     3600        $this->caption->Stroke($aImg,$x+$this->mark->width/2+$this->iCaptionMargin,$y);
     3601
     3602        $this->csimarea .= $this->mark->GetCSIMAreas();
    34773603    }
    34783604}
     
    34853611
    34863612class TextPropertyBelow extends TextProperty {
    3487     function TextPropertyBelow($aTxt='') {
    3488         parent::TextProperty($aTxt);
     3613    function __construct($aTxt='') {
     3614        parent::__construct($aTxt);
    34893615    }
    34903616
    34913617    function GetColWidth($aImg,$aMargin=0) {
    3492         // Since we are not stroking the title in the columns
    3493         // but rather under the graph we want this to return 0.
    3494         return array(0);
     3618        // Since we are not stroking the title in the columns
     3619        // but rather under the graph we want this to return 0.
     3620        return array(0);
    34953621    }
    34963622}
     
    34983624class GanttVLine extends GanttPlotObject {
    34993625
    3500     private $iLine,$title_margin=3, $iDayOffset=1;
    3501        
    3502 //---------------
    3503 // CONSTRUCTOR 
    3504     function GanttVLine($aDate,$aTitle="",$aColor="black",$aWeight=3,$aStyle="dashed") {
    3505         GanttPlotObject::GanttPlotObject();
    3506         $this->iLine = new LineProperty();
    3507         $this->iLine->SetColor($aColor);
    3508         $this->iLine->SetWeight($aWeight);
    3509         $this->iLine->SetStyle($aStyle);
    3510         $this->iStart = $aDate;
    3511         $this->title = new TextPropertyBelow();
    3512         $this->title->Set($aTitle);
    3513     }
    3514 
    3515 //---------------
    3516 // PUBLIC METHODS       
     3626    private $iLine,$title_margin=3, $iDayOffset=0.5;
     3627    private $iStartRow = -1, $iEndRow = -1;
     3628
     3629    //---------------
     3630    // CONSTRUCTOR
     3631    function __construct($aDate,$aTitle="",$aColor="darkred",$aWeight=2,$aStyle="solid") {
     3632        GanttPlotObject::__construct();
     3633        $this->iLine = new LineProperty();
     3634        $this->iLine->SetColor($aColor);
     3635        $this->iLine->SetWeight($aWeight);
     3636        $this->iLine->SetStyle($aStyle);
     3637        $this->iStart = $aDate;
     3638        $this->title = new TextPropertyBelow();
     3639        $this->title->Set($aTitle);
     3640    }
     3641
     3642    //---------------
     3643    // PUBLIC METHODS
     3644
     3645    // Set start and end rows for the VLine. By default the entire heigh of the
     3646    // Gantt chart is used
     3647    function SetRowSpan($aStart, $aEnd=-1) {
     3648        $this->iStartRow = $aStart;
     3649        $this->iEndRow = $aEnd;
     3650    }
    35173651
    35183652    function SetDayOffset($aOff=0.5) {
    3519         if( $aOff < 0.0 || $aOff > 1.0 )
    3520             JpGraphError::RaiseL(6029);
    3521 //("Offset for vertical line must be in range [0,1]");
    3522         $this->iDayOffset = $aOff;
    3523     }
    3524        
     3653        if( $aOff < 0.0 || $aOff > 1.0 ) {
     3654                JpGraphError::RaiseL(6029);
     3655                //("Offset for vertical line must be in range [0,1]");
     3656        }
     3657        $this->iDayOffset = $aOff;
     3658    }
     3659
    35253660    function SetTitleMargin($aMarg) {
    3526         $this->title_margin = $aMarg;
    3527     }
    3528        
     3661        $this->title_margin = $aMarg;
     3662    }
     3663
     3664    function SetWeight($aWeight) {
     3665        $this->iLine->SetWeight($aWeight);
     3666    }
     3667
    35293668    function Stroke($aImg,$aScale) {
    3530         $d = $aScale->NormalizeDate($this->iStart);
    3531         if( $d <  $aScale->iStartDate || $d > $aScale->iEndDate )
    3532             return;     
    3533         if($this->iDayOffset != 0.0)
    3534             $d += 24*60*60*$this->iDayOffset;   
    3535         $x = $aScale->TranslateDate($d);       
    3536         $y1 = $aScale->iVertHeaderSize+$aImg->top_margin;
    3537         $y2 = $aImg->height - $aImg->bottom_margin;     
    3538         $this->iLine->Stroke($aImg,$x,$y1,$x,$y2);
    3539         $this->title->Align("center","top");
    3540         $this->title->Stroke($aImg,$x,$y2+$this->title_margin);
    3541     }   
     3669        $d = $aScale->NormalizeDate($this->iStart);
     3670        if( $d <  $aScale->iStartDate || $d > $aScale->iEndDate )
     3671            return;
     3672        if($this->iDayOffset != 0.0)
     3673            $d += 24*60*60*$this->iDayOffset;
     3674        $x = $aScale->TranslateDate($d);//d=1006858800,
     3675
     3676        if( $this->iStartRow > -1 ) {
     3677            $y1 = $aScale->TranslateVertPos($this->iStartRow,true) ;
     3678        }
     3679        else {
     3680            $y1 = $aScale->iVertHeaderSize+$aImg->top_margin;
     3681        }
     3682
     3683        if( $this->iEndRow > -1 ) {
     3684            $y2 = $aScale->TranslateVertPos($this->iEndRow);
     3685        }
     3686        else {
     3687            $y2 = $aImg->height - $aImg->bottom_margin;
     3688        }
     3689
     3690        $this->iLine->Stroke($aImg,$x,$y1,$x,$y2);
     3691        $this->title->Align("center","top");
     3692        $this->title->Stroke($aImg,$x,$y2+$this->title_margin);
     3693    }
    35423694}
    35433695
    35443696//===================================================
    35453697// CLASS LinkArrow
    3546 // Handles the drawing of a an arrow 
     3698// Handles the drawing of a an arrow
    35473699//===================================================
    35483700class LinkArrow {
    35493701    private $ix,$iy;
    35503702    private $isizespec = array(
    3551         array(2,3),array(3,5),array(3,8),array(6,15),array(8,22));
     3703    array(2,3),array(3,5),array(3,8),array(6,15),array(8,22));
    35523704    private $iDirection=ARROW_DOWN,$iType=ARROWT_SOLID,$iSize=ARROW_S2;
    35533705    private $iColor='black';
    35543706
    3555     function LinkArrow($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) {
    3556         $this->iDirection = $aDirection;
    3557         $this->iType = $aType;
    3558         $this->iSize = $aSize;
    3559         $this->ix = $x;
    3560         $this->iy = $y;
    3561     }
    3562    
     3707    function __construct($x,$y,$aDirection,$aType=ARROWT_SOLID,$aSize=ARROW_S2) {
     3708        $this->iDirection = $aDirection;
     3709        $this->iType = $aType;
     3710        $this->iSize = $aSize;
     3711        $this->ix = $x;
     3712        $this->iy = $y;
     3713    }
     3714
    35633715    function SetColor($aColor) {
    3564         $this->iColor = $aColor;
     3716        $this->iColor = $aColor;
    35653717    }
    35663718
    35673719    function SetSize($aSize) {
    3568         $this->iSize = $aSize;
     3720        $this->iSize = $aSize;
    35693721    }
    35703722
    35713723    function SetType($aType) {
    3572         $this->iType = $aType;
     3724        $this->iType = $aType;
    35733725    }
    35743726
    35753727    function Stroke($aImg) {
    3576         list($dx,$dy) = $this->isizespec[$this->iSize];
    3577         $x = $this->ix;
    3578         $y = $this->iy;
    3579         switch ( $this->iDirection ) {
    3580             case ARROW_DOWN:
    3581                 $c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y);
    3582                 break;
    3583             case ARROW_UP:
    3584                 $c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y);
    3585                 break;
    3586             case ARROW_LEFT:
    3587                 $c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y);
    3588                 break;
    3589             case ARROW_RIGHT:
    3590                 $c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y);
    3591                 break;
    3592             default:
    3593                 JpGraphError::RaiseL(6030);
    3594 //('Unknown arrow direction for link.');
    3595                 die();
    3596                 break;
    3597         }
    3598         $aImg->SetColor($this->iColor);
    3599         switch( $this->iType ) {
    3600             case ARROWT_SOLID:
    3601                 $aImg->FilledPolygon($c);
    3602                 break;
    3603             case ARROWT_OPEN:
    3604                 $aImg->Polygon($c);
    3605                 break;
    3606             default:
    3607                 JpGraphError::RaiseL(6031);
    3608 //('Unknown arrow type for link.');
    3609                 die();
    3610                 break;         
    3611         }
     3728        list($dx,$dy) = $this->isizespec[$this->iSize];
     3729        $x = $this->ix;
     3730        $y = $this->iy;
     3731        switch ( $this->iDirection ) {
     3732            case ARROW_DOWN:
     3733                $c = array($x,$y,$x-$dx,$y-$dy,$x+$dx,$y-$dy,$x,$y);
     3734                break;
     3735            case ARROW_UP:
     3736                $c = array($x,$y,$x-$dx,$y+$dy,$x+$dx,$y+$dy,$x,$y);
     3737                break;
     3738            case ARROW_LEFT:
     3739                $c = array($x,$y,$x+$dy,$y-$dx,$x+$dy,$y+$dx,$x,$y);
     3740                break;
     3741            case ARROW_RIGHT:
     3742                $c = array($x,$y,$x-$dy,$y-$dx,$x-$dy,$y+$dx,$x,$y);
     3743                break;
     3744            default:
     3745                JpGraphError::RaiseL(6030);
     3746                //('Unknown arrow direction for link.');
     3747                die();
     3748                break;
     3749        }
     3750        $aImg->SetColor($this->iColor);
     3751        switch( $this->iType ) {
     3752            case ARROWT_SOLID:
     3753                $aImg->FilledPolygon($c);
     3754                break;
     3755            case ARROWT_OPEN:
     3756                $aImg->Polygon($c);
     3757                break;
     3758            default:
     3759                JpGraphError::RaiseL(6031);
     3760                //('Unknown arrow type for link.');
     3761                die();
     3762                break;
     3763        }
    36123764    }
    36133765}
     
    36243776    private $iArrowSize=ARROW_S2,$iArrowType=ARROWT_SOLID;
    36253777
    3626     function GanttLink($x1=0,$y1=0,$x2=0,$y2=0) {
    3627         $this->ix1 = $x1;
    3628         $this->ix2 = $x2;
    3629         $this->iy1 = $y1;
    3630         $this->iy2 = $y2;
     3778    function __construct($x1=0,$y1=0,$x2=0,$y2=0) {
     3779        $this->ix1 = $x1;
     3780        $this->ix2 = $x2;
     3781        $this->iy1 = $y1;
     3782        $this->iy2 = $y2;
    36313783    }
    36323784
    36333785    function SetPos($x1,$y1,$x2,$y2) {
    3634         $this->ix1 = $x1;
    3635         $this->ix2 = $x2;
    3636         $this->iy1 = $y1;
    3637         $this->iy2 = $y2;
     3786        $this->ix1 = $x1;
     3787        $this->ix2 = $x2;
     3788        $this->iy1 = $y1;
     3789        $this->iy2 = $y2;
    36383790    }
    36393791
    36403792    function SetPath($aPath) {
    3641         $this->iPathType = $aPath;
     3793        $this->iPathType = $aPath;
    36423794    }
    36433795
    36443796    function SetColor($aColor) {
    3645         $this->iColor = $aColor;
     3797        $this->iColor = $aColor;
    36463798    }
    36473799
    36483800    function SetArrow($aSize,$aType=ARROWT_SOLID) {
    3649         $this->iArrowSize = $aSize;
    3650         $this->iArrowType = $aType;
    3651     }
    3652    
     3801        $this->iArrowSize = $aSize;
     3802        $this->iArrowType = $aType;
     3803    }
     3804
    36533805    function SetWeight($aWeight) {
    3654         $this->iWeight = $aWeight;
     3806        $this->iWeight = $aWeight;
    36553807    }
    36563808
    36573809    function Stroke($aImg) {
    3658         // The way the path for the arrow is constructed is partly based
    3659         // on some heuristics. This is not an exact science but draws the
    3660         // path in a way that, for me, makes esthetic sence. For example
    3661         // if the start and end activities are very close we make a small
    3662         // detour to endter the target horixontally. If there are more
    3663         // space between axctivities then no suh detour is made and the
    3664         // target is "hit" directly vertical. I have tried to keep this
    3665         // simple. no doubt this could become almost infinitive complex
    3666         // and have some real AI. Feel free to modify this.
    3667         // This will no-doubt be tweaked as times go by. One design aim
    3668         // is to avoid having the user choose what types of arrow
    3669         // he wants.
    3670 
    3671         // The arrow is drawn between (x1,y1) to (x2,y2)
    3672         $x1 = $this->ix1 ;
    3673         $x2 = $this->ix2 ;
    3674         $y1 = $this->iy1 ;
    3675         $y2 = $this->iy2 ;
    3676 
    3677         // Depending on if the target is below or above we have to
    3678         // handle thi different.
    3679         if( $y2 > $y1 ) {
    3680             $arrowtype = ARROW_DOWN;
    3681             $midy = round(($y2-$y1)/2+$y1);
    3682             if( $x2 > $x1 ) {
    3683                 switch ( $this->iPathType  ) {
    3684                     case 0:
    3685                         $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
    3686                         break;
    3687                     case 1:
    3688                     case 2:
    3689                     case 3:
    3690                         $c = array($x1,$y1,$x2,$y1,$x2,$y2);
    3691                         break;
    3692                     default:
    3693                         JpGraphError::RaiseL(6032,$this->iPathType);
    3694 //('Internal error: Unknown path type (='.$this->iPathType .') specified for link.');
    3695                         exit(1);
    3696                         break;
    3697                 }
    3698             }
    3699             else {
    3700                 switch ( $this->iPathType  ) {
    3701                     case 0:
    3702                     case 1:
    3703                         $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
    3704                         break;
    3705                     case 2:
    3706                         // Always extend out horizontally a bit from the first point
    3707                         // If we draw a link back in time (end to start) and the bars
    3708                         // are very close we also change the path so it comes in from
    3709                         // the left on the activity
    3710                         $c = array($x1,$y1,$x1+$this->iPathExtend,$y1,
    3711                                    $x1+$this->iPathExtend,$midy,
    3712                                    $x2,$midy,$x2,$y2);
    3713                         break;
    3714                     case 3:
    3715                         if( $y2-$midy < 6 ) {
    3716                             $c = array($x1,$y1,$x1,$midy,
    3717                                        $x2-$this->iPathExtend,$midy,
    3718                                        $x2-$this->iPathExtend,$y2,
    3719                                        $x2,$y2);
    3720                             $arrowtype = ARROW_RIGHT;
    3721                         }
    3722                         else {
    3723                             $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
    3724                         }
    3725                         break;
    3726                     default:
    3727                         JpGraphError::RaiseL(6032,$this->iPathType);
    3728 //('Internal error: Unknown path type specified for link.');
    3729                         exit(1);
    3730                         break;
    3731                 }
    3732             }
    3733             $arrow = new LinkArrow($x2,$y2,$arrowtype);
    3734         }
    3735         else {
    3736             // Y2 < Y1
    3737             $arrowtype = ARROW_UP;
    3738             $midy = round(($y1-$y2)/2+$y2);
    3739             if( $x2 > $x1 ) {
    3740                 switch ( $this->iPathType  ) {
    3741                     case 0:
    3742                     case 1:
    3743                         $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
    3744                         break;
    3745                     case 3:
    3746                         if( $midy-$y2 < 8 ) {
    3747                             $arrowtype = ARROW_RIGHT;
    3748                             $c = array($x1,$y1,$x1,$y2,$x2,$y2);
    3749                         }
    3750                         else {
    3751                             $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
    3752                         }
    3753                         break;
    3754                     default:
    3755                         JpGraphError::RaiseL(6032,$this->iPathType);
    3756 //('Internal error: Unknown path type specified for link.');
    3757                         break;
    3758                 }
    3759             }
    3760             else {
    3761                 switch ( $this->iPathType  ) {
    3762                     case 0:
    3763                     case 1:
    3764                         $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
    3765                         break;
    3766                     case 2:
    3767                         // Always extend out horizontally a bit from the first point
    3768                         $c = array($x1,$y1,$x1+$this->iPathExtend,$y1,
    3769                                    $x1+$this->iPathExtend,$midy,
    3770                                    $x2,$midy,$x2,$y2);
    3771                         break;
    3772                     case 3:
    3773                         if( $midy-$y2 < 16 ) {
    3774                             $arrowtype = ARROW_RIGHT;
    3775                             $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy,
    3776                                        $x2-$this->iPathExtend,$y2,
    3777                                        $x2,$y2);
    3778                         }
    3779                         else {
    3780                             $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
    3781                         }
    3782                         break;
    3783                     default:
    3784                         JpGraphError::RaiseL(6032,$this->iPathType);
    3785 //('Internal error: Unknown path type specified for link.');
    3786                         break;
    3787                 }
    3788             }
    3789             $arrow = new LinkArrow($x2,$y2,$arrowtype);
    3790         }
    3791         $aImg->SetColor($this->iColor);
    3792         $aImg->SetLineWeight($this->iWeight);
    3793         $aImg->Polygon($c);
    3794         $aImg->SetLineWeight(1);
    3795         $arrow->SetColor($this->iColor);
    3796         $arrow->SetSize($this->iArrowSize);
    3797         $arrow->SetType($this->iArrowType);
    3798         $arrow->Stroke($aImg);
     3810        // The way the path for the arrow is constructed is partly based
     3811        // on some heuristics. This is not an exact science but draws the
     3812        // path in a way that, for me, makes esthetic sence. For example
     3813        // if the start and end activities are very close we make a small
     3814        // detour to endter the target horixontally. If there are more
     3815        // space between axctivities then no suh detour is made and the
     3816        // target is "hit" directly vertical. I have tried to keep this
     3817        // simple. no doubt this could become almost infinitive complex
     3818        // and have some real AI. Feel free to modify this.
     3819        // This will no-doubt be tweaked as times go by. One design aim
     3820        // is to avoid having the user choose what types of arrow
     3821        // he wants.
     3822
     3823        // The arrow is drawn between (x1,y1) to (x2,y2)
     3824        $x1 = $this->ix1 ;
     3825        $x2 = $this->ix2 ;
     3826        $y1 = $this->iy1 ;
     3827        $y2 = $this->iy2 ;
     3828
     3829        // Depending on if the target is below or above we have to
     3830        // handle thi different.
     3831        if( $y2 > $y1 ) {
     3832            $arrowtype = ARROW_DOWN;
     3833            $midy = round(($y2-$y1)/2+$y1);
     3834            if( $x2 > $x1 ) {
     3835                switch ( $this->iPathType  ) {
     3836                    case 0:
     3837                        $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
     3838                        break;
     3839                    case 1:
     3840                    case 2:
     3841                    case 3:
     3842                        $c = array($x1,$y1,$x2,$y1,$x2,$y2);
     3843                        break;
     3844                    default:
     3845                        JpGraphError::RaiseL(6032,$this->iPathType);
     3846                        //('Internal error: Unknown path type (='.$this->iPathType .') specified for link.');
     3847                        exit(1);
     3848                        break;
     3849                }
     3850            }
     3851            else {
     3852                switch ( $this->iPathType  ) {
     3853                    case 0:
     3854                    case 1:
     3855                        $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
     3856                        break;
     3857                    case 2:
     3858                        // Always extend out horizontally a bit from the first point
     3859                        // If we draw a link back in time (end to start) and the bars
     3860                        // are very close we also change the path so it comes in from
     3861                        // the left on the activity
     3862                        $c = array($x1,$y1,$x1+$this->iPathExtend,$y1,
     3863                        $x1+$this->iPathExtend,$midy,
     3864                        $x2,$midy,$x2,$y2);
     3865                        break;
     3866                    case 3:
     3867                        if( $y2-$midy < 6 ) {
     3868                            $c = array($x1,$y1,$x1,$midy,
     3869                            $x2-$this->iPathExtend,$midy,
     3870                            $x2-$this->iPathExtend,$y2,
     3871                            $x2,$y2);
     3872                            $arrowtype = ARROW_RIGHT;
     3873                        }
     3874                        else {
     3875                            $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
     3876                        }
     3877                        break;
     3878                    default:
     3879                        JpGraphError::RaiseL(6032,$this->iPathType);
     3880                        //('Internal error: Unknown path type specified for link.');
     3881                        exit(1);
     3882                        break;
     3883                }
     3884            }
     3885            $arrow = new LinkArrow($x2,$y2,$arrowtype);
     3886        }
     3887        else {
     3888            // Y2 < Y1
     3889            $arrowtype = ARROW_UP;
     3890            $midy = round(($y1-$y2)/2+$y2);
     3891            if( $x2 > $x1 ) {
     3892                switch ( $this->iPathType  ) {
     3893                    case 0:
     3894                    case 1:
     3895                        $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
     3896                        break;
     3897                    case 3:
     3898                        if( $midy-$y2 < 8 ) {
     3899                            $arrowtype = ARROW_RIGHT;
     3900                            $c = array($x1,$y1,$x1,$y2,$x2,$y2);
     3901                        }
     3902                        else {
     3903                            $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
     3904                        }
     3905                        break;
     3906                    default:
     3907                        JpGraphError::RaiseL(6032,$this->iPathType);
     3908                        //('Internal error: Unknown path type specified for link.');
     3909                        break;
     3910                }
     3911            }
     3912            else {
     3913                switch ( $this->iPathType  ) {
     3914                    case 0:
     3915                    case 1:
     3916                        $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
     3917                        break;
     3918                    case 2:
     3919                        // Always extend out horizontally a bit from the first point
     3920                        $c = array($x1,$y1,$x1+$this->iPathExtend,$y1,
     3921                        $x1+$this->iPathExtend,$midy,
     3922                        $x2,$midy,$x2,$y2);
     3923                        break;
     3924                    case 3:
     3925                        if( $midy-$y2 < 16 ) {
     3926                            $arrowtype = ARROW_RIGHT;
     3927                            $c = array($x1,$y1,$x1,$midy,$x2-$this->iPathExtend,$midy,
     3928                            $x2-$this->iPathExtend,$y2,
     3929                            $x2,$y2);
     3930                        }
     3931                        else {
     3932                            $c = array($x1,$y1,$x1,$midy,$x2,$midy,$x2,$y2);
     3933                        }
     3934                        break;
     3935                    default:
     3936                        JpGraphError::RaiseL(6032,$this->iPathType);
     3937                        //('Internal error: Unknown path type specified for link.');
     3938                        break;
     3939                }
     3940            }
     3941            $arrow = new LinkArrow($x2,$y2,$arrowtype);
     3942        }
     3943        $aImg->SetColor($this->iColor);
     3944        $aImg->SetLineWeight($this->iWeight);
     3945        $aImg->Polygon($c);
     3946        $aImg->SetLineWeight(1);
     3947        $arrow->SetColor($this->iColor);
     3948        $arrow->SetSize($this->iArrowSize);
     3949        $arrow->SetType($this->iArrowType);
     3950        $arrow->Stroke($aImg);
    37993951    }
    38003952}
Note: See TracChangeset for help on using the changeset viewer.