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

Legend:

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

    r2 r265  
    11<?php
    22//=======================================================================
    3 // File:        JPGRAPH.PHP
    4 // Description: PHP Graph Plotting library. Base module.
    5 // Created:     2001-01-08
    6 // Ver:         $Id: jpgraph.php 1091 2009-01-18 22:57:40Z ljp $
     3// File:        JPGRAPH.PHP
     4// Description: PHP Graph Plotting library. Base module.
     5// Created:     2001-01-08
     6// Ver:         $Id: jpgraph.php 1924 2010-01-11 14:03:26Z ljp $
    77//
    8 // Copyright (c) Aditus Consulting. All rights reserved.
     8// Copyright (c) Asial Corporation. All rights reserved.
    99//========================================================================
    1010
     
    1616require_once('jpgraph_text.inc.php');
    1717require_once('jpgraph_legend.inc.php');
     18require_once('jpgraph_theme.inc.php');
     19require_once('gd_image.inc.php');
    1820
    1921// Version info
    20 define('JPG_VERSION','2.3.5-dev');
     22define('JPG_VERSION','4.2.6');
    2123
    2224// Minimum required PHP version
    2325define('MIN_PHPVERSION','5.1.0');
    2426
    25 // Should the image be a truecolor image?
    26 define('USE_TRUECOLOR',true);
    27 
    28 //------------------------------------------------------------------------
    29 // Automatic settings of path for cache and font directory
    30 // if they have not been previously specified
    31 //------------------------------------------------------------------------
    32 if(USE_CACHE) {
    33     if (!defined('CACHE_DIR')) {
    34         if ( strstr( PHP_OS, 'WIN') ) {
    35             if( empty($_SERVER['TEMP']) ) {
    36                 $t = new ErrMsgText();
    37                 $msg = $t->Get(11,$file,$lineno);
    38                 die($msg);
    39             }
    40             else {
    41                 define('CACHE_DIR', $_SERVER['TEMP'] . '/');
    42             }
    43         } else {
    44             define('CACHE_DIR','/tmp/jpgraph_cache/');
    45         }
    46     }
    47 }
    48 elseif( !defined('CACHE_DIR') ) {
    49     define('CACHE_DIR', '');
    50 }
    51 
    52 if (!defined('TTF_DIR')) {
    53     if (strstr( PHP_OS, 'WIN') ) {
    54         $sroot = getenv('SystemRoot');
    55         if( empty($sroot) ) {
    56             $t = new ErrMsgText();
    57             $msg = $t->Get(12,$file,$lineno);
    58             die($msg);
    59         }
    60         else {
    61           define('TTF_DIR', $sroot.'/fonts/');
    62         }
    63     } else {
    64         define('TTF_DIR','/usr/share/fonts/truetype/');
    65     }
    66 }
    67 
    68 if (!defined('MBTTF_DIR')) {
    69     if (strstr( PHP_OS, 'WIN') ) {
    70         $sroot = getenv('SystemRoot');
    71         if( empty($sroot) ) {
    72             $t = new ErrMsgText();
    73             $msg = $t->Get(12,$file,$lineno);
    74             die($msg);
    75         }
    76         else {
    77           define('TTF_DIR', $sroot.'/fonts/');
    78         }
    79     } else {
    80         define('MBTTF_DIR','/usr/share/fonts/ja/TrueType/');
    81     }
    82 }
    83 
    84 //------------------------------------------------------------------
    85 // Constants which are used as parameters for the method calls
    86 //------------------------------------------------------------------
    87 
     27// Special file name to indicate that we only want to calc
     28// the image map in the call to Graph::Stroke() used
     29// internally from the GetHTMLCSIM() method.
     30define('_CSIM_SPECIALFILE','_csim_special_');
     31
     32// HTTP GET argument that is used with image map
     33// to indicate to the script to just generate the image
     34// and not the full CSIM HTML page.
     35define('_CSIM_DISPLAY','_jpg_csimd');
     36
     37// Special filename for Graph::Stroke(). If this filename is given
     38// then the image will NOT be streamed to browser of file. Instead the
     39// Stroke call will return the handler for the created GD image.
     40define('_IMG_HANDLER','__handle');
     41
     42// Special filename for Graph::Stroke(). If this filename is given
     43// the image will be stroked to a file with a name based on the script name.
     44define('_IMG_AUTO','auto');
    8845
    8946// Tick density
     
    9350define("TICKD_VERYSPARSE",4);
    9451
    95 // Side for ticks and labels. 
     52// Side for ticks and labels.
    9653define("SIDE_LEFT",-1);
    9754define("SIDE_RIGHT",1);
     
    156113define("HORIZONTAL",0);
    157114
    158 
    159115// Axis styles for scientific style axis
    160116define('AXSTYLE_SIMPLE',1);
     
    176132define('TITLEBKG_FILLSTYLE_SOLID',3);
    177133
     134// Styles for axis labels background
     135define('LABELBKG_NONE',0);
     136define('LABELBKG_XAXIS',1);
     137define('LABELBKG_YAXIS',2);
     138define('LABELBKG_XAXISFULL',3);
     139define('LABELBKG_YAXISFULL',4);
     140define('LABELBKG_XYFULL',5);
     141define('LABELBKG_XY',6);
     142
     143
    178144// Style for background gradient fills
    179145define('BGRAD_FRAME',1);
     
    191157define('SKEW3D_RIGHT',3);
    192158
    193 // Line styles
    194 define('LINESTYLE_SOLID',1);
    195 define('LINESTYLE_DOTTED',2);
    196 define('LINESTYLE_DASHED',3);
    197 define('LINESTYLE_LONGDASH',4);
    198 
    199159// For internal use only
    200160define("_JPG_DEBUG",false);
     
    202162define("_FORCE_IMGDIR",'/tmp/jpgimg/');
    203163
    204 require_once('gd_image.inc.php');
    205 
    206 function CheckPHPVersion($aMinVersion)
    207 {
    208     list($majorC, $minorC, $editC) = split('[/.-]', PHP_VERSION);
    209     list($majorR, $minorR, $editR) = split('[/.-]', $aMinVersion);
    210  
    211     if ($majorC != $majorR) return false;
     164
     165//
     166// Automatic settings of path for cache and font directory
     167// if they have not been previously specified
     168//
     169if(USE_CACHE) {
     170    if (!defined('CACHE_DIR')) {
     171        if ( strstr( PHP_OS, 'WIN') ) {
     172            if( empty($_SERVER['TEMP']) ) {
     173                $t = new ErrMsgText();
     174                $msg = $t->Get(11,$file,$lineno);
     175                die($msg);
     176            }
     177            else {
     178                define('CACHE_DIR', $_SERVER['TEMP'] . '/');
     179            }
     180        } else {
     181            define('CACHE_DIR','/tmp/jpgraph_cache/');
     182        }
     183    }
     184}
     185elseif( !defined('CACHE_DIR') ) {
     186    define('CACHE_DIR', '');
     187}
     188
     189//
     190// Setup path for western/latin TTF fonts
     191//
     192if (!defined('TTF_DIR')) {
     193    if (strstr( PHP_OS, 'WIN') ) {
     194        $sroot = getenv('SystemRoot');
     195        if( empty($sroot) ) {
     196            $t = new ErrMsgText();
     197            $msg = $t->Get(12,$file,$lineno);
     198            die($msg);
     199        }
     200        else {
     201            define('TTF_DIR', $sroot.'/fonts/');
     202        }
     203    } else {
     204        define('TTF_DIR','/usr/share/fonts/truetype/');
     205    }
     206}
     207
     208//
     209// Setup path for MultiByte TTF fonts (japanese, chinese etc.)
     210//
     211if (!defined('MBTTF_DIR')) {
     212    if (strstr( PHP_OS, 'WIN') ) {
     213        $sroot = getenv('SystemRoot');
     214        if( empty($sroot) ) {
     215            $t = new ErrMsgText();
     216            $msg = $t->Get(12,$file,$lineno);
     217            die($msg);
     218        }
     219        else {
     220            define('MBTTF_DIR', $sroot.'/fonts/');
     221        }
     222    } else {
     223        define('MBTTF_DIR','/usr/share/fonts/truetype/');
     224    }
     225}
     226
     227//
     228// Check minimum PHP version
     229//
     230function CheckPHPVersion($aMinVersion) {
     231    list($majorC, $minorC, $editC) = preg_split('/[\/.-]/', PHP_VERSION);
     232    list($majorR, $minorR, $editR) = preg_split('/[\/.-]/', $aMinVersion);
     233
    212234    if ($majorC < $majorR) return false;
    213     // same major - check ninor
    214     if ($minorC > $minorR) return true;
    215     if ($minorC < $minorR) return false;
    216     // and same minor
    217     if ($editC  >= $editR)  return true;
     235
     236    if ($majorC == $majorR) {
     237        if($minorC < $minorR) return false;
     238
     239        if($minorC == $minorR){
     240            if($editC < $editR) return false;
     241        }
     242    }
     243
    218244    return true;
    219245}
     
    227253}
    228254
    229 
    230255//
    231256// Make GD sanity check
     
    233258if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) {
    234259    JpGraphError::RaiseL(25001);
    235 //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)");
     260    //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)");
    236261}
    237262
     
    242267    // Respect current error level
    243268    if( $errno & error_reporting() ) {
    244         JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg);
     269        JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg);
    245270    }
    246271}
     
    251276
    252277//
    253 //Check if there were any warnings, perhaps some wrong includes by the
    254 //user
     278// Check if there were any warnings, perhaps some wrong includes by the user. In this
     279// case we raise it immediately since otherwise the image will not show and makes
     280// debugging difficult. This is controlled by the user setting CATCH_PHPERRMSG
    255281//
    256 if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG &&
    257     !preg_match('/|Deprecated|/i', $GLOBALS['php_errormsg']) ) {
     282if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && !preg_match('/|Deprecated|/i', $GLOBALS['php_errormsg']) ) {
    258283    JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']);
    259284}
    260285
    261 
    262286// Useful mathematical function
    263287function sign($a) {return $a >= 0 ? 1 : -1;}
    264288
     289//
    265290// Utility function to generate an image name based on the filename we
    266291// are running from and assuming we use auto detection of graphic format
    267292// (top level), i.e it is safe to call this function
    268293// from a script that uses JpGraph
     294//
    269295function GenImgName() {
    270296    // Determine what format we should use when we save the images
    271297    $supported = imagetypes();
    272     if( $supported & IMG_PNG )     $img_format="png";
     298    if( $supported & IMG_PNG )    $img_format="png";
    273299    elseif( $supported & IMG_GIF ) $img_format="gif";
    274300    elseif( $supported & IMG_JPG ) $img_format="jpeg";
     
    277303
    278304
    279     if( !isset($_SERVER['PHP_SELF']) )
    280         JpGraphError::RaiseL(25005);
    281 //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files.");
     305    if( !isset($_SERVER['PHP_SELF']) ) {
     306        JpGraphError::RaiseL(25005);
     307        //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files.");
     308    }
    282309    $fname = basename($_SERVER['PHP_SELF']);
    283310    if( !empty($_SERVER['QUERY_STRING']) ) {
    284         $q = @$_SERVER['QUERY_STRING'];
    285         $fname .= '_'.preg_replace("/\W/", "_", $q).'.'.$img_format;
     311        $q = @$_SERVER['QUERY_STRING'];
     312        $fname .= '_'.preg_replace("/\W/", "_", $q).'.'.$img_format;
    286313    }
    287314    else {
    288         $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format;
     315        $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format;
    289316    }
    290317    return $fname;
    291318}
    292 
    293319
    294320//===================================================
     
    299325//===================================================
    300326class JpgTimer {
    301     private $start, $idx;       
    302 //---------------
    303 // CONSTRUCTOR
    304     function JpgTimer() {
    305         $this->idx=0;
    306     }
    307 
    308 //---------------
    309 // PUBLIC METHODS       
     327    private $start, $idx;
     328
     329    function __construct() {
     330        $this->idx=0;
     331    }
    310332
    311333    // Push a new timer start on stack
    312334    function Push() {
    313         list($ms,$s)=explode(" ",microtime()); 
    314         $this->start[$this->idx++]=floor($ms*1000) + 1000*$s;   
     335        list($ms,$s)=explode(" ",microtime());
     336        $this->start[$this->idx++]=floor($ms*1000) + 1000*$s;
    315337    }
    316338
     
    318340    // current time
    319341    function Pop() {
    320         assert($this->idx>0);
    321         list($ms,$s)=explode(" ",microtime()); 
    322         $etime=floor($ms*1000) + (1000*$s);
    323         $this->idx--;
    324         return $etime-$this->start[$this->idx];
     342        assert($this->idx>0);
     343        list($ms,$s)=explode(" ",microtime());
     344        $etime=floor($ms*1000) + (1000*$s);
     345        $this->idx--;
     346        return $etime-$this->start[$this->idx];
    325347    }
    326348} // Class
    327349
    328 $gJpgBrandTiming = BRAND_TIMING;
    329350//===================================================
    330351// CLASS DateLocale
     
    332353//===================================================
    333354class DateLocale {
    334  
     355
    335356    public $iLocale = 'C'; // environmental locale be used by default
    336357    private $iDayAbb = null, $iShortDay = null, $iShortMonth = null, $iMonthName = null;
    337358
    338 //---------------
    339 // CONSTRUCTOR 
    340     function DateLocale() {
    341         settype($this->iDayAbb, 'array');
    342         settype($this->iShortDay, 'array');
    343         settype($this->iShortMonth, 'array');
    344         settype($this->iMonthName, 'array');
    345 
    346 
    347         $this->Set('C');
    348     }
    349 
    350 //---------------
    351 // PUBLIC METHODS       
     359    function __construct() {
     360        settype($this->iDayAbb, 'array');
     361        settype($this->iShortDay, 'array');
     362        settype($this->iShortMonth, 'array');
     363        settype($this->iMonthName, 'array');
     364        $this->Set('C');
     365    }
     366
    352367    function Set($aLocale) {
    353         if ( in_array($aLocale, array_keys($this->iDayAbb)) ){
    354             $this->iLocale = $aLocale;
    355             return TRUE;  // already cached nothing else to do!
    356         }
    357 
    358         $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME
    359 
    360         if (is_array($aLocale)) {
    361             foreach ($aLocale as $loc) {
    362                 $res = @setlocale(LC_TIME, $loc);
    363                 if ( $res ) {
    364                     $aLocale = $loc;
    365                     break;
    366                 }
    367             }
    368         }
    369         else {
    370             $res = @setlocale(LC_TIME, $aLocale);
    371         }
    372 
    373         if ( ! $res ){
    374             JpGraphError::RaiseL(25007,$aLocale);
    375 //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region.");
    376             return FALSE;
    377         }
    378  
    379         $this->iLocale = $aLocale;
    380         for ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){
    381             $day = strftime('%a', strtotime("$ofs day"));
    382             $day[0] = strtoupper($day[0]);
    383             $this->iDayAbb[$aLocale][]= $day[0];
    384             $this->iShortDay[$aLocale][]= $day;
    385         }
    386 
    387         for($i=1; $i<=12; ++$i) {
    388             list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01")));
    389             $this->iShortMonth[$aLocale][] = ucfirst($short);
    390             $this->iMonthName [$aLocale][] = ucfirst($full);
    391         }
    392                
    393         setlocale(LC_TIME, $pLocale);
    394 
    395         return TRUE;
     368        if ( in_array($aLocale, array_keys($this->iDayAbb)) ){
     369            $this->iLocale = $aLocale;
     370            return TRUE;  // already cached nothing else to do!
     371        }
     372
     373        $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME
     374
     375        if (is_array($aLocale)) {
     376            foreach ($aLocale as $loc) {
     377                $res = @setlocale(LC_TIME, $loc);
     378                if ( $res ) {
     379                    $aLocale = $loc;
     380                    break;
     381                }
     382            }
     383        }
     384        else {
     385            $res = @setlocale(LC_TIME, $aLocale);
     386        }
     387
     388        if ( ! $res ) {
     389            JpGraphError::RaiseL(25007,$aLocale);
     390            //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region.");
     391            return FALSE;
     392        }
     393
     394        $this->iLocale = $aLocale;
     395        for( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ) {
     396            $day = strftime('%a', strtotime("$ofs day"));
     397            $day[0] = strtoupper($day[0]);
     398            $this->iDayAbb[$aLocale][]= $day[0];
     399            $this->iShortDay[$aLocale][]= $day;
     400        }
     401
     402        for($i=1; $i<=12; ++$i) {
     403            list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01")));
     404            $this->iShortMonth[$aLocale][] = ucfirst($short);
     405            $this->iMonthName [$aLocale][] = ucfirst($full);
     406        }
     407
     408        setlocale(LC_TIME, $pLocale);
     409
     410        return TRUE;
    396411    }
    397412
    398413
    399414    function GetDayAbb() {
    400         return $this->iDayAbb[$this->iLocale];
    401     }
    402        
     415        return $this->iDayAbb[$this->iLocale];
     416    }
     417
    403418    function GetShortDay() {
    404         return $this->iShortDay[$this->iLocale];
     419        return $this->iShortDay[$this->iLocale];
    405420    }
    406421
    407422    function GetShortMonth() {
    408         return $this->iShortMonth[$this->iLocale];
    409     }
    410        
     423        return $this->iShortMonth[$this->iLocale];
     424    }
     425
    411426    function GetShortMonthName($aNbr) {
    412         return $this->iShortMonth[$this->iLocale][$aNbr];
     427        return $this->iShortMonth[$this->iLocale][$aNbr];
    413428    }
    414429
    415430    function GetLongMonthName($aNbr) {
    416         return $this->iMonthName[$this->iLocale][$aNbr];
     431        return $this->iMonthName[$this->iLocale][$aNbr];
    417432    }
    418433
    419434    function GetMonth() {
    420         return $this->iMonthName[$this->iLocale];
     435        return $this->iMonthName[$this->iLocale];
    421436    }
    422437}
    423438
     439// Global object handlers
    424440$gDateLocale = new DateLocale();
    425441$gJpgDateLocale = new DateLocale();
     
    432448    public $iLeftMargin = 3, $iRightMargin = 3, $iBottomMargin = 3 ;
    433449    public $left,$center,$right;
    434 
    435     function Footer() {
    436         $this->left = new Text();
    437         $this->left->ParagraphAlign('left');
    438         $this->center = new Text();
    439         $this->center->ParagraphAlign('center');
    440         $this->right = new Text();
    441         $this->right->ParagraphAlign('right');
     450    private $iTimer=null, $itimerpoststring='';
     451
     452    function __construct() {
     453        $this->left = new Text();
     454        $this->left->ParagraphAlign('left');
     455        $this->center = new Text();
     456        $this->center->ParagraphAlign('center');
     457        $this->right = new Text();
     458        $this->right->ParagraphAlign('right');
     459    }
     460
     461    function SetTimer($aTimer,$aTimerPostString='') {
     462        $this->iTimer = $aTimer;
     463        $this->itimerpoststring = $aTimerPostString;
    442464    }
    443465
    444466    function SetMargin($aLeft=3,$aRight=3,$aBottom=3) {
    445         $this->iLeftMargin = $aLeft;
    446         $this->iRightMargin = $aRight;
    447         $this->iBottomMargin = $aBottom;
     467        $this->iLeftMargin = $aLeft;
     468        $this->iRightMargin = $aRight;
     469        $this->iBottomMargin = $aBottom;
    448470    }
    449471
    450472    function Stroke($aImg) {
    451         $y = $aImg->height - $this->iBottomMargin;
    452         $x = $this->iLeftMargin;
    453         $this->left->Align('left','bottom');
    454         $this->left->Stroke($aImg,$x,$y);
    455 
    456         $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2;
    457         $this->center->Align('center','bottom');
    458         $this->center->Stroke($aImg,$x,$y);
    459 
    460         $x = $aImg->width - $this->iRightMargin;
    461         $this->right->Align('right','bottom');
    462         $this->right->Stroke($aImg,$x,$y);
     473        $y = $aImg->height - $this->iBottomMargin;
     474        $x = $this->iLeftMargin;
     475        $this->left->Align('left','bottom');
     476        $this->left->Stroke($aImg,$x,$y);
     477
     478        $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2;
     479        $this->center->Align('center','bottom');
     480        $this->center->Stroke($aImg,$x,$y);
     481
     482        $x = $aImg->width - $this->iRightMargin;
     483        $this->right->Align('right','bottom');
     484        if( $this->iTimer != null ) {
     485            $this->right->Set( $this->right->t . sprintf('%.3f',$this->iTimer->Pop()/1000.0) . $this->itimerpoststring );
     486        }
     487        $this->right->Stroke($aImg,$x,$y);
    463488    }
    464489}
     
    470495//===================================================
    471496class Graph {
    472     public $cache=null;                 // Cache object (singleton)
    473     public $img=null;                   // Img object (singleton)
    474     public $plots=array();              // Array of all plot object in the graph (for Y 1 axis)
    475     public $y2plots=array();            // Array of all plot object in the graph (for Y 2 axis)
     497    public $cache=null;   // Cache object (singleton)
     498    public $img=null;   // Img object (singleton)
     499    public $plots=array();  // Array of all plot object in the graph (for Y 1 axis)
     500    public $y2plots=array();  // Array of all plot object in the graph (for Y 2 axis)
    476501    public $ynplots=array();
    477     public $xscale=null;                // X Scale object (could be instance of LinearScale or LogScale
     502    public $xscale=null;  // X Scale object (could be instance of LinearScale or LogScale
    478503    public $yscale=null,$y2scale=null, $ynscale=array();
    479     public $iIcons = array();           // Array of Icons to add to
    480     public $cache_name;                 // File name to be used for the current graph in the cache directory
    481     public $xgrid=null;                 // X Grid object (linear or logarithmic)
    482     public $ygrid=null,$y2grid=null;    //dito for Y
    483     public $doframe=true,$frame_color=array(0,0,0), $frame_weight=1;    // Frame around graph
    484     public $boxed=false, $box_color=array(0,0,0), $box_weight=1;                // Box around plot area
    485     public $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102);    // Shadow for graph
    486     public $xaxis=null;                 // X-axis (instane of Axis class)
    487     public $yaxis=null, $y2axis=null, $ynaxis=array();  // Y axis (instance of Axis class)
    488     public $margin_color=array(200,200,200);    // Margin color of graph
    489     public $plotarea_color=array(255,255,255);  // Plot area color
    490     public $title,$subtitle,$subsubtitle;       // Title and subtitle(s) text object
    491     public $axtype="linlin";            // Type of axis
    492     public $xtick_factor,$ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width
    493     public $texts=null, $y2texts=null;  // Text object to ge shown in the graph
     504    public $iIcons = array();  // Array of Icons to add to
     505    public $cache_name;   // File name to be used for the current graph in the cache directory
     506    public $xgrid=null;   // X Grid object (linear or logarithmic)
     507    public $ygrid=null,$y2grid=null; //dito for Y
     508    public $doframe,$frame_color, $frame_weight; // Frame around graph
     509    public $boxed=false, $box_color='black', $box_weight=1;  // Box around plot area
     510    public $doshadow=false,$shadow_width=4,$shadow_color='gray@0.5'; // Shadow for graph
     511    public $xaxis=null;   // X-axis (instane of Axis class)
     512    public $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class)
     513    public $margin_color; // Margin color of graph
     514    public $plotarea_color=array(255,255,255); // Plot area color
     515    public $title,$subtitle,$subsubtitle;  // Title and subtitle(s) text object
     516    public $axtype="linlin";  // Type of axis
     517    public $xtick_factor,$ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width
     518    public $texts=null, $y2texts=null; // Text object to ge shown in the graph
    494519    public $lines=null, $y2lines=null;
    495520    public $bands=null, $y2bands=null;
    496     public $text_scale_off=0, $text_scale_abscenteroff=-1;      // Text scale in fractions and for centering bars
    497     public $background_image="",$background_image_type=-1,$background_image_format="png";
     521    public $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale in fractions and for centering bars
     522    public $background_image='',$background_image_type=-1,$background_image_format="png";
    498523    public $background_image_bright=0,$background_image_contr=0,$background_image_sat=0;
    499524    public $background_image_xpos=0,$background_image_ypos=0;
     
    501526    public $inline;
    502527    public $showcsim=0,$csimcolor="red";//debug stuff, draw the csim boundaris on the image if <>0
    503     public $grid_depth=DEPTH_BACK;      // Draw grid under all plots as default
     528    public $grid_depth=DEPTH_BACK; // Draw grid under all plots as default
    504529    public $iAxisStyle = AXSTYLE_SIMPLE;
    505530    public $iCSIMdisplay=false,$iHasStroked = false;
     
    511536    public $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN;
    512537    public $bkg_gradfrom='navy', $bkg_gradto='silver';
     538    public $plot_gradtype=-1,$plot_gradstyle=BGRAD_MARGIN;
     539    public $plot_gradfrom='silver', $plot_gradto='navy';
     540
    513541    public $titlebackground = false;
    514542    public $titlebackground_color = 'lightblue',
    515         $titlebackground_style = 1,
    516         $titlebackground_framecolor = 'blue',
    517         $titlebackground_framestyle = 2,
    518         $titlebackground_frameweight = 1,
    519         $titlebackground_bevelheight = 3 ;
     543           $titlebackground_style = 1,
     544           $titlebackground_framecolor,
     545           $titlebackground_framestyle,
     546           $titlebackground_frameweight,
     547           $titlebackground_bevelheight;
    520548    public $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;
    521549    public $titlebkg_scolor1='black',$titlebkg_scolor2='white';
    522     public $framebevel = false, $framebeveldepth = 2 ;
    523     public $framebevelborder = false, $framebevelbordercolor='black';
    524     public $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4';
     550    public $framebevel, $framebeveldepth;
     551    public $framebevelborder, $framebevelbordercolor;
     552    public $framebevelcolor1, $framebevelcolor2;
    525553    public $background_image_mix=100;
    526554    public $background_cflag = '';
     
    528556    public $background_cflag_mix = 100;
    529557    public $iImgTrans=false,
    530         $iImgTransHorizon = 100,$iImgTransSkewDist=150,
    531         $iImgTransDirection = 1, $iImgTransMinSize = true,
    532         $iImgTransFillColor='white',$iImgTransHighQ=false,
    533         $iImgTransBorder=false,$iImgTransHorizonPos=0.5;
     558           $iImgTransHorizon = 100,$iImgTransSkewDist=150,
     559           $iImgTransDirection = 1, $iImgTransMinSize = true,
     560           $iImgTransFillColor='white',$iImgTransHighQ=false,
     561           $iImgTransBorder=false,$iImgTransHorizonPos=0.5;
    534562    public $legend;
     563    public $graph_theme;
    535564    protected $iYAxisDeltaPos=50;
    536565    protected $iIconDepth=DEPTH_BACK;
    537566    protected $iAxisLblBgType = 0,
    538         $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black',
    539         $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black';
     567              $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black',
     568              $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black';
    540569    protected $iTables=NULL;
    541570
    542 //---------------
    543 // CONSTRUCTOR
    544 
    545     // aWIdth           Width in pixels of image
    546     // aHeight          Height in pixels of image
    547     // aCachedName      Name for image file in cache directory
    548     // aTimeOut         Timeout in minutes for image in cache
    549     // aInline          If true the image is streamed back in the call to Stroke()
    550     //                  If false the image is just created in the cache
    551     function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) {
    552         GLOBAL $gJpgBrandTiming;
    553         // If timing is used create a new timing object
    554         if( $gJpgBrandTiming ) {
    555             global $tim;
    556             $tim = new JpgTimer();
    557             $tim->Push();
    558         }
    559 
    560         if( !is_numeric($aWidth) || !is_numeric($aHeight) ) {
    561             JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric');
    562         }               
    563 
    564         // Automatically generate the image file name based on the name of the script that
    565         // generates the graph
    566         if( $aCachedName=="auto" )
    567             $aCachedName=GenImgName();
    568                        
    569         // Should the image be streamed back to the browser or only to the cache?
    570         $this->inline=$aInline;
    571                
    572         $this->img      = new RotImage($aWidth,$aHeight);
    573 
    574         $this->cache    = new ImgStreamCache($this->img);
    575         $this->cache->SetTimeOut($aTimeOut);
    576 
    577         $this->title = new Text();
    578         $this->title->ParagraphAlign('center');
    579         $this->title->SetFont(FF_FONT2,FS_BOLD);
    580         $this->title->SetMargin(3);
    581         $this->title->SetAlign('center');
    582 
    583         $this->subtitle = new Text();
    584         $this->subtitle->ParagraphAlign('center');
    585         $this->subtitle->SetMargin(2);
    586         $this->subtitle->SetAlign('center');
    587 
    588         $this->subsubtitle = new Text();
    589         $this->subsubtitle->ParagraphAlign('center');
    590         $this->subsubtitle->SetMargin(2);
    591         $this->subsubtitle->SetAlign('center');
    592 
    593         $this->legend = new Legend();
    594         $this->footer = new Footer();
    595 
    596         // Window doesn't like '?' in the file name so replace it with an '_'
    597         $aCachedName = str_replace("?","_",$aCachedName);
    598 
    599         // If the cached version exist just read it directly from the
    600         // cache, stream it back to browser and exit
    601         if( $aCachedName!="" && READ_CACHE && $aInline )
    602             if( $this->cache->GetAndStream($aCachedName) ) {
    603                 exit();
    604             }
    605                                
    606         $this->cache_name = $aCachedName;
    607         $this->SetTickDensity(); // Normal density
    608 
    609         $this->tabtitle = new GraphTabTitle();
    610     }
    611 //---------------
    612 // PUBLIC METHODS       
    613    
     571    protected $isRunningClear = false;
     572    protected $inputValues;
     573    protected $isAfterSetScale = false;
     574
     575    // aWIdth   Width in pixels of image
     576    // aHeight   Height in pixels of image
     577    // aCachedName Name for image file in cache directory
     578    // aTimeOut  Timeout in minutes for image in cache
     579    // aInline  If true the image is streamed back in the call to Stroke()
     580    //   If false the image is just created in the cache
     581    function __construct($aWidth=300,$aHeight=200,$aCachedName='',$aTimeout=0,$aInline=true) {
     582
     583        if( !is_numeric($aWidth) || !is_numeric($aHeight) ) {
     584            JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric');
     585        }
     586
     587        // Initialize frame and margin
     588        $this->InitializeFrameAndMargin();
     589
     590        // Automatically generate the image file name based on the name of the script that
     591        // generates the graph
     592        if( $aCachedName == 'auto' ) {
     593            $aCachedName=GenImgName();
     594        }
     595
     596        // Should the image be streamed back to the browser or only to the cache?
     597        $this->inline=$aInline;
     598
     599        $this->img = new RotImage($aWidth,$aHeight);
     600        $this->cache  = new ImgStreamCache();
     601
     602        // Window doesn't like '?' in the file name so replace it with an '_'
     603        $aCachedName = str_replace("?","_",$aCachedName);
     604        $this->SetupCache($aCachedName, $aTimeout);
     605
     606        $this->title = new Text();
     607        $this->title->ParagraphAlign('center');
     608        $this->title->SetFont(FF_DEFAULT,FS_NORMAL); //FF_FONT2, FS_BOLD
     609        $this->title->SetMargin(5);
     610        $this->title->SetAlign('center');
     611
     612        $this->subtitle = new Text();
     613        $this->subtitle->ParagraphAlign('center');
     614        $this->subtitle->SetMargin(3);
     615        $this->subtitle->SetAlign('center');
     616
     617        $this->subsubtitle = new Text();
     618        $this->subsubtitle->ParagraphAlign('center');
     619        $this->subsubtitle->SetMargin(3);
     620        $this->subsubtitle->SetAlign('center');
     621
     622        $this->legend = new Legend();
     623        $this->footer = new Footer();
     624
     625        // If the cached version exist just read it directly from the
     626        // cache, stream it back to browser and exit
     627        if( $aCachedName!='' && READ_CACHE && $aInline ) {
     628            if( $this->cache->GetAndStream($this->img,$aCachedName) ) {
     629                exit();
     630            }
     631        }
     632
     633        $this->SetTickDensity(); // Normal density
     634
     635        $this->tabtitle = new GraphTabTitle();
     636
     637        if (!$this->isRunningClear) {
     638            $this->inputValues = array();
     639            $this->inputValues['aWidth'] = $aWidth;
     640            $this->inputValues['aHeight'] = $aHeight;
     641            $this->inputValues['aCachedName'] = $aCachedName;
     642            $this->inputValues['aTimeout'] = $aTimeout;
     643            $this->inputValues['aInline'] = $aInline;
     644
     645            $theme_class = DEFAULT_THEME_CLASS;
     646            if (class_exists($theme_class)) {
     647                $this->graph_theme = new $theme_class();
     648            }
     649        }
     650    }
     651
     652    function InitializeFrameAndMargin() {
     653        $this->doframe=true;
     654        $this->frame_color='black';
     655        $this->frame_weight=1;
     656
     657        $this->titlebackground_framecolor = 'blue';
     658        $this->titlebackground_framestyle = 2;
     659        $this->titlebackground_frameweight = 1;
     660        $this->titlebackground_bevelheight = 3;
     661        $this->titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;
     662        $this->titlebkg_scolor1='black';
     663        $this->titlebkg_scolor2='white';
     664        $this->framebevel = false;
     665        $this->framebeveldepth = 2;
     666        $this->framebevelborder = false;
     667        $this->framebevelbordercolor='black';
     668        $this->framebevelcolor1='white@0.4';
     669        $this->framebevelcolor2='black@0.4';
     670
     671        $this->margin_color = array(250,250,250);
     672    }
     673
     674    function SetupCache($aFilename,$aTimeout=60) {
     675        $this->cache_name = $aFilename;
     676        $this->cache->SetTimeOut($aTimeout);
     677    }
     678
    614679    // Enable final image perspective transformation
    615680    function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) {
    616         $this->iImgTrans = true;
    617         $this->iImgTransHorizon = $aHorizon;
    618         $this->iImgTransSkewDist= $aSkewDist;
    619         $this->iImgTransDirection = $aDir;
    620         $this->iImgTransMinSize = $aMinSize;
    621         $this->iImgTransFillColor=$aFillColor;
    622         $this->iImgTransHighQ=$aQuality;
    623         $this->iImgTransBorder=$aBorder;
    624         $this->iImgTransHorizonPos=$aHorizonPos;
     681        $this->iImgTrans = true;
     682        $this->iImgTransHorizon = $aHorizon;
     683        $this->iImgTransSkewDist= $aSkewDist;
     684        $this->iImgTransDirection = $aDir;
     685        $this->iImgTransMinSize = $aMinSize;
     686        $this->iImgTransFillColor=$aFillColor;
     687        $this->iImgTransHighQ=$aQuality;
     688        $this->iImgTransBorder=$aBorder;
     689        $this->iImgTransHorizonPos=$aHorizonPos;
    625690    }
    626691
    627692    function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
    628         $this->img->ttf->SetUserFont($aNormal,$aBold,$aItalic,$aBoldIt);
     693        $this->img->ttf->SetUserFont($aNormal,$aBold,$aItalic,$aBoldIt);
    629694    }
    630695
    631696    function SetUserFont1($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
    632         $this->img->ttf->SetUserFont1($aNormal,$aBold,$aItalic,$aBoldIt);
     697        $this->img->ttf->SetUserFont1($aNormal,$aBold,$aItalic,$aBoldIt);
    633698    }
    634699
    635700    function SetUserFont2($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
    636         $this->img->ttf->SetUserFont2($aNormal,$aBold,$aItalic,$aBoldIt);
     701        $this->img->ttf->SetUserFont2($aNormal,$aBold,$aItalic,$aBoldIt);
    637702    }
    638703
    639704    function SetUserFont3($aNormal,$aBold='',$aItalic='',$aBoldIt='') {
    640         $this->img->ttf->SetUserFont3($aNormal,$aBold,$aItalic,$aBoldIt);
     705        $this->img->ttf->SetUserFont3($aNormal,$aBold,$aItalic,$aBoldIt);
    641706    }
    642707
    643708    // Set Image format and optional quality
    644709    function SetImgFormat($aFormat,$aQuality=75) {
    645         $this->img->SetImgFormat($aFormat,$aQuality);
     710        $this->img->SetImgFormat($aFormat,$aQuality);
    646711    }
    647712
    648713    // Should the grid be in front or back of the plot?
    649714    function SetGridDepth($aDepth) {
    650         $this->grid_depth=$aDepth;
     715        $this->grid_depth=$aDepth;
    651716    }
    652717
    653718    function SetIconDepth($aDepth) {
    654         $this->iIconDepth=$aDepth;
    655     }
    656        
     719        $this->iIconDepth=$aDepth;
     720    }
     721
    657722    // Specify graph angle 0-360 degrees.
    658723    function SetAngle($aAngle) {
    659         $this->img->SetAngle($aAngle);
     724        $this->img->SetAngle($aAngle);
    660725    }
    661726
    662727    function SetAlphaBlending($aFlg=true) {
    663         $this->img->SetAlphaBlending($aFlg);
     728        $this->img->SetAlphaBlending($aFlg);
    664729    }
    665730
    666731    // Shortcut to image margin
    667732    function SetMargin($lm,$rm,$tm,$bm) {
    668         $this->img->SetMargin($lm,$rm,$tm,$bm);
     733        $this->img->SetMargin($lm,$rm,$tm,$bm);
    669734    }
    670735
    671736    function SetY2OrderBack($aBack=true) {
    672         $this->y2orderback = $aBack;
    673     }
    674 
    675     // Rotate the graph 90 degrees and set the margin 
     737        $this->y2orderback = $aBack;
     738    }
     739
     740    // Rotate the graph 90 degrees and set the margin
    676741    // when we have done a 90 degree rotation
    677742    function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) {
    678         $lm = $lm ==0 ? floor(0.2 * $this->img->width)  : $lm ;
    679         $rm = $rm ==0 ? floor(0.1 * $this->img->width)  : $rm ;
    680         $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ;
    681         $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ;
    682 
    683         $adj = ($this->img->height - $this->img->width)/2;
    684         $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj);
    685         $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));
    686         $this->SetAngle(90);
    687         if( empty($this->yaxis) || empty($this->xaxis) ) {
    688             JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()');
    689         }
    690         $this->xaxis->SetLabelAlign('right','center');
    691         $this->yaxis->SetLabelAlign('center','bottom');
    692     }
    693        
     743        $adj = ($this->img->height - $this->img->width)/2;
     744        $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj);
     745        $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));
     746        $this->SetAngle(90);
     747        if( empty($this->yaxis) || empty($this->xaxis) ) {
     748            JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()');
     749        }
     750        $this->xaxis->SetLabelAlign('right','center');
     751        $this->yaxis->SetLabelAlign('center','bottom');
     752    }
     753
    694754    function SetClipping($aFlg=true) {
    695         $this->iDoClipping = $aFlg ;
     755        $this->iDoClipping = $aFlg ;
    696756    }
    697757
    698758    // Add a plot object to the graph
    699759    function Add($aPlot) {
    700         if( $aPlot == null )
    701             JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph.");
    702         if( is_array($aPlot) && count($aPlot) > 0 )
    703             $cl = $aPlot[0];
    704         else
    705             $cl = $aPlot;
    706 
    707         if( $cl instanceof Text )
    708             $this->AddText($aPlot);
    709         elseif( $cl instanceof PlotLine )
    710             $this->AddLine($aPlot);
    711         elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) )
    712             $this->AddBand($aPlot);
    713         elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) )
    714             $this->AddIcon($aPlot);
    715         elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) )
    716             $this->AddTable($aPlot);
    717         else
    718             $this->plots[] = $aPlot;
     760        if( $aPlot == null ) {
     761            JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph.");
     762        }
     763        if( is_array($aPlot) && count($aPlot) > 0 ) {
     764            $cl = $aPlot[0];
     765        }
     766        else {
     767            $cl = $aPlot;
     768        }
     769
     770        if( $cl instanceof Text ) $this->AddText($aPlot);
     771        elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) )  $this->AddLine($aPlot);
     772        elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) $this->AddBand($aPlot);
     773        elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot);
     774        elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) ) $this->AddTable($aPlot);
     775        else {
     776            if( is_array($aPlot) ) {
     777                $this->plots = array_merge($this->plots,$aPlot);
     778            }
     779            else {
     780                $this->plots[] = $aPlot;
     781            }
     782        }
     783
     784        if ($this->graph_theme) {
     785            $this->graph_theme->SetupPlot($aPlot);
     786        }
    719787    }
    720788
    721789    function AddTable($aTable) {
    722         if( is_array($aTable) ) {
    723             for($i=0; $i < count($aTable); ++$i )
    724                 $this->iTables[]=$aTable[$i];
    725         }
    726         else {
    727             $this->iTables[] = $aTable ;
    728         }       
     790        if( is_array($aTable) ) {
     791            for($i=0; $i < count($aTable); ++$i ) {
     792                $this->iTables[]=$aTable[$i];
     793            }
     794        }
     795        else {
     796            $this->iTables[] = $aTable ;
     797        }
    729798    }
    730799
    731800    function AddIcon($aIcon) {
    732         if( is_array($aIcon) ) {
    733             for($i=0; $i < count($aIcon); ++$i )
    734                 $this->iIcons[]=$aIcon[$i];
    735         }
    736         else {
    737             $this->iIcons[] = $aIcon ;
    738         }       
     801        if( is_array($aIcon) ) {
     802            for($i=0; $i < count($aIcon); ++$i ) {
     803                $this->iIcons[]=$aIcon[$i];
     804            }
     805        }
     806        else {
     807            $this->iIcons[] = $aIcon ;
     808        }
    739809    }
    740810
    741811    // Add plot to second Y-scale
    742812    function AddY2($aPlot) {
    743         if( $aPlot == null )
    744             JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph.");       
    745 
    746         if( is_array($aPlot) && count($aPlot) > 0 )
    747             $cl = $aPlot[0];
    748         else
    749             $cl = $aPlot;
    750 
    751         if( $cl instanceof Text )
    752             $this->AddText($aPlot,true);
    753         elseif( $cl instanceof PlotLine )
    754             $this->AddLine($aPlot,true);
    755         elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) )
    756             $this->AddBand($aPlot,true);
    757         else
    758             $this->y2plots[] = $aPlot;
    759     }
    760        
     813        if( $aPlot == null ) {
     814            JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph.");
     815        }
     816
     817        if( is_array($aPlot) && count($aPlot) > 0 ) {
     818            $cl = $aPlot[0];
     819        }
     820        else {
     821            $cl = $aPlot;
     822        }
     823
     824        if( $cl instanceof Text ) {
     825            $this->AddText($aPlot,true);
     826        }
     827        elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) {
     828            $this->AddLine($aPlot,true);
     829        }
     830        elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) {
     831            $this->AddBand($aPlot,true);
     832        }
     833        else {
     834            $this->y2plots[] = $aPlot;
     835        }
     836
     837        if ($this->graph_theme) {
     838            $this->graph_theme->SetupPlot($aPlot);
     839        }
     840    }
     841
    761842    // Add plot to the extra Y-axises
    762843    function AddY($aN,$aPlot) {
    763844
    764         if( $aPlot == null )
    765             JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph.");       
    766 
    767         if( is_array($aPlot) && count($aPlot) > 0 )
    768             $cl = $aPlot[0];
    769         else
    770             $cl = $aPlot;
    771 
    772         if( ($cl instanceof Text) || ($cl instanceof PlotLine) ||
    773             (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) )
    774             JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis');
    775         else
    776             $this->ynplots[$aN][] = $aPlot;
     845        if( $aPlot == null ) {
     846            JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph.");
     847        }
     848
     849        if( is_array($aPlot) && count($aPlot) > 0 ) {
     850            $cl = $aPlot[0];
     851        }
     852        else {
     853            $cl = $aPlot;
     854        }
     855
     856        if( ($cl instanceof Text) ||
     857            (class_exists('PlotLine',false) && ($cl instanceof PlotLine)) ||
     858            (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) ) {
     859            JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis');
     860        }
     861        else {
     862            $this->ynplots[$aN][] = $aPlot;
     863        }
     864
     865        if ($this->graph_theme) {
     866            $this->graph_theme->SetupPlot($aPlot);
     867        }
    777868    }
    778869
    779870    // Add text object to the graph
    780871    function AddText($aTxt,$aToY2=false) {
    781         if( $aTxt == null )
    782             JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph.");             
    783         if( $aToY2 ) {
    784             if( is_array($aTxt) ) {
    785                 for($i=0; $i < count($aTxt); ++$i )
    786                     $this->y2texts[]=$aTxt[$i];
    787             }
    788             else
    789                 $this->y2texts[] = $aTxt;
    790         }
    791         else {
    792             if( is_array($aTxt) ) {
    793                 for($i=0; $i < count($aTxt); ++$i )
    794                     $this->texts[]=$aTxt[$i];
    795             }
    796             else
    797                 $this->texts[] = $aTxt;
    798         }
    799     }
    800        
     872        if( $aTxt == null ) {
     873            JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph.");
     874        }
     875        if( $aToY2 ) {
     876            if( is_array($aTxt) ) {
     877                for($i=0; $i < count($aTxt); ++$i ) {
     878                    $this->y2texts[]=$aTxt[$i];
     879                }
     880            }
     881            else {
     882                $this->y2texts[] = $aTxt;
     883            }
     884        }
     885        else {
     886            if( is_array($aTxt) ) {
     887                for($i=0; $i < count($aTxt); ++$i ) {
     888                    $this->texts[]=$aTxt[$i];
     889                }
     890            }
     891            else {
     892                $this->texts[] = $aTxt;
     893            }
     894        }
     895    }
     896
    801897    // Add a line object (class PlotLine) to the graph
    802898    function AddLine($aLine,$aToY2=false) {
    803         if( $aLine == null )
    804             JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph.");     
    805 
    806         if( $aToY2 ) {
    807             if( is_array($aLine) ) {
    808                 for($i=0; $i < count($aLine); ++$i )
    809                     $this->y2lines[]=$aLine[$i];
    810             }
    811             else
    812                 $this->y2lines[] = $aLine;
    813         }
    814         else {
    815             if( is_array($aLine) ) {
    816                 for($i=0; $i<count($aLine); ++$i )
    817                     $this->lines[]=$aLine[$i];
    818             }
    819             else
    820                 $this->lines[] = $aLine;
    821         }
     899        if( $aLine == null ) {
     900            JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph.");
     901        }
     902
     903        if( $aToY2 ) {
     904            if( is_array($aLine) ) {
     905                for($i=0; $i < count($aLine); ++$i ) {
     906                    //$this->y2lines[]=$aLine[$i];
     907                    $this->y2plots[]=$aLine[$i];
     908                }
     909            }
     910            else {
     911                //$this->y2lines[] = $aLine;
     912                $this->y2plots[]=$aLine;
     913            }
     914        }
     915        else {
     916            if( is_array($aLine) ) {
     917                for($i=0; $i<count($aLine); ++$i ) {
     918                    //$this->lines[]=$aLine[$i];
     919                    $this->plots[]=$aLine[$i];
     920                }
     921            }
     922            else {
     923                //$this->lines[] = $aLine;
     924                $this->plots[] = $aLine;
     925            }
     926        }
    822927    }
    823928
    824929    // Add vertical or horizontal band
    825930    function AddBand($aBand,$aToY2=false) {
    826         if( $aBand == null )
    827             JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph.");
    828 
    829         if( $aToY2 ) {
    830             if( is_array($aBand) ) {
    831                 for($i=0; $i < count($aBand); ++$i )
    832                     $this->y2bands[] = $aBand[$i];
    833             }
    834             else
    835                 $this->y2bands[] = $aBand;
    836         }
    837         else {
    838             if( is_array($aBand) ) {
    839                 for($i=0; $i < count($aBand); ++$i )
    840                     $this->bands[] = $aBand[$i];
    841             }
    842             else
    843                 $this->bands[] = $aBand;
    844         }
     931        if( $aBand == null ) {
     932            JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph.");
     933        }
     934
     935        if( $aToY2 ) {
     936            if( is_array($aBand) ) {
     937                for($i=0; $i < count($aBand); ++$i ) {
     938                    $this->y2bands[] = $aBand[$i];
     939                }
     940            }
     941            else {
     942                $this->y2bands[] = $aBand;
     943            }
     944        }
     945        else {
     946            if( is_array($aBand) ) {
     947                for($i=0; $i < count($aBand); ++$i ) {
     948                    $this->bands[] = $aBand[$i];
     949                }
     950            }
     951            else {
     952                $this->bands[] = $aBand;
     953            }
     954        }
     955    }
     956
     957    function SetPlotGradient($aFrom='navy',$aTo='silver',$aGradType=2) {
     958        $this->plot_gradtype=$aGradType;
     959        $this->plot_gradfrom = $aFrom;
     960        $this->plot_gradto = $aTo;
    845961    }
    846962
    847963    function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) {
    848         $this->bkg_gradtype=$aGradType;
    849         $this->bkg_gradstyle=$aStyle;
    850         $this->bkg_gradfrom = $aFrom;
    851         $this->bkg_gradto = $aTo;
    852     } 
    853        
     964        $this->bkg_gradtype=$aGradType;
     965        $this->bkg_gradstyle=$aStyle;
     966        $this->bkg_gradfrom = $aFrom;
     967        $this->bkg_gradto = $aTo;
     968    }
     969
    854970    // Set a country flag in the background
    855971    function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
    856         $this->background_cflag = $aName;
    857         $this->background_cflag_type = $aBgType;
    858         $this->background_cflag_mix = $aMix;
     972        $this->background_cflag = $aName;
     973        $this->background_cflag_type = $aBgType;
     974        $this->background_cflag_mix = $aMix;
    859975    }
    860976
    861977    // Alias for the above method
    862978    function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
    863         $this->background_cflag = $aName;
    864         $this->background_cflag_type = $aBgType;
    865         $this->background_cflag_mix = $aMix;
     979        $this->background_cflag = $aName;
     980        $this->background_cflag_type = $aBgType;
     981        $this->background_cflag_mix = $aMix;
    866982    }
    867983
    868984
    869985    // Specify a background image
    870     function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat="auto") {
    871 
    872         if( !USE_TRUECOLOR ) {
    873             JpGraphError::RaiseL(25017);//("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x you <b>must</b> enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts.");
    874         }
    875 
    876         // Get extension to determine image type
    877         if( $aImgFormat == "auto" ) {
    878             $e = explode('.',$aFileName);
    879             if( !$e ) {
    880                 JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type');
    881             }
    882 
    883             $valid_formats = array('png', 'jpg', 'gif');
    884             $aImgFormat = strtolower($e[count($e)-1]);
    885             if ($aImgFormat == 'jpeg')  {
    886                 $aImgFormat = 'jpg';
    887             }
    888             elseif (!in_array($aImgFormat, $valid_formats) )  {
    889                 JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
    890             }   
    891         }
    892 
    893         $this->background_image = $aFileName;
    894         $this->background_image_type=$aBgType;
    895         $this->background_image_format=$aImgFormat;
     986    function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat='auto') {
     987
     988        // Get extension to determine image type
     989        if( $aImgFormat == 'auto' ) {
     990            $e = explode('.',$aFileName);
     991            if( !$e ) {
     992                JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type');
     993            }
     994
     995            $valid_formats = array('png', 'jpg', 'gif');
     996            $aImgFormat = strtolower($e[count($e)-1]);
     997            if ($aImgFormat == 'jpeg')  {
     998                $aImgFormat = 'jpg';
     999            }
     1000            elseif (!in_array($aImgFormat, $valid_formats) )  {
     1001                JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
     1002            }
     1003        }
     1004
     1005        $this->background_image = $aFileName;
     1006        $this->background_image_type=$aBgType;
     1007        $this->background_image_format=$aImgFormat;
    8961008    }
    8971009
    8981010    function SetBackgroundImageMix($aMix) {
    899         $this->background_image_mix = $aMix ;
    900     }
    901        
     1011        $this->background_image_mix = $aMix ;
     1012    }
     1013
    9021014    // Adjust background image position
    9031015    function SetBackgroundImagePos($aXpos,$aYpos) {
    904         $this->background_image_xpos = $aXpos ;
    905         $this->background_image_ypos = $aYpos ;
    906     }
    907        
     1016        $this->background_image_xpos = $aXpos ;
     1017        $this->background_image_ypos = $aYpos ;
     1018    }
     1019
    9081020    // Specify axis style (boxed or single)
    9091021    function SetAxisStyle($aStyle) {
    9101022        $this->iAxisStyle = $aStyle ;
    9111023    }
    912        
     1024
    9131025    // Set a frame around the plot area
    9141026    function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) {
    915         $this->boxed = $aDrawPlotFrame;
    916         $this->box_weight = $aPlotFrameWeight;
    917         $this->box_color = $aPlotFrameColor;
    918     }
    919        
     1027        $this->boxed = $aDrawPlotFrame;
     1028        $this->box_weight = $aPlotFrameWeight;
     1029        $this->box_color = $aPlotFrameColor;
     1030    }
     1031
    9201032    // Specify color for the plotarea (not the margins)
    9211033    function SetColor($aColor) {
    922         $this->plotarea_color=$aColor;
    923     }
    924        
     1034        $this->plotarea_color=$aColor;
     1035    }
     1036
    9251037    // Specify color for the margins (all areas outside the plotarea)
    9261038    function SetMarginColor($aColor) {
    927         $this->margin_color=$aColor;
    928     }
    929        
     1039        $this->margin_color=$aColor;
     1040    }
     1041
    9301042    // Set a frame around the entire image
    9311043    function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) {
    932         $this->doframe = $aDrawImgFrame;
    933         $this->frame_color = $aImgFrameColor;
    934         $this->frame_weight = $aImgFrameWeight;
     1044        $this->doframe = $aDrawImgFrame;
     1045        $this->frame_color = $aImgFrameColor;
     1046        $this->frame_weight = $aImgFrameWeight;
    9351047    }
    9361048
    9371049    function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) {
    938         $this->framebevel = $aFlg ;
    939         $this->framebeveldepth = $aDepth ;
    940         $this->framebevelborder = $aBorder ;
    941         $this->framebevelbordercolor = $aBorderColor ;
    942         $this->framebevelcolor1 = $aColor1 ;
    943         $this->framebevelcolor2 = $aColor2 ;
    944 
    945         $this->doshadow = false ;
     1050        $this->framebevel = $aFlg ;
     1051        $this->framebeveldepth = $aDepth ;
     1052        $this->framebevelborder = $aBorder ;
     1053        $this->framebevelbordercolor = $aBorderColor ;
     1054        $this->framebevelcolor1 = $aColor1 ;
     1055        $this->framebevelcolor2 = $aColor2 ;
     1056
     1057        $this->doshadow = false ;
    9461058    }
    9471059
    9481060    // Set the shadow around the whole image
    949     function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) {
    950         $this->doshadow = $aShowShadow;
    951         $this->shadow_color = $aShadowColor;
    952         $this->shadow_width = $aShadowWidth;
    953         $this->footer->iBottomMargin += $aShadowWidth;
    954         $this->footer->iRightMargin += $aShadowWidth;
     1061    function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor='darkgray') {
     1062        $this->doshadow = $aShowShadow;
     1063        $this->shadow_color = $aShadowColor;
     1064        $this->shadow_width = $aShadowWidth;
     1065        $this->footer->iBottomMargin += $aShadowWidth;
     1066        $this->footer->iRightMargin += $aShadowWidth;
    9551067    }
    9561068
     
    9581070    // you must also specify the tick distance with a call to Ticks::Set()
    9591071    function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) {
    960         $this->axtype = $aAxisType;
    961 
    962         if( $aYMax < $aYMin || $aXMax < $aXMin )
    963             JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
    964 
    965         $yt=substr($aAxisType,-3,3);
    966         if( $yt=="lin" )
    967             $this->yscale = new LinearScale($aYMin,$aYMax);
    968         elseif( $yt == "int" ) {
    969             $this->yscale = new LinearScale($aYMin,$aYMax);
    970             $this->yscale->SetIntScale();
    971         }
    972         elseif( $yt=="log" )
    973             $this->yscale = new LogScale($aYMin,$aYMax);
    974         else
    975             JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)");
    976                        
    977         $xt=substr($aAxisType,0,3);
    978         if( $xt == "lin" || $xt == "tex" ) {
    979             $this->xscale = new LinearScale($aXMin,$aXMax,"x");
    980             $this->xscale->textscale = ($xt == "tex");
    981         }
    982         elseif( $xt == "int" ) {
    983             $this->xscale = new LinearScale($aXMin,$aXMax,"x");
    984             $this->xscale->SetIntScale();
    985         }
    986         elseif( $xt == "dat" ) {
    987             $this->xscale = new DateScale($aXMin,$aXMax,"x");
    988         }
    989         elseif( $xt == "log" )
    990             $this->xscale = new LogScale($aXMin,$aXMax,"x");
    991         else
    992             JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)");
    993 
    994         $this->xaxis = new Axis($this->img,$this->xscale);
    995         $this->yaxis = new Axis($this->img,$this->yscale);
    996         $this->xgrid = new Grid($this->xaxis);
    997         $this->ygrid = new Grid($this->yaxis); 
    998         $this->ygrid->Show();                   
    999     }
    1000        
     1072        $this->axtype = $aAxisType;
     1073
     1074        if( $aYMax < $aYMin || $aXMax < $aXMin ) {
     1075            JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
     1076        }
     1077
     1078        $yt=substr($aAxisType,-3,3);
     1079        if( $yt == 'lin' ) {
     1080            $this->yscale = new LinearScale($aYMin,$aYMax);
     1081        }
     1082        elseif( $yt == 'int' ) {
     1083            $this->yscale = new LinearScale($aYMin,$aYMax);
     1084            $this->yscale->SetIntScale();
     1085        }
     1086        elseif( $yt == 'log' ) {
     1087            $this->yscale = new LogScale($aYMin,$aYMax);
     1088        }
     1089        else {
     1090            JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)");
     1091        }
     1092
     1093        $xt=substr($aAxisType,0,3);
     1094        if( $xt == 'lin' || $xt == 'tex' ) {
     1095            $this->xscale = new LinearScale($aXMin,$aXMax,'x');
     1096            $this->xscale->textscale = ($xt == 'tex');
     1097        }
     1098        elseif( $xt == 'int' ) {
     1099            $this->xscale = new LinearScale($aXMin,$aXMax,'x');
     1100            $this->xscale->SetIntScale();
     1101        }
     1102        elseif( $xt == 'dat' ) {
     1103            $this->xscale = new DateScale($aXMin,$aXMax,'x');
     1104        }
     1105        elseif( $xt == 'log' ) {
     1106            $this->xscale = new LogScale($aXMin,$aXMax,'x');
     1107        }
     1108        else {
     1109            JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)");
     1110        }
     1111
     1112        $this->xaxis = new Axis($this->img,$this->xscale);
     1113        $this->yaxis = new Axis($this->img,$this->yscale);
     1114        $this->xgrid = new Grid($this->xaxis);
     1115        $this->ygrid = new Grid($this->yaxis);
     1116        $this->ygrid->Show();
     1117
     1118
     1119        if (!$this->isRunningClear) {
     1120            $this->inputValues['aAxisType'] = $aAxisType;
     1121            $this->inputValues['aYMin'] = $aYMin;
     1122            $this->inputValues['aYMax'] = $aYMax;
     1123            $this->inputValues['aXMin'] = $aXMin;
     1124            $this->inputValues['aXMax'] = $aXMax;
     1125
     1126            if ($this->graph_theme) {
     1127                $this->graph_theme->ApplyGraph($this);
     1128            }
     1129        }
     1130
     1131        $this->isAfterSetScale = true;
     1132    }
     1133
    10011134    // Specify secondary Y scale
    1002     function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) {
    1003         if( $aAxisType=="lin" )
    1004             $this->y2scale = new LinearScale($aY2Min,$aY2Max);
    1005         elseif( $aAxisType == "int" ) {
    1006             $this->y2scale = new LinearScale($aY2Min,$aY2Max);
    1007             $this->y2scale->SetIntScale();
    1008         }
    1009         elseif( $aAxisType=="log" ) {
    1010             $this->y2scale = new LogScale($aY2Min,$aY2Max);
    1011         }
    1012         else JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)");
    1013                        
    1014         $this->y2axis = new Axis($this->img,$this->y2scale);
    1015         $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
    1016         $this->y2axis->SetLabelSide(SIDE_RIGHT);
    1017         $this->y2axis->SetPos('max');
    1018         $this->y2axis->SetTitleSide(SIDE_RIGHT);
    1019                
    1020         // Deafult position is the max x-value
    1021         $this->y2grid = new Grid($this->y2axis);                                                       
     1135    function SetY2Scale($aAxisType='lin',$aY2Min=1,$aY2Max=1) {
     1136        if( $aAxisType == 'lin' ) {
     1137            $this->y2scale = new LinearScale($aY2Min,$aY2Max);
     1138        }
     1139        elseif( $aAxisType == 'int' ) {
     1140            $this->y2scale = new LinearScale($aY2Min,$aY2Max);
     1141            $this->y2scale->SetIntScale();
     1142        }
     1143        elseif( $aAxisType == 'log' ) {
     1144            $this->y2scale = new LogScale($aY2Min,$aY2Max);
     1145        }
     1146        else {
     1147            JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)");
     1148        }
     1149
     1150        $this->y2axis = new Axis($this->img,$this->y2scale);
     1151        $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
     1152        $this->y2axis->SetLabelSide(SIDE_RIGHT);
     1153        $this->y2axis->SetPos('max');
     1154        $this->y2axis->SetTitleSide(SIDE_RIGHT);
     1155
     1156        // Deafult position is the max x-value
     1157        $this->y2grid = new Grid($this->y2axis);
     1158
     1159        if ($this->graph_theme) {
     1160          $this->graph_theme->ApplyGraph($this);
     1161        }
    10221162    }
    10231163
    10241164    // Set the delta position (in pixels) between the multiple Y-axis
    10251165    function SetYDeltaDist($aDist) {
    1026         $this->iYAxisDeltaPos = $aDist;
     1166        $this->iYAxisDeltaPos = $aDist;
    10271167    }
    10281168
     
    10301170    function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) {
    10311171
    1032         if( $aAxisType=="lin" )
    1033             $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
    1034         elseif( $aAxisType == "int" ) {
    1035             $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
    1036             $this->ynscale[$aN]->SetIntScale();
    1037         }
    1038         elseif( $aAxisType=="log" ) {
    1039             $this->ynscale[$aN] = new LogScale($aYMin,$aYMax);
    1040         }
    1041         else JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)");
    1042                        
    1043         $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]);
    1044         $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT);
    1045         $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT);
     1172        if( $aAxisType == 'lin' ) {
     1173            $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
     1174        }
     1175        elseif( $aAxisType == 'int' ) {
     1176            $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
     1177            $this->ynscale[$aN]->SetIntScale();
     1178        }
     1179        elseif( $aAxisType == 'log' ) {
     1180            $this->ynscale[$aN] = new LogScale($aYMin,$aYMax);
     1181        }
     1182        else {
     1183            JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)");
     1184        }
     1185
     1186        $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]);
     1187        $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT);
     1188        $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT);
     1189
     1190        if ($this->graph_theme) {
     1191            $this->graph_theme->ApplyGraph($this);
     1192        }
    10461193    }
    10471194
    10481195    // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'
    1049     // The dividing factor have been determined heuristically according to my aesthetic 
     1196    // The dividing factor have been determined heuristically according to my aesthetic
    10501197    // sense (or lack off) y.m.m.v !
    10511198    function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) {
    1052         $this->xtick_factor=30;
    1053         $this->ytick_factor=25;         
    1054         switch( $aYDensity ) {
    1055             case TICKD_DENSE:
    1056                 $this->ytick_factor=12;                 
    1057                 break;
    1058             case TICKD_NORMAL:
    1059                 $this->ytick_factor=25;                 
    1060                 break;
    1061             case TICKD_SPARSE:
    1062                 $this->ytick_factor=40;                 
    1063                 break;
    1064             case TICKD_VERYSPARSE:
    1065                 $this->ytick_factor=100;                       
    1066                 break;         
    1067             default:
    1068                 JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy");
    1069         }
    1070         switch( $aXDensity ) {
    1071             case TICKD_DENSE:
    1072                 $this->xtick_factor=15;                                                 
    1073                 break;
    1074             case TICKD_NORMAL:
    1075                 $this->xtick_factor=30;                 
    1076                 break;
    1077             case TICKD_SPARSE:
    1078                 $this->xtick_factor=45;                                 
    1079                 break;
    1080             case TICKD_VERYSPARSE:
    1081                 $this->xtick_factor=60;                                                         
    1082                 break;         
    1083             default:
    1084                 JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx");
    1085         }               
    1086     }
    1087        
    1088 
    1089     // Get a string of all image map areas     
     1199        $this->xtick_factor=30;
     1200        $this->ytick_factor=25;
     1201        switch( $aYDensity ) {
     1202            case TICKD_DENSE:
     1203                $this->ytick_factor=12;
     1204                break;
     1205            case TICKD_NORMAL:
     1206                $this->ytick_factor=25;
     1207                break;
     1208            case TICKD_SPARSE:
     1209                $this->ytick_factor=40;
     1210                break;
     1211            case TICKD_VERYSPARSE:
     1212                $this->ytick_factor=100;
     1213                break;
     1214            default:
     1215                JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy");
     1216        }
     1217        switch( $aXDensity ) {
     1218            case TICKD_DENSE:
     1219                $this->xtick_factor=15;
     1220                break;
     1221            case TICKD_NORMAL:
     1222                $this->xtick_factor=30;
     1223                break;
     1224            case TICKD_SPARSE:
     1225                $this->xtick_factor=45;
     1226                break;
     1227            case TICKD_VERYSPARSE:
     1228                $this->xtick_factor=60;
     1229                break;
     1230            default:
     1231                JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx");
     1232        }
     1233    }
     1234
     1235
     1236    // Get a string of all image map areas
    10901237    function GetCSIMareas() {
    1091         if( !$this->iHasStroked )
    1092             $this->Stroke(_CSIM_SPECIALFILE);
    1093 
    1094         $csim = $this->title->GetCSIMAreas();
    1095         $csim .= $this->subtitle->GetCSIMAreas();
    1096         $csim .= $this->subsubtitle->GetCSIMAreas();
    1097         $csim .= $this->legend->GetCSIMAreas();
    1098 
    1099         if( $this->y2axis != NULL ) {
    1100             $csim .= $this->y2axis->title->GetCSIMAreas();
    1101         }
    1102 
    1103         if( $this->texts != null ) {
    1104             $n = count($this->texts);
    1105             for($i=0; $i < $n; ++$i ) {
    1106                 $csim .= $this->texts[$i]->GetCSIMAreas();
    1107             }
    1108         }
    1109 
    1110         if( $this->y2texts != null && $this->y2scale != null ) {
    1111             $n = count($this->y2texts);
    1112             for($i=0; $i < $n; ++$i ) {
    1113                 $csim .= $this->y2texts[$i]->GetCSIMAreas();
    1114             }
    1115         }
    1116 
    1117         if( $this->yaxis != null && $this->xaxis != null ) {
    1118             $csim .= $this->yaxis->title->GetCSIMAreas();       
    1119             $csim .= $this->xaxis->title->GetCSIMAreas();
    1120         }
    1121 
    1122         $n = count($this->plots);
    1123         for( $i=0; $i < $n; ++$i )
    1124             $csim .= $this->plots[$i]->GetCSIMareas();
    1125 
    1126         $n = count($this->y2plots);
    1127         for( $i=0; $i < $n; ++$i )
    1128             $csim .= $this->y2plots[$i]->GetCSIMareas();
    1129 
    1130         $n = count($this->ynaxis);
    1131         for( $i=0; $i < $n; ++$i ) {
    1132             $m = count($this->ynplots[$i]);
    1133             for($j=0; $j < $m; ++$j ) {
    1134                 $csim .= $this->ynplots[$i][$j]->GetCSIMareas();
    1135             }
    1136         }
    1137 
    1138         $n = count($this->iTables);
    1139         for( $i=0; $i < $n; ++$i ) {
    1140             $csim .= $this->iTables[$i]->GetCSIMareas();
    1141         }
    1142 
    1143         return $csim;
    1144     }
    1145        
     1238        if( !$this->iHasStroked ) {
     1239            $this->Stroke(_CSIM_SPECIALFILE);
     1240        }
     1241
     1242        $csim = $this->title->GetCSIMAreas();
     1243        $csim .= $this->subtitle->GetCSIMAreas();
     1244        $csim .= $this->subsubtitle->GetCSIMAreas();
     1245        $csim .= $this->legend->GetCSIMAreas();
     1246
     1247        if( $this->y2axis != NULL ) {
     1248            $csim .= $this->y2axis->title->GetCSIMAreas();
     1249        }
     1250
     1251        if( $this->texts != null ) {
     1252            $n = count($this->texts);
     1253            for($i=0; $i < $n; ++$i ) {
     1254                $csim .= $this->texts[$i]->GetCSIMAreas();
     1255            }
     1256        }
     1257
     1258        if( $this->y2texts != null && $this->y2scale != null ) {
     1259            $n = count($this->y2texts);
     1260            for($i=0; $i < $n; ++$i ) {
     1261                $csim .= $this->y2texts[$i]->GetCSIMAreas();
     1262            }
     1263        }
     1264
     1265        if( $this->yaxis != null && $this->xaxis != null ) {
     1266            $csim .= $this->yaxis->title->GetCSIMAreas();
     1267            $csim .= $this->xaxis->title->GetCSIMAreas();
     1268        }
     1269
     1270        $n = count($this->plots);
     1271        for( $i=0; $i < $n; ++$i ) {
     1272            $csim .= $this->plots[$i]->GetCSIMareas();
     1273        }
     1274
     1275        $n = count($this->y2plots);
     1276        for( $i=0; $i < $n; ++$i ) {
     1277            $csim .= $this->y2plots[$i]->GetCSIMareas();
     1278        }
     1279
     1280        $n = count($this->ynaxis);
     1281        for( $i=0; $i < $n; ++$i ) {
     1282            $m = count($this->ynplots[$i]);
     1283            for($j=0; $j < $m; ++$j ) {
     1284                $csim .= $this->ynplots[$i][$j]->GetCSIMareas();
     1285            }
     1286        }
     1287
     1288        if($this->iTables != null) {
     1289            $n = count($this->iTables);
     1290            for ($i = 0; $i < $n; ++$i) {
     1291                $csim .= $this->iTables[$i]->GetCSIMareas();
     1292            }
     1293        }
     1294
     1295        return $csim;
     1296    }
     1297
    11461298    // Get a complete <MAP>..</MAP> tag for the final image map
    11471299    function GetHTMLImageMap($aMapName) {
    1148         $im = "<map name=\"$aMapName\" id=\"$aMapName\" >\n";
    1149         $im .= $this->GetCSIMareas();
    1150         $im .= "</map>";
    1151         return $im;
     1300        $im = "<map name=\"$aMapName\" id=\"$aMapName\" >\n";
     1301        $im .= $this->GetCSIMareas();
     1302        $im .= "</map>";
     1303        return $im;
    11521304    }
    11531305
    11541306    function CheckCSIMCache($aCacheName,$aTimeOut=60) {
    1155         global $_SERVER;
    1156 
    1157         if( $aCacheName=='auto' )
    1158             $aCacheName=basename($_SERVER['PHP_SELF']);
    1159 
    1160         $urlarg = $this->GetURLArguments();
    1161         $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg;
    1162         $this->csimcachetimeout = $aTimeOut;
    1163 
    1164         // First determine if we need to check for a cached version
    1165         // This differs from the standard cache in the sense that the
    1166         // image and CSIM map HTML file is written relative to the directory
    1167         // the script executes in and not the specified cache directory.
    1168         // The reason for this is that the cache directory is not necessarily
    1169         // accessible from the HTTP server.
    1170         if( $this->csimcachename != '' ) {
    1171             $dir = dirname($this->csimcachename);
    1172             $base = basename($this->csimcachename);
    1173             $base = strtok($base,'.');
    1174             $suffix = strtok('.');
    1175             $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html';
    1176             $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format;
    1177 
    1178             $timedout=false;
    1179             // Does it exist at all ?
    1180            
    1181             if( file_exists($basecsim) && file_exists($baseimg) ) {
    1182                 // Check that it hasn't timed out
    1183                 $diff=time()-filemtime($basecsim);
    1184                 if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) {
    1185                     $timedout=true;
    1186                     @unlink($basecsim);
    1187                     @unlink($baseimg);
    1188                 }
    1189                 else {
    1190                     if ($fh = @fopen($basecsim, "r")) {
    1191                         fpassthru($fh);
    1192                         return true;
    1193                     }
    1194                     else
    1195                         JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading.");
    1196                 }
    1197             }
    1198         }
    1199         return false;
     1307        global $_SERVER;
     1308
     1309        if( $aCacheName=='auto' ) {
     1310            $aCacheName=basename($_SERVER['PHP_SELF']);
     1311        }
     1312
     1313        $urlarg = $this->GetURLArguments();
     1314        $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg;
     1315        $this->csimcachetimeout = $aTimeOut;
     1316
     1317        // First determine if we need to check for a cached version
     1318        // This differs from the standard cache in the sense that the
     1319        // image and CSIM map HTML file is written relative to the directory
     1320        // the script executes in and not the specified cache directory.
     1321        // The reason for this is that the cache directory is not necessarily
     1322        // accessible from the HTTP server.
     1323        if( $this->csimcachename != '' ) {
     1324            $dir = dirname($this->csimcachename);
     1325            $base = basename($this->csimcachename);
     1326            $base = strtok($base,'.');
     1327            $suffix = strtok('.');
     1328            $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html';
     1329            $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format;
     1330
     1331            $timedout=false;
     1332            // Does it exist at all ?
     1333
     1334            if( file_exists($basecsim) && file_exists($baseimg) ) {
     1335                // Check that it hasn't timed out
     1336                $diff=time()-filemtime($basecsim);
     1337                if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) {
     1338                    $timedout=true;
     1339                    @unlink($basecsim);
     1340                    @unlink($baseimg);
     1341                }
     1342                else {
     1343                    if ($fh = @fopen($basecsim, "r")) {
     1344                        fpassthru($fh);
     1345                        return true;
     1346                    }
     1347                    else {
     1348                        JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading.");
     1349                    }
     1350                }
     1351            }
     1352        }
     1353        return false;
    12001354    }
    12011355
    12021356    // Build the argument string to be used with the csim images
    1203     function GetURLArguments() {
    1204                
    1205         // This is a JPGRAPH internal defined that prevents
    1206         // us from recursively coming here again
    1207         $urlarg = _CSIM_DISPLAY.'=1';
    1208 
    1209         // Now reconstruct any user URL argument
    1210         reset($_GET);
    1211         while( list($key,$value) = each($_GET) ) {
    1212             if( is_array($value) ) {
    1213                 foreach ( $value as $k => $v ) {
    1214                     $urlarg .= '&amp;'.$key.'%5B'.$k.'%5D='.urlencode($v);
    1215                 }
    1216             }
    1217             else {
    1218                 $urlarg .= '&amp;'.$key.'='.urlencode($value);
    1219             }
    1220         }
    1221 
    1222         // It's not ideal to convert POST argument to GET arguments
    1223         // but there is little else we can do. One idea for the
    1224         // future might be recreate the POST header in case.
    1225         reset($_POST);
    1226         while( list($key,$value) = each($_POST) ) {
    1227             if( is_array($value) ) {
    1228                 foreach ( $value as $k => $v ) {
    1229                     $urlarg .= '&amp;'.$key.'%5B'.$k.'%5D='.urlencode($v);
    1230                 }
    1231             }
    1232             else {
    1233                 $urlarg .= '&amp;'.$key.'='.urlencode($value);
    1234             }
    1235         }
    1236 
    1237         return $urlarg;
     1357    static function GetURLArguments($aAddRecursiveBlocker=false) {
     1358
     1359        if( $aAddRecursiveBlocker ) {
     1360            // This is a JPGRAPH internal defined that prevents
     1361            // us from recursively coming here again
     1362            $urlarg = _CSIM_DISPLAY.'=1';
     1363        }
     1364
     1365        // Now reconstruct any user URL argument
     1366        reset($_GET);
     1367        foreach ($_GET as $key => $value) {
     1368            if( is_array($value) ) {
     1369                foreach ( $value as $k => $v ) {
     1370                    $urlarg .= '&amp;'.$key.'%5B'.$k.'%5D='.urlencode($v);
     1371                }
     1372            }
     1373            else {
     1374                $urlarg .= '&amp;'.$key.'='.urlencode($value);
     1375            }
     1376        }
     1377
     1378        // It's not ideal to convert POST argument to GET arguments
     1379        // but there is little else we can do. One idea for the
     1380        // future might be recreate the POST header in case.
     1381        reset($_POST);
     1382        foreach ($_POST as $key => $value) {
     1383            if( is_array($value) ) {
     1384                foreach ( $value as $k => $v ) {
     1385                    $urlarg .= '&amp;'.$key.'%5B'.$k.'%5D='.urlencode($v);
     1386                }
     1387            }
     1388            else {
     1389                $urlarg .= '&amp;'.$key.'='.urlencode($value);
     1390            }
     1391        }
     1392
     1393        return $urlarg;
    12381394    }
    12391395
    12401396    function SetCSIMImgAlt($aAlt) {
    1241         $this->iCSIMImgAlt = $aAlt;
     1397        $this->iCSIMImgAlt = $aAlt;
    12421398    }
    12431399
    12441400    function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) {
    1245         if( $aCSIMName=='' ) {
    1246             // create a random map name
    1247             srand ((double) microtime() * 1000000);
    1248             $r = rand(0,100000);
    1249             $aCSIMName='__mapname'.$r.'__';
    1250         }
    1251 
    1252         if( $aScriptName=='auto' )
    1253             $aScriptName=basename($_SERVER['PHP_SELF']);
    1254 
    1255         $urlarg = $this->GetURLArguments();
    1256 
    1257         if( empty($_GET[_CSIM_DISPLAY]) ) {
    1258             // First determine if we need to check for a cached version
    1259             // This differs from the standard cache in the sense that the
    1260             // image and CSIM map HTML file is written relative to the directory
    1261             // the script executes in and not the specified cache directory.
    1262             // The reason for this is that the cache directory is not necessarily
    1263             // accessible from the HTTP server.
    1264             if( $this->csimcachename != '' ) {
    1265                 $dir = dirname($this->csimcachename);
    1266                 $base = basename($this->csimcachename);
    1267                 $base = strtok($base,'.');
    1268                 $suffix = strtok('.');
    1269                 $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html';
    1270                 $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format;
    1271 
    1272                 // Check that apache can write to directory specified
    1273 
    1274                 if( file_exists($dir) && !is_writeable($dir) ) {
    1275                     JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');
    1276                 }
    1277                
    1278                 // Make sure directory exists
    1279                 $this->cache->MakeDirs($dir);
    1280 
    1281                 // Write the image file
    1282                 $this->Stroke(CSIMCACHE_DIR.$baseimg);
    1283 
    1284                 // Construct wrapper HTML and write to file and send it back to browser
    1285 
    1286                 // In the src URL we must replace the '?' with its encoding to prevent the arguments
    1287                 // to be converted to real arguments.
    1288                 $tmp = str_replace('?','%3f',$baseimg);
    1289                 $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n".
    1290                     '<img src="'.CSIMCACHE_HTTP_DIR.$tmp.'" ismap="ismap" usemap="#'.$aCSIMName.'" border="'.$aBorder.'" width="'.$this->img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n";
    1291 
    1292                 if($fh =  @fopen($basecsim,'w') ) {
    1293                     fwrite($fh,$htmlwrap);
    1294                     fclose($fh);
    1295                     echo $htmlwrap;
    1296                 }
    1297                 else
    1298                     JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions.");
    1299             }
    1300             else {
    1301 
    1302                 if( $aScriptName=='' ) {
    1303                     JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().');
    1304                 }
    1305                 echo $this->GetHTMLImageMap($aCSIMName);
    1306                 echo "<img src=\"".$aScriptName.'?'.$urlarg."\" ismap=\"ismap\" usemap=\"#".$aCSIMName.'" border="'.$aBorder.'" width="'.$this->img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n";
    1307             }
    1308         }
    1309         else {
    1310             $this->Stroke();
    1311         }
     1401        if( $aCSIMName=='' ) {
     1402            // create a random map name
     1403            srand ((double) microtime() * 1000000);
     1404            $r = rand(0,100000);
     1405            $aCSIMName='__mapname'.$r.'__';
     1406        }
     1407
     1408        if( $aScriptName=='auto' ) {
     1409            $aScriptName=basename($_SERVER['PHP_SELF']);
     1410        }
     1411
     1412        $urlarg = $this->GetURLArguments(true);
     1413
     1414        if( empty($_GET[_CSIM_DISPLAY]) ) {
     1415            // First determine if we need to check for a cached version
     1416            // This differs from the standard cache in the sense that the
     1417            // image and CSIM map HTML file is written relative to the directory
     1418            // the script executes in and not the specified cache directory.
     1419            // The reason for this is that the cache directory is not necessarily
     1420            // accessible from the HTTP server.
     1421            if( $this->csimcachename != '' ) {
     1422                $dir = dirname($this->csimcachename);
     1423                $base = basename($this->csimcachename);
     1424                $base = strtok($base,'.');
     1425                $suffix = strtok('.');
     1426                $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html';
     1427                $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format;
     1428
     1429                // Check that apache can write to directory specified
     1430
     1431                if( file_exists($dir) && !is_writeable($dir) ) {
     1432                    JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');
     1433                }
     1434
     1435                // Make sure directory exists
     1436                $this->cache->MakeDirs($dir);
     1437
     1438                // Write the image file
     1439                $this->Stroke(CSIMCACHE_DIR.$baseimg);
     1440
     1441                // Construct wrapper HTML and write to file and send it back to browser
     1442
     1443                // In the src URL we must replace the '?' with its encoding to prevent the arguments
     1444                // to be converted to real arguments.
     1445                $tmp = str_replace('?','%3f',$baseimg);
     1446                $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n".
     1447                            '<img src="'.CSIMCACHE_HTTP_DIR.$tmp.'" ismap="ismap" usemap="#'.$aCSIMName.' width="'.$this->img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n";
     1448
     1449                if($fh =  @fopen($basecsim,'w') ) {
     1450                    fwrite($fh,$htmlwrap);
     1451                    fclose($fh);
     1452                    echo $htmlwrap;
     1453                }
     1454                else {
     1455                    JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions.");
     1456                }
     1457            }
     1458            else {
     1459
     1460                if( $aScriptName=='' ) {
     1461                    JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().');
     1462                }
     1463                echo $this->GetHTMLImageMap($aCSIMName) . $this->GetCSIMImgHTML($aCSIMName, $aScriptName, $aBorder);
     1464            }
     1465        }
     1466        else {
     1467            $this->Stroke();
     1468        }
     1469    }
     1470
     1471    function StrokeCSIMImage() {
     1472        if( @$_GET[_CSIM_DISPLAY] == 1 ) {
     1473            $this->Stroke();
     1474        }
     1475    }
     1476
     1477    function GetCSIMImgHTML($aCSIMName, $aScriptName='auto', $aBorder=0 ) {
     1478        if( $aScriptName=='auto' ) {
     1479            $aScriptName=basename($_SERVER['PHP_SELF']);
     1480        }
     1481        $urlarg = $this->GetURLArguments(true);
     1482        return "<img src=\"".$aScriptName.'?'.$urlarg."\" ismap=\"ismap\" usemap=\"#".$aCSIMName.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n";
    13121483    }
    13131484
    13141485    function GetTextsYMinMax($aY2=false) {
    1315         if( $aY2 )
    1316             $txts = $this->y2texts;
    1317         else
    1318             $txts = $this->texts;
    1319         $n = count($txts);
    1320         $min=null;
    1321         $max=null;
    1322         for( $i=0; $i < $n; ++$i ) {
    1323             if( $txts[$i]->iScalePosY !== null &&
    1324                 $txts[$i]->iScalePosX !== null  ) {
    1325                 if( $min === null  ) {
    1326                     $min = $max = $txts[$i]->iScalePosY ;
    1327                 }
    1328                 else {
    1329                     $min = min($min,$txts[$i]->iScalePosY);
    1330                     $max = max($max,$txts[$i]->iScalePosY);
    1331                 }
    1332             }
    1333         }
    1334         if( $min !== null ) {
    1335             return array($min,$max);
    1336         }
    1337         else
    1338             return null;
     1486        if( $aY2 ) {
     1487            $txts = $this->y2texts;
     1488        }
     1489        else {
     1490            $txts = $this->texts;
     1491        }
     1492        $n = is_array($txts) ? count($txts) : 0;
     1493        $min=null;
     1494        $max=null;
     1495        for( $i=0; $i < $n; ++$i ) {
     1496            if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null  ) {
     1497                if( $min === null  ) {
     1498                    $min = $max = $txts[$i]->iScalePosY ;
     1499                }
     1500                else {
     1501                    $min = min($min,$txts[$i]->iScalePosY);
     1502                    $max = max($max,$txts[$i]->iScalePosY);
     1503                }
     1504            }
     1505        }
     1506        if( $min !== null ) {
     1507            return array($min,$max);
     1508        }
     1509        else {
     1510            return null;
     1511        }
    13391512    }
    13401513
    13411514    function GetTextsXMinMax($aY2=false) {
    1342         if( $aY2 )
    1343             $txts = $this->y2texts;
    1344         else
    1345             $txts = $this->texts;
    1346         $n = count($txts);
    1347         $min=null;
    1348         $max=null;
    1349         for( $i=0; $i < $n; ++$i ) {
    1350             if( $txts[$i]->iScalePosY !== null &&
    1351                 $txts[$i]->iScalePosX !== null  ) {
    1352                 if( $min === null  ) {
    1353                     $min = $max = $txts[$i]->iScalePosX ;
    1354                 }
    1355                 else {
    1356                     $min = min($min,$txts[$i]->iScalePosX);
    1357                     $max = max($max,$txts[$i]->iScalePosX);
    1358                 }
    1359             }
    1360         }
    1361         if( $min !== null ) {
    1362             return array($min,$max);
    1363         }
    1364         else
    1365             return null;
     1515        if( $aY2 ) {
     1516            $txts = $this->y2texts;
     1517        }
     1518        else {
     1519            $txts = $this->texts;
     1520        }
     1521        $n = is_array($txts) ? count($txts) : 0;
     1522        $min=null;
     1523        $max=null;
     1524        for( $i=0; $i < $n; ++$i ) {
     1525            if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null  ) {
     1526                if( $min === null  ) {
     1527                    $min = $max = $txts[$i]->iScalePosX ;
     1528                }
     1529                else {
     1530                    $min = min($min,$txts[$i]->iScalePosX);
     1531                    $max = max($max,$txts[$i]->iScalePosX);
     1532                }
     1533            }
     1534        }
     1535        if( $min !== null ) {
     1536            return array($min,$max);
     1537        }
     1538        else {
     1539            return null;
     1540        }
    13661541    }
    13671542
    13681543    function GetXMinMax() {
    1369         list($min,$ymin) = $this->plots[0]->Min();
    1370         list($max,$ymax) = $this->plots[0]->Max();
    1371         foreach( $this->plots as $p ) {
    1372             list($xmin,$ymin) = $p->Min();
    1373             list($xmax,$ymax) = $p->Max();                     
    1374             $min = Min($xmin,$min);
    1375             $max = Max($xmax,$max);
    1376         }
    1377 
    1378         if( $this->y2axis != null ) {
    1379             foreach( $this->y2plots as $p ) {
    1380                 list($xmin,$ymin) = $p->Min();
    1381                         list($xmax,$ymax) = $p->Max();                 
    1382                         $min = Min($xmin,$min);
    1383                         $max = Max($xmax,$max);
    1384             }               
    1385         }
    1386 
    1387         $n = count($this->ynaxis);
    1388         for( $i=0; $i < $n; ++$i ) {
    1389             if( $this->ynaxis[$i] != null) {
    1390                 foreach( $this->ynplots[$i] as $p ) {
    1391                     list($xmin,$ymin) = $p->Min();
    1392                     list($xmax,$ymax) = $p->Max();                     
    1393                     $min = Min($xmin,$min);
    1394                     $max = Max($xmax,$max);
    1395                 }                   
    1396             }
    1397         }
    1398         return array($min,$max);
     1544
     1545        list($min,$ymin) = $this->plots[0]->Min();
     1546        list($max,$ymax) = $this->plots[0]->Max();
     1547
     1548        $i=0;
     1549        // Some plots, e.g. PlotLine should not affect the scale
     1550        // and will return (null,null). We should ignore those
     1551        // values.
     1552        while( ($min===null || $max === null) && ($i < count($this->plots)-1) ) {
     1553            ++$i;
     1554            list($min,$ymin) = $this->plots[$i]->Min();
     1555            list($max,$ymax) = $this->plots[$i]->Max();
     1556        }
     1557
     1558        foreach( $this->plots as $p ) {
     1559            list($xmin,$ymin) = $p->Min();
     1560            list($xmax,$ymax) = $p->Max();
     1561
     1562            if( $xmin !== null && $xmax !== null ) {
     1563                $min = Min($xmin,$min);
     1564                $max = Max($xmax,$max);
     1565            }
     1566        }
     1567
     1568        if( $this->y2axis != null ) {
     1569            foreach( $this->y2plots as $p ) {
     1570                list($xmin,$ymin) = $p->Min();
     1571                list($xmax,$ymax) = $p->Max();
     1572                if( $xmin !== null && $xmax !== null ) {
     1573                    $min = Min($xmin, $min);
     1574                    $max = Max($xmax, $max);
     1575                }
     1576            }
     1577        }
     1578
     1579        $n = count($this->ynaxis);
     1580        for( $i=0; $i < $n; ++$i ) {
     1581            if( $this->ynaxis[$i] != null) {
     1582                foreach( $this->ynplots[$i] as $p ) {
     1583                    list($xmin,$ymin) = $p->Min();
     1584                    list($xmax,$ymax) = $p->Max();
     1585                    if( $xmin !== null && $xmax !== null ) {
     1586                        $min = Min($xmin, $min);
     1587                        $max = Max($xmax, $max);
     1588                    }
     1589                }
     1590            }
     1591        }
     1592        return array($min,$max);
    13991593    }
    14001594
    14011595    function AdjustMarginsForTitles() {
    1402         $totrequired =
    1403             ($this->title->t != '' ?
    1404              $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) +
    1405             ($this->subtitle->t != '' ?
    1406              $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) +
    1407             ($this->subsubtitle->t != '' ?
    1408              $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ;
    1409        
    1410 
    1411         $btotrequired = 0;
    1412         if($this->xaxis != null &&  !$this->xaxis->hide && !$this->xaxis->hide_labels ) {
    1413             // Minimum bottom margin
    1414             if( $this->xaxis->title->t != '' ) {
    1415                 if( $this->img->a == 90 )
    1416                     $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 5 ;
    1417                 else
    1418                     $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 5 ;
    1419             }
    1420             else
    1421                 $btotrequired = 0;
    1422            
    1423             if( $this->img->a == 90 ) {
    1424                 $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style,
    1425                                     $this->yaxis->font_size);
    1426                 $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle);
    1427             }
    1428             else {
    1429                 $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style,
    1430                                     $this->xaxis->font_size);
    1431                 $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle);
    1432             }
    1433            
    1434             $btotrequired += $lh + 5;
    1435         }
    1436 
    1437         if( $this->img->a == 90 ) {
    1438             // DO Nothing. It gets too messy to do this properly for 90 deg...
    1439         }
    1440         else{
    1441             if( $this->img->top_margin < $totrequired ) {
    1442                 $this->SetMargin($this->img->left_margin,$this->img->right_margin,
    1443                                  $totrequired,$this->img->bottom_margin);
    1444             }
    1445             if( $this->img->bottom_margin < $btotrequired ) {
    1446                 $this->SetMargin($this->img->left_margin,$this->img->right_margin,
    1447                                  $this->img->top_margin,$btotrequired);
    1448             }
    1449         }
    1450     }
     1596        $totrequired =
     1597            ($this->title->t != ''
     1598                ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * SUPERSAMPLING_SCALE
     1599                : 0 ) +
     1600            ($this->subtitle->t != ''
     1601                ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * SUPERSAMPLING_SCALE
     1602                : 0 ) +
     1603            ($this->subsubtitle->t != ''
     1604                ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * SUPERSAMPLING_SCALE
     1605                : 0 ) ;
     1606
     1607        $btotrequired = 0;
     1608        if($this->xaxis != null &&  !$this->xaxis->hide && !$this->xaxis->hide_labels ) {
     1609            // Minimum bottom margin
     1610            if( $this->xaxis->title->t != '' ) {
     1611                if( $this->img->a == 90 ) {
     1612                    $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7 ;
     1613                }
     1614                else {
     1615                    $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7 ;
     1616                }
     1617            }
     1618            else {
     1619                $btotrequired = 0;
     1620            }
     1621
     1622            if( $this->img->a == 90 ) {
     1623                $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style,
     1624                $this->yaxis->font_size);
     1625                $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle);
     1626            }
     1627            else {
     1628                $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style,
     1629                $this->xaxis->font_size);
     1630                $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle);
     1631            }
     1632
     1633            $btotrequired += $lh + 6;
     1634        }
     1635
     1636        if( $this->img->a == 90 ) {
     1637            // DO Nothing. It gets too messy to do this properly for 90 deg...
     1638        }
     1639        else{
     1640            // need more top margin
     1641            if( $this->img->top_margin < $totrequired ) {
     1642                $this->SetMargin(
     1643                    $this->img->raw_left_margin,
     1644                    $this->img->raw_right_margin,
     1645                    $totrequired / SUPERSAMPLING_SCALE,
     1646                    $this->img->raw_bottom_margin
     1647                );
     1648            }
     1649
     1650            // need more bottom margin
     1651            if( $this->img->bottom_margin < $btotrequired ) {
     1652                $this->SetMargin(
     1653                    $this->img->raw_left_margin,
     1654                    $this->img->raw_right_margin,
     1655                    $this->img->raw_top_margin,
     1656                    $btotrequired / SUPERSAMPLING_SCALE
     1657                );
     1658            }
     1659        }
     1660    }
     1661
     1662    function StrokeStore($aStrokeFileName) {
     1663        // Get the handler to prevent the library from sending the
     1664        // image to the browser
     1665        $ih = $this->Stroke(_IMG_HANDLER);
     1666
     1667        // Stroke it to a file
     1668        $this->img->Stream($aStrokeFileName);
     1669
     1670        // Send it back to browser
     1671        $this->img->Headers();
     1672        $this->img->Stream();
     1673    }
     1674
     1675    function doAutoscaleXAxis() {
     1676    //Check if we should autoscale x-axis
     1677        if( !$this->xscale->IsSpecified() ) {
     1678            if( substr($this->axtype,0,4) == "text" ) {
     1679                $max=0;
     1680                $n = count($this->plots);
     1681                for($i=0; $i < $n; ++$i ) {
     1682                    $p = $this->plots[$i];
     1683                    // We need some unfortunate sub class knowledge here in order
     1684                    // to increase number of data points in case it is a line plot
     1685                    // which has the barcenter set. If not it could mean that the
     1686                    // last point of the data is outside the scale since the barcenter
     1687                    // settings means that we will shift the entire plot half a tick step
     1688                    // to the right in oder to align with the center of the bars.
     1689                    if( class_exists('BarPlot',false) ) {
     1690                        $cl = strtolower(get_class($p));
     1691                        if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) || empty($p->barcenter) ) {
     1692                            $max=max($max,$p->numpoints-1);
     1693                        }
     1694                        else {
     1695                            $max=max($max,$p->numpoints);
     1696                        }
     1697                    }
     1698                    else {
     1699                        if( empty($p->barcenter) ) {
     1700                            $max=max($max,$p->numpoints-1);
     1701                        }
     1702                        else {
     1703                            $max=max($max,$p->numpoints);
     1704                        }
     1705                    }
     1706                }
     1707                $min=0;
     1708                if( $this->y2axis != null ) {
     1709                    foreach( $this->y2plots as $p ) {
     1710                        $max=max($max,$p->numpoints-1);
     1711                    }
     1712                }
     1713                $n = count($this->ynaxis);
     1714                for( $i=0; $i < $n; ++$i ) {
     1715                    if( $this->ynaxis[$i] != null) {
     1716                        foreach( $this->ynplots[$i] as $p ) {
     1717                            $max=max($max,$p->numpoints-1);
     1718                        }
     1719                    }
     1720                }
     1721
     1722                $this->xscale->Update($this->img,$min,$max);
     1723                $this->xscale->ticks->Set($this->xaxis->tick_step,1);
     1724                $this->xscale->ticks->SupressMinorTickMarks();
     1725            }
     1726            else {
     1727                list($min,$max) = $this->GetXMinMax();
     1728
     1729                $lres = $this->GetLinesXMinMax($this->lines);
     1730                if( $lres ) {
     1731                    list($linmin,$linmax) = $lres ;
     1732                    $min = min($min,$linmin);
     1733                    $max = max($max,$linmax);
     1734                }
     1735
     1736                $lres = $this->GetLinesXMinMax($this->y2lines);
     1737                if( $lres ) {
     1738                    list($linmin,$linmax) = $lres ;
     1739                    $min = min($min,$linmin);
     1740                    $max = max($max,$linmax);
     1741                }
     1742
     1743                $tres = $this->GetTextsXMinMax();
     1744                if( $tres ) {
     1745                    list($tmin,$tmax) = $tres ;
     1746                    $min = min($min,$tmin);
     1747                    $max = max($max,$tmax);
     1748                }
     1749
     1750                $tres = $this->GetTextsXMinMax(true);
     1751                if( $tres ) {
     1752                    list($tmin,$tmax) = $tres ;
     1753                    $min = min($min,$tmin);
     1754                    $max = max($max,$tmax);
     1755                }
     1756
     1757                $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor));
     1758            }
     1759
     1760            //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale
     1761            if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) {
     1762                $this->yaxis->SetPos($this->xscale->GetMinVal());
     1763            }
     1764        }
     1765        elseif( $this->xscale->IsSpecified() &&
     1766                ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) {
     1767            // The tick calculation will use the user suplied min/max values to determine
     1768            // the ticks. If auto_ticks is false the exact user specifed min and max
     1769            // values will be used for the scale.
     1770            // If auto_ticks is true then the scale might be slightly adjusted
     1771            // so that the min and max values falls on an even major step.
     1772            $min = $this->xscale->scale[0];
     1773            $max = $this->xscale->scale[1];
     1774            $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor),false);
     1775
     1776            // Now make sure we show enough precision to accurate display the
     1777            // labels. If this is not done then the user might end up with
     1778            // a scale that might actually start with, say 13.5, butdue to rounding
     1779            // the scale label will ony show 14.
     1780            if( abs(floor($min)-$min) > 0 ) {
     1781
     1782                // If the user has set a format then we bail out
     1783                if( $this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '' ) {
     1784                    $this->xscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
     1785                }
     1786            }
     1787        }
     1788
     1789        // Position the optional Y2 and Yn axis to the rightmost position of the x-axis
     1790        if( $this->y2axis != null ) {
     1791            if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) {
     1792                $this->y2axis->SetPos($this->xscale->GetMaxVal());
     1793            }
     1794            $this->y2axis->SetTitleSide(SIDE_RIGHT);
     1795        }
     1796
     1797        $n = count($this->ynaxis);
     1798        $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0;
     1799        for( $i=0; $i < $n; ++$i ) {
     1800            if( $this->ynaxis[$i] != null ) {
     1801                if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) {
     1802                    $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal());
     1803                    $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj);
     1804                }
     1805                $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT);
     1806            }
     1807        }
     1808    }
     1809
     1810
     1811    function doAutoScaleYnAxis() {
     1812
     1813        if( $this->y2scale != null) {
     1814            if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) {
     1815                list($min,$max) = $this->GetPlotsYMinMax($this->y2plots);
     1816
     1817                $lres = $this->GetLinesYMinMax($this->y2lines);
     1818                if( is_array($lres) ) {
     1819                    list($linmin,$linmax) = $lres ;
     1820                    $min = min($min,$linmin);
     1821                    $max = max($max,$linmax);
     1822                }
     1823                $tres = $this->GetTextsYMinMax(true);
     1824                if( is_array($tres) ) {
     1825                    list($tmin,$tmax) = $tres ;
     1826                    $min = min($min,$tmin);
     1827                    $max = max($max,$tmax);
     1828                }
     1829                $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
     1830            }
     1831            elseif( $this->y2scale->IsSpecified() && ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) {
     1832                // The tick calculation will use the user suplied min/max values to determine
     1833                // the ticks. If auto_ticks is false the exact user specifed min and max
     1834                // values will be used for the scale.
     1835                // If auto_ticks is true then the scale might be slightly adjusted
     1836                // so that the min and max values falls on an even major step.
     1837                $min = $this->y2scale->scale[0];
     1838                $max = $this->y2scale->scale[1];
     1839                $this->y2scale->AutoScale($this->img,$min,$max,
     1840                $this->img->plotheight/$this->ytick_factor,
     1841                $this->y2scale->auto_ticks);
     1842
     1843                // Now make sure we show enough precision to accurate display the
     1844                // labels. If this is not done then the user might end up with
     1845                // a scale that might actually start with, say 13.5, butdue to rounding
     1846                // the scale label will ony show 14.
     1847                if( abs(floor($min)-$min) > 0 ) {
     1848                    // If the user has set a format then we bail out
     1849                    if( $this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '' ) {
     1850                        $this->y2scale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
     1851                    }
     1852                }
     1853
     1854            }
     1855        }
     1856
     1857
     1858        //
     1859        // Autoscale the extra Y-axises
     1860        //
     1861        $n = count($this->ynaxis);
     1862        for( $i=0; $i < $n; ++$i ) {
     1863            if( $this->ynscale[$i] != null) {
     1864                if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) {
     1865                    list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]);
     1866                    $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
     1867                }
     1868                elseif( $this->ynscale[$i]->IsSpecified() && ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) {
     1869                    // The tick calculation will use the user suplied min/max values to determine
     1870                    // the ticks. If auto_ticks is false the exact user specifed min and max
     1871                    // values will be used for the scale.
     1872                    // If auto_ticks is true then the scale might be slightly adjusted
     1873                    // so that the min and max values falls on an even major step.
     1874                    $min = $this->ynscale[$i]->scale[0];
     1875                    $max = $this->ynscale[$i]->scale[1];
     1876                    $this->ynscale[$i]->AutoScale($this->img,$min,$max,
     1877                    $this->img->plotheight/$this->ytick_factor,
     1878                    $this->ynscale[$i]->auto_ticks);
     1879
     1880                    // Now make sure we show enough precision to accurate display the
     1881                    // labels. If this is not done then the user might end up with
     1882                    // a scale that might actually start with, say 13.5, butdue to rounding
     1883                    // the scale label will ony show 14.
     1884                    if( abs(floor($min)-$min) > 0 ) {
     1885                        // If the user has set a format then we bail out
     1886                        if( $this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '' ) {
     1887                            $this->ynscale[$i]->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
     1888                        }
     1889                    }
     1890                }
     1891            }
     1892        }
     1893    }
     1894
     1895    function doAutoScaleYAxis() {
     1896
     1897        //Check if we should autoscale y-axis
     1898        if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) {
     1899            list($min,$max) = $this->GetPlotsYMinMax($this->plots);
     1900            $lres = $this->GetLinesYMinMax($this->lines);
     1901            if( is_array($lres) ) {
     1902                list($linmin,$linmax) = $lres ;
     1903                $min = min($min,$linmin);
     1904                $max = max($max,$linmax);
     1905            }
     1906            $tres = $this->GetTextsYMinMax();
     1907            if( is_array($tres) ) {
     1908                list($tmin,$tmax) = $tres ;
     1909                $min = min($min,$tmin);
     1910                $max = max($max,$tmax);
     1911            }
     1912            $this->yscale->AutoScale($this->img,$min,$max,
     1913            $this->img->plotheight/$this->ytick_factor);
     1914        }
     1915        elseif( $this->yscale->IsSpecified() && ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) {
     1916            // The tick calculation will use the user suplied min/max values to determine
     1917            // the ticks. If auto_ticks is false the exact user specifed min and max
     1918            // values will be used for the scale.
     1919            // If auto_ticks is true then the scale might be slightly adjusted
     1920            // so that the min and max values falls on an even major step.
     1921            $min = $this->yscale->scale[0];
     1922            $max = $this->yscale->scale[1];
     1923            $this->yscale->AutoScale($this->img,$min,$max,
     1924            $this->img->plotheight/$this->ytick_factor,
     1925            $this->yscale->auto_ticks);
     1926
     1927            // Now make sure we show enough precision to accurate display the
     1928            // labels. If this is not done then the user might end up with
     1929            // a scale that might actually start with, say 13.5, butdue to rounding
     1930            // the scale label will ony show 14.
     1931            if( abs(floor($min)-$min) > 0 ) {
     1932
     1933                // If the user has set a format then we bail out
     1934                if( $this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '' ) {
     1935                    $this->yscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
     1936                }
     1937            }
     1938        }
     1939
     1940    }
     1941
     1942    function InitScaleConstants() {
     1943        // Setup scale constants
     1944        if( $this->yscale ) $this->yscale->InitConstants($this->img);
     1945        if( $this->xscale ) $this->xscale->InitConstants($this->img);
     1946        if( $this->y2scale ) $this->y2scale->InitConstants($this->img);
     1947
     1948        $n=count($this->ynscale);
     1949        for($i=0; $i < $n; ++$i) {
     1950            if( $this->ynscale[$i] ) {
     1951                $this->ynscale[$i]->InitConstants($this->img);
     1952            }
     1953        }
     1954    }
     1955
     1956    function doPrestrokeAdjustments() {
     1957
     1958        // Do any pre-stroke adjustment that is needed by the different plot types
     1959        // (i.e bar plots want's to add an offset to the x-labels etc)
     1960        for($i=0; $i < count($this->plots) ; ++$i ) {
     1961            $this->plots[$i]->PreStrokeAdjust($this);
     1962            $this->plots[$i]->DoLegend($this);
     1963        }
     1964
     1965        // Any plots on the second Y scale?
     1966        if( $this->y2scale != null ) {
     1967            for($i=0; $i<count($this->y2plots) ; ++$i ) {
     1968                $this->y2plots[$i]->PreStrokeAdjust($this);
     1969                $this->y2plots[$i]->DoLegend($this);
     1970            }
     1971        }
     1972
     1973        // Any plots on the extra Y axises?
     1974        $n = count($this->ynaxis);
     1975        for($i=0; $i<$n ; ++$i ) {
     1976            if( $this->ynplots == null || $this->ynplots[$i] == null) {
     1977                JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i");
     1978            }
     1979            $m = count($this->ynplots[$i]);
     1980            for($j=0; $j < $m; ++$j ) {
     1981                $this->ynplots[$i][$j]->PreStrokeAdjust($this);
     1982                $this->ynplots[$i][$j]->DoLegend($this);
     1983            }
     1984        }
     1985    }
     1986
     1987    function StrokeBands($aDepth,$aCSIM) {
     1988    // Stroke bands
     1989        if( $this->bands != null && !$aCSIM) {
     1990            for($i=0; $i < count($this->bands); ++$i) {
     1991            // Stroke all bands that asks to be in the background
     1992                if( $this->bands[$i]->depth == $aDepth ) {
     1993                    $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);
     1994                }
     1995            }
     1996        }
     1997
     1998        if( $this->y2bands != null && $this->y2scale != null && !$aCSIM ) {
     1999            for($i=0; $i < count($this->y2bands); ++$i) {
     2000            // Stroke all bands that asks to be in the foreground
     2001                if( $this->y2bands[$i]->depth == $aDepth ) {
     2002                    $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
     2003                }
     2004            }
     2005        }
     2006    }
     2007
    14512008
    14522009    // Stroke the graph
    1453     // $aStrokeFileName If != "" the image will be written to this file and NOT
     2010    // $aStrokeFileName If != "" the image will be written to this file and NOT
    14542011    // streamed back to the browser
    1455     function Stroke($aStrokeFileName="") {             
    1456 
    1457         // Fist make a sanity check that user has specified a scale
    1458         if( empty($this->yscale) ) {
    1459             JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().');
    1460         }
    1461 
    1462         // Start by adjusting the margin so that potential titles will fit.
    1463         $this->AdjustMarginsForTitles();
    1464 
    1465         // Setup scale constants
    1466         if( $this->yscale ) $this->yscale->InitConstants($this->img);
    1467         if( $this->xscale ) $this->xscale->InitConstants($this->img);
    1468         if( $this->y2scale ) $this->y2scale->InitConstants($this->img);
    1469        
    1470         $n=count($this->ynscale);
    1471         for($i=0; $i < $n; ++$i) {
    1472           if( $this->ynscale[$i] ) $this->ynscale[$i]->InitConstants($this->img);
    1473         }
    1474 
    1475         // If the filename is the predefined value = '_csim_special_'
    1476         // we assume that the call to stroke only needs to do enough
    1477         // to correctly generate the CSIM maps.
    1478         // We use this variable to skip things we don't strictly need
    1479         // to do to generate the image map to improve performance
    1480         // a best we can. Therefor you will see a lot of tests !$_csim in the
    1481         // code below.
    1482         $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
    1483 
    1484         // We need to know if we have stroked the plot in the
    1485         // GetCSIMareas. Otherwise the CSIM hasn't been generated
    1486         // and in the case of GetCSIM called before stroke to generate
    1487         // CSIM without storing an image to disk GetCSIM must call Stroke.
    1488         $this->iHasStroked = true;
    1489 
    1490         // Do any pre-stroke adjustment that is needed by the different plot types
    1491         // (i.e bar plots want's to add an offset to the x-labels etc)
    1492         for($i=0; $i < count($this->plots) ; ++$i ) {
    1493             $this->plots[$i]->PreStrokeAdjust($this);
    1494             $this->plots[$i]->DoLegend($this);
    1495         }
    1496                
    1497         // Any plots on the second Y scale?
    1498         if( $this->y2scale != null ) {
    1499             for($i=0; $i<count($this->y2plots)  ; ++$i ) {
    1500                 $this->y2plots[$i]->PreStrokeAdjust($this);
    1501                 $this->y2plots[$i]->DoLegend($this);
    1502             }
    1503         }
    1504 
    1505         // Any plots on the extra Y axises?
    1506         $n = count($this->ynaxis);
    1507         for($i=0; $i<$n ; ++$i ) {
    1508             if( $this->ynplots == null || $this->ynplots[$i] == null) {
    1509                 JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i");
    1510             }
    1511             $m = count($this->ynplots[$i]);
    1512             for($j=0; $j < $m; ++$j ) {
    1513                 $this->ynplots[$i][$j]->PreStrokeAdjust($this);
    1514                 $this->ynplots[$i][$j]->DoLegend($this);
    1515             }
    1516         }
    1517 
    1518         // Bail out if any of the Y-axis not been specified and
    1519         // has no plots. (This means it is impossible to do autoscaling and
    1520         // no other scale was given so we can't possible draw anything). If you use manual
    1521         // scaling you also have to supply the tick steps as well.
    1522         if( (!$this->yscale->IsSpecified() && count($this->plots)==0) ||
    1523             ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) {
    1524             //$e = "n=".count($this->y2plots)."\n";
    1525             // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n";
    1526             // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n";
    1527             // $e .= "2. Specified a scale manually but have forgot to specify the tick steps";
    1528             JpGraphError::RaiseL(25026);
    1529         }
    1530                
    1531         // Bail out if no plots and no specified X-scale
    1532         if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) )
    1533             JpGraphError::RaiseL(25034);//("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>");
    1534 
    1535         //Check if we should autoscale y-axis
    1536         if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) {
    1537             list($min,$max) = $this->GetPlotsYMinMax($this->plots);
    1538             $lres = $this->GetLinesYMinMax($this->lines);
    1539             if( is_array($lres) ) {
    1540                 list($linmin,$linmax) = $lres ;
    1541                 $min = min($min,$linmin);
    1542                 $max = max($max,$linmax);
    1543             }
    1544             $tres = $this->GetTextsYMinMax();
    1545             if( is_array($tres) ) {
    1546                 list($tmin,$tmax) = $tres ;
    1547                 $min = min($min,$tmin);
    1548                 $max = max($max,$tmax);
    1549             }
    1550             $this->yscale->AutoScale($this->img,$min,$max,
    1551                                      $this->img->plotheight/$this->ytick_factor);
    1552         }
    1553         elseif( $this->yscale->IsSpecified() &&
    1554                 ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) {
    1555             // The tick calculation will use the user suplied min/max values to determine
    1556             // the ticks. If auto_ticks is false the exact user specifed min and max
    1557             // values will be used for the scale.
    1558             // If auto_ticks is true then the scale might be slightly adjusted
    1559             // so that the min and max values falls on an even major step.
    1560             $min = $this->yscale->scale[0];
    1561             $max = $this->yscale->scale[1];
    1562             $this->yscale->AutoScale($this->img,$min,$max,
    1563                                      $this->img->plotheight/$this->ytick_factor,
    1564                                      $this->yscale->auto_ticks);
    1565 
    1566             // Now make sure we show enough precision to accurate display the
    1567             // labels. If this is not done then the user might end up with
    1568             // a scale that might actually start with, say 13.5, butdue to rounding
    1569             // the scale label will ony show 14.
    1570             if( abs(floor($min)-$min) > 0 ) {
    1571                
    1572                 // If the user has set a format then we bail out
    1573                 if( $this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '' ) {
    1574                     $this->yscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
    1575                 }
    1576             }
    1577         }
    1578 
    1579         if( $this->y2scale != null) {
    1580             if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) {
    1581                 list($min,$max) = $this->GetPlotsYMinMax($this->y2plots);
    1582 
    1583                 $lres = $this->GetLinesYMinMax($this->y2lines);
    1584                 if( is_array($lres) ) {
    1585                     list($linmin,$linmax) = $lres ;
    1586                     $min = min($min,$linmin);
    1587                     $max = max($max,$linmax);
    1588                 }
    1589                 $tres = $this->GetTextsYMinMax(true);
    1590                 if( is_array($tres) ) {
    1591                     list($tmin,$tmax) = $tres ;
    1592                     $min = min($min,$tmin);
    1593                     $max = max($max,$tmax);
    1594                 }
    1595                 $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
    1596             }                   
    1597             elseif( $this->y2scale->IsSpecified() &&
    1598                     ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) {
    1599                 // The tick calculation will use the user suplied min/max values to determine
    1600                 // the ticks. If auto_ticks is false the exact user specifed min and max
    1601                 // values will be used for the scale.
    1602                 // If auto_ticks is true then the scale might be slightly adjusted
    1603                 // so that the min and max values falls on an even major step.
    1604                 $min = $this->y2scale->scale[0];
    1605                 $max = $this->y2scale->scale[1];
    1606                 $this->y2scale->AutoScale($this->img,$min,$max,
    1607                                           $this->img->plotheight/$this->ytick_factor,
    1608                                           $this->y2scale->auto_ticks);
    1609 
    1610             // Now make sure we show enough precision to accurate display the
    1611             // labels. If this is not done then the user might end up with
    1612             // a scale that might actually start with, say 13.5, butdue to rounding
    1613             // the scale label will ony show 14.
    1614             if( abs(floor($min)-$min) > 0 ) {
    1615                
    1616                 // If the user has set a format then we bail out
    1617                 if( $this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '' ) {
    1618                     $this->y2scale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
    1619                 }
    1620             }
    1621 
    1622             }
    1623         }
    1624                                
    1625         //
    1626         // Autoscale the extra Y-axises
    1627         //
    1628         $n = count($this->ynaxis);
    1629         for( $i=0; $i < $n; ++$i ) {
    1630           if( $this->ynscale[$i] != null) {
    1631             if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) {
    1632               list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]);
    1633               $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
    1634             }                   
    1635             elseif( $this->ynscale[$i]->IsSpecified() &&
    1636                     ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) {
    1637                 // The tick calculation will use the user suplied min/max values to determine
    1638                 // the ticks. If auto_ticks is false the exact user specifed min and max
    1639                 // values will be used for the scale.
    1640                 // If auto_ticks is true then the scale might be slightly adjusted
    1641                 // so that the min and max values falls on an even major step.
    1642               $min = $this->ynscale[$i]->scale[0];
    1643               $max = $this->ynscale[$i]->scale[1];
    1644               $this->ynscale[$i]->AutoScale($this->img,$min,$max,
    1645                                             $this->img->plotheight/$this->ytick_factor,
    1646                                             $this->ynscale[$i]->auto_ticks);
    1647 
    1648               // Now make sure we show enough precision to accurate display the
    1649               // labels. If this is not done then the user might end up with
    1650               // a scale that might actually start with, say 13.5, butdue to rounding
    1651               // the scale label will ony show 14.
    1652               if( abs(floor($min)-$min) > 0 ) {
    1653                
    1654                   // If the user has set a format then we bail out
    1655                   if( $this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '' ) {
    1656                       $this->ynscale[$i]->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
    1657                   }
    1658               }
    1659 
    1660             }
    1661           }
    1662         }
    1663                
    1664         //Check if we should autoscale x-axis
    1665         if( !$this->xscale->IsSpecified() ) {
    1666             if( substr($this->axtype,0,4) == "text" ) {
    1667                 $max=0;
    1668                 $n = count($this->plots);
    1669                 for($i=0; $i < $n; ++$i ) {
    1670                     $p = $this->plots[$i];
    1671                     // We need some unfortunate sub class knowledge here in order
    1672                     // to increase number of data points in case it is a line plot
    1673                     // which has the barcenter set. If not it could mean that the
    1674                     // last point of the data is outside the scale since the barcenter
    1675                     // settings means that we will shift the entire plot half a tick step
    1676                     // to the right in oder to align with the center of the bars.
    1677                     if( class_exists('BarPlot',false) ) {
    1678                         $cl = strtolower(get_class($p));
    1679                         if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) ||
    1680                             empty($p->barcenter) )
    1681                             $max=max($max,$p->numpoints-1);
    1682                         else {
    1683                             $max=max($max,$p->numpoints);
    1684                         }
    1685                     }
    1686                     else {
    1687                         if( empty($p->barcenter) ) {
    1688                             $max=max($max,$p->numpoints-1);
    1689                         }
    1690                         else {
    1691                             $max=max($max,$p->numpoints);
    1692                         }
    1693                     }
    1694                 }
    1695                 $min=0;
    1696                 if( $this->y2axis != null ) {
    1697                     foreach( $this->y2plots as $p ) {
    1698                         $max=max($max,$p->numpoints-1);
    1699                     }               
    1700                 }
    1701                 $n = count($this->ynaxis);
    1702                 for( $i=0; $i < $n; ++$i ) {
    1703                     if( $this->ynaxis[$i] != null) {
    1704                         foreach( $this->ynplots[$i] as $p ) {
    1705                             $max=max($max,$p->numpoints-1);
    1706                         }                   
    1707                     }
    1708                 }
    1709                
    1710                 $this->xscale->Update($this->img,$min,$max);
    1711                 $this->xscale->ticks->Set($this->xaxis->tick_step,1);
    1712                 $this->xscale->ticks->SupressMinorTickMarks();
    1713             }
    1714             else {
    1715                 list($min,$max) = $this->GetXMinMax();
    1716 
    1717                 $lres = $this->GetLinesXMinMax($this->lines);
    1718                 if( $lres ) {
    1719                     list($linmin,$linmax) = $lres ;
    1720                     $min = min($min,$linmin);
    1721                     $max = max($max,$linmax);
    1722                 }
    1723 
    1724                 $lres = $this->GetLinesXMinMax($this->y2lines);
    1725                 if( $lres ) {
    1726                     list($linmin,$linmax) = $lres ;
    1727                     $min = min($min,$linmin);
    1728                     $max = max($max,$linmax);
    1729                 }
    1730 
    1731                 $tres = $this->GetTextsXMinMax();
    1732                 if( $tres ) {
    1733                     list($tmin,$tmax) = $tres ;
    1734                     $min = min($min,$tmin);
    1735                     $max = max($max,$tmax);
    1736                 }
    1737 
    1738                 $tres = $this->GetTextsXMinMax(true);
    1739                 if( $tres ) {
    1740                     list($tmin,$tmax) = $tres ;
    1741                     $min = min($min,$tmin);
    1742                     $max = max($max,$tmax);
    1743                 }
    1744 
    1745                 $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor));
    1746             }
    1747                        
    1748             //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale
    1749             if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) )
    1750                 $this->yaxis->SetPos($this->xscale->GetMinVal());
    1751             if( $this->y2axis != null ) {
    1752                 if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) )
    1753                     $this->y2axis->SetPos($this->xscale->GetMaxVal());
    1754                 $this->y2axis->SetTitleSide(SIDE_RIGHT);
    1755             }
    1756             $n = count($this->ynaxis);
    1757             $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0;
    1758             for( $i=0; $i < $n; ++$i ) {
    1759                 if( $this->ynaxis[$i] != null ) {
    1760                     if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) {
    1761                         $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal());
    1762                   $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj);
    1763                     }
    1764                     $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT);
    1765                 }
    1766             }
    1767 
    1768         }       
    1769         elseif( $this->xscale->IsSpecified() && 
    1770                 ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) {
    1771             // The tick calculation will use the user suplied min/max values to determine
    1772             // the ticks. If auto_ticks is false the exact user specifed min and max
    1773             // values will be used for the scale.
    1774             // If auto_ticks is true then the scale might be slightly adjusted
    1775             // so that the min and max values falls on an even major step.
    1776             $min = $this->xscale->scale[0];
    1777             $max = $this->xscale->scale[1];
    1778             $this->xscale->AutoScale($this->img,$min,$max,
    1779                                      round($this->img->plotwidth/$this->xtick_factor),
    1780                                      false);
    1781 
    1782             // Now make sure we show enough precision to accurate display the
    1783             // labels. If this is not done then the user might end up with
    1784             // a scale that might actually start with, say 13.5, butdue to rounding
    1785             // the scale label will ony show 14.
    1786             if( abs(floor($min)-$min) > 0 ) {
    1787                
    1788                 // If the user has set a format then we bail out
    1789                 if( $this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '' ) {
    1790                     $this->xscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1;
    1791                 }
    1792             }
    1793 
    1794 
    1795             if( $this->y2axis != null ) {
    1796                 if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) )
    1797                     $this->y2axis->SetPos($this->xscale->GetMaxVal());
    1798                 $this->y2axis->SetTitleSide(SIDE_RIGHT);
    1799             }
    1800 
    1801         }
    1802                
    1803         // If we have a negative values and x-axis position is at 0
    1804         // we need to supress the first and possible the last tick since
    1805         // they will be drawn on top of the y-axis (and possible y2 axis)
    1806         // The test below might seem strange the reasone being that if
    1807         // the user hasn't specified a value for position this will not
    1808         // be set until we do the stroke for the axis so as of now it
    1809         // is undefined.
    1810         // For X-text scale we ignore all this since the tick are usually
    1811         // much further in and not close to the Y-axis. Hence the test
    1812         // for 'text'   
    1813 
    1814         if( ($this->yaxis->pos==$this->xscale->GetMinVal() ||
    1815              (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) && 
    1816             !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 &&
    1817             substr($this->axtype,0,4) != 'text' && $this->xaxis->pos!="min" ) {
    1818 
    1819             //$this->yscale->ticks->SupressZeroLabel(false);
    1820             $this->xscale->ticks->SupressFirst();
    1821             if( $this->y2axis != null ) {
    1822                 $this->xscale->ticks->SupressLast();
    1823             }
    1824         }
    1825         elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) {
    1826             $this->xscale->ticks->SupressLast();
    1827         }
    1828        
    1829 
    1830         if( !$_csim ) {
    1831             $this->StrokePlotArea();
    1832             if( $this->iIconDepth == DEPTH_BACK ) {
    1833                 $this->StrokeIcons();
    1834             }
    1835         }
    1836         $this->StrokeAxis(false);
    1837 
    1838         // Stroke bands
    1839         if( $this->bands != null && !$_csim)
    1840             for($i=0; $i < count($this->bands); ++$i) {
    1841                 // Stroke all bands that asks to be in the background
    1842                 if( $this->bands[$i]->depth == DEPTH_BACK )
    1843                     $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);
    1844             }
    1845 
    1846         if( $this->y2bands != null && $this->y2scale != null && !$_csim )
    1847             for($i=0; $i < count($this->y2bands); ++$i) {
    1848                 // Stroke all bands that asks to be in the foreground
    1849                 if( $this->y2bands[$i]->depth == DEPTH_BACK )
    1850                     $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
    1851             }
    1852 
    1853 
    1854         if( $this->grid_depth == DEPTH_BACK && !$_csim) {
    1855             $this->ygrid->Stroke();
    1856             $this->xgrid->Stroke();
    1857         }
    1858                                
    1859         // Stroke Y2-axis
    1860         if( $this->y2axis != null && !$_csim) {         
    1861             $this->y2axis->Stroke($this->xscale);                               
    1862             $this->y2grid->Stroke();
    1863         }
    1864 
    1865         // Stroke yn-axis
    1866         $n = count($this->ynaxis);
    1867         for( $i=0; $i < $n; ++$i ) {
    1868             $this->ynaxis[$i]->Stroke($this->xscale);                           
    1869         }
    1870 
    1871         $oldoff=$this->xscale->off;
    1872         if(substr($this->axtype,0,4)=="text") {
    1873             if( $this->text_scale_abscenteroff > -1 ) {
    1874                 // For a text scale the scale factor is the number of pixel per step.
    1875                 // Hence we can use the scale factor as a substitute for number of pixels
    1876                 // per major scale step and use that in order to adjust the offset so that
    1877                 // an object of width "abscenteroff" becomes centered.
    1878                 $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2);
    1879             }
    1880             else {
    1881                 $this->xscale->off +=
    1882                     ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step);
    1883             }
    1884         }
    1885 
    1886         if( $this->iDoClipping ) {
    1887             $oldimage = $this->img->CloneCanvasH();
    1888         }
    1889 
    1890         if( ! $this->y2orderback ) {
    1891             // Stroke all plots for Y1 axis
    1892             for($i=0; $i < count($this->plots); ++$i) {
    1893                 $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
    1894                 $this->plots[$i]->StrokeMargin($this->img);
    1895             }                                           
    1896         }
    1897 
    1898         // Stroke all plots for Y2 axis
    1899         if( $this->y2scale != null )
    1900             for($i=0; $i< count($this->y2plots); ++$i ) {       
    1901                 $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
    1902             }           
    1903 
    1904         if( $this->y2orderback ) {
    1905             // Stroke all plots for Y1 axis
    1906             for($i=0; $i < count($this->plots); ++$i) {
    1907                 $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
    1908                 $this->plots[$i]->StrokeMargin($this->img);
    1909             }                                           
    1910         }
    1911 
    1912         $n = count($this->ynaxis);
    1913         for( $i=0; $i < $n; ++$i ) {
    1914             $m = count($this->ynplots[$i]);
    1915             for( $j=0; $j < $m; ++$j ) {
    1916                 $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]);
    1917                 $this->ynplots[$i][$j]->StrokeMargin($this->img);
    1918             }
    1919         }
    1920 
    1921         if( $this->iIconDepth == DEPTH_FRONT) {
    1922             $this->StrokeIcons();
    1923         }
    1924        
    1925         if( $this->iDoClipping ) {
    1926             // Clipping only supports graphs at 0 and 90 degrees
    1927             if( $this->img->a == 0 ) {
    1928                 $this->img->CopyCanvasH($oldimage,$this->img->img,
    1929                                         $this->img->left_margin,$this->img->top_margin,
    1930                                         $this->img->left_margin,$this->img->top_margin,
    1931                                         $this->img->plotwidth+1,$this->img->plotheight);
    1932             }
    1933             elseif( $this->img->a == 90 ) {
    1934                 $adj = ($this->img->height - $this->img->width)/2;
    1935                 $this->img->CopyCanvasH($oldimage,$this->img->img,
    1936                                         $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
    1937                                         $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
    1938                                         $this->img->plotheight+1,$this->img->plotwidth);
    1939             }
    1940             else {
    1941                 JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.');
    1942             }
    1943             $this->img->Destroy();
    1944             $this->img->SetCanvasH($oldimage);
    1945         }
    1946 
    1947         $this->xscale->off=$oldoff;
    1948                
    1949         if( $this->grid_depth == DEPTH_FRONT && !$_csim ) {
    1950             $this->ygrid->Stroke();
    1951             $this->xgrid->Stroke();
    1952         }
    1953 
    1954         // Stroke bands
    1955         if( $this->bands!= null )
    1956             for($i=0; $i < count($this->bands); ++$i) {
    1957                 // Stroke all bands that asks to be in the foreground
    1958                 if( $this->bands[$i]->depth == DEPTH_FRONT )
    1959                     $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);
    1960             }
    1961 
    1962         if( $this->y2bands!= null && $this->y2scale != null )
    1963             for($i=0; $i < count($this->y2bands); ++$i) {
    1964                 // Stroke all bands that asks to be in the foreground
    1965                 if( $this->y2bands[$i]->depth == DEPTH_FRONT )
    1966                     $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
    1967             }
    1968 
    1969 
    1970         // Stroke any lines added
    1971         if( $this->lines != null ) {
    1972             for($i=0; $i < count($this->lines); ++$i) {
    1973                 $this->lines[$i]->Stroke($this->img,$this->xscale,$this->yscale);
    1974                 $this->lines[$i]->DoLegend($this);
    1975             }
    1976         }
    1977 
    1978         if( $this->y2lines != null && $this->y2scale != null ) {
    1979             for($i=0; $i < count($this->y2lines); ++$i) {
    1980                 $this->y2lines[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
    1981                 $this->y2lines[$i]->DoLegend($this);
    1982             }
    1983         }
    1984 
    1985         // Finally draw the axis again since some plots may have nagged
    1986         // the axis in the edges.
    1987         if( !$_csim ) {
    1988             $this->StrokeAxis();
    1989         }
    1990 
    1991         if( $this->y2scale != null && !$_csim )
    1992             $this->y2axis->Stroke($this->xscale,false);         
    1993                
    1994         if( !$_csim ) {
    1995             $this->StrokePlotBox();
    1996         }
    1997                
    1998         // The titles and legends never gets rotated so make sure
    1999         // that the angle is 0 before stroking them                             
    2000         $aa = $this->img->SetAngle(0);
    2001         $this->StrokeTitles();
    2002         $this->footer->Stroke($this->img);
    2003         $this->legend->Stroke($this->img);             
    2004         $this->img->SetAngle($aa);     
    2005         $this->StrokeTexts();   
    2006         $this->StrokeTables();
    2007 
    2008         if( !$_csim ) {
    2009 
    2010             $this->img->SetAngle($aa); 
    2011                        
    2012             // Draw an outline around the image map     
    2013             if(_JPG_DEBUG) {
    2014                 $this->DisplayClientSideaImageMapAreas();               
    2015             }
    2016            
    2017             // Should we do any final image transformation
    2018             if( $this->iImgTrans ) {
    2019                 if( !class_exists('ImgTrans',false) ) {
    2020                     require_once('jpgraph_imgtrans.php');
    2021                     //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');
    2022                 }
    2023                
    2024                 $tform = new ImgTrans($this->img->img);
    2025                 $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
    2026                                                  $this->iImgTransDirection,$this->iImgTransHighQ,
    2027                                                  $this->iImgTransMinSize,$this->iImgTransFillColor,
    2028                                                  $this->iImgTransBorder);
    2029             }
    2030 
    2031             // If the filename is given as the special "__handle"
    2032             // then the image handler is returned and the image is NOT
    2033             // streamed back
    2034             if( $aStrokeFileName == _IMG_HANDLER ) {
    2035                 return $this->img->img;
    2036             }
    2037             else {
    2038                 // Finally stream the generated picture                                 
    2039                 $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);               
    2040             }
    2041         }
     2012    function Stroke($aStrokeFileName='') {
     2013        // Fist make a sanity check that user has specified a scale
     2014        if( empty($this->yscale) ) {
     2015            JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().');
     2016        }
     2017
     2018        // Start by adjusting the margin so that potential titles will fit.
     2019        $this->AdjustMarginsForTitles();
     2020
     2021        // Give the plot a chance to do any scale adjuments the individual plots
     2022        // wants to do. Right now this is only used by the contour plot to set scale
     2023        // limits
     2024        for($i=0; $i < count($this->plots) ; ++$i ) {
     2025            $this->plots[$i]->PreScaleSetup($this);
     2026        }
     2027
     2028        // Init scale constants that are used to calculate the transformation from
     2029        // world to pixel coordinates
     2030        $this->InitScaleConstants();
     2031
     2032        // If the filename is the predefined value = '_csim_special_'
     2033        // we assume that the call to stroke only needs to do enough
     2034        // to correctly generate the CSIM maps.
     2035        // We use this variable to skip things we don't strictly need
     2036        // to do to generate the image map to improve performance
     2037        // a best we can. Therefor you will see a lot of tests !$_csim in the
     2038        // code below.
     2039        $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
     2040
     2041        // If we are called the second time (perhaps the user has called GetHTMLImageMap()
     2042        // himself then the legends have alsready been populated once in order to get the
     2043        // CSIM coordinats. Since we do not want the legends to be populated a second time
     2044        // we clear the legends
     2045        $this->legend->Clear();
     2046
     2047        // We need to know if we have stroked the plot in the
     2048        // GetCSIMareas. Otherwise the CSIM hasn't been generated
     2049        // and in the case of GetCSIM called before stroke to generate
     2050        // CSIM without storing an image to disk GetCSIM must call Stroke.
     2051        $this->iHasStroked = true;
     2052
     2053        // Setup pre-stroked adjustments and Legends
     2054        $this->doPrestrokeAdjustments();
     2055
     2056        if ($this->graph_theme) {
     2057            $this->graph_theme->PreStrokeApply($this);
     2058        }
     2059
     2060        // Bail out if any of the Y-axis not been specified and
     2061        // has no plots. (This means it is impossible to do autoscaling and
     2062        // no other scale was given so we can't possible draw anything). If you use manual
     2063        // scaling you also have to supply the tick steps as well.
     2064        if( (!$this->yscale->IsSpecified() && count($this->plots)==0) ||
     2065            ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) {
     2066            //$e = "n=".count($this->y2plots)."\n";
     2067            // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n";
     2068            // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n";
     2069            // $e .= "2. Specified a scale manually but have forgot to specify the tick steps";
     2070            JpGraphError::RaiseL(25026);
     2071        }
     2072
     2073        // Bail out if no plots and no specified X-scale
     2074        if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) {
     2075            JpGraphError::RaiseL(25034);//("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>");
     2076        }
     2077
     2078        // Autoscale the normal Y-axis
     2079        $this->doAutoScaleYAxis();
     2080
     2081        // Autoscale all additiopnal y-axis
     2082        $this->doAutoScaleYnAxis();
     2083
     2084        // Autoscale the regular x-axis and position the y-axis properly
     2085        $this->doAutoScaleXAxis();
     2086
     2087        // If we have a negative values and x-axis position is at 0
     2088        // we need to supress the first and possible the last tick since
     2089        // they will be drawn on top of the y-axis (and possible y2 axis)
     2090        // The test below might seem strange the reasone being that if
     2091        // the user hasn't specified a value for position this will not
     2092        // be set until we do the stroke for the axis so as of now it
     2093        // is undefined.
     2094        // For X-text scale we ignore all this since the tick are usually
     2095        // much further in and not close to the Y-axis. Hence the test
     2096        // for 'text'
     2097        if( ($this->yaxis->pos==$this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) &&
     2098            !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 &&
     2099            substr($this->axtype,0,4) != 'text' && $this->xaxis->pos != 'min' ) {
     2100
     2101            //$this->yscale->ticks->SupressZeroLabel(false);
     2102            $this->xscale->ticks->SupressFirst();
     2103            if( $this->y2axis != null ) {
     2104                $this->xscale->ticks->SupressLast();
     2105            }
     2106        }
     2107        elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) {
     2108            $this->xscale->ticks->SupressLast();
     2109        }
     2110
     2111        if( !$_csim ) {
     2112            $this->StrokePlotArea();
     2113            if( $this->iIconDepth == DEPTH_BACK ) {
     2114                $this->StrokeIcons();
     2115            }
     2116        }
     2117        $this->StrokeAxis(false);
     2118
     2119        // Stroke colored bands
     2120        $this->StrokeBands(DEPTH_BACK,$_csim);
     2121
     2122        if( $this->grid_depth == DEPTH_BACK && !$_csim) {
     2123            $this->ygrid->Stroke();
     2124            $this->xgrid->Stroke();
     2125        }
     2126
     2127        // Stroke Y2-axis
     2128        if( $this->y2axis != null && !$_csim) {
     2129            $this->y2axis->Stroke($this->xscale);
     2130            $this->y2grid->Stroke();
     2131        }
     2132
     2133        // Stroke yn-axis
     2134        $n = count($this->ynaxis);
     2135        for( $i=0; $i < $n; ++$i ) {
     2136            $this->ynaxis[$i]->Stroke($this->xscale);
     2137        }
     2138
     2139        $oldoff=$this->xscale->off;
     2140        if( substr($this->axtype,0,4) == 'text' ) {
     2141            if( $this->text_scale_abscenteroff > -1 ) {
     2142                // For a text scale the scale factor is the number of pixel per step.
     2143                // Hence we can use the scale factor as a substitute for number of pixels
     2144                // per major scale step and use that in order to adjust the offset so that
     2145                // an object of width "abscenteroff" becomes centered.
     2146                $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2);
     2147            }
     2148            else {
     2149                $this->xscale->off += ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step);
     2150            }
     2151        }
     2152
     2153        if( $this->iDoClipping ) {
     2154            $oldimage = $this->img->CloneCanvasH();
     2155        }
     2156
     2157        if( ! $this->y2orderback ) {
     2158            // Stroke all plots for Y1 axis
     2159            for($i=0; $i < count($this->plots); ++$i) {
     2160                $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
     2161                $this->plots[$i]->StrokeMargin($this->img);
     2162            }
     2163        }
     2164
     2165        // Stroke all plots for Y2 axis
     2166        if( $this->y2scale != null ) {
     2167            for($i=0; $i< count($this->y2plots); ++$i ) {
     2168                $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
     2169            }
     2170        }
     2171
     2172        if( $this->y2orderback ) {
     2173            // Stroke all plots for Y1 axis
     2174            for($i=0; $i < count($this->plots); ++$i) {
     2175                $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
     2176                $this->plots[$i]->StrokeMargin($this->img);
     2177            }
     2178        }
     2179
     2180        $n = count($this->ynaxis);
     2181        for( $i=0; $i < $n; ++$i ) {
     2182            $m = count($this->ynplots[$i]);
     2183            for( $j=0; $j < $m; ++$j ) {
     2184                $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]);
     2185                $this->ynplots[$i][$j]->StrokeMargin($this->img);
     2186            }
     2187        }
     2188
     2189        if( $this->iIconDepth == DEPTH_FRONT) {
     2190            $this->StrokeIcons();
     2191        }
     2192
     2193        if( $this->iDoClipping ) {
     2194            // Clipping only supports graphs at 0 and 90 degrees
     2195            if( $this->img->a == 0 ) {
     2196                $this->img->CopyCanvasH($oldimage,$this->img->img,
     2197                $this->img->left_margin,$this->img->top_margin,
     2198                $this->img->left_margin,$this->img->top_margin,
     2199                $this->img->plotwidth+1,$this->img->plotheight);
     2200            }
     2201            elseif( $this->img->a == 90 ) {
     2202                $adj = ($this->img->height - $this->img->width)/2;
     2203                $this->img->CopyCanvasH($oldimage,$this->img->img,
     2204                $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
     2205                $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
     2206                $this->img->plotheight+1,$this->img->plotwidth);
     2207            }
     2208            else {
     2209                JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.');
     2210            }
     2211            $this->img->Destroy();
     2212            $this->img->SetCanvasH($oldimage);
     2213        }
     2214
     2215        $this->xscale->off=$oldoff;
     2216
     2217        if( $this->grid_depth == DEPTH_FRONT && !$_csim ) {
     2218            $this->ygrid->Stroke();
     2219            $this->xgrid->Stroke();
     2220        }
     2221
     2222        // Stroke colored bands
     2223        $this->StrokeBands(DEPTH_FRONT,$_csim);
     2224
     2225        // Finally draw the axis again since some plots may have nagged
     2226        // the axis in the edges.
     2227        if( !$_csim ) {
     2228            $this->StrokeAxis();
     2229        }
     2230
     2231        if( $this->y2scale != null && !$_csim ) {
     2232            $this->y2axis->Stroke($this->xscale,false);
     2233        }
     2234
     2235        if( !$_csim ) {
     2236            $this->StrokePlotBox();
     2237        }
     2238
     2239        // The titles and legends never gets rotated so make sure
     2240        // that the angle is 0 before stroking them
     2241        $aa = $this->img->SetAngle(0);
     2242        $this->StrokeTitles();
     2243        $this->footer->Stroke($this->img);
     2244        $this->legend->Stroke($this->img);
     2245        $this->img->SetAngle($aa);
     2246        $this->StrokeTexts();
     2247        $this->StrokeTables();
     2248
     2249        if( !$_csim ) {
     2250
     2251            $this->img->SetAngle($aa);
     2252
     2253            // Draw an outline around the image map
     2254            if(_JPG_DEBUG) {
     2255                $this->DisplayClientSideaImageMapAreas();
     2256            }
     2257
     2258            // Should we do any final image transformation
     2259            if( $this->iImgTrans ) {
     2260                if( !class_exists('ImgTrans',false) ) {
     2261                    require_once('jpgraph_imgtrans.php');
     2262                    //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');
     2263                }
     2264
     2265                $tform = new ImgTrans($this->img->img);
     2266                $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
     2267                $this->iImgTransDirection,$this->iImgTransHighQ,
     2268                $this->iImgTransMinSize,$this->iImgTransFillColor,
     2269                $this->iImgTransBorder);
     2270            }
     2271
     2272            // If the filename is given as the special "__handle"
     2273            // then the image handler is returned and the image is NOT
     2274            // streamed back
     2275            if( $aStrokeFileName == _IMG_HANDLER ) {
     2276                return $this->img->img;
     2277            }
     2278            else {
     2279                // Finally stream the generated picture
     2280                $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);
     2281            }
     2282        }
    20422283    }
    20432284
    20442285    function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') {
    2045         $this->iAxisLblBgType = $aType;
    2046         $this->iXAxisLblBgFillColor = $aXFColor;
    2047         $this->iXAxisLblBgColor = $aXColor;
    2048         $this->iYAxisLblBgFillColor = $aYFColor;
    2049         $this->iYAxisLblBgColor = $aYColor;
    2050     }
    2051 
    2052 //---------------
    2053 // PRIVATE METHODS     
     2286        $this->iAxisLblBgType = $aType;
     2287        $this->iXAxisLblBgFillColor = $aXFColor;
     2288        $this->iXAxisLblBgColor = $aXColor;
     2289        $this->iYAxisLblBgFillColor = $aYFColor;
     2290        $this->iYAxisLblBgColor = $aYColor;
     2291    }
    20542292
    20552293    function StrokeAxisLabelBackground() {
    2056         // Types
    2057         // 0 = No background
    2058         // 1 = Only X-labels, length of axis
    2059         // 2 = Only Y-labels, length of axis
    2060         // 3 = As 1 but extends to width of graph
    2061         // 4 = As 2 but extends to height of graph
    2062         // 5 = Combination of 3 & 4
    2063         // 6 = Combination of 1 & 2
    2064  
    2065         $t = $this->iAxisLblBgType ;
    2066         if( $t < 1 ) return;
    2067         // Stroke optional X-axis label background color
    2068         if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) {
    2069             $this->img->PushColor($this->iXAxisLblBgFillColor);
    2070             if( $t == 1 || $t == 6 ) {
    2071                 $xl = $this->img->left_margin;
    2072                 $yu = $this->img->height - $this->img->bottom_margin + 1;
    2073                 $xr = $this->img->width - $this->img->right_margin ;
    2074                 $yl = $this->img->height-1-$this->frame_weight;
    2075             }
    2076             else { // t==3 || t==5
    2077                 $xl = $this->frame_weight;
    2078                 $yu = $this->img->height - $this->img->bottom_margin + 1;
    2079                 $xr = $this->img->width - 1 - $this->frame_weight;
    2080                 $yl = $this->img->height-1-$this->frame_weight;
    2081             }
    2082 
    2083             $this->img->FilledRectangle($xl,$yu,$xr,$yl);
    2084             $this->img->PopColor();
    2085 
    2086             // Check if we should add the vertical lines at left and right edge
    2087             if( $this->iXAxisLblBgColor !== '' ) {
    2088                 // Hardcode to one pixel wide
    2089                 $this->img->SetLineWeight(1);
    2090                 $this->img->PushColor($this->iXAxisLblBgColor);
    2091                 if( $t == 1 || $t == 6 ) {
    2092                     $this->img->Line($xl,$yu,$xl,$yl);
    2093                     $this->img->Line($xr,$yu,$xr,$yl);
    2094                 }
    2095                 else {
    2096                     $xl = $this->img->width - $this->img->right_margin ;
    2097                     $this->img->Line($xl,$yu-1,$xr,$yu-1);
    2098                 }
    2099                 $this->img->PopColor();
    2100             }
    2101         }
    2102 
    2103         if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) {
    2104             $this->img->PushColor($this->iYAxisLblBgFillColor);
    2105             if( $t == 2 || $t == 6 ) {     
    2106                 $xl = $this->frame_weight;
    2107                 $yu = $this->frame_weight+$this->img->top_margin;
    2108                 $xr = $this->img->left_margin - 1;
    2109                 $yl = $this->img->height - $this->img->bottom_margin + 1;
    2110             }
    2111             else {
    2112                 $xl = $this->frame_weight;
    2113                 $yu = $this->frame_weight;
    2114                 $xr = $this->img->left_margin - 1;
    2115                 $yl = $this->img->height-1-$this->frame_weight;
    2116             }
    2117 
    2118             $this->img->FilledRectangle($xl,$yu,$xr,$yl);
    2119             $this->img->PopColor();
    2120 
    2121             // Check if we should add the vertical lines at left and right edge
    2122             if( $this->iXAxisLblBgColor !== '' ) {
    2123                 $this->img->PushColor($this->iXAxisLblBgColor);
    2124                 if( $t == 2 || $t == 6 ) {
    2125                     $this->img->Line($xl,$yu-1,$xr,$yu-1);
    2126                     $this->img->Line($xl,$yl-1,$xr,$yl-1);                 
    2127                 }
    2128                 else {
    2129                     $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin);               
    2130                 }
    2131                 $this->img->PopColor();
    2132             }
    2133 
    2134         }
     2294        // Types
     2295        // 0 = No background
     2296        // 1 = Only X-labels, length of axis
     2297        // 2 = Only Y-labels, length of axis
     2298        // 3 = As 1 but extends to width of graph
     2299        // 4 = As 2 but extends to height of graph
     2300        // 5 = Combination of 3 & 4
     2301        // 6 = Combination of 1 & 2
     2302
     2303        $t = $this->iAxisLblBgType ;
     2304        if( $t < 1 ) return;
     2305
     2306        // Stroke optional X-axis label background color
     2307        if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) {
     2308            $this->img->PushColor($this->iXAxisLblBgFillColor);
     2309            if( $t == 1 || $t == 6 ) {
     2310                $xl = $this->img->left_margin;
     2311                $yu = $this->img->height - $this->img->bottom_margin + 1;
     2312                $xr = $this->img->width - $this->img->right_margin ;
     2313                $yl = $this->img->height-1-$this->frame_weight;
     2314            }
     2315            else { // t==3 || t==5
     2316                $xl = $this->frame_weight;
     2317                $yu = $this->img->height - $this->img->bottom_margin + 1;
     2318                $xr = $this->img->width - 1 - $this->frame_weight;
     2319                $yl = $this->img->height-1-$this->frame_weight;
     2320            }
     2321
     2322            $this->img->FilledRectangle($xl,$yu,$xr,$yl);
     2323            $this->img->PopColor();
     2324
     2325            // Check if we should add the vertical lines at left and right edge
     2326            if( $this->iXAxisLblBgColor !== '' ) {
     2327                // Hardcode to one pixel wide
     2328                $this->img->SetLineWeight(1);
     2329                $this->img->PushColor($this->iXAxisLblBgColor);
     2330                if( $t == 1 || $t == 6 ) {
     2331                    $this->img->Line($xl,$yu,$xl,$yl);
     2332                    $this->img->Line($xr,$yu,$xr,$yl);
     2333                }
     2334                else {
     2335                    $xl = $this->img->width - $this->img->right_margin ;
     2336                    $this->img->Line($xl,$yu-1,$xr,$yu-1);
     2337                }
     2338                $this->img->PopColor();
     2339            }
     2340        }
     2341
     2342        if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) {
     2343            $this->img->PushColor($this->iYAxisLblBgFillColor);
     2344            if( $t == 2 || $t == 6 ) {
     2345                $xl = $this->frame_weight;
     2346                $yu = $this->frame_weight+$this->img->top_margin;
     2347                $xr = $this->img->left_margin - 1;
     2348                $yl = $this->img->height - $this->img->bottom_margin + 1;
     2349            }
     2350            else {
     2351                $xl = $this->frame_weight;
     2352                $yu = $this->frame_weight;
     2353                $xr = $this->img->left_margin - 1;
     2354                $yl = $this->img->height-1-$this->frame_weight;
     2355            }
     2356
     2357            $this->img->FilledRectangle($xl,$yu,$xr,$yl);
     2358            $this->img->PopColor();
     2359
     2360            // Check if we should add the vertical lines at left and right edge
     2361            if( $this->iXAxisLblBgColor !== '' ) {
     2362                $this->img->PushColor($this->iXAxisLblBgColor);
     2363                if( $t == 2 || $t == 6 ) {
     2364                    $this->img->Line($xl,$yu-1,$xr,$yu-1);
     2365                    $this->img->Line($xl,$yl-1,$xr,$yl-1);
     2366                }
     2367                else {
     2368                    $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin);
     2369                }
     2370                $this->img->PopColor();
     2371            }
     2372
     2373        }
    21352374    }
    21362375
    21372376    function StrokeAxis($aStrokeLabels=true) {
    2138        
    2139         if( $aStrokeLabels ) {
    2140             $this->StrokeAxisLabelBackground();
    2141         }
    2142 
    2143         // Stroke axis
    2144         if( $this->iAxisStyle != AXSTYLE_SIMPLE ) {
    2145             switch( $this->iAxisStyle ) {
    2146                 case AXSTYLE_BOXIN :
    2147                     $toppos = SIDE_DOWN;
    2148                     $bottompos = SIDE_UP;
    2149                     $leftpos = SIDE_RIGHT;
    2150                     $rightpos = SIDE_LEFT;
    2151                     break;
    2152                 case AXSTYLE_BOXOUT :
    2153                     $toppos = SIDE_UP;
    2154                     $bottompos = SIDE_DOWN;         
    2155                     $leftpos = SIDE_LEFT;
    2156                     $rightpos = SIDE_RIGHT;
    2157                     break;
    2158                 case AXSTYLE_YBOXIN:
    2159                     $toppos = FALSE;
    2160                     $bottompos = SIDE_UP;
    2161                     $leftpos = SIDE_RIGHT;
    2162                     $rightpos = SIDE_LEFT;
    2163                     break;
    2164                 case AXSTYLE_YBOXOUT:
    2165                     $toppos = FALSE;
    2166                     $bottompos = SIDE_DOWN;         
    2167                     $leftpos = SIDE_LEFT;
    2168                     $rightpos = SIDE_RIGHT;
    2169                     break;
    2170                 default:
    2171                     JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle);
    2172                     break;
    2173             }
    2174            
    2175             // By default we hide the first label so it doesn't cross the
    2176             // Y-axis in case the positon hasn't been set by the user.
    2177             // However, if we use a box we always want the first value
    2178             // displayed so we make sure it will be displayed.
    2179             $this->xscale->ticks->SupressFirst(false);   
    2180 
    2181             // Now draw the bottom X-axis
    2182             $this->xaxis->SetPos('min');
    2183             $this->xaxis->SetLabelSide(SIDE_DOWN);
    2184             $this->xaxis->scale->ticks->SetSide($bottompos);
    2185             $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
    2186 
    2187             if( $toppos !== FALSE ) {
    2188                 // We also want a top X-axis
    2189                 $this->xaxis = $this->xaxis;
    2190                 $this->xaxis->SetPos('max');
    2191                 $this->xaxis->SetLabelSide(SIDE_UP);
    2192                 // No title for the top X-axis
    2193                 if( $aStrokeLabels ) {
    2194                     $this->xaxis->title->Set('');
    2195                 }
    2196                 $this->xaxis->scale->ticks->SetSide($toppos);
    2197                 $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
    2198             }
    2199 
    2200             // Stroke the left Y-axis
    2201             $this->yaxis->SetPos('min');
    2202             $this->yaxis->SetLabelSide(SIDE_LEFT);
    2203             $this->yaxis->scale->ticks->SetSide($leftpos);
    2204             $this->yaxis->Stroke($this->xscale,$aStrokeLabels);
    2205 
    2206             // Stroke the  right Y-axis
    2207             $this->yaxis->SetPos('max');
    2208             // No title for the right side
    2209             if( $aStrokeLabels ) {
    2210                 $this->yaxis->title->Set('');
    2211             }
    2212             $this->yaxis->SetLabelSide(SIDE_RIGHT);
    2213             $this->yaxis->scale->ticks->SetSide($rightpos);
    2214             $this->yaxis->Stroke($this->xscale,$aStrokeLabels); 
    2215         }
    2216         else {
    2217             $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
    2218             $this->yaxis->Stroke($this->xscale,$aStrokeLabels);         
    2219         }
     2377
     2378        if( $aStrokeLabels ) {
     2379            $this->StrokeAxisLabelBackground();
     2380        }
     2381
     2382        // Stroke axis
     2383        if( $this->iAxisStyle != AXSTYLE_SIMPLE ) {
     2384            switch( $this->iAxisStyle ) {
     2385                case AXSTYLE_BOXIN :
     2386                    $toppos = SIDE_DOWN;
     2387                    $bottompos = SIDE_UP;
     2388                    $leftpos = SIDE_RIGHT;
     2389                    $rightpos = SIDE_LEFT;
     2390                    break;
     2391                case AXSTYLE_BOXOUT :
     2392                    $toppos = SIDE_UP;
     2393                    $bottompos = SIDE_DOWN;
     2394                    $leftpos = SIDE_LEFT;
     2395                    $rightpos = SIDE_RIGHT;
     2396                    break;
     2397                case AXSTYLE_YBOXIN:
     2398                    $toppos = FALSE;
     2399                    $bottompos = SIDE_UP;
     2400                    $leftpos = SIDE_RIGHT;
     2401                    $rightpos = SIDE_LEFT;
     2402                    break;
     2403                case AXSTYLE_YBOXOUT:
     2404                    $toppos = FALSE;
     2405                    $bottompos = SIDE_DOWN;
     2406                    $leftpos = SIDE_LEFT;
     2407                    $rightpos = SIDE_RIGHT;
     2408                    break;
     2409                default:
     2410                    JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle);
     2411                    break;
     2412            }
     2413
     2414            // By default we hide the first label so it doesn't cross the
     2415            // Y-axis in case the positon hasn't been set by the user.
     2416            // However, if we use a box we always want the first value
     2417            // displayed so we make sure it will be displayed.
     2418            $this->xscale->ticks->SupressFirst(false);
     2419
     2420            // Now draw the bottom X-axis
     2421            $this->xaxis->SetPos('min');
     2422            $this->xaxis->SetLabelSide(SIDE_DOWN);
     2423            $this->xaxis->scale->ticks->SetSide($bottompos);
     2424            $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
     2425
     2426            if( $toppos !== FALSE ) {
     2427                // We also want a top X-axis
     2428                $this->xaxis = $this->xaxis;
     2429                $this->xaxis->SetPos('max');
     2430                $this->xaxis->SetLabelSide(SIDE_UP);
     2431                // No title for the top X-axis
     2432                if( $aStrokeLabels ) {
     2433                    $this->xaxis->title->Set('');
     2434                }
     2435                $this->xaxis->scale->ticks->SetSide($toppos);
     2436                $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
     2437            }
     2438
     2439            // Stroke the left Y-axis
     2440            $this->yaxis->SetPos('min');
     2441            $this->yaxis->SetLabelSide(SIDE_LEFT);
     2442            $this->yaxis->scale->ticks->SetSide($leftpos);
     2443            $this->yaxis->Stroke($this->xscale,$aStrokeLabels);
     2444
     2445            // Stroke the  right Y-axis
     2446            $this->yaxis->SetPos('max');
     2447            // No title for the right side
     2448            if( $aStrokeLabels ) {
     2449                $this->yaxis->title->Set('');
     2450            }
     2451            $this->yaxis->SetLabelSide(SIDE_RIGHT);
     2452            $this->yaxis->scale->ticks->SetSide($rightpos);
     2453            $this->yaxis->Stroke($this->xscale,$aStrokeLabels);
     2454        }
     2455        else {
     2456            $this->xaxis->Stroke($this->yscale,$aStrokeLabels);
     2457            $this->yaxis->Stroke($this->xscale,$aStrokeLabels);
     2458        }
    22202459    }
    22212460
     
    22232462    // Private helper function for backgound image
    22242463    static function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') {
    2225         if( $aImgStr != '' ) {
    2226             return Image::CreateFromString($aImgStr);
    2227         }
    2228 
    2229         // Remove case sensitivity and setup appropriate function to create image
    2230         // Get file extension. This should be the LAST '.' separated part of the filename
    2231         $e = explode('.',$aFile);
    2232         $ext = strtolower($e[count($e)-1]);
    2233         if ($ext == "jpeg")  {
    2234             $ext = "jpg";
    2235         }
    2236        
    2237         if( trim($ext) == '' )
    2238             $ext = 'png';  // Assume PNG if no extension specified
    2239 
    2240         if( $aImgFormat == '' )
    2241             $imgtag = $ext;
    2242         else
    2243             $imgtag = $aImgFormat;
    2244 
    2245         $supported = imagetypes();
    2246         if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) ||
    2247             ( $ext == 'gif' && !($supported & IMG_GIF) ) ||
    2248             ( $ext == 'png' && !($supported & IMG_PNG) ) ||
    2249             ( $ext == 'bmp' && !($supported & IMG_WBMP) ) ||
    2250             ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) {
    2251 
    2252             JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. ');
    2253         }
    2254 
    2255 
    2256         if( $imgtag == "jpg" || $imgtag == "jpeg")
    2257         {
    2258             $f = "imagecreatefromjpeg";
    2259             $imgtag = "jpg";
    2260         }
    2261         else
    2262         {
    2263             $f = "imagecreatefrom".$imgtag;
    2264         }
    2265 
    2266         // Compare specified image type and file extension
    2267         if( $imgtag != $ext ) {
    2268             //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'";
    2269             JpGraphError::RaiseL(25038, $aImgFormat, $aFile);
    2270         }
    2271 
    2272         $img = @$f($aFile);
    2273         if( !$img ) {
    2274             JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'");   
    2275         }
    2276         return $img;
    2277     }   
     2464        if( $aImgStr != '' ) {
     2465            return Image::CreateFromString($aImgStr);
     2466        }
     2467
     2468        // Remove case sensitivity and setup appropriate function to create image
     2469        // Get file extension. This should be the LAST '.' separated part of the filename
     2470        $e = explode('.',$aFile);
     2471        $ext = strtolower($e[count($e)-1]);
     2472        if ($ext == "jpeg")  {
     2473            $ext = "jpg";
     2474        }
     2475
     2476        if( trim($ext) == '' ) {
     2477            $ext = 'png';  // Assume PNG if no extension specified
     2478        }
     2479
     2480        if( $aImgFormat == '' ) {
     2481            $imgtag = $ext;
     2482        }
     2483        else {
     2484            $imgtag = $aImgFormat;
     2485        }
     2486
     2487        $supported = imagetypes();
     2488        if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) ||
     2489            ( $ext == 'gif' && !($supported & IMG_GIF) ) ||
     2490            ( $ext == 'png' && !($supported & IMG_PNG) ) ||
     2491            ( $ext == 'bmp' && !($supported & IMG_WBMP) ) ||
     2492            ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) {
     2493
     2494            JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. ');
     2495        }
     2496
     2497
     2498        if( $imgtag == "jpg" || $imgtag == "jpeg") {
     2499            $f = "imagecreatefromjpeg";
     2500            $imgtag = "jpg";
     2501        }
     2502        else {
     2503            $f = "imagecreatefrom".$imgtag;
     2504        }
     2505
     2506        // Compare specified image type and file extension
     2507        if( $imgtag != $ext ) {
     2508            //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'";
     2509            JpGraphError::RaiseL(25038, $aImgFormat, $aFile);
     2510        }
     2511
     2512        $img = @$f($aFile);
     2513        if( !$img ) {
     2514            JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'");
     2515        }
     2516        return $img;
     2517    }
     2518
     2519    function StrokePlotGrad() {
     2520        if( $this->plot_gradtype < 0  )
     2521            return;
     2522           
     2523        $grad = new Gradient($this->img);
     2524        $xl = $this->img->left_margin;
     2525        $yt = $this->img->top_margin;
     2526        $xr = $xl + $this->img->plotwidth+1 ;
     2527        $yb = $yt + $this->img->plotheight ;
     2528        $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->plot_gradfrom,$this->plot_gradto,$this->plot_gradtype);
     2529
     2530    }
    22782531
    22792532    function StrokeBackgroundGrad() {
    2280         if( $this->bkg_gradtype < 0  )
    2281             return;
    2282         $grad = new Gradient($this->img);
    2283         if( $this->bkg_gradstyle == BGRAD_PLOT ) {
    2284             $xl = $this->img->left_margin;
    2285             $yt = $this->img->top_margin;
    2286             $xr = $xl + $this->img->plotwidth+1 ;
    2287             $yb = $yt + $this->img->plotheight ;
    2288             $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);
    2289         }
    2290         else {
    2291             $xl = 0;
    2292             $yt = 0;
    2293             $xr = $xl + $this->img->width - 1;
    2294             $yb = $yt + $this->img->height ;
    2295             if( $this->doshadow  ) {
    2296                 $xr -= $this->shadow_width;
    2297                 $yb -= $this->shadow_width;
    2298             }
    2299             if( $this->doframe ) {
    2300                 $yt += $this->frame_weight;
    2301                 $yb -= $this->frame_weight;   
    2302                 $xl += $this->frame_weight;
    2303                 $xr -= $this->frame_weight;
    2304             }
    2305             $aa = $this->img->SetAngle(0);
    2306             $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);
    2307             $aa = $this->img->SetAngle($aa);
    2308         }
     2533        if( $this->bkg_gradtype < 0  )
     2534            return;
     2535
     2536        $grad = new Gradient($this->img);
     2537        if( $this->bkg_gradstyle == BGRAD_PLOT ) {
     2538            $xl = $this->img->left_margin;
     2539            $yt = $this->img->top_margin;
     2540            $xr = $xl + $this->img->plotwidth+1 ;
     2541            $yb = $yt + $this->img->plotheight ;
     2542            $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);
     2543        }
     2544        else {
     2545            $xl = 0;
     2546            $yt = 0;
     2547            $xr = $xl + $this->img->width - 1;
     2548            $yb = $yt + $this->img->height - 1 ;
     2549            if( $this->doshadow  ) {
     2550                $xr -= $this->shadow_width;
     2551                $yb -= $this->shadow_width;
     2552            }
     2553            if( $this->doframe ) {
     2554                $yt += $this->frame_weight;
     2555                $yb -= $this->frame_weight;
     2556                $xl += $this->frame_weight;
     2557                $xr -= $this->frame_weight;
     2558            }
     2559            $aa = $this->img->SetAngle(0);
     2560            $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype);
     2561            $aa = $this->img->SetAngle($aa);
     2562        }
    23092563    }
    23102564
    23112565    function StrokeFrameBackground() {
    2312         if( $this->background_image != "" && $this->background_cflag != "" ) {
    2313             JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.');
    2314         }
    2315         if( $this->background_image != "" ) {
    2316             $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image);
    2317         }
    2318         elseif( $this->background_cflag != "" ) {
    2319             if( ! class_exists('FlagImages',false) ) {
    2320                 JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.');
    2321             }
    2322             $fobj = new FlagImages(FLAGSIZE4);
    2323             $dummy='';
    2324             $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy);
    2325             $this->background_image_mix = $this->background_cflag_mix;
    2326             $this->background_image_type = $this->background_cflag_type;
    2327         }
    2328         else {
    2329             return ;
    2330         }
    2331 
    2332         $bw = ImageSX($bkgimg);
    2333         $bh = ImageSY($bkgimg);
    2334 
    2335         // No matter what the angle is we always stroke the image and frame
    2336         // assuming it is 0 degree
    2337         $aa = $this->img->SetAngle(0);
    2338                
    2339         switch( $this->background_image_type ) {
    2340             case BGIMG_FILLPLOT: // Resize to just fill the plotarea
    2341                 $this->FillMarginArea();
    2342                 $this->StrokeFrame();
    2343                 // Special case to hande 90 degree rotated graph corectly
    2344                 if( $aa == 90 ) {
    2345                     $this->img->SetAngle(90);
    2346                     $this->FillPlotArea();
    2347                     $aa = $this->img->SetAngle(0);
    2348                     $adj = ($this->img->height - $this->img->width)/2;
    2349                     $this->img->CopyMerge($bkgimg,
    2350                                           $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
    2351                                           0,0,
    2352                                           $this->img->plotheight+1,$this->img->plotwidth,
    2353                                           $bw,$bh,$this->background_image_mix);
    2354 
    2355                 }
    2356                 else {
    2357                     $this->FillPlotArea();
    2358                     $this->img->CopyMerge($bkgimg,
    2359                                           $this->img->left_margin,$this->img->top_margin,
    2360                                           0,0,$this->img->plotwidth+1,$this->img->plotheight,
    2361                                           $bw,$bh,$this->background_image_mix);
    2362                 }
    2363                 break;
    2364             case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit
    2365                 $hadj=0; $vadj=0;
    2366                 if( $this->doshadow ) {
    2367                     $hadj = $this->shadow_width;
    2368                     $vadj = $this->shadow_width;
    2369                 }
    2370                 $this->FillMarginArea();
    2371                 $this->FillPlotArea();
    2372                 $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj,
    2373                                       $bw,$bh,$this->background_image_mix);
    2374                 $this->StrokeFrame();
    2375                 break;
    2376             case BGIMG_COPY: // Just copy the image from left corner, no resizing
    2377                 $this->FillMarginArea();
    2378                 $this->FillPlotArea();
    2379                 $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh,
    2380                                       $bw,$bh,$this->background_image_mix);
    2381                 $this->StrokeFrame();
    2382                 break;
    2383             case BGIMG_CENTER: // Center original image in the plot area
    2384                 $this->FillMarginArea();
    2385                 $this->FillPlotArea();
    2386                 $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2);
    2387                 $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2);
    2388                 $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh,
    2389                                       $bw,$bh,$this->background_image_mix);
    2390                 $this->StrokeFrame();
    2391                 break;
    2392             case BGIMG_FREE: // Just copy the image to the specified location
    2393                 $this->img->CopyMerge($bkgimg,
    2394                                       $this->background_image_xpos,$this->background_image_ypos,
    2395                                       0,0,$bw,$bh,$bw,$bh,$this->background_image_mix);
    2396                 $this->StrokeFrame(); // New
    2397                 break;
    2398             default:
    2399                 JpGraphError::RaiseL(25042);//(" Unknown background image layout");
    2400         }                       
    2401         $this->img->SetAngle($aa);             
     2566        if( $this->background_image != '' && $this->background_cflag != '' ) {
     2567            JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.');
     2568        }
     2569        if( $this->background_image != '' ) {
     2570            $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image);
     2571        }
     2572        elseif( $this->background_cflag != '' ) {
     2573            if( ! class_exists('FlagImages',false) ) {
     2574                JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.');
     2575            }
     2576            $fobj = new FlagImages(FLAGSIZE4);
     2577            $dummy='';
     2578            $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy);
     2579            $this->background_image_mix = $this->background_cflag_mix;
     2580            $this->background_image_type = $this->background_cflag_type;
     2581        }
     2582        else {
     2583            return ;
     2584        }
     2585
     2586        $bw = ImageSX($bkgimg);
     2587        $bh = ImageSY($bkgimg);
     2588
     2589        // No matter what the angle is we always stroke the image and frame
     2590        // assuming it is 0 degree
     2591        $aa = $this->img->SetAngle(0);
     2592
     2593        switch( $this->background_image_type ) {
     2594            case BGIMG_FILLPLOT: // Resize to just fill the plotarea
     2595                $this->FillMarginArea();
     2596                $this->StrokeFrame();
     2597                // Special case to hande 90 degree rotated graph corectly
     2598                if( $aa == 90 ) {
     2599                    $this->img->SetAngle(90);
     2600                    $this->FillPlotArea();
     2601                    $aa = $this->img->SetAngle(0);
     2602                    $adj = ($this->img->height - $this->img->width)/2;
     2603                    $this->img->CopyMerge($bkgimg,
     2604                        $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
     2605                        0,0,
     2606                        $this->img->plotheight+1,$this->img->plotwidth,
     2607                        $bw,$bh,$this->background_image_mix);
     2608                }
     2609                else {
     2610                    $this->FillPlotArea();
     2611                    $this->img->CopyMerge($bkgimg,
     2612                        $this->img->left_margin,$this->img->top_margin+1,
     2613                        0,0,$this->img->plotwidth+1,$this->img->plotheight,
     2614                        $bw,$bh,$this->background_image_mix);
     2615                }
     2616                break;
     2617            case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit
     2618                $hadj=0; $vadj=0;
     2619                if( $this->doshadow ) {
     2620                    $hadj = $this->shadow_width;
     2621                    $vadj = $this->shadow_width;
     2622                }
     2623                $this->FillMarginArea();
     2624                $this->FillPlotArea();
     2625                $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj,
     2626                $bw,$bh,$this->background_image_mix);
     2627                $this->StrokeFrame();
     2628                break;
     2629            case BGIMG_COPY: // Just copy the image from left corner, no resizing
     2630                $this->FillMarginArea();
     2631                $this->FillPlotArea();
     2632                $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh,
     2633                $bw,$bh,$this->background_image_mix);
     2634                $this->StrokeFrame();
     2635                break;
     2636            case BGIMG_CENTER: // Center original image in the plot area
     2637                $this->FillMarginArea();
     2638                $this->FillPlotArea();
     2639                $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2);
     2640                $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2);
     2641                $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh,
     2642                $bw,$bh,$this->background_image_mix);
     2643                $this->StrokeFrame();
     2644                break;
     2645            case BGIMG_FREE: // Just copy the image to the specified location
     2646                $this->img->CopyMerge($bkgimg,
     2647                $this->background_image_xpos,$this->background_image_ypos,
     2648                0,0,$bw,$bh,$bw,$bh,$this->background_image_mix);
     2649                $this->StrokeFrame(); // New
     2650                break;
     2651            default:
     2652                JpGraphError::RaiseL(25042);//(" Unknown background image layout");
     2653        }
     2654        $this->img->SetAngle($aa);
    24022655    }
    24032656
     
    24052658    // Draw a frame around the image
    24062659    function StrokeFrame() {
    2407         if( !$this->doframe ) return;
    2408 
    2409         if( $this->background_image_type <= 1 &&
    2410             ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) {
    2411             $c = $this->margin_color;
    2412         }
    2413         else {
    2414             $c = false;
    2415         }
    2416        
    2417         if( $this->doshadow ) {
    2418             $this->img->SetColor($this->frame_color);                   
    2419             $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height,
    2420                                         $c,$this->shadow_width,$this->shadow_color);
    2421         }
    2422         elseif( $this->framebevel ) {
    2423             if( $c ) {
    2424                 $this->img->SetColor($this->margin_color);
    2425                 $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
    2426             }
    2427             $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
    2428                               $this->framebeveldepth,
    2429                               $this->framebevelcolor1,$this->framebevelcolor2);
    2430             if( $this->framebevelborder ) {
    2431                 $this->img->SetColor($this->framebevelbordercolor);
    2432                 $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
    2433             }
    2434         }
    2435         else {
    2436             $this->img->SetLineWeight($this->frame_weight);
    2437             if( $c ) {
    2438                 $this->img->SetColor($this->margin_color);
    2439                 $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
    2440             }
    2441             $this->img->SetColor($this->frame_color);
    2442             $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);               
    2443         }
     2660        if( !$this->doframe ) return;
     2661
     2662        if( $this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) {
     2663            $c = $this->margin_color;
     2664        }
     2665        else {
     2666            $c = false;
     2667        }
     2668
     2669        if( $this->doshadow ) {
     2670            $this->img->SetColor($this->frame_color);
     2671            $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height,
     2672            $c,$this->shadow_width,$this->shadow_color);
     2673        }
     2674        elseif( $this->framebevel ) {
     2675            if( $c ) {
     2676                $this->img->SetColor($this->margin_color);
     2677                $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
     2678            }
     2679            $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
     2680            $this->framebeveldepth,
     2681            $this->framebevelcolor1,$this->framebevelcolor2);
     2682            if( $this->framebevelborder ) {
     2683                $this->img->SetColor($this->framebevelbordercolor);
     2684                $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
     2685            }
     2686        }
     2687        else {
     2688            $this->img->SetLineWeight($this->frame_weight);
     2689            if( $c ) {
     2690                $this->img->SetColor($this->margin_color);
     2691                $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
     2692            }
     2693            $this->img->SetColor($this->frame_color);
     2694            $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
     2695        }
    24442696    }
    24452697
    24462698    function FillMarginArea() {
    2447         $hadj=0; $vadj=0;
    2448         if( $this->doshadow ) {
    2449             $hadj = $this->shadow_width;
    2450             $vadj = $this->shadow_width;
    2451         }
    2452 
    2453         $this->img->SetColor($this->margin_color);
    2454 //      $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj);
    2455 
    2456         $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin);
    2457         $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj);
    2458         $this->img->FilledRectangle($this->img->left_margin+1,
    2459                                     $this->img->height-$this->img->bottom_margin,
    2460                                     $this->img->width-1-$hadj,
    2461                                     $this->img->height-1-$hadj);
    2462         $this->img->FilledRectangle($this->img->width-$this->img->right_margin,
    2463                                     $this->img->top_margin+1,
    2464                                     $this->img->width-1-$hadj,
    2465                                     $this->img->height-$this->img->bottom_margin-1);
     2699        $hadj=0; $vadj=0;
     2700        if( $this->doshadow ) {
     2701            $hadj = $this->shadow_width;
     2702            $vadj = $this->shadow_width;
     2703        }
     2704
     2705        $this->img->SetColor($this->margin_color);
     2706        $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj);
     2707
     2708        $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin);
     2709        $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj);
     2710        $this->img->FilledRectangle($this->img->left_margin+1,
     2711        $this->img->height-$this->img->bottom_margin,
     2712        $this->img->width-1-$hadj,
     2713        $this->img->height-1-$hadj);
     2714        $this->img->FilledRectangle($this->img->width-$this->img->right_margin,
     2715        $this->img->top_margin+1,
     2716        $this->img->width-1-$hadj,
     2717        $this->img->height-$this->img->bottom_margin-1);
    24662718    }
    24672719
    24682720    function FillPlotArea() {
    2469         $this->img->PushColor($this->plotarea_color);
    2470         $this->img->FilledRectangle($this->img->left_margin,
    2471                                     $this->img->top_margin,
    2472                                     $this->img->width-$this->img->right_margin,
    2473                                     $this->img->height-$this->img->bottom_margin);     
    2474         $this->img->PopColor();
    2475     }
    2476    
     2721        $this->img->PushColor($this->plotarea_color);
     2722        $this->img->FilledRectangle($this->img->left_margin,
     2723        $this->img->top_margin,
     2724        $this->img->width-$this->img->right_margin,
     2725        $this->img->height-$this->img->bottom_margin);
     2726        $this->img->PopColor();
     2727    }
     2728
    24772729    // Stroke the plot area with either a solid color or a background image
    24782730    function StrokePlotArea() {
    2479         // Note: To be consistent we really should take a possible shadow
    2480         // into account. However, that causes some problem for the LinearScale class
    2481         // since in the current design it does not have any links to class Graph which
    2482         // means it has no way of compensating for the adjusted plotarea in case of a
    2483         // shadow. So, until I redesign LinearScale we can't compensate for this.
    2484         // So just set the two adjustment parameters to zero for now.
    2485         $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ;
    2486         $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ;
    2487 
    2488         if( $this->background_image != "" || $this->background_cflag != "" ) {
    2489             $this->StrokeFrameBackground();
    2490         }
    2491         else {
    2492             $aa = $this->img->SetAngle(0);
    2493             $this->StrokeFrame();
    2494             $aa = $this->img->SetAngle($aa);
    2495             $this->StrokeBackgroundGrad();
    2496             if( $this->bkg_gradtype < 0 ||
    2497                 ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) {
    2498                 $this->FillPlotArea();
    2499             }
    2500         }       
    2501     }   
     2731        // Note: To be consistent we really should take a possible shadow
     2732        // into account. However, that causes some problem for the LinearScale class
     2733        // since in the current design it does not have any links to class Graph which
     2734        // means it has no way of compensating for the adjusted plotarea in case of a
     2735        // shadow. So, until I redesign LinearScale we can't compensate for this.
     2736        // So just set the two adjustment parameters to zero for now.
     2737        $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ;
     2738        $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ;
     2739
     2740        if( $this->background_image != '' || $this->background_cflag != '' ) {
     2741            $this->StrokeFrameBackground();
     2742        }
     2743        else {
     2744            $aa = $this->img->SetAngle(0);
     2745            $this->StrokeFrame();
     2746            $aa = $this->img->SetAngle($aa);
     2747            $this->StrokeBackgroundGrad();
     2748            if( $this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) {
     2749                $this->FillPlotArea();
     2750            }
     2751            $this->StrokePlotGrad();
     2752        }
     2753    }
    25022754
    25032755    function StrokeIcons() {
    2504         $n = count($this->iIcons);
    2505         for( $i=0; $i < $n; ++$i ) {
    2506             $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
    2507         }
    2508     }
    2509        
     2756        $n = count($this->iIcons);
     2757        for( $i=0; $i < $n; ++$i ) {
     2758            $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
     2759        }
     2760    }
     2761
    25102762    function StrokePlotBox() {
    2511         // Should we draw a box around the plot area?
    2512         if( $this->boxed ) {
    2513             $this->img->SetLineWeight(1);
    2514             $this->img->SetLineStyle('solid');
    2515             $this->img->SetColor($this->box_color);
    2516             for($i=0; $i < $this->box_weight; ++$i ) {
    2517                 $this->img->Rectangle(
    2518                     $this->img->left_margin-$i,$this->img->top_margin-$i,
    2519                     $this->img->width-$this->img->right_margin+$i,
    2520                     $this->img->height-$this->img->bottom_margin+$i);
    2521             }
    2522         }                                               
    2523     }           
     2763        // Should we draw a box around the plot area?
     2764        if( $this->boxed ) {
     2765            $this->img->SetLineWeight(1);
     2766            $this->img->SetLineStyle('solid');
     2767            $this->img->SetColor($this->box_color);
     2768            for($i=0; $i < $this->box_weight; ++$i ) {
     2769                $this->img->Rectangle(
     2770                $this->img->left_margin-$i,$this->img->top_margin-$i,
     2771                $this->img->width-$this->img->right_margin+$i,
     2772                $this->img->height-$this->img->bottom_margin+$i);
     2773            }
     2774        }
     2775    }
    25242776
    25252777    function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') {
    2526         $this->titlebkg_fillstyle = $aStyle;
    2527         $this->titlebkg_scolor1 = $aColor1;
    2528         $this->titlebkg_scolor2 = $aColor2;
     2778        $this->titlebkg_fillstyle = $aStyle;
     2779        $this->titlebkg_scolor1 = $aColor1;
     2780        $this->titlebkg_scolor2 = $aColor2;
    25292781    }
    25302782
    25312783    function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) {
    2532         $this->titlebackground = $aEnable;
    2533         $this->titlebackground_color = $aBackColor;
    2534         $this->titlebackground_style = $aStyle;
    2535         $this->titlebackground_framecolor = $aFrameColor;
    2536         $this->titlebackground_framestyle = $aFrameStyle;
    2537         $this->titlebackground_frameweight = $aFrameWeight;     
    2538         $this->titlebackground_bevelheight = $aBevelHeight ;
     2784        $this->titlebackground = $aEnable;
     2785        $this->titlebackground_color = $aBackColor;
     2786        $this->titlebackground_style = $aStyle;
     2787        $this->titlebackground_framecolor = $aFrameColor;
     2788        $this->titlebackground_framestyle = $aFrameStyle;
     2789        $this->titlebackground_frameweight = $aFrameWeight;
     2790        $this->titlebackground_bevelheight = $aBevelHeight ;
    25392791    }
    25402792
     
    25422794    function StrokeTitles() {
    25432795
    2544         $margin=3;
    2545 
    2546         if( $this->titlebackground ) {
    2547 
    2548             // Find out height
    2549             $this->title->margin += 2 ;
    2550             $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin;
    2551             if( $this->subtitle->t != "" && !$this->subtitle->hide ) {
    2552                 $h += $this->subtitle->GetTextHeight($this->img)+$margin+
    2553                     $this->subtitle->margin;
    2554                 $h += 2;
    2555             }
    2556             if( $this->subsubtitle->t != "" && !$this->subsubtitle->hide ) {
    2557                 $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+
    2558                     $this->subsubtitle->margin;
    2559                 $h += 2;
    2560             }
    2561             $this->img->PushColor($this->titlebackground_color);
    2562             if( $this->titlebackground_style === TITLEBKG_STYLE1 ) {
    2563                 // Inside the frame
    2564                 if( $this->framebevel ) {
    2565                     $x1 = $y1 = $this->framebeveldepth + 1 ;
    2566                     $x2 = $this->img->width - $this->framebeveldepth - 2 ;
    2567                     $this->title->margin += $this->framebeveldepth + 1 ;
    2568                     $h += $y1 ;
    2569                     $h += 2;
    2570                 }
    2571                 else {
    2572                     $x1 = $y1 = $this->frame_weight;
    2573                     $x2 = $this->img->width - 2*$x1;
    2574                 }
    2575             }
    2576             elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) {
    2577                 // Cover the frame as well
    2578                 $x1 = $y1 = 0;
    2579                 $x2 = $this->img->width - 1 ;
    2580             }
    2581             elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) {
    2582                 // Cover the frame as well (the difference is that
    2583                 // for style==3 a bevel frame border is on top
    2584                 // of the title background)
    2585                 $x1 = $y1 = 0;
    2586                 $x2 = $this->img->width - 1 ;
    2587                 $h += $this->framebeveldepth ;
    2588                 $this->title->margin += $this->framebeveldepth ;
    2589             }
    2590             else {
    2591                 JpGraphError::RaiseL(25043);//('Unknown title background style.');
    2592             }
    2593 
    2594             if( $this->titlebackground_framestyle === 3 ) {
    2595                 $h += $this->titlebackground_bevelheight*2 + 1  ;
    2596                 $this->title->margin += $this->titlebackground_bevelheight ;
    2597             }
    2598 
    2599             if( $this->doshadow ) {
    2600                 $x2 -= $this->shadow_width ;
    2601             }
    2602            
    2603             $indent=0;
    2604             if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {
    2605                 $ind = $this->titlebackground_bevelheight;
    2606             }
    2607 
    2608             if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) {
    2609                 $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind,
    2610                                              $this->titlebkg_scolor1,
    2611                                              $this->titlebkg_scolor2);
    2612             }
    2613             elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) {
    2614                 $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind,
    2615                                              $this->titlebkg_scolor1,
    2616                                              $this->titlebkg_scolor2,2);
    2617             }
    2618             else {
    2619                 // Solid fill
    2620                 $this->img->FilledRectangle($x1,$y1,$x2,$h);
    2621             }
    2622             $this->img->PopColor();
    2623 
    2624             $this->img->PushColor($this->titlebackground_framecolor);
    2625             $this->img->SetLineWeight($this->titlebackground_frameweight);
    2626             if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) {
    2627                 // Frame background
    2628                 $this->img->Rectangle($x1,$y1,$x2,$h);
    2629             }
    2630             elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) {
    2631                 // Bottom line only
    2632                 $this->img->Line($x1,$h,$x2,$h);
    2633             }
    2634             elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {
    2635                 $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight);
    2636             }
    2637             $this->img->PopColor();
    2638 
    2639             // This is clumsy. But we neeed to stroke the whole graph frame if it is
    2640             // set to bevel to get the bevel shading on top of the text background
    2641             if( $this->framebevel && $this->doframe &&
    2642                 $this->titlebackground_style === 3 ) {
    2643                 $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
    2644                                   $this->framebeveldepth,
    2645                                   $this->framebevelcolor1,$this->framebevelcolor2);
    2646                 if( $this->framebevelborder ) {
    2647                     $this->img->SetColor($this->framebevelbordercolor);
    2648                     $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
    2649                 }
    2650             }
    2651         }
    2652 
    2653         // Stroke title
    2654         $y = $this->title->margin;
    2655         if( $this->title->halign == 'center' )
    2656             $this->title->Center(0,$this->img->width,$y);
    2657         elseif( $this->title->halign == 'left' ) {
    2658             $this->title->SetPos($this->title->margin+2,$y);
    2659         }
    2660         elseif( $this->title->halign == 'right' ) {
    2661             $indent = 0;
    2662             if( $this->doshadow )
    2663                 $indent = $this->shadow_width+2;
    2664             $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right');       
    2665         }
    2666         $this->title->Stroke($this->img);
    2667                
    2668         // ... and subtitle
    2669         $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
    2670         if( $this->subtitle->halign == 'center' )
    2671             $this->subtitle->Center(0,$this->img->width,$y);
    2672         elseif( $this->subtitle->halign == 'left' ) {
    2673             $this->subtitle->SetPos($this->subtitle->margin+2,$y);
    2674         }
    2675         elseif( $this->subtitle->halign == 'right' ) {
    2676             $indent = 0;
    2677             if( $this->doshadow )
    2678                 $indent = $this->shadow_width+2;
    2679             $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right');
    2680         }
    2681         $this->subtitle->Stroke($this->img);
    2682 
    2683         // ... and subsubtitle
    2684         $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
    2685         if( $this->subsubtitle->halign == 'center' )
    2686             $this->subsubtitle->Center(0,$this->img->width,$y);
    2687         elseif( $this->subsubtitle->halign == 'left' ) {
    2688             $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y);
    2689         }
    2690         elseif( $this->subsubtitle->halign == 'right' ) {
    2691             $indent = 0;
    2692             if( $this->doshadow )
    2693                 $indent = $this->shadow_width+2;
    2694             $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right');
    2695         }
    2696         $this->subsubtitle->Stroke($this->img);
    2697 
    2698         // ... and fancy title
    2699         $this->tabtitle->Stroke($this->img);
     2796        $margin=3;
     2797
     2798        if( $this->titlebackground ) {
     2799            // Find out height
     2800            $this->title->margin += 2 ;
     2801            $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin;
     2802            if( $this->subtitle->t != '' && !$this->subtitle->hide ) {
     2803                $h += $this->subtitle->GetTextHeight($this->img)+$margin+
     2804                $this->subtitle->margin;
     2805                $h += 2;
     2806            }
     2807            if( $this->subsubtitle->t != '' && !$this->subsubtitle->hide ) {
     2808                $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+
     2809                $this->subsubtitle->margin;
     2810                $h += 2;
     2811            }
     2812            $this->img->PushColor($this->titlebackground_color);
     2813            if( $this->titlebackground_style === TITLEBKG_STYLE1 ) {
     2814                // Inside the frame
     2815                if( $this->framebevel ) {
     2816                    $x1 = $y1 = $this->framebeveldepth + 1 ;
     2817                    $x2 = $this->img->width - $this->framebeveldepth - 2 ;
     2818                    $this->title->margin += $this->framebeveldepth + 1 ;
     2819                    $h += $y1 ;
     2820                    $h += 2;
     2821                }
     2822                else {
     2823                    $x1 = $y1 = $this->frame_weight;
     2824                    $x2 = $this->img->width - $this->frame_weight-1;
     2825                }
     2826            }
     2827            elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) {
     2828                // Cover the frame as well
     2829                $x1 = $y1 = 0;
     2830                $x2 = $this->img->width - 1 ;
     2831            }
     2832            elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) {
     2833                // Cover the frame as well (the difference is that
     2834                // for style==3 a bevel frame border is on top
     2835                // of the title background)
     2836                $x1 = $y1 = 0;
     2837                $x2 = $this->img->width - 1 ;
     2838                $h += $this->framebeveldepth ;
     2839                $this->title->margin += $this->framebeveldepth ;
     2840            }
     2841            else {
     2842                JpGraphError::RaiseL(25043);//('Unknown title background style.');
     2843            }
     2844
     2845            if( $this->titlebackground_framestyle === 3 ) {
     2846                $h += $this->titlebackground_bevelheight*2 + 1  ;
     2847                $this->title->margin += $this->titlebackground_bevelheight ;
     2848            }
     2849
     2850            if( $this->doshadow ) {
     2851                $x2 -= $this->shadow_width ;
     2852            }
     2853
     2854            $indent=0;
     2855            if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {
     2856                $indent = $this->titlebackground_bevelheight;
     2857            }
     2858
     2859            if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) {
     2860                $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent,
     2861                $this->titlebkg_scolor1,
     2862                $this->titlebkg_scolor2);
     2863            }
     2864            elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) {
     2865                $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent,
     2866                $this->titlebkg_scolor1,
     2867                $this->titlebkg_scolor2,2);
     2868            }
     2869            else {
     2870                // Solid fill
     2871                $this->img->FilledRectangle($x1,$y1,$x2,$h);
     2872            }
     2873            $this->img->PopColor();
     2874
     2875            $this->img->PushColor($this->titlebackground_framecolor);
     2876            $this->img->SetLineWeight($this->titlebackground_frameweight);
     2877            if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) {
     2878                // Frame background
     2879                $this->img->Rectangle($x1,$y1,$x2,$h);
     2880            }
     2881            elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) {
     2882                // Bottom line only
     2883                $this->img->Line($x1,$h,$x2,$h);
     2884            }
     2885            elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) {
     2886                $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight);
     2887            }
     2888            $this->img->PopColor();
     2889
     2890            // This is clumsy. But we neeed to stroke the whole graph frame if it is
     2891            // set to bevel to get the bevel shading on top of the text background
     2892            if( $this->framebevel && $this->doframe && $this->titlebackground_style === 3 ) {
     2893                $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
     2894                $this->framebeveldepth,
     2895                $this->framebevelcolor1,$this->framebevelcolor2);
     2896                if( $this->framebevelborder ) {
     2897                    $this->img->SetColor($this->framebevelbordercolor);
     2898                    $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
     2899                }
     2900            }
     2901        }
     2902
     2903        // Stroke title
     2904        $y = $this->title->margin;
     2905        if( $this->title->halign == 'center' ) {
     2906            $this->title->Center(0,$this->img->width,$y);
     2907        }
     2908        elseif( $this->title->halign == 'left' ) {
     2909            $this->title->SetPos($this->title->margin+2,$y);
     2910        }
     2911        elseif( $this->title->halign == 'right' ) {
     2912            $indent = 0;
     2913            if( $this->doshadow ) {
     2914                $indent = $this->shadow_width+2;
     2915            }
     2916            $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right');
     2917        }
     2918        $this->title->Stroke($this->img);
     2919
     2920        // ... and subtitle
     2921        $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
     2922        if( $this->subtitle->halign == 'center' ) {
     2923            $this->subtitle->Center(0,$this->img->width,$y);
     2924        }
     2925        elseif( $this->subtitle->halign == 'left' ) {
     2926            $this->subtitle->SetPos($this->subtitle->margin+2,$y);
     2927        }
     2928        elseif( $this->subtitle->halign == 'right' ) {
     2929            $indent = 0;
     2930            if( $this->doshadow )
     2931            $indent = $this->shadow_width+2;
     2932            $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right');
     2933        }
     2934        $this->subtitle->Stroke($this->img);
     2935
     2936        // ... and subsubtitle
     2937        $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
     2938        if( $this->subsubtitle->halign == 'center' ) {
     2939            $this->subsubtitle->Center(0,$this->img->width,$y);
     2940        }
     2941        elseif( $this->subsubtitle->halign == 'left' ) {
     2942            $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y);
     2943        }
     2944        elseif( $this->subsubtitle->halign == 'right' ) {
     2945            $indent = 0;
     2946            if( $this->doshadow )
     2947            $indent = $this->shadow_width+2;
     2948            $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right');
     2949        }
     2950        $this->subsubtitle->Stroke($this->img);
     2951
     2952        // ... and fancy title
     2953        $this->tabtitle->Stroke($this->img);
    27002954
    27012955    }
    27022956
    27032957    function StrokeTexts() {
    2704         // Stroke any user added text objects
    2705         if( $this->texts != null ) {
    2706             for($i=0; $i < count($this->texts); ++$i) {
    2707                 $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
    2708             }
    2709         }
    2710 
    2711         if( $this->y2texts != null && $this->y2scale != null ) {
    2712             for($i=0; $i < count($this->y2texts); ++$i) {
    2713                 $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale);
    2714             }
    2715         }
     2958        // Stroke any user added text objects
     2959        if( $this->texts != null ) {
     2960            for($i=0; $i < count($this->texts); ++$i) {
     2961                $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
     2962            }
     2963        }
     2964
     2965        if( $this->y2texts != null && $this->y2scale != null ) {
     2966            for($i=0; $i < count($this->y2texts); ++$i) {
     2967                $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale);
     2968            }
     2969        }
    27162970
    27172971    }
    27182972
    27192973    function StrokeTables() {
    2720         if( $this->iTables != null ) {
    2721             $n = count($this->iTables);
    2722             for( $i=0; $i < $n; ++$i ) {
    2723                 $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
    2724             }
    2725         }
     2974        if( $this->iTables != null ) {
     2975            $n = count($this->iTables);
     2976            for( $i=0; $i < $n; ++$i ) {
     2977                $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
     2978            }
     2979        }
    27262980    }
    27272981
    27282982    function DisplayClientSideaImageMapAreas() {
    2729         // Debug stuff - display the outline of the image map areas
    2730         $csim='';
    2731         foreach ($this->plots as $p) {
    2732             $csim.= $p->GetCSIMareas();
    2733         }
    2734         $csim .= $this->legend->GetCSIMareas();
    2735         if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) {
    2736             $this->img->SetColor($this->csimcolor);
    2737             $n = count($coords[0]);
    2738             for ($i=0; $i < $n; $i++) {
    2739                 if ($coords[1][$i]=="poly") {
    2740                     preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts);
    2741                     $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
    2742                     $m = count($pts[0]);
    2743                     for ($j=0; $j < $m; $j++) {
    2744                         $this->img->LineTo($pts[1][$j],$pts[2][$j]);
    2745                     }
    2746                 } else if ($coords[1][$i]=="rect") {
    2747                     $pts = preg_split('/,/', $coords[2][$i]);
    2748                     $this->img->SetStartPoint($pts[0],$pts[1]);
    2749                     $this->img->LineTo($pts[2],$pts[1]);
    2750                     $this->img->LineTo($pts[2],$pts[3]);
    2751                     $this->img->LineTo($pts[0],$pts[3]);
    2752                     $this->img->LineTo($pts[0],$pts[1]);                                       
    2753                 }
    2754             }
    2755         }
     2983        // Debug stuff - display the outline of the image map areas
     2984        $csim='';
     2985        foreach ($this->plots as $p) {
     2986            $csim.= $p->GetCSIMareas();
     2987        }
     2988        $csim .= $this->legend->GetCSIMareas();
     2989        if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) {
     2990            $this->img->SetColor($this->csimcolor);
     2991            $n = count($coords[0]);
     2992            for ($i=0; $i < $n; $i++) {
     2993                if ( $coords[1][$i] == 'poly' ) {
     2994                    preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts);
     2995                    $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
     2996                    $m = count($pts[0]);
     2997                    for ($j=0; $j < $m; $j++) {
     2998                        $this->img->LineTo($pts[1][$j],$pts[2][$j]);
     2999                    }
     3000                } elseif ( $coords[1][$i] == 'rect' ) {
     3001                    $pts = preg_split('/,/', $coords[2][$i]);
     3002                    $this->img->SetStartPoint($pts[0],$pts[1]);
     3003                    $this->img->LineTo($pts[2],$pts[1]);
     3004                    $this->img->LineTo($pts[2],$pts[3]);
     3005                    $this->img->LineTo($pts[0],$pts[3]);
     3006                    $this->img->LineTo($pts[0],$pts[1]);
     3007                }
     3008            }
     3009        }
    27563010    }
    27573011
    27583012    // Text scale offset in world coordinates
    27593013    function SetTextScaleOff($aOff) {
    2760         $this->text_scale_off = $aOff;
    2761         $this->xscale->text_scale_off = $aOff;
     3014        $this->text_scale_off = $aOff;
     3015        $this->xscale->text_scale_off = $aOff;
    27623016    }
    27633017
    27643018    // Text width of bar to be centered in absolute pixels
    27653019    function SetTextScaleAbsCenterOff($aOff) {
    2766         $this->text_scale_abscenteroff = $aOff;
     3020        $this->text_scale_abscenteroff = $aOff;
    27673021    }
    27683022
    27693023    // Get Y min and max values for added lines
    27703024    function GetLinesYMinMax( $aLines ) {
    2771         $n = count($aLines);
    2772         if( $n == 0 ) return false;
    2773         $min = $aLines[0]->scaleposition ;
    2774         $max = $min ;
    2775         $flg = false;
    2776         for( $i=0; $i < $n; ++$i ) {
    2777             if( $aLines[$i]->direction == HORIZONTAL ) {
    2778                 $flg = true ;
    2779                 $v = $aLines[$i]->scaleposition ;
    2780                 if( $min > $v ) $min = $v ;
    2781                 if( $max < $v ) $max = $v ;
    2782             }
    2783         }
    2784         return $flg ? array($min,$max) : false ;
     3025        $n = is_array($aLines) ? count($aLines) : 0;
     3026        if( $n == 0 ) return false;
     3027        $min = $aLines[0]->scaleposition ;
     3028        $max = $min ;
     3029        $flg = false;
     3030        for( $i=0; $i < $n; ++$i ) {
     3031            if( $aLines[$i]->direction == HORIZONTAL ) {
     3032                $flg = true ;
     3033                $v = $aLines[$i]->scaleposition ;
     3034                if( $min > $v ) $min = $v ;
     3035                if( $max < $v ) $max = $v ;
     3036            }
     3037        }
     3038        return $flg ? array($min,$max) : false ;
    27853039    }
    27863040
    27873041    // Get X min and max values for added lines
    27883042    function GetLinesXMinMax( $aLines ) {
    2789         $n = count($aLines);
    2790         if( $n == 0 ) return false ;
    2791         $min = $aLines[0]->scaleposition ;
    2792         $max = $min ;
    2793         $flg = false;
    2794         for( $i=0; $i < $n; ++$i ) {
    2795             if( $aLines[$i]->direction == VERTICAL ) {
    2796                 $flg = true ;
    2797                 $v = $aLines[$i]->scaleposition ;
    2798                 if( $min > $v ) $min = $v ;
    2799                 if( $max < $v ) $max = $v ;
    2800             }
    2801         }
    2802         return $flg ? array($min,$max) : false ;
     3043        $n = is_array($aLines) ? count($aLines) : 0;
     3044        if( $n == 0 ) return false ;
     3045        $min = $aLines[0]->scaleposition ;
     3046        $max = $min ;
     3047        $flg = false;
     3048        for( $i=0; $i < $n; ++$i ) {
     3049            if( $aLines[$i]->direction == VERTICAL ) {
     3050                $flg = true ;
     3051                $v = $aLines[$i]->scaleposition ;
     3052                if( $min > $v ) $min = $v ;
     3053                if( $max < $v ) $max = $v ;
     3054            }
     3055        }
     3056        return $flg ? array($min,$max) : false ;
    28033057    }
    28043058
    28053059    // Get min and max values for all included plots
    28063060    function GetPlotsYMinMax($aPlots) {
    2807         $n = count($aPlots);
    2808         $i=0;
    2809         do {
    2810             list($xmax,$max) = $aPlots[$i]->Max();
    2811         } while( ++$i < $n && !is_numeric($max) );
    2812 
    2813         $i=0;
    2814         do {
    2815             list($xmin,$min) = $aPlots[$i]->Min();
    2816         } while( ++$i < $n && !is_numeric($min) );
    2817        
    2818         if( !is_numeric($min) || !is_numeric($max) ) {
    2819             JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value  of the Y-axis (only null values).');
    2820         }
    2821 
    2822         for($i=0; $i < $n; ++$i ) {
    2823             list($xmax,$ymax)=$aPlots[$i]->Max();
    2824             list($xmin,$ymin)=$aPlots[$i]->Min();
    2825             if (is_numeric($ymax)) $max=max($max,$ymax);
    2826             if (is_numeric($ymin)) $min=min($min,$ymin);
    2827         }
    2828         if( $min == '' ) $min = 0;
    2829         if( $max == '' ) $max = 0;
    2830         if( $min == 0 && $max == 0 ) {
    2831             // Special case if all values are 0
    2832             $min=0;$max=1;                     
    2833         }
    2834         return array($min,$max);
     3061        $n = count($aPlots);
     3062        $i=0;
     3063        do {
     3064            list($xmax,$max) = $aPlots[$i]->Max();
     3065        } while( ++$i < $n && !is_numeric($max) );
     3066
     3067        $i=0;
     3068        do {
     3069            list($xmin,$min) = $aPlots[$i]->Min();
     3070        } while( ++$i < $n && !is_numeric($min) );
     3071
     3072        if( !is_numeric($min) || !is_numeric($max) ) {
     3073            JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value  of the Y-axis (only null values).');
     3074        }
     3075
     3076        for($i=0; $i < $n; ++$i ) {
     3077            list($xmax,$ymax)=$aPlots[$i]->Max();
     3078            list($xmin,$ymin)=$aPlots[$i]->Min();
     3079            if (is_numeric($ymax)) $max=max($max,$ymax);
     3080            if (is_numeric($ymin)) $min=min($min,$ymin);
     3081        }
     3082        if( $min == '' ) $min = 0;
     3083        if( $max == '' ) $max = 0;
     3084        if( $min == 0 && $max == 0 ) {
     3085            // Special case if all values are 0
     3086            $min=0;$max=1;
     3087        }
     3088        return array($min,$max);
     3089    }
     3090
     3091    function hasLinePlotAndBarPlot() {
     3092        $has_line = false;
     3093        $has_bar  = false;
     3094
     3095        foreach ($this->plots as $plot) {
     3096            if ($plot instanceof LinePlot) {
     3097                $has_line = true;
     3098            }
     3099            if ($plot instanceof BarPlot) {
     3100                $has_bar = true;
     3101            }
     3102        }
     3103
     3104        if ($has_line && $has_bar) {
     3105            return true;
     3106        }
     3107
     3108        return false;
     3109    }
     3110
     3111    function SetTheme($graph_theme) {
     3112
     3113        if (!($this instanceof PieGraph)) {
     3114            if (!$this->isAfterSetScale) {
     3115                JpGraphError::RaiseL(25133);//('Use Graph::SetTheme() after Graph::SetScale().');
     3116            }
     3117        }
     3118
     3119        if ($this->graph_theme) {
     3120            $this->ClearTheme();
     3121        }
     3122        $this->graph_theme = $graph_theme;
     3123        $this->graph_theme->ApplyGraph($this);
     3124    }
     3125
     3126    function ClearTheme() {
     3127        $this->graph_theme = null;
     3128
     3129        $this->isRunningClear = true;
     3130
     3131        $this->__construct(
     3132                $this->inputValues['aWidth'],
     3133                $this->inputValues['aHeight'],
     3134                $this->inputValues['aCachedName'],
     3135                $this->inputValues['aTimeout'],
     3136                $this->inputValues['aInline']
     3137            );
     3138 
     3139        if (!($this instanceof PieGraph)) {
     3140            if ($this->isAfterSetScale) {
     3141                $this->SetScale(
     3142                        $this->inputValues['aAxisType'],
     3143                        $this->inputValues['aYMin'],
     3144                        $this->inputValues['aYMax'],
     3145                        $this->inputValues['aXMin'],
     3146                        $this->inputValues['aXMax']
     3147                    );       
     3148            }
     3149        }
     3150
     3151        $this->isRunningClear = false;
     3152    }
     3153
     3154    function SetSupersampling($do = false, $scale = 2) {
     3155        if ($do) {
     3156            define('SUPERSAMPLING_SCALE', $scale);
     3157           // $this->img->scale = $scale;
     3158        } else {
     3159            define('SUPERSAMPLING_SCALE', 1);
     3160            //$this->img->scale = 0;
     3161        }
    28353162    }
    28363163
     
    28423169//===================================================
    28433170class LineProperty {
    2844     public $iWeight=1, $iColor="black",$iStyle="solid",$iShow=true;
    2845        
    2846 //---------------
    2847 // PUBLIC METHODS       
     3171    public $iWeight=1, $iColor='black', $iStyle='solid', $iShow=false;
     3172
     3173    function __construct($aWeight=1,$aColor='black',$aStyle='solid') {
     3174        $this->iWeight = $aWeight;
     3175        $this->iColor = $aColor;
     3176        $this->iStyle = $aStyle;
     3177    }
     3178
    28483179    function SetColor($aColor) {
    2849         $this->iColor = $aColor;
    2850     }
    2851        
     3180        $this->iColor = $aColor;
     3181    }
     3182
    28523183    function SetWeight($aWeight) {
    2853         $this->iWeight = $aWeight;
    2854     }
    2855        
     3184        $this->iWeight = $aWeight;
     3185    }
     3186
    28563187    function SetStyle($aStyle) {
    2857         $this->iStyle = $aStyle;
    2858     }
    2859                
     3188        $this->iStyle = $aStyle;
     3189    }
     3190
    28603191    function Show($aShow=true) {
    2861         $this->iShow=$aShow;
    2862     }
    2863        
     3192        $this->iShow=$aShow;
     3193    }
     3194
    28643195    function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) {
    2865         if( $this->iShow ) {
    2866             $aImg->PushColor($this->iColor);
    2867             $oldls = $aImg->line_style;
    2868             $oldlw = $aImg->line_weight;
    2869             $aImg->SetLineWeight($this->iWeight);
    2870             $aImg->SetLineStyle($this->iStyle);                 
    2871             $aImg->StyleLine($aX1,$aY1,$aX2,$aY2);
    2872             $aImg->PopColor($this->iColor);
    2873             $aImg->line_style = $oldls;
    2874             $aImg->line_weight = $oldlw;
    2875 
    2876         }
     3196        if( $this->iShow ) {
     3197            $aImg->PushColor($this->iColor);
     3198            $oldls = $aImg->line_style;
     3199            $oldlw = $aImg->line_weight;
     3200            $aImg->SetLineWeight($this->iWeight);
     3201            $aImg->SetLineStyle($this->iStyle);
     3202            $aImg->StyleLine($aX1,$aY1,$aX2,$aY2);
     3203            $aImg->PopColor($this->iColor);
     3204            $aImg->line_style = $oldls;
     3205            $aImg->line_weight = $oldlw;
     3206
     3207        }
    28773208    }
    28783209}
    28793210
     3211//===================================================
     3212// CLASS GraphTabTitle
     3213// Description: Draw "tab" titles on top of graphs
     3214//===================================================
    28803215class GraphTabTitle extends Text{
    28813216    private $corner = 6 , $posx = 7, $posy = 4;
    28823217    private $fillcolor='lightyellow',$bordercolor='black';
    28833218    private $align = 'left', $width=TABTITLE_WIDTHFIT;
    2884     function GraphTabTitle() {
    2885         $this->t = '';
    2886         $this->font_style = FS_BOLD;
    2887         $this->hide = true;
    2888         $this->color = 'darkred';
     3219    function __construct() {
     3220        $this->t = '';
     3221        $this->font_style = FS_BOLD;
     3222        $this->hide = true;
     3223        $this->color = 'darkred';
    28893224    }
    28903225
    28913226    function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') {
    2892         $this->color = $aTxtColor;
    2893         $this->fillcolor = $aFillColor;
    2894         $this->bordercolor = $aBorderColor;
     3227        $this->color = $aTxtColor;
     3228        $this->fillcolor = $aFillColor;
     3229        $this->bordercolor = $aBorderColor;
    28953230    }
    28963231
    28973232    function SetFillColor($aFillColor) {
    2898         $this->fillcolor = $aFillColor;
     3233        $this->fillcolor = $aFillColor;
    28993234    }
    29003235
    29013236    function SetTabAlign($aAlign) {
    2902         $this->align = $aAlign;
    2903     }
    2904    
     3237        $this->align = $aAlign;
     3238    }
     3239
    29053240    function SetWidth($aWidth) {
    2906         $this->width = $aWidth ;
     3241        $this->width = $aWidth ;
    29073242    }
    29083243
    29093244    function Set($t) {
    2910         $this->t = $t;
    2911         $this->hide = false;
     3245        $this->t = $t;
     3246        $this->hide = false;
    29123247    }
    29133248
    29143249    function SetCorner($aD) {
    2915         $this->corner = $aD ;
     3250        $this->corner = $aD ;
    29163251    }
    29173252
    29183253    function Stroke($aImg,$aDummy1=null,$aDummy2=null) {
    2919         if( $this->hide )
    2920             return;
    2921         $this->boxed = false;
    2922         $w = $this->GetWidth($aImg) + 2*$this->posx;
    2923         $h = $this->GetTextHeight($aImg) + 2*$this->posy;
    2924 
    2925         $x = $aImg->left_margin;
    2926         $y = $aImg->top_margin;
    2927 
    2928         if( $this->width === TABTITLE_WIDTHFIT ) {
    2929             if( $this->align == 'left' ) {
    2930                 $p = array($x,                $y,
    2931                            $x,                $y-$h+$this->corner,
    2932                            $x + $this->corner,$y-$h,
    2933                            $x + $w - $this->corner, $y-$h,
    2934                            $x + $w, $y-$h+$this->corner,
    2935                            $x + $w, $y);
    2936             }
    2937             elseif( $this->align == 'center' ) {
    2938                 $x += round($aImg->plotwidth/2) - round($w/2);
    2939                 $p = array($x, $y,
    2940                            $x, $y-$h+$this->corner,
    2941                            $x + $this->corner, $y-$h,
    2942                            $x + $w - $this->corner, $y-$h,
    2943                            $x + $w, $y-$h+$this->corner,
    2944                            $x + $w, $y);
    2945             }
    2946             else {
    2947                 $x += $aImg->plotwidth -$w;
    2948                 $p = array($x, $y,
    2949                            $x, $y-$h+$this->corner,
    2950                            $x + $this->corner,$y-$h,
    2951                            $x + $w - $this->corner, $y-$h,
    2952                            $x + $w, $y-$h+$this->corner,
    2953                            $x + $w, $y);
    2954             }
    2955         }
    2956         else {
    2957             if( $this->width === TABTITLE_WIDTHFULL )
    2958                 $w = $aImg->plotwidth ;
    2959             else
    2960                 $w = $this->width ;
    2961 
    2962             // Make the tab fit the width of the plot area
    2963             $p = array($x,                $y,
    2964                        $x,                $y-$h+$this->corner,
    2965                        $x + $this->corner,$y-$h,
    2966                        $x + $w - $this->corner, $y-$h,
    2967                        $x + $w, $y-$h+$this->corner,
    2968                        $x + $w, $y);
    2969            
    2970         }
    2971         if( $this->halign == 'left' ) {
    2972             $aImg->SetTextAlign('left','bottom');
    2973             $x += $this->posx;
    2974             $y -= $this->posy;
    2975         }
    2976         elseif( $this->halign == 'center' ) {
    2977             $aImg->SetTextAlign('center','bottom');
    2978             $x += $w/2;
    2979             $y -= $this->posy;
    2980         }
    2981         else {
    2982             $aImg->SetTextAlign('right','bottom');
    2983             $x += $w - $this->posx;
    2984             $y -= $this->posy;
    2985         }
    2986 
    2987         $aImg->SetColor($this->fillcolor);
    2988         $aImg->FilledPolygon($p);
    2989 
    2990         $aImg->SetColor($this->bordercolor);
    2991         $aImg->Polygon($p,true);
    2992        
    2993         $aImg->SetColor($this->color);
    2994         $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
    2995         $aImg->StrokeText($x,$y,$this->t,0,'center');
     3254        if( $this->hide )
     3255            return;
     3256        $this->boxed = false;
     3257        $w = $this->GetWidth($aImg) + 2*$this->posx;
     3258        $h = $this->GetTextHeight($aImg) + 2*$this->posy;
     3259
     3260        $x = $aImg->left_margin;
     3261        $y = $aImg->top_margin;
     3262
     3263        if( $this->width === TABTITLE_WIDTHFIT ) {
     3264            if( $this->align == 'left' ) {
     3265                $p = array($x,                $y,
     3266                $x,                $y-$h+$this->corner,
     3267                $x + $this->corner,$y-$h,
     3268                $x + $w - $this->corner, $y-$h,
     3269                $x + $w, $y-$h+$this->corner,
     3270                $x + $w, $y);
     3271            }
     3272            elseif( $this->align == 'center' ) {
     3273                $x += round($aImg->plotwidth/2) - round($w/2);
     3274                $p = array($x, $y,
     3275                $x, $y-$h+$this->corner,
     3276                $x + $this->corner, $y-$h,
     3277                $x + $w - $this->corner, $y-$h,
     3278                $x + $w, $y-$h+$this->corner,
     3279                $x + $w, $y);
     3280            }
     3281            else {
     3282                $x += $aImg->plotwidth -$w;
     3283                $p = array($x, $y,
     3284                $x, $y-$h+$this->corner,
     3285                $x + $this->corner,$y-$h,
     3286                $x + $w - $this->corner, $y-$h,
     3287                $x + $w, $y-$h+$this->corner,
     3288                $x + $w, $y);
     3289            }
     3290        }
     3291        else {
     3292            if( $this->width === TABTITLE_WIDTHFULL ) {
     3293                $w = $aImg->plotwidth ;
     3294            }
     3295            else {
     3296                $w = $this->width ;
     3297            }
     3298
     3299            // Make the tab fit the width of the plot area
     3300            $p = array($x, $y,
     3301            $x, $y-$h+$this->corner,
     3302            $x + $this->corner,$y-$h,
     3303            $x + $w - $this->corner, $y-$h,
     3304            $x + $w, $y-$h+$this->corner,
     3305            $x + $w, $y);
     3306
     3307        }
     3308        if( $this->halign == 'left' ) {
     3309            $aImg->SetTextAlign('left','bottom');
     3310            $x += $this->posx;
     3311            $y -= $this->posy;
     3312        }
     3313        elseif( $this->halign == 'center' ) {
     3314            $aImg->SetTextAlign('center','bottom');
     3315            $x += $w/2;
     3316            $y -= $this->posy;
     3317        }
     3318        else {
     3319            $aImg->SetTextAlign('right','bottom');
     3320            $x += $w - $this->posx;
     3321            $y -= $this->posy;
     3322        }
     3323
     3324        $aImg->SetColor($this->fillcolor);
     3325        $aImg->FilledPolygon($p);
     3326
     3327        $aImg->SetColor($this->bordercolor);
     3328        $aImg->Polygon($p,true);
     3329
     3330        $aImg->SetColor($this->color);
     3331        $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
     3332        $aImg->StrokeText($x,$y,$this->t,0,'center');
    29963333    }
    29973334
     
    30033340//===================================================
    30043341class SuperScriptText extends Text {
    3005     private $iSuper="";
    3006     private $sfont_family="",$sfont_style="",$sfont_size=8;
     3342    private $iSuper='';
     3343    private $sfont_family='',$sfont_style='',$sfont_size=8;
    30073344    private $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65;
    30083345    private $iSDir=0;
    30093346    private $iSimple=false;
    30103347
    3011     function SuperScriptText($aTxt="",$aSuper="",$aXAbsPos=0,$aYAbsPos=0) {
    3012         parent::Text($aTxt,$aXAbsPos,$aYAbsPos);
    3013         $this->iSuper = $aSuper;
     3348    function __construct($aTxt='',$aSuper='',$aXAbsPos=0,$aYAbsPos=0) {
     3349        parent::__construct($aTxt,$aXAbsPos,$aYAbsPos);
     3350        $this->iSuper = $aSuper;
    30143351    }
    30153352
    30163353    function FromReal($aVal,$aPrecision=2) {
    3017         // Convert a floating point number to scientific notation
    3018         $neg=1.0;
    3019         if( $aVal < 0 ) {
    3020             $neg = -1.0;
    3021             $aVal = -$aVal;
    3022         }
    3023                
    3024         $l = floor(log10($aVal));
    3025         $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision));
    3026         $a *= $neg;
    3027         if( $this->iSimple && ($a == 1 || $a==-1) ) $a = '';
    3028        
    3029         if( $a != '' )
    3030             $this->t = $a.' * 10';
    3031         else {
    3032             if( $neg == 1 )
    3033                 $this->t = '10';
    3034             else
    3035                 $this->t = '-10';
    3036         }
    3037         $this->iSuper = $l;
    3038     }
    3039 
    3040     function Set($aTxt,$aSuper="") {
    3041         $this->t = $aTxt;
    3042         $this->iSuper = $aSuper;
     3354        // Convert a floating point number to scientific notation
     3355        $neg=1.0;
     3356        if( $aVal < 0 ) {
     3357            $neg = -1.0;
     3358            $aVal = -$aVal;
     3359        }
     3360
     3361        $l = floor(log10($aVal));
     3362        $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision));
     3363        $a *= $neg;
     3364        if( $this->iSimple && ($a == 1 || $a==-1) ) $a = '';
     3365
     3366        if( $a != '' ) {
     3367            $this->t = $a.' * 10';
     3368        }
     3369        else {
     3370            if( $neg == 1 ) {
     3371                $this->t = '10';
     3372            }
     3373            else {
     3374                $this->t = '-10';
     3375            }
     3376        }
     3377        $this->iSuper = $l;
     3378    }
     3379
     3380    function Set($aTxt,$aSuper='') {
     3381        $this->t = $aTxt;
     3382        $this->iSuper = $aSuper;
    30433383    }
    30443384
    30453385    function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) {
    3046         $this->sfont_family = $aFontFam;
    3047         $this->sfont_style = $aFontStyle;
    3048         $this->sfont_size = $aFontSize;
     3386        $this->sfont_family = $aFontFam;
     3387        $this->sfont_style = $aFontStyle;
     3388        $this->sfont_size = $aFontSize;
    30493389    }
    30503390
    30513391    // Total width of text
    30523392    function GetWidth($aImg) {
    3053         $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
    3054         $w = $aImg->GetTextWidth($this->t);
    3055         $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
    3056         $w += $aImg->GetTextWidth($this->iSuper);
    3057         $w += $this->iSuperMargin;
    3058         return $w;
    3059     }
    3060        
     3393        $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
     3394        $w = $aImg->GetTextWidth($this->t);
     3395        $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
     3396        $w += $aImg->GetTextWidth($this->iSuper);
     3397        $w += $this->iSuperMargin;
     3398        return $w;
     3399    }
     3400
    30613401    // Hight of font (approximate the height of the text)
    30623402    function GetFontHeight($aImg) {
    3063         $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); 
    3064         $h = $aImg->GetFontHeight();
    3065         $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
    3066         $h += $aImg->GetFontHeight();
    3067         return $h;
     3403        $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
     3404        $h = $aImg->GetFontHeight();
     3405        $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
     3406        $h += $aImg->GetFontHeight();
     3407        return $h;
    30683408    }
    30693409
    30703410    // Hight of text
    30713411    function GetTextHeight($aImg) {
    3072         $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
    3073         $h = $aImg->GetTextHeight($this->t);
    3074         $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
    3075         $h += $aImg->GetTextHeight($this->iSuper);
    3076         return $h;
     3412        $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
     3413        $h = $aImg->GetTextHeight($this->t);
     3414        $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
     3415        $h += $aImg->GetTextHeight($this->iSuper);
     3416        return $h;
    30773417    }
    30783418
    30793419    function Stroke($aImg,$ax=-1,$ay=-1) {
    3080        
     3420
    30813421        // To position the super script correctly we need different
    3082         // cases to handle the alignmewnt specified since that will
    3083         // determine how we can interpret the x,y coordinates
    3084        
    3085         $w = parent::GetWidth($aImg);
    3086         $h = parent::GetTextHeight($aImg);
    3087         switch( $this->valign ) {
    3088             case 'top':
    3089                 $sy = $this->y;
    3090                 break;
    3091             case 'center':
    3092                 $sy = $this->y - $h/2;
    3093                 break;
    3094             case 'bottom':
    3095                 $sy = $this->y - $h;
    3096                 break;
    3097             default:
    3098                 JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text');
    3099                 break;
    3100         }
    3101 
    3102         switch( $this->halign ) {
    3103             case 'left':
    3104                 $sx = $this->x + $w;
    3105                 break;
    3106             case 'center':
    3107                 $sx = $this->x + $w/2;
    3108                 break;
    3109             case 'right':
    3110                 $sx = $this->x;
    3111                 break;
    3112             default:
    3113                 JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text');
    3114                 break;
    3115         }
    3116 
    3117         $sx += $this->iSuperMargin;
    3118         $sy += $this->iVertOverlap;
    3119 
    3120         // Should we automatically determine the font or
    3121         // has the user specified it explicetly?
    3122         if( $this->sfont_family == "" ) {
    3123             if( $this->font_family <= FF_FONT2 ) {
    3124                 if( $this->font_family == FF_FONT0 ) {
    3125                     $sff = FF_FONT0;
    3126                 }
    3127                 elseif( $this->font_family == FF_FONT1 ) {
    3128                     if( $this->font_style == FS_NORMAL )
    3129                         $sff = FF_FONT0;
    3130                     else
    3131                         $sff = FF_FONT1;
    3132                 }
    3133                 else {
    3134                     $sff = FF_FONT1;
    3135                 }
    3136                 $sfs = $this->font_style;
    3137                 $sfz = $this->font_size;
    3138             }
    3139             else {
    3140                 // TTF fonts
    3141                 $sff = $this->font_family;
    3142                 $sfs = $this->font_style;
    3143                 $sfz = floor($this->font_size*$this->iSuperScale);             
    3144                 if( $sfz < 8 ) $sfz = 8;
    3145             }       
    3146             $this->sfont_family = $sff;
    3147             $this->sfont_style = $sfs;
    3148             $this->sfont_size = $sfz;       
    3149         }
    3150         else {
    3151             $sff = $this->sfont_family;
    3152             $sfs = $this->sfont_style;
    3153             $sfz = $this->sfont_size;       
    3154         }
    3155 
    3156         parent::Stroke($aImg,$ax,$ay);
    3157 
    3158 
    3159         // For the builtin fonts we need to reduce the margins
    3160         // since the bounding bx reported for the builtin fonts
    3161         // are much larger than for the TTF fonts.
    3162         if( $sff <= FF_FONT2 ) {
    3163             $sx -= 2;
    3164             $sy += 3;
    3165         }
    3166 
    3167         $aImg->SetTextAlign('left','bottom');   
    3168         $aImg->SetFont($sff,$sfs,$sfz);
    3169         $aImg->PushColor($this->color);
    3170         $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left');
    3171         $aImg->PopColor();     
     3422        // cases to handle the alignmewnt specified since that will
     3423        // determine how we can interpret the x,y coordinates
     3424
     3425        $w = parent::GetWidth($aImg);
     3426        $h = parent::GetTextHeight($aImg);
     3427        switch( $this->valign ) {
     3428            case 'top':
     3429                $sy = $this->y;
     3430                break;
     3431            case 'center':
     3432                $sy = $this->y - $h/2;
     3433                break;
     3434            case 'bottom':
     3435                $sy = $this->y - $h;
     3436                break;
     3437            default:
     3438                JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text');
     3439                break;
     3440        }
     3441
     3442        switch( $this->halign ) {
     3443            case 'left':
     3444                $sx = $this->x + $w;
     3445                break;
     3446            case 'center':
     3447                $sx = $this->x + $w/2;
     3448                break;
     3449            case 'right':
     3450                $sx = $this->x;
     3451                break;
     3452            default:
     3453                JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text');
     3454                break;
     3455        }
     3456
     3457        $sx += $this->iSuperMargin;
     3458        $sy += $this->iVertOverlap;
     3459
     3460        // Should we automatically determine the font or
     3461        // has the user specified it explicetly?
     3462        if( $this->sfont_family == '' ) {
     3463            if( $this->font_family <= FF_FONT2 ) {
     3464                if( $this->font_family == FF_FONT0 ) {
     3465                    $sff = FF_FONT0;
     3466                }
     3467                elseif( $this->font_family == FF_FONT1 ) {
     3468                    if( $this->font_style == FS_NORMAL ) {
     3469                        $sff = FF_FONT0;
     3470                    }
     3471                    else {
     3472                        $sff = FF_FONT1;
     3473                    }
     3474                }
     3475                else {
     3476                    $sff = FF_FONT1;
     3477                }
     3478                $sfs = $this->font_style;
     3479                $sfz = $this->font_size;
     3480            }
     3481            else {
     3482                // TTF fonts
     3483                $sff = $this->font_family;
     3484                $sfs = $this->font_style;
     3485                $sfz = floor($this->font_size*$this->iSuperScale);
     3486                if( $sfz < 8 ) $sfz = 8;
     3487            }
     3488            $this->sfont_family = $sff;
     3489            $this->sfont_style = $sfs;
     3490            $this->sfont_size = $sfz;
     3491        }
     3492        else {
     3493            $sff = $this->sfont_family;
     3494            $sfs = $this->sfont_style;
     3495            $sfz = $this->sfont_size;
     3496        }
     3497
     3498        parent::Stroke($aImg,$ax,$ay);
     3499
     3500        // For the builtin fonts we need to reduce the margins
     3501        // since the bounding bx reported for the builtin fonts
     3502        // are much larger than for the TTF fonts.
     3503        if( $sff <= FF_FONT2 ) {
     3504            $sx -= 2;
     3505            $sy += 3;
     3506        }
     3507
     3508        $aImg->SetTextAlign('left','bottom');
     3509        $aImg->SetFont($sff,$sfs,$sfz);
     3510        $aImg->PushColor($this->color);
     3511        $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left');
     3512        $aImg->PopColor();
    31723513    }
    31733514}
     
    31813522    protected $img;
    31823523    protected $scale;
    3183     protected $grid_color='#DDDDDD',$grid_mincolor='#DDDDDD';
    3184     protected $type="solid";
    3185     protected $show=false, $showMinor=false,$weight=1;
     3524    protected $majorcolor='#CCCCCC',$minorcolor='#DDDDDD';
     3525    protected $majortype='solid',$minortype='solid';
     3526    protected $show=false, $showMinor=false,$majorweight=1,$minorweight=1;
    31863527    protected $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF');
    3187 //---------------
    3188 // CONSTRUCTOR
    3189     function Grid($aAxis) {
    3190         $this->scale = $aAxis->scale;
    3191         $this->img = $aAxis->img;
    3192     }
    3193 //---------------
    3194 // PUBLIC METHODS
     3528
     3529    function __construct($aAxis) {
     3530        $this->scale = $aAxis->scale;
     3531        $this->img = $aAxis->img;
     3532    }
     3533
    31953534    function SetColor($aMajColor,$aMinColor=false) {
    3196         $this->grid_color=$aMajColor;
    3197         if( $aMinColor === false )
    3198             $aMinColor = $aMajColor ;
    3199         $this->grid_mincolor = $aMinColor;
    3200     }
    3201        
    3202     function SetWeight($aWeight) {
    3203         $this->weight=$aWeight;
    3204     }
    3205        
     3535        $this->majorcolor=$aMajColor;
     3536        if( $aMinColor === false ) {
     3537            $aMinColor = $aMajColor ;
     3538        }
     3539        $this->minorcolor = $aMinColor;
     3540    }
     3541
     3542    function SetWeight($aMajorWeight,$aMinorWeight=1) {
     3543        $this->majorweight=$aMajorWeight;
     3544        $this->minorweight=$aMinorWeight;
     3545    }
     3546
    32063547    // Specify if grid should be dashed, dotted or solid
    3207     function SetLineStyle($aType) {
    3208         $this->type = $aType;
    3209     }
    3210        
     3548    function SetLineStyle($aMajorType,$aMinorType='solid') {
     3549        $this->majortype = $aMajorType;
     3550        $this->minortype = $aMinorType;
     3551    }
     3552
     3553    function SetStyle($aMajorType,$aMinorType='solid') {
     3554        $this->SetLineStyle($aMajorType,$aMinorType);
     3555    }
     3556
    32113557    // Decide if both major and minor grid should be displayed
    32123558    function Show($aShowMajor=true,$aShowMinor=false) {
    3213         $this->show=$aShowMajor;
    3214         $this->showMinor=$aShowMinor;
    3215     }
    3216    
     3559        $this->show=$aShowMajor;
     3560        $this->showMinor=$aShowMinor;
     3561    }
     3562
    32173563    function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') {
    3218         $this->fill = $aFlg;
    3219         $this->fillcolor = array( $aColor1, $aColor2 );
    3220     }
    3221        
     3564        $this->fill = $aFlg;
     3565        $this->fillcolor = array( $aColor1, $aColor2 );
     3566    }
     3567
    32223568    // Display the grid
    32233569    function Stroke() {
    3224         if( $this->showMinor && !$this->scale->textscale ) {
    3225             $tmp = $this->grid_color;
    3226             $this->grid_color = $this->grid_mincolor;
    3227             $this->DoStroke($this->scale->ticks->ticks_pos);
    3228 
    3229             $this->grid_color = $tmp;
    3230             $this->DoStroke($this->scale->ticks->maj_ticks_pos);
    3231         }
    3232         else {
    3233             $this->DoStroke($this->scale->ticks->maj_ticks_pos);
    3234         }
    3235     }
    3236        
    3237 //--------------
    3238 // Private methods     
     3570        if( $this->showMinor && !$this->scale->textscale ) {
     3571            $this->DoStroke($this->scale->ticks->ticks_pos,$this->minortype,$this->minorcolor,$this->minorweight);
     3572            $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight);
     3573        }
     3574        else {
     3575            $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight);
     3576        }
     3577    }
     3578
     3579    //--------------
     3580    // Private methods
    32393581    // Draw the grid
    3240     function DoStroke($aTicksPos) {
    3241         if( !$this->show )
    3242             return;     
    3243         $nbrgrids = count($aTicksPos); 
    3244 
    3245         if( $this->scale->type=="y" ) {
    3246             $xl=$this->img->left_margin;
    3247             $xr=$this->img->width-$this->img->right_margin;
    3248            
    3249             if( $this->fill ) {
    3250                 // Draw filled areas
    3251                 $y2 = $aTicksPos[0];
    3252                 $i=1;
    3253                 while( $i < $nbrgrids ) {
    3254                     $y1 = $y2;
    3255                     $y2 = $aTicksPos[$i++];
    3256                     $this->img->SetColor($this->fillcolor[$i & 1]);
    3257                     $this->img->FilledRectangle($xl,$y1,$xr,$y2);
    3258                 }
    3259             }
    3260 
    3261             $this->img->SetColor($this->grid_color);
    3262             $this->img->SetLineWeight($this->weight);
    3263 
    3264             // Draw grid lines
    3265             switch( $this->type ) {
    3266                 case "solid":  $style = LINESTYLE_SOLID; break;
    3267                 case "dotted": $style = LINESTYLE_DOTTED; break;
    3268                 case "dashed": $style = LINESTYLE_DASHED; break;
    3269                 case "longdashed": $style = LINESTYLE_LONGDASH; break;
    3270                 default:
    3271                     $style = LINESTYLE_SOLID; break;
    3272             }
    3273 
    3274             for($i=0; $i < $nbrgrids; ++$i) {
    3275                 $y=$aTicksPos[$i];
    3276                 $this->img->StyleLine($xl,$y,$xr,$y,$style);
    3277             }
    3278         }
    3279         elseif( $this->scale->type=="x" ) {     
    3280             $yu=$this->img->top_margin;
    3281             $yl=$this->img->height-$this->img->bottom_margin;
    3282             $limit=$this->img->width-$this->img->right_margin;
    3283 
    3284             if( $this->fill ) {
    3285                 // Draw filled areas
    3286                 $x2 = $aTicksPos[0];
    3287                 $i=1;
    3288                 while( $i < $nbrgrids ) {
    3289                     $x1 = $x2;
    3290                     $x2 = min($aTicksPos[$i++],$limit) ;
    3291                     $this->img->SetColor($this->fillcolor[$i & 1]);
    3292                     $this->img->FilledRectangle($x1,$yu,$x2,$yl);
    3293                 }
    3294             }
    3295 
    3296             $this->img->SetColor($this->grid_color);
    3297             $this->img->SetLineWeight($this->weight);
    3298 
    3299             // We must also test for limit since we might have
    3300             // an offset and the number of ticks is calculated with
    3301             // assumption offset==0 so we might end up drawing one
    3302             // to many gridlines
    3303             $i=0;
    3304             $x=$aTicksPos[$i];     
    3305             while( $i<count($aTicksPos) && ($x=$aTicksPos[$i]) <= $limit ) {
    3306                 if( $this->type == "solid" )                           
    3307                     $this->img->Line($x,$yl,$x,$yu);
    3308                 elseif( $this->type == "dotted" )
    3309                     $this->img->DashedLine($x,$yl,$x,$yu,1,6);
    3310                 elseif( $this->type == "dashed" )
    3311                     $this->img->DashedLine($x,$yl,$x,$yu,2,4);
    3312                 elseif( $this->type == "longdashed" )
    3313                     $this->img->DashedLine($x,$yl,$x,$yu,8,6); 
    3314                 ++$i; 
    3315             }
    3316         }       
    3317         else {
    3318             JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']');
    3319         }
    3320         return true;
     3582    function DoStroke($aTicksPos,$aType,$aColor,$aWeight) {
     3583        if( !$this->show ) return;
     3584        $nbrgrids = count($aTicksPos);
     3585
     3586        if( $this->scale->type == 'y' ) {
     3587            $xl=$this->img->left_margin;
     3588            $xr=$this->img->width-$this->img->right_margin;
     3589
     3590            if( $this->fill ) {
     3591                // Draw filled areas
     3592                $y2 = !empty($aTicksPos) ? $aTicksPos[0] : null;
     3593                $i=1;
     3594                while( $i < $nbrgrids ) {
     3595                    $y1 = $y2;
     3596                    $y2 = $aTicksPos[$i++];
     3597                    $this->img->SetColor($this->fillcolor[$i & 1]);
     3598                    $this->img->FilledRectangle($xl,$y1,$xr,$y2);
     3599                }
     3600            }
     3601
     3602            $this->img->SetColor($aColor);
     3603            $this->img->SetLineWeight($aWeight);
     3604
     3605            // Draw grid lines
     3606            switch( $aType ) {
     3607                case 'solid':  $style = LINESTYLE_SOLID; break;
     3608                case 'dotted': $style = LINESTYLE_DOTTED; break;
     3609                case 'dashed': $style = LINESTYLE_DASHED; break;
     3610                case 'longdashed': $style = LINESTYLE_LONGDASH; break;
     3611                default:
     3612                    $style = LINESTYLE_SOLID; break;
     3613            }
     3614
     3615            for($i=0; $i < $nbrgrids; ++$i) {
     3616                $y=$aTicksPos[$i];
     3617                $this->img->StyleLine($xl,$y,$xr,$y,$style,true);
     3618            }
     3619        }
     3620        elseif( $this->scale->type == 'x' ) {
     3621            $yu=$this->img->top_margin;
     3622            $yl=$this->img->height-$this->img->bottom_margin;
     3623            $limit=$this->img->width-$this->img->right_margin;
     3624
     3625            if( $this->fill ) {
     3626                // Draw filled areas
     3627                $x2 = $aTicksPos[0];
     3628                $i=1;
     3629                while( $i < $nbrgrids ) {
     3630                    $x1 = $x2;
     3631                    $x2 = min($aTicksPos[$i++],$limit) ;
     3632                    $this->img->SetColor($this->fillcolor[$i & 1]);
     3633                    $this->img->FilledRectangle($x1,$yu,$x2,$yl);
     3634                }
     3635            }
     3636
     3637            $this->img->SetColor($aColor);
     3638            $this->img->SetLineWeight($aWeight);
     3639
     3640            // We must also test for limit since we might have
     3641            // an offset and the number of ticks is calculated with
     3642            // assumption offset==0 so we might end up drawing one
     3643            // to many gridlines
     3644            $i=0;
     3645            $x=$aTicksPos[$i];
     3646            while( $i<count($aTicksPos) && ($x=$aTicksPos[$i]) <= $limit ) {
     3647                if    ( $aType == 'solid' )      $this->img->Line($x,$yl,$x,$yu);
     3648                elseif( $aType == 'dotted' )     $this->img->DashedLineForGrid($x,$yl,$x,$yu,1,6);
     3649                elseif( $aType == 'dashed' )     $this->img->DashedLineForGrid($x,$yl,$x,$yu,2,4);
     3650                elseif( $aType == 'longdashed' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,8,6);
     3651                ++$i;
     3652            }
     3653        }
     3654        else {
     3655            JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']');
     3656        }
     3657        return true;
    33213658    }
    33223659} // Class
     
    33283665// several occasion must know wheter it's an X or Y axis.
    33293666// This was a design decision to make the code easier to
    3330 // follow. 
     3667// follow.
    33313668//===================================================
    33323669class AxisPrototype {
    3333     public $scale=null; 
     3670    public $scale=null;
    33343671    public $img=null;
    33353672    public $hide=false,$hide_labels=false;
    33363673    public $title=null;
    3337     public $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0;
     3674    public $font_family=FF_DEFAULT,$font_style=FS_NORMAL,$font_size=8,$label_angle=0;
    33383675    public $tick_step=1;
    33393676    public $pos = false;
     
    33483685    protected $labelPos=0;   // Which side of the axis should the labels be?
    33493686    protected $title_adjust,$title_margin,$title_side=SIDE_LEFT;
    3350     protected $tick_label_margin=7;
     3687    protected $tick_label_margin=5;
    33513688    protected $label_halign = '',$label_valign = '', $label_para_align='left';
    33523689    protected $hide_line=false;
    33533690    protected $iDeltaAbsPos=0;
    33543691
    3355 //---------------
    3356 // CONSTRUCTOR
    3357     function Axis($img,$aScale,$color=array(0,0,0)) {
    3358         $this->img = $img;
    3359         $this->scale = $aScale;
    3360         $this->color = $color;
    3361         $this->title=new Text("");
    3362                
    3363         if( $aScale->type=="y" ) {
    3364             $this->title_margin = 25;
    3365             $this->title_adjust="middle";
    3366             $this->title->SetOrientation(90);
    3367             $this->tick_label_margin=7;
    3368             $this->labelPos=SIDE_LEFT;
    3369         }
    3370         else {
    3371             $this->title_margin = 5;
    3372             $this->title_adjust="high";
    3373             $this->title->SetOrientation(0);                   
    3374             $this->tick_label_margin=7;
    3375             $this->labelPos=SIDE_DOWN;
    3376             $this->title_side=SIDE_DOWN;
    3377         }
    3378     }
    3379 //---------------
    3380 // PUBLIC METHODS       
    3381        
     3692    function __construct($img,$aScale,$color = array(0,0,0)) {
     3693        $this->img = $img;
     3694        $this->scale = $aScale;
     3695        $this->color = $color;
     3696        $this->title=new Text('');
     3697
     3698        if( $aScale->type == 'y' ) {
     3699            $this->title_margin = 25;
     3700            $this->title_adjust = 'middle';
     3701            $this->title->SetOrientation(90);
     3702            $this->tick_label_margin=7;
     3703            $this->labelPos=SIDE_LEFT;
     3704        }
     3705        else {
     3706            $this->title_margin = 5;
     3707            $this->title_adjust = 'high';
     3708            $this->title->SetOrientation(0);
     3709            $this->tick_label_margin=5;
     3710            $this->labelPos=SIDE_DOWN;
     3711            $this->title_side=SIDE_DOWN;
     3712        }
     3713    }
     3714
    33823715    function SetLabelFormat($aFormStr) {
    3383         $this->scale->ticks->SetLabelFormat($aFormStr);
     3716        $this->scale->ticks->SetLabelFormat($aFormStr);
    33843717    }
    33853718
    33863719    function SetLabelFormatString($aFormStr,$aDate=false) {
    3387         $this->scale->ticks->SetLabelFormat($aFormStr,$aDate);
    3388     }
    3389        
     3720        $this->scale->ticks->SetLabelFormat($aFormStr,$aDate);
     3721    }
     3722
    33903723    function SetLabelFormatCallback($aFuncName) {
    3391         $this->scale->ticks->SetFormatCallback($aFuncName);
    3392     }
    3393 
    3394     function SetLabelAlign($aHAlign,$aVAlign="top",$aParagraphAlign='left') {
    3395         $this->label_halign = $aHAlign;
    3396         $this->label_valign = $aVAlign;
    3397         $this->label_para_align = $aParagraphAlign;
    3398     }           
     3724        $this->scale->ticks->SetFormatCallback($aFuncName);
     3725    }
     3726
     3727    function SetLabelAlign($aHAlign,$aVAlign='top',$aParagraphAlign='left') {
     3728        $this->label_halign = $aHAlign;
     3729        $this->label_valign = $aVAlign;
     3730        $this->label_para_align = $aParagraphAlign;
     3731    }
    33993732
    34003733    // Don't display the first label
    34013734    function HideFirstTickLabel($aShow=false) {
    3402         $this->show_first_label=$aShow;
     3735        $this->show_first_label=$aShow;
    34033736    }
    34043737
    34053738    function HideLastTickLabel($aShow=false) {
    3406         $this->show_last_label=$aShow;
     3739        $this->show_last_label=$aShow;
    34073740    }
    34083741
    34093742    // Manually specify the major and (optional) minor tick position and labels
    34103743    function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) {
    3411         $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels);
     3744        $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels);
    34123745    }
    34133746
    34143747    // Manually specify major tick positions and optional labels
    34153748    function SetMajTickPositions($aMajPos,$aLabels=NULL) {
    3416         $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels);
     3749        $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels);
    34173750    }
    34183751
    34193752    // Hide minor or major tick marks
    34203753    function HideTicks($aHideMinor=true,$aHideMajor=true) {
    3421         $this->scale->ticks->SupressMinorTickMarks($aHideMinor);
    3422         $this->scale->ticks->SupressTickMarks($aHideMajor);
     3754        $this->scale->ticks->SupressMinorTickMarks($aHideMinor);
     3755        $this->scale->ticks->SupressTickMarks($aHideMajor);
    34233756    }
    34243757
    34253758    // Hide zero label
    34263759    function HideZeroLabel($aFlag=true) {
    3427         $this->scale->ticks->SupressZeroLabel();
    3428     }
    3429        
     3760        $this->scale->ticks->SupressZeroLabel();
     3761    }
     3762
    34303763    function HideFirstLastLabel() {
    3431         // The two first calls to ticks method will supress
    3432         // automatically generated scale values. However, that
    3433         // will not affect manually specified value, e.g text-scales.
    3434         // therefor we also make a kludge here to supress manually
    3435         // specified scale labels.
    3436         $this->scale->ticks->SupressLast();
    3437         $this->scale->ticks->SupressFirst();
    3438         $this->show_first_label = false;
    3439         $this->show_last_label = false;
    3440     }
    3441        
     3764        // The two first calls to ticks method will supress
     3765        // automatically generated scale values. However, that
     3766        // will not affect manually specified value, e.g text-scales.
     3767        // therefor we also make a kludge here to supress manually
     3768        // specified scale labels.
     3769        $this->scale->ticks->SupressLast();
     3770        $this->scale->ticks->SupressFirst();
     3771        $this->show_first_label = false;
     3772        $this->show_last_label = false;
     3773    }
     3774
    34423775    // Hide the axis
    34433776    function Hide($aHide=true) {
    3444         $this->hide=$aHide;
     3777        $this->hide=$aHide;
    34453778    }
    34463779
    34473780    // Hide the actual axis-line, but still print the labels
    34483781    function HideLine($aHide=true) {
    3449         $this->hide_line = $aHide;
     3782        $this->hide_line = $aHide;
    34503783    }
    34513784
    34523785    function HideLabels($aHide=true) {
    3453         $this->hide_labels = $aHide;
    3454     }
    3455    
     3786        $this->hide_labels = $aHide;
     3787    }
    34563788
    34573789    // Weight of axis
    34583790    function SetWeight($aWeight) {
    3459         $this->weight = $aWeight;
     3791        $this->weight = $aWeight;
    34603792    }
    34613793
    34623794    // Axis color
    34633795    function SetColor($aColor,$aLabelColor=false) {
    3464         $this->color = $aColor;
    3465         if( !$aLabelColor ) $this->label_color = $aColor;
    3466         else $this->label_color = $aLabelColor;
    3467     }
    3468        
     3796        $this->color = $aColor;
     3797        if( !$aLabelColor ) $this->label_color = $aColor;
     3798        else $this->label_color = $aLabelColor;
     3799    }
     3800
    34693801    // Title on axis
    3470     function SetTitle($aTitle,$aAdjustAlign="high") {
    3471         $this->title->Set($aTitle);
    3472         $this->title_adjust=$aAdjustAlign;
    3473     }
    3474        
     3802    function SetTitle($aTitle,$aAdjustAlign='high') {
     3803        $this->title->Set($aTitle);
     3804        $this->title_adjust=$aAdjustAlign;
     3805    }
     3806
    34753807    // Specify distance from the axis
    34763808    function SetTitleMargin($aMargin) {
    3477         $this->title_margin=$aMargin;
    3478     }
    3479        
     3809        $this->title_margin=$aMargin;
     3810    }
     3811
    34803812    // Which side of the axis should the axis title be?
    34813813    function SetTitleSide($aSideOfAxis) {
    3482         $this->title_side = $aSideOfAxis;
    3483     }
    3484 
    3485     // Utility function to set the direction for tick marks
    3486     function SetTickDirection($aDir) {
    3487         // Will be deprecated from 1.7         
    3488         if( ERR_DEPRECATED )
    3489             JpGraphError::RaiseL(25055);//('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead');
    3490         $this->scale->ticks->SetSide($aDir);
    3491     }
    3492    
     3814        $this->title_side = $aSideOfAxis;
     3815    }
     3816
    34933817    function SetTickSide($aDir) {
    3494         $this->scale->ticks->SetSide($aDir);
    3495     }
    3496        
     3818        $this->scale->ticks->SetSide($aDir);
     3819    }
     3820
     3821    function SetTickSize($aMajSize,$aMinSize=3) {
     3822        $this->scale->ticks->SetSize($aMajSize,$aMinSize=3);
     3823    }
     3824
    34973825    // Specify text labels for the ticks. One label for each data point
    34983826    function SetTickLabels($aLabelArray,$aLabelColorArray=null) {
    3499         $this->ticks_label = $aLabelArray;
    3500         $this->ticks_label_colors = $aLabelColorArray;
    3501     }
    3502        
    3503     // How far from the axis should the labels be drawn
    3504     function SetTickLabelMargin($aMargin) {
    3505         if( ERR_DEPRECATED )           
    3506             JpGraphError::RaiseL(25056);//('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.');
    3507         $this->tick_label_margin=$aMargin;
     3827        $this->ticks_label = $aLabelArray;
     3828        $this->ticks_label_colors = $aLabelColorArray;
    35083829    }
    35093830
    35103831    function SetLabelMargin($aMargin) {
    3511         $this->tick_label_margin=$aMargin;
    3512     }
    3513        
     3832        $this->tick_label_margin=$aMargin;
     3833    }
     3834
    35143835    // Specify that every $step of the ticks should be displayed starting
    35153836    // at $start
    3516     // DEPRECATED FUNCTION: USE SetTextTickInterval() INSTEAD
    3517     function SetTextTicks($step,$start=0) {
    3518         JpGraphError::RaiseL(25057);//(" SetTextTicks() is deprecated. Use SetTextTickInterval() instead.");           
    3519     }
    3520 
    3521     // Specify that every $step of the ticks should be displayed starting
    3522     // at $start       
    35233837    function SetTextTickInterval($aStep,$aStart=0) {
    3524         $this->scale->ticks->SetTextLabelStart($aStart);
    3525         $this->tick_step=$aStep;
    3526     }
    3527          
    3528     // Specify that every $step tick mark should have a label 
     3838        $this->scale->ticks->SetTextLabelStart($aStart);
     3839        $this->tick_step=$aStep;
     3840    }
     3841
     3842    // Specify that every $step tick mark should have a label
    35293843    // should be displayed starting
    35303844    function SetTextLabelInterval($aStep) {
    3531         if( $aStep < 1 )
    3532             JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1.");
    3533         $this->label_step=$aStep;
    3534     }
    3535        
    3536     // Which side of the axis should the labels be on?
    3537     function SetLabelPos($aSidePos) {
    3538         // This will be deprecated from 1.7
    3539         if( ERR_DEPRECATED )           
    3540             JpGraphError::RaiseL(25059);//('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.');
    3541         $this->labelPos=$aSidePos;
    3542     }
    3543    
     3845        if( $aStep < 1 ) {
     3846            JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1.");
     3847        }
     3848        $this->label_step=$aStep;
     3849    }
     3850
    35443851    function SetLabelSide($aSidePos) {
    3545         $this->labelPos=$aSidePos;
     3852        $this->labelPos=$aSidePos;
    35463853    }
    35473854
    35483855    // Set the font
    35493856    function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) {
    3550         $this->font_family = $aFamily;
    3551         $this->font_style = $aStyle;
    3552         $this->font_size = $aSize;
     3857        $this->font_family = $aFamily;
     3858        $this->font_style = $aStyle;
     3859        $this->font_size = $aSize;
    35533860    }
    35543861
    35553862    // Position for axis line on the "other" scale
    35563863    function SetPos($aPosOnOtherScale) {
    3557         $this->pos=$aPosOnOtherScale;
    3558     }
    3559 
    3560     // Set the position of the axis to be X-pixels delta to the right 
     3864        $this->pos=$aPosOnOtherScale;
     3865    }
     3866
     3867    // Set the position of the axis to be X-pixels delta to the right
    35613868    // of the max X-position (used to position the multiple Y-axis)
    35623869    function SetPosAbsDelta($aDelta) {
    3563       $this->iDeltaAbsPos=$aDelta;
    3564     }
    3565        
     3870        $this->iDeltaAbsPos=$aDelta;
     3871    }
     3872
    35663873    // Specify the angle for the tick labels
    35673874    function SetLabelAngle($aAngle) {
    3568         $this->label_angle = $aAngle;
    3569     }   
     3875        $this->label_angle = $aAngle;
     3876    }
    35703877
    35713878} // Class
     
    35783885// several occasion must know wheter it's an X or Y axis.
    35793886// This was a design decision to make the code easier to
    3580 // follow. 
     3887// follow.
    35813888//===================================================
    35823889class Axis extends AxisPrototype {
    35833890
    3584     function Axis($img,$aScale,$color=array(0,0,0)) {
    3585         parent::Axis($img,$aScale,$color);
    3586     }
    3587        
     3891    function __construct($img,$aScale,$color='black') {
     3892        parent::__construct($img,$aScale,$color);
     3893    }
     3894
    35883895    // Stroke the axis.
    3589     function Stroke($aOtherAxisScale,$aStrokeLabels=true) {             
    3590         if( $this->hide ) return;               
    3591         if( is_numeric($this->pos) ) {
    3592             $pos=$aOtherAxisScale->Translate($this->pos);
    3593         }
    3594         else {  // Default to minimum of other scale if pos not set             
    3595             if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos=="min" ) {
    3596                 $pos = $aOtherAxisScale->scale_abs[0];
    3597             }
    3598             elseif($this->pos == "max") {
    3599                 $pos = $aOtherAxisScale->scale_abs[1];
    3600             }
    3601             else { // If negative set x-axis at 0
    3602                 $this->pos=0;
    3603                 $pos=$aOtherAxisScale->Translate(0);
    3604             }
    3605         }
    3606         $pos += $this->iDeltaAbsPos;   
    3607         $this->img->SetLineWeight($this->weight);
    3608         $this->img->SetColor($this->color);             
    3609         $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
    3610         if( $this->scale->type == "x" ) {
    3611             if( !$this->hide_line )
    3612                 $this->img->FilledRectangle($this->img->left_margin,$pos,
    3613                                             $this->img->width-$this->img->right_margin,$pos+$this->weight-1);
    3614             if( $this->title_side == SIDE_DOWN ) {
    3615                 $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin;
    3616                 $yalign = 'top';
    3617             }
    3618             else {
    3619                 $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin;
    3620                 $yalign = 'bottom';
    3621             }
    3622 
    3623             if( $this->title_adjust=='high' )
    3624                 $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign);
    3625             elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' )
    3626                 $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign);
    3627             elseif($this->title_adjust=='low')
    3628                 $this->title->SetPos($this->img->left_margin,$y,'left',$yalign);
    3629             else {     
    3630                 JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')');
    3631             }
    3632         }
    3633         elseif( $this->scale->type == "y" ) {
    3634             // Add line weight to the height of the axis since
    3635             // the x-axis could have a width>1 and we want the axis to fit nicely together.
    3636             if( !$this->hide_line )
    3637                 $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin,
    3638                                             $pos,$this->img->height-$this->img->bottom_margin+$this->weight-1);
    3639             $x=$pos ;
    3640             if( $this->title_side == SIDE_LEFT ) {
    3641                 $x -= $this->title_margin;
    3642                 $x -= $this->title->margin;
    3643                 $halign="right";
    3644             }
    3645             else {
    3646                 $x += $this->title_margin;
    3647                 $x += $this->title->margin;
    3648                 $halign="left";
    3649             }
    3650             // If the user has manually specified an hor. align
    3651             // then we override the automatic settings with this
    3652             // specifed setting. Since default is 'left' we compare
    3653             // with that. (This means a manually set 'left' align
    3654             // will have no effect.)
    3655             if( $this->title->halign != 'left' )
    3656                 $halign = $this->title->halign;
    3657             if( $this->title_adjust=="high" )
    3658                 $this->title->SetPos($x,$this->img->top_margin,$halign,"top");
    3659             elseif($this->title_adjust=="middle" || $this->title_adjust=="center") 
    3660                 $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center");
    3661             elseif($this->title_adjust=="low")
    3662                 $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,"bottom");
    3663             else       
    3664                 JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')');
    3665                
    3666         }
    3667         $this->scale->ticks->Stroke($this->img,$this->scale,$pos);
    3668         if( $aStrokeLabels ) {
    3669             if( !$this->hide_labels )
    3670                 $this->StrokeLabels($pos);
    3671             $this->title->Stroke($this->img);
    3672         }
    3673     }
    3674 
    3675 //---------------
    3676 // PRIVATE METHODS     
     3896    function Stroke($aOtherAxisScale,$aStrokeLabels=true) {
     3897        if( $this->hide )
     3898            return;
     3899        if( is_numeric($this->pos) ) {
     3900            $pos=$aOtherAxisScale->Translate($this->pos);
     3901        }
     3902        else { // Default to minimum of other scale if pos not set
     3903            if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos == 'min' ) {
     3904                $pos = $aOtherAxisScale->scale_abs[0];
     3905            }
     3906            elseif($this->pos == "max") {
     3907                $pos = $aOtherAxisScale->scale_abs[1];
     3908            }
     3909            else { // If negative set x-axis at 0
     3910                $this->pos=0;
     3911                $pos=$aOtherAxisScale->Translate(0);
     3912            }
     3913        }
     3914
     3915        $pos += $this->iDeltaAbsPos;
     3916        $this->img->SetLineWeight($this->weight);
     3917        $this->img->SetColor($this->color);
     3918        $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
     3919
     3920        if( $this->scale->type == "x" ) {
     3921            if( !$this->hide_line ) {
     3922                // Stroke X-axis
     3923                $this->img->FilledRectangle(
     3924                    $this->img->left_margin,
     3925                    $pos,
     3926                    $this->img->width - $this->img->right_margin,
     3927                    $pos + $this->weight-1
     3928                );
     3929            }
     3930            if( $this->title_side == SIDE_DOWN ) {
     3931                $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin;
     3932                $yalign = 'top';
     3933            }
     3934            else {
     3935                $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin;
     3936                $yalign = 'bottom';
     3937            }
     3938
     3939            if( $this->title_adjust=='high' ) {
     3940                $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign);
     3941            }
     3942            elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' ) {
     3943                $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign);
     3944            }
     3945            elseif($this->title_adjust=='low') {
     3946                $this->title->SetPos($this->img->left_margin,$y,'left',$yalign);
     3947            }
     3948            else {
     3949                JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')');
     3950            }
     3951        }
     3952        elseif( $this->scale->type == "y" ) {
     3953            // Add line weight to the height of the axis since
     3954            // the x-axis could have a width>1 and we want the axis to fit nicely together.
     3955            if( !$this->hide_line ) {
     3956                // Stroke Y-axis
     3957                $this->img->FilledRectangle(
     3958                    $pos - $this->weight + 1,
     3959                    $this->img->top_margin,
     3960                    $pos,
     3961                    $this->img->height - $this->img->bottom_margin + $this->weight - 1
     3962                );
     3963            }
     3964
     3965            $x=$pos ;
     3966            if( $this->title_side == SIDE_LEFT ) {
     3967                $x -= $this->title_margin;
     3968                $x -= $this->title->margin;
     3969                $halign = 'right';
     3970            }
     3971            else {
     3972                $x += $this->title_margin;
     3973                $x += $this->title->margin;
     3974                $halign = 'left';
     3975            }
     3976            // If the user has manually specified an hor. align
     3977            // then we override the automatic settings with this
     3978            // specifed setting. Since default is 'left' we compare
     3979            // with that. (This means a manually set 'left' align
     3980            // will have no effect.)
     3981            if( $this->title->halign != 'left' ) {
     3982                $halign = $this->title->halign;
     3983            }
     3984            if( $this->title_adjust == 'high' ) {
     3985                $this->title->SetPos($x,$this->img->top_margin,$halign,'top');
     3986            }
     3987            elseif($this->title_adjust=='middle' || $this->title_adjust=='center') {
     3988                $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center");
     3989            }
     3990            elseif($this->title_adjust=='low') {
     3991                $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,'bottom');
     3992            }
     3993            else {
     3994                JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')');
     3995            }
     3996        }
     3997        $this->scale->ticks->Stroke($this->img,$this->scale,$pos);
     3998        if( $aStrokeLabels ) {
     3999            if( !$this->hide_labels ) {
     4000                $this->StrokeLabels($pos);
     4001            }
     4002            $this->title->Stroke($this->img);
     4003        }
     4004    }
     4005
     4006    //---------------
     4007    // PRIVATE METHODS
    36774008    // Draw all the tick labels on major tick marks
    36784009    function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) {
    36794010
    3680         $this->img->SetColor($this->label_color);
    3681         $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
    3682         $yoff=$this->img->GetFontHeight()/2;
    3683 
    3684         // Only draw labels at major tick marks
    3685         $nbr = count($this->scale->ticks->maj_ticks_label);
    3686 
    3687         // We have the option to not-display the very first mark
    3688         // (Usefull when the first label might interfere with another
    3689         // axis.)
    3690         $i = $this->show_first_label ? 0 : 1 ;
    3691         if( !$this->show_last_label ) --$nbr;
    3692         // Now run through all labels making sure we don't overshoot the end
    3693         // of the scale.       
    3694         $ncolor=0;
    3695         if( isset($this->ticks_label_colors) )
    3696             $ncolor=count($this->ticks_label_colors);
    3697         while( $i<$nbr ) {
    3698             // $tpos holds the absolute text position for the label
    3699             $tpos=$this->scale->ticks->maj_ticklabels_pos[$i];
    3700 
    3701             // Note. the $limit is only used for the x axis since we
    3702             // might otherwise overshoot if the scale has been centered
    3703             // This is due to us "loosing" the last tick mark if we center.
    3704             if( $this->scale->type=="x" && $tpos > $this->img->width-$this->img->right_margin+1 ) {
    3705                 return;
    3706             }
    3707             // we only draw every $label_step label
    3708             if( ($i % $this->label_step)==0 ) {
    3709 
    3710                 // Set specific label color if specified
    3711                 if( $ncolor > 0 )
    3712                     $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]);
    3713                
    3714                 // If the label has been specified use that and in other case
    3715                 // just label the mark with the actual scale value
    3716                 $m=$this->scale->ticks->GetMajor();
    3717                                
    3718                 // ticks_label has an entry for each data point and is the array
    3719                 // that holds the labels set by the user. If the user hasn't
    3720                 // specified any values we use whats in the automatically asigned
    3721                 // labels in the maj_ticks_label
    3722                 if( isset($this->ticks_label[$i*$m]) )
    3723                     $label=$this->ticks_label[$i*$m];
    3724                 else {
    3725                     if( $aAbsLabel )
    3726                         $label=abs($this->scale->ticks->maj_ticks_label[$i]);
    3727                     else
    3728                         $label=$this->scale->ticks->maj_ticks_label[$i];
    3729                     if( $this->scale->textscale && $this->scale->ticks->label_formfunc == '' ) {
    3730                         ++$label;
    3731                     }
    3732                 }
    3733                                        
    3734                 if( $this->scale->type == "x" ) {
    3735                     if( $this->labelPos == SIDE_DOWN ) {
    3736                         if( $this->label_angle==0 || $this->label_angle==90 ) {
    3737                             if( $this->label_halign=='' && $this->label_valign=='')
    3738                                 $this->img->SetTextAlign('center','top');
    3739                             else
    3740                                 $this->img->SetTextAlign($this->label_halign,$this->label_valign);
    3741                            
    3742                         }
    3743                         else {
    3744                             if( $this->label_halign=='' && $this->label_valign=='')
    3745                                 $this->img->SetTextAlign("right","top");
    3746                             else
    3747                                 $this->img->SetTextAlign($this->label_halign,$this->label_valign);
    3748                         }
    3749                         $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin+1,$label,
    3750                                                $this->label_angle,$this->label_para_align);
    3751                     }
    3752                     else {
    3753                         if( $this->label_angle==0 || $this->label_angle==90 ) {
    3754                             if( $this->label_halign=='' && $this->label_valign=='')
    3755                                 $this->img->SetTextAlign("center","bottom");
    3756                             else
    3757                                 $this->img->SetTextAlign($this->label_halign,$this->label_valign);
    3758                         }
    3759                         else {
    3760                             if( $this->label_halign=='' && $this->label_valign=='')
    3761                                 $this->img->SetTextAlign("right","bottom");
    3762                             else
    3763                                 $this->img->SetTextAlign($this->label_halign,$this->label_valign);
    3764                         }
    3765                         $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label,
    3766                                                $this->label_angle,$this->label_para_align);
    3767                     }
    3768                 }
    3769                 else {
    3770                     // scale->type == "y"
    3771                     //if( $this->label_angle!=0 )
    3772                     //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis");
    3773                     if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis                                       
    3774                         if( $this->label_halign=='' && $this->label_valign=='')
    3775                             $this->img->SetTextAlign("right","center");
    3776                         else
    3777                             $this->img->SetTextAlign($this->label_halign,$this->label_valign);
    3778                         $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
    3779                     }
    3780                     else { // To the right of the y-axis
    3781                         if( $this->label_halign=='' && $this->label_valign=='')
    3782                             $this->img->SetTextAlign("left","center");
    3783                         else
    3784                             $this->img->SetTextAlign($this->label_halign,$this->label_valign);
    3785                         $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
    3786                     }
    3787                 }
    3788             }
    3789             ++$i;       
    3790         }                                                               
    3791     }                       
     4011        if( is_array($this->label_color) && count($this->label_color) > 3 ) {
     4012            $this->ticks_label_colors = $this->label_color;
     4013            $this->img->SetColor($this->label_color[0]);
     4014        }
     4015        else {
     4016            $this->img->SetColor($this->label_color);
     4017        }
     4018        $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
     4019        $yoff=$this->img->GetFontHeight()/2;
     4020
     4021        // Only draw labels at major tick marks
     4022        $nbr = count($this->scale->ticks->maj_ticks_label);
     4023
     4024        // We have the option to not-display the very first mark
     4025        // (Usefull when the first label might interfere with another
     4026        // axis.)
     4027        $i = $this->show_first_label ? 0 : 1 ;
     4028        if( !$this->show_last_label ) {
     4029            --$nbr;
     4030        }
     4031        // Now run through all labels making sure we don't overshoot the end
     4032        // of the scale.
     4033        $ncolor=0;
     4034        if( isset($this->ticks_label_colors) ) {
     4035            $ncolor=count($this->ticks_label_colors);
     4036        }
     4037        while( $i < $nbr ) {
     4038            // $tpos holds the absolute text position for the label
     4039            $tpos=$this->scale->ticks->maj_ticklabels_pos[$i];
     4040
     4041            // Note. the $limit is only used for the x axis since we
     4042            // might otherwise overshoot if the scale has been centered
     4043            // This is due to us "loosing" the last tick mark if we center.
     4044            if( $this->scale->type == 'x' && $tpos > $this->img->width-$this->img->right_margin+1 ) {
     4045                return;
     4046            }
     4047            // we only draw every $label_step label
     4048            if( ($i % $this->label_step)==0 ) {
     4049
     4050                // Set specific label color if specified
     4051                if( $ncolor > 0 ) {
     4052                    $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]);
     4053                }
     4054
     4055                // If the label has been specified use that and in other case
     4056                // just label the mark with the actual scale value
     4057                $m=$this->scale->ticks->GetMajor();
     4058
     4059                // ticks_label has an entry for each data point and is the array
     4060                // that holds the labels set by the user. If the user hasn't
     4061                // specified any values we use whats in the automatically asigned
     4062                // labels in the maj_ticks_label
     4063                if( isset($this->ticks_label[$i*$m]) ) {
     4064                    $label=$this->ticks_label[$i*$m];
     4065                }
     4066                else {
     4067                    if( $aAbsLabel ) {
     4068                        $label=abs($this->scale->ticks->maj_ticks_label[$i]);
     4069                    }
     4070                    else {
     4071                        $label=$this->scale->ticks->maj_ticks_label[$i];
     4072                    }
     4073
     4074                    // We number the scale from 1 and not from 0 so increase by one
     4075                    if( $this->scale->textscale &&
     4076                        $this->scale->ticks->label_formfunc == '' &&
     4077                        ! $this->scale->ticks->HaveManualLabels() ) {
     4078
     4079                        ++$label;
     4080                       
     4081                    }
     4082                }
     4083
     4084                if( $this->scale->type == "x" ) {
     4085                    if( $this->labelPos == SIDE_DOWN ) {
     4086                        if( $this->label_angle==0 || $this->label_angle==90 ) {
     4087                            if( $this->label_halign=='' && $this->label_valign=='') {
     4088                                $this->img->SetTextAlign('center','top');
     4089                            }
     4090                            else {
     4091                                $this->img->SetTextAlign($this->label_halign,$this->label_valign);
     4092                            }
     4093
     4094                        }
     4095                        else {
     4096                            if( $this->label_halign=='' && $this->label_valign=='') {
     4097                                $this->img->SetTextAlign("right","top");
     4098                            }
     4099                            else {
     4100                                $this->img->SetTextAlign($this->label_halign,$this->label_valign);
     4101                            }
     4102                        }
     4103                        $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label,
     4104                        $this->label_angle,$this->label_para_align);
     4105                    }
     4106                    else {
     4107                        if( $this->label_angle==0 || $this->label_angle==90 ) {
     4108                            if( $this->label_halign=='' && $this->label_valign=='') {
     4109                                $this->img->SetTextAlign("center","bottom");
     4110                            }
     4111                            else {
     4112                                $this->img->SetTextAlign($this->label_halign,$this->label_valign);
     4113                            }
     4114                        }
     4115                        else {
     4116                            if( $this->label_halign=='' && $this->label_valign=='') {
     4117                                $this->img->SetTextAlign("right","bottom");
     4118                            }
     4119                            else {
     4120                                $this->img->SetTextAlign($this->label_halign,$this->label_valign);
     4121                            }
     4122                        }
     4123                        $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label,
     4124                        $this->label_angle,$this->label_para_align);
     4125                    }
     4126                }
     4127                else {
     4128                    // scale->type == "y"
     4129                    //if( $this->label_angle!=0 )
     4130                    //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis");
     4131                    if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis
     4132                        if( $this->label_halign=='' && $this->label_valign=='') {
     4133                            $this->img->SetTextAlign("right","center");
     4134                        }
     4135                        else {
     4136                            $this->img->SetTextAlign($this->label_halign,$this->label_valign);
     4137                        }
     4138                        $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
     4139                    }
     4140                    else { // To the right of the y-axis
     4141                        if( $this->label_halign=='' && $this->label_valign=='') {
     4142                            $this->img->SetTextAlign("left","center");
     4143                        }
     4144                        else {
     4145                            $this->img->SetTextAlign($this->label_halign,$this->label_valign);
     4146                        }
     4147                        $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
     4148                    }
     4149                }
     4150            }
     4151            ++$i;
     4152        }
     4153    }
    37924154
    37934155}
     
    38054167    public $direction=1; // Should ticks be in(=1) the plot area or outside (=-1)
    38064168    public $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false;
    3807     public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), 
    3808            $ticks_pos = array(), $maj_ticks_label = array();
     4169    public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(),
     4170           $ticks_pos = array(), $maj_ticks_label = array();
    38094171    public $precision;
    38104172
     
    38134175    protected $is_set=false;
    38144176    protected $supress_zerolabel=false,$supress_first=false;
    3815     protected $mincolor="",$majcolor="";
     4177    protected $mincolor='',$majcolor='';
    38164178    protected $weight=1;
    38174179    protected $label_usedateformat=FALSE;
    38184180
    3819 //---------------
    3820 // CONSTRUCTOR
    3821     function Ticks($aScale) {
    3822         $this->scale=$aScale;
    3823         $this->precision = -1;
    3824     }
    3825 
    3826 //---------------
    3827 // PUBLIC METHODS       
     4181    function __construct($aScale) {
     4182        $this->scale=$aScale;
     4183        $this->precision = -1;
     4184    }
     4185
    38284186    // Set format string for automatic labels
    38294187    function SetLabelFormat($aFormatString,$aDate=FALSE) {
    3830         $this->label_formatstr=$aFormatString;
    3831         $this->label_usedateformat=$aDate;
    3832     }
    3833        
     4188        $this->label_formatstr=$aFormatString;
     4189        $this->label_usedateformat=$aDate;
     4190    }
     4191
    38344192    function SetLabelDateFormat($aFormatString) {
    3835         $this->label_dateformatstr=$aFormatString;
    3836     }
    3837        
     4193        $this->label_dateformatstr=$aFormatString;
     4194    }
     4195
    38384196    function SetFormatCallback($aCallbackFuncName) {
    3839         $this->label_formfunc = $aCallbackFuncName;
    3840     }
    3841        
     4197        $this->label_formfunc = $aCallbackFuncName;
     4198    }
     4199
    38424200    // Don't display the first zero label
    38434201    function SupressZeroLabel($aFlag=true) {
    3844         $this->supress_zerolabel=$aFlag;
    3845     }
    3846        
     4202        $this->supress_zerolabel=$aFlag;
     4203    }
     4204
    38474205    // Don't display minor tick marks
    38484206    function SupressMinorTickMarks($aHide=true) {
    3849         $this->supress_minor_tickmarks=$aHide;
    3850     }
    3851        
     4207        $this->supress_minor_tickmarks=$aHide;
     4208    }
     4209
    38524210    // Don't display major tick marks
    38534211    function SupressTickMarks($aHide=true) {
    3854         $this->supress_tickmarks=$aHide;
    3855     }
    3856        
     4212        $this->supress_tickmarks=$aHide;
     4213    }
     4214
    38574215    // Hide the first tick mark
    38584216    function SupressFirst($aHide=true) {
    3859         $this->supress_first=$aHide;
    3860     }
    3861        
     4217        $this->supress_first=$aHide;
     4218    }
     4219
    38624220    // Hide the last tick mark
    38634221    function SupressLast($aHide=true) {
    3864         $this->supress_last=$aHide;
     4222        $this->supress_last=$aHide;
    38654223    }
    38664224
    38674225    // Size (in pixels) of minor tick marks
    38684226    function GetMinTickAbsSize() {
    3869         return $this->minor_abs_size;
    3870     }
    3871        
     4227        return $this->minor_abs_size;
     4228    }
     4229
    38724230    // Size (in pixels) of major tick marks
    38734231    function GetMajTickAbsSize() {
    3874         return $this->major_abs_size;           
    3875     }
    3876        
     4232        return $this->major_abs_size;
     4233    }
     4234
    38774235    function SetSize($aMajSize,$aMinSize=3) {
    3878         $this->major_abs_size = $aMajSize;             
    3879         $this->minor_abs_size = $aMinSize;             
     4236        $this->major_abs_size = $aMajSize;
     4237        $this->minor_abs_size = $aMinSize;
    38804238    }
    38814239
    38824240    // Have the ticks been specified
    38834241    function IsSpecified() {
    3884         return $this->is_set;
    3885     }
    3886                
    3887     // Specify number of decimals in automatic labels
    3888     // Deprecated from 1.4. Use SetFormatString() instead
    3889     function SetPrecision($aPrecision) {       
    3890         if( ERR_DEPRECATED )
    3891             JpGraphError::RaiseL(25063);//('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead');
    3892         $this->precision=$aPrecision;
     4242        return $this->is_set;
    38934243    }
    38944244
    38954245    function SetSide($aSide) {
    3896         $this->direction=$aSide;
    3897     }
    3898        
     4246        $this->direction=$aSide;
     4247    }
     4248
    38994249    // Which side of the axis should the ticks be on
    39004250    function SetDirection($aSide=SIDE_RIGHT) {
    3901         $this->direction=$aSide;
    3902     }
    3903        
     4251        $this->direction=$aSide;
     4252    }
     4253
    39044254    // Set colors for major and minor tick marks
    3905     function SetMarkColor($aMajorColor,$aMinorColor="") {
    3906         $this->SetColor($aMajorColor,$aMinorColor);
    3907     }
    3908    
    3909     function SetColor($aMajorColor,$aMinorColor="") {
    3910         $this->majcolor=$aMajorColor;
    3911                
    3912         // If not specified use same as major
    3913         if( $aMinorColor=="" )
    3914             $this->mincolor=$aMajorColor;
    3915         else
    3916             $this->mincolor=$aMinorColor;
    3917     }
    3918        
     4255    function SetMarkColor($aMajorColor,$aMinorColor='') {
     4256        $this->SetColor($aMajorColor,$aMinorColor);
     4257    }
     4258
     4259    function SetColor($aMajorColor,$aMinorColor='') {
     4260        $this->majcolor=$aMajorColor;
     4261
     4262        // If not specified use same as major
     4263        if( $aMinorColor == '' ) {
     4264            $this->mincolor=$aMajorColor;
     4265        }
     4266        else {
     4267            $this->mincolor=$aMinorColor;
     4268        }
     4269    }
     4270
    39194271    function SetWeight($aWeight) {
    3920         $this->weight=$aWeight;
    3921     }
    3922        
     4272        $this->weight=$aWeight;
     4273    }
     4274
    39234275} // Class
    39244276
     
    39364288    private $iAdjustForDST = false; // If a date falls within the DST period add one hour to the diaplyed time
    39374289
    3938 //---------------
    3939 // CONSTRUCTOR
    3940     function LinearTicks() {
    3941         $this->precision = -1;
    3942     }
    3943 
    3944 //---------------
    3945 // PUBLIC METHODS       
    3946        
    3947        
     4290    function __construct() {
     4291        $this->precision = -1;
     4292    }
     4293
    39484294    // Return major step size in world coordinates
    39494295    function GetMajor() {
    3950         return $this->major_step;
    3951     }
    3952        
     4296        return $this->major_step;
     4297    }
     4298
    39534299    // Return minor step size in world coordinates
    39544300    function GetMinor() {
    3955         return $this->minor_step;
    3956     }
    3957        
     4301        return $this->minor_step;
     4302    }
     4303
    39584304    // Set Minor and Major ticks (in world coordinates)
    39594305    function Set($aMajStep,$aMinStep=false) {
    3960         if( $aMinStep==false )
    3961             $aMinStep=$aMajStep;
    3962        
    3963         if( $aMajStep <= 0 || $aMinStep <= 0 ) {
    3964             JpGraphError::RaiseL(25064);
    3965 //(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem.");
    3966         }
    3967                
    3968         $this->major_step=$aMajStep;
    3969         $this->minor_step=$aMinStep;
    3970         $this->is_set = true;
     4306        if( $aMinStep==false ) {
     4307            $aMinStep=$aMajStep;
     4308        }
     4309
     4310        if( $aMajStep <= 0 || $aMinStep <= 0 ) {
     4311            JpGraphError::RaiseL(25064);
     4312            //(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem.");
     4313        }
     4314
     4315        $this->major_step=$aMajStep;
     4316        $this->minor_step=$aMinStep;
     4317        $this->is_set = true;
    39714318    }
    39724319
    39734320    function SetMajTickPositions($aMajPos,$aLabels=NULL) {
    3974         $this->SetTickPositions($aMajPos,NULL,$aLabels);
     4321        $this->SetTickPositions($aMajPos,NULL,$aLabels);
    39754322    }
    39764323
    39774324    function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) {
    3978         if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) {
    3979             JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()');
    3980             return;
    3981         }
    3982         $n=count($aMajPos);
    3983         if( is_array($aLabels) && (count($aLabels) != $n) ) {
    3984             JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.');
    3985             return;
    3986         }
    3987         $this->iManualTickPos = $aMajPos;
    3988         $this->iManualMinTickPos = $aMinPos;
    3989         $this->iManualTickLabels = $aLabels;
    3990     }
    3991 
    3992     // Specify all the tick positions manually and possible also the exact labels
    3993     function _doManualTickPos($aScale) {
    3994         $n=count($this->iManualTickPos);
    3995         $m=count($this->iManualMinTickPos);
    3996         $doLbl=count($this->iManualTickLabels) > 0;
    3997 
    3998         $this->maj_ticks_pos = array();
    3999         $this->maj_ticklabels_pos = array();
    4000         $this->ticks_pos = array();
    4001 
    4002         // Now loop through the supplied positions and translate them to screen coordinates
    4003         // and store them in the maj_label_positions
    4004         $minScale = $aScale->scale[0];
    4005         $maxScale = $aScale->scale[1];
    4006         $j=0;
    4007         for($i=0; $i < $n ; ++$i ) {
    4008             // First make sure that the first tick is not lower than the lower scale value
    4009             if( !isset($this->iManualTickPos[$i])  ||
    4010                 $this->iManualTickPos[$i] < $minScale  || $this->iManualTickPos[$i] > $maxScale) {
    4011                 continue;
    4012             }
    4013 
    4014 
    4015             $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]);
    4016             $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j];   
    4017 
    4018             // Set the minor tick marks the same as major if not specified
    4019             if( $m <= 0 ) {
    4020                 $this->ticks_pos[$j] = $this->maj_ticks_pos[$j];
    4021             }
    4022 
    4023             if( $doLbl ) {
    4024                 $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i];
    4025             }
    4026             else {
    4027                 $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n);
    4028             }
    4029             ++$j;
    4030         }
    4031 
    4032         // Some sanity check
    4033         if( count($this->maj_ticks_pos) < 2 ) {
    4034             JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.');
    4035         }
    4036 
    4037         // Setup the minor tick marks
    4038         $j=0;
    4039         for($i=0; $i < $m; ++$i ) {
    4040             if(  empty($this->iManualMinTickPos[$i]) ||
    4041                  $this->iManualMinTickPos[$i] < $minScale  || $this->iManualMinTickPos[$i] > $maxScale)
    4042                 continue;
    4043             $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]);
    4044             ++$j;
    4045         }
     4325        if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) {
     4326            JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()');
     4327            return;
     4328        }
     4329        $n=count($aMajPos);
     4330        if( is_array($aLabels) && (count($aLabels) != $n) ) {
     4331            JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.');
     4332        }
     4333        $this->iManualTickPos = $aMajPos;
     4334        $this->iManualMinTickPos = $aMinPos;
     4335        $this->iManualTickLabels = $aLabels;
     4336    }
     4337
     4338    function HaveManualLabels() {
     4339        return is_array($this->iManualTickLabels) ? count($this->iManualTickLabels) > 0 : false;
     4340    }
     4341
     4342    // Specify all the tick positions manually and possible also the exact labels
     4343    function _doManualTickPos($aScale) {
     4344        $n=count($this->iManualTickPos);
     4345        $m= is_array($this->iManualMinTickPos) ? count($this->iManualMinTickPos) : 0;
     4346        $doLbl= is_array($this->iManualTickLabels) ? count($this->iManualTickLabels) > 0 : false;
     4347
     4348        $this->maj_ticks_pos = array();
     4349        $this->maj_ticklabels_pos = array();
     4350        $this->ticks_pos = array();
     4351
     4352        // Now loop through the supplied positions and translate them to screen coordinates
     4353        // and store them in the maj_label_positions
     4354        $minScale = $aScale->scale[0];
     4355        $maxScale = $aScale->scale[1];
     4356        $j=0;
     4357        for($i=0; $i < $n ; ++$i ) {
     4358            // First make sure that the first tick is not lower than the lower scale value
     4359            if( !isset($this->iManualTickPos[$i]) || $this->iManualTickPos[$i] < $minScale  || $this->iManualTickPos[$i] > $maxScale) {
     4360                continue;
     4361            }
     4362
     4363            $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]);
     4364            $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j];
     4365
     4366            // Set the minor tick marks the same as major if not specified
     4367            if( $m <= 0 ) {
     4368                $this->ticks_pos[$j] = $this->maj_ticks_pos[$j];
     4369            }
     4370            if( $doLbl ) {
     4371                $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i];
     4372            }
     4373            else {
     4374                $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n);
     4375            }
     4376            ++$j;
     4377        }
     4378
     4379        // Some sanity check
     4380        if( count($this->maj_ticks_pos) < 2 ) {
     4381            JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.');
     4382        }
     4383
     4384        // Setup the minor tick marks
     4385        $j=0;
     4386        for($i=0; $i < $m; ++$i ) {
     4387            if(  empty($this->iManualMinTickPos[$i]) || $this->iManualMinTickPos[$i] < $minScale  || $this->iManualMinTickPos[$i] > $maxScale) {
     4388                continue;
     4389            }
     4390            $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]);
     4391            ++$j;
     4392        }
    40464393    }
    40474394
    40484395    function _doAutoTickPos($aScale) {
    4049         $maj_step_abs = $aScale->scale_factor*$this->major_step;               
    4050         $min_step_abs = $aScale->scale_factor*$this->minor_step;               
    4051 
    4052         if( $min_step_abs==0 || $maj_step_abs==0 ) {
    4053             JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')");
    4054         }
    4055         // We need to make this an int since comparing it below
    4056         // with the result from round() can give wrong result, such that
    4057         // (40 < 40) == TRUE !!!
    4058         $limit = (int)$aScale->scale_abs[1];   
    4059 
    4060         if( $aScale->textscale ) {
    4061             // This can only be true for a X-scale (horizontal)
    4062             // Define ticks for a text scale. This is slightly different from a
    4063             // normal linear type of scale since the position might be adjusted
    4064             // and the labels start at on
    4065             $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset;   
    4066             $start_abs=$aScale->scale_factor*$this->text_label_start;
    4067             $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;       
    4068 
    4069             $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs;   
    4070             for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) {
    4071                 // Apply format to label
    4072                 $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks);
    4073                 $label+=$this->major_step;
    4074 
    4075                 // The x-position of the tick marks can be different from the labels.
    4076                 // Note that we record the tick position (not the label) so that the grid
    4077                 // happen upon tick marks and not labels.
    4078                 $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs;
    4079                 $this->maj_ticks_pos[$i]=$xtick;
    4080                 $this->maj_ticklabels_pos[$i] = round($x);                             
    4081                 $x += $maj_step_abs;
    4082             }
    4083         }
    4084         else {
    4085             $label = $aScale->GetMinVal();     
    4086             $abs_pos = $aScale->scale_abs[0];
    4087             $j=0; $i=0;
    4088             $step = round($maj_step_abs/$min_step_abs);
    4089             if( $aScale->type == "x" ) {
    4090                 // For a normal linear type of scale the major ticks will always be multiples
    4091                 // of the minor ticks. In order to avoid any rounding issues the major ticks are
    4092                 // defined as every "step" minor ticks and not calculated separately
    4093                 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
    4094                 while( round($abs_pos) <= $limit ) {
    4095                     $this->ticks_pos[] = round($abs_pos);
    4096                     $this->ticks_label[] = $label;
    4097                     if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) {
    4098                         $this->maj_ticks_pos[$j] = round($abs_pos);
    4099                         $this->maj_ticklabels_pos[$j] = round($abs_pos);
    4100                         $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);
    4101                         ++$j;
    4102                     }
    4103                     ++$i;
    4104                     $abs_pos += $min_step_abs;
    4105                     $label+=$this->minor_step;
    4106                 }
    4107             }
    4108             elseif( $aScale->type == "y" ) {
    4109                 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1;
    4110                 while( round($abs_pos) >= $limit ) {
    4111                     $this->ticks_pos[$i] = round($abs_pos);
    4112                     $this->ticks_label[$i]=$label;
    4113                     if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) {
    4114                         $this->maj_ticks_pos[$j] = round($abs_pos);
    4115                         $this->maj_ticklabels_pos[$j] = round($abs_pos);
    4116                         $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);
    4117                         ++$j;
    4118                     }
    4119                     ++$i;
    4120                     $abs_pos += $min_step_abs;
    4121                     $label += $this->minor_step;
    4122                 }       
    4123             }
    4124         }       
     4396        $maj_step_abs = $aScale->scale_factor*$this->major_step;
     4397        $min_step_abs = $aScale->scale_factor*$this->minor_step;
     4398
     4399        if( $min_step_abs==0 || $maj_step_abs==0 ) {
     4400            JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')");
     4401        }
     4402        // We need to make this an int since comparing it below
     4403        // with the result from round() can give wrong result, such that
     4404        // (40 < 40) == TRUE !!!
     4405        $limit = (int)$aScale->scale_abs[1];
     4406
     4407        if( $aScale->textscale ) {
     4408            // This can only be true for a X-scale (horizontal)
     4409            // Define ticks for a text scale. This is slightly different from a
     4410            // normal linear type of scale since the position might be adjusted
     4411            // and the labels start at on
     4412            $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset;
     4413            $start_abs=$aScale->scale_factor*$this->text_label_start;
     4414            $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
     4415
     4416            $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs;
     4417            for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) {
     4418                // Apply format to label
     4419                $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks);
     4420                $label+=$this->major_step;
     4421
     4422                // The x-position of the tick marks can be different from the labels.
     4423                // Note that we record the tick position (not the label) so that the grid
     4424                // happen upon tick marks and not labels.
     4425                $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs;
     4426                $this->maj_ticks_pos[$i]=$xtick;
     4427                $this->maj_ticklabels_pos[$i] = round($x);
     4428                $x += $maj_step_abs;
     4429            }
     4430        }
     4431        else {
     4432            $label = $aScale->GetMinVal();
     4433            $abs_pos = $aScale->scale_abs[0];
     4434            $j=0; $i=0;
     4435            $step = round($maj_step_abs/$min_step_abs);
     4436            if( $aScale->type == "x" ) {
     4437                // For a normal linear type of scale the major ticks will always be multiples
     4438                // of the minor ticks. In order to avoid any rounding issues the major ticks are
     4439                // defined as every "step" minor ticks and not calculated separately
     4440                $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
     4441                while( round($abs_pos) <= $limit ) {
     4442                    $this->ticks_pos[] = round($abs_pos);
     4443                    $this->ticks_label[] = $label;
     4444                    if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) {
     4445                        $this->maj_ticks_pos[$j] = round($abs_pos);
     4446                        $this->maj_ticklabels_pos[$j] = round($abs_pos);
     4447                        $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);
     4448                        ++$j;
     4449                    }
     4450                    ++$i;
     4451                    $abs_pos += $min_step_abs;
     4452                    $label+=$this->minor_step;
     4453                }
     4454            }
     4455            elseif( $aScale->type == "y" ) {
     4456                //@todo  s=2:20,12  s=1:50,6  $this->major_step:$nbr
     4457                // abs_point,limit s=1:270,80 s=2:540,160
     4458             // $this->major_step = 50;
     4459                $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1;
     4460//                $step = 5;
     4461                while( round($abs_pos) >= $limit ) {
     4462                    $this->ticks_pos[$i] = round($abs_pos);
     4463                    $this->ticks_label[$i]=$label;
     4464                    if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) {
     4465                        $this->maj_ticks_pos[$j] = round($abs_pos);
     4466                        $this->maj_ticklabels_pos[$j] = round($abs_pos);
     4467                        $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks);
     4468                        ++$j;
     4469                    }
     4470                    ++$i;
     4471                    $abs_pos += $min_step_abs;
     4472                    $label += $this->minor_step;
     4473                }
     4474            }
     4475        }
    41254476    }
    41264477
    41274478    function AdjustForDST($aFlg=true) {
    4128         $this->iAdjustForDST = $aFlg;
     4479        $this->iAdjustForDST = $aFlg;
    41294480    }
    41304481
     
    41324483    function _doLabelFormat($aVal,$aIdx,$aNbrTicks) {
    41334484
    4134         // If precision hasn't been specified set it to a sensible value
    4135         if( $this->precision==-1 ) {
    4136             $t = log10($this->minor_step);
    4137             if( $t > 0 )
    4138                 $precision = 0;
    4139             else
    4140                 $precision = -floor($t);
    4141         }
    4142         else
    4143             $precision = $this->precision;
    4144 
    4145         if( $this->label_formfunc != '' ) {
    4146             $f=$this->label_formfunc;
    4147             $l = call_user_func($f,$aVal);
    4148         }       
    4149         elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) {
    4150             if( $this->label_usedateformat ) {
    4151                 // Adjust the value to take daylight savings into account
    4152                 if (date("I",$aVal)==1 && $this->iAdjustForDST ) // DST
    4153                     $aVal+=3600;
    4154 
    4155                 $l = date($this->label_formatstr,$aVal);
    4156                 if( $this->label_formatstr == 'W' ) {
    4157                     // If we use week formatting then add a single 'w' in front of the
    4158                     // week number to differentiate it from dates
    4159                     $l = 'w'.$l;
    4160                 }
    4161             }
    4162             else {
    4163                 if( $this->label_dateformatstr !== '' ) {
    4164                     // Adjust the value to take daylight savings into account
    4165                     if (date("I",$aVal)==1 && $this->iAdjustForDST ) // DST
    4166                         $aVal+=3600;
    4167 
    4168                     $l = date($this->label_dateformatstr,$aVal);
    4169                     if( $this->label_formatstr == 'W' ) {
    4170                         // If we use week formatting then add a single 'w' in front of the
    4171                         // week number to differentiate it from dates
    4172                         $l = 'w'.$l;
    4173                     }
    4174                 }
    4175                 else
    4176                     $l = sprintf($this->label_formatstr,$aVal);
    4177             }
    4178         }
    4179         else {
    4180             $l = sprintf('%01.'.$precision.'f',round($aVal,$precision));
    4181         }
    4182        
    4183         if( ($this->supress_zerolabel && $l==0) ||  ($this->supress_first && $aIdx==0) ||
    4184             ($this->supress_last  && $aIdx==$aNbrTicks-1) ) {
    4185             $l='';
    4186         }
    4187         return $l;
     4485        // If precision hasn't been specified set it to a sensible value
     4486        if( $this->precision==-1 ) {
     4487            $t = log10($this->minor_step);
     4488            if( $t > 0 || $t === 0.0) {
     4489                $precision = 0;
     4490            }
     4491            else {
     4492                $precision = -floor($t);
     4493            }
     4494        }
     4495        else {
     4496            $precision = $this->precision;
     4497        }
     4498
     4499        if( $this->label_formfunc != '' ) {
     4500            $f=$this->label_formfunc;
     4501            if( $this->label_formatstr == '' ) {
     4502                $l = call_user_func($f,$aVal);
     4503            }
     4504            else {
     4505                $l = sprintf($this->label_formatstr, call_user_func($f,$aVal));
     4506            }
     4507        }
     4508        elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) {
     4509            if( $this->label_usedateformat ) {
     4510                // Adjust the value to take daylight savings into account
     4511                if (date("I",$aVal)==1 && $this->iAdjustForDST ) {
     4512                    // DST
     4513                    $aVal+=3600;
     4514                }
     4515
     4516                $l = date($this->label_formatstr,$aVal);
     4517                if( $this->label_formatstr == 'W' ) {
     4518                    // If we use week formatting then add a single 'w' in front of the
     4519                    // week number to differentiate it from dates
     4520                    $l = 'w'.$l;
     4521                }
     4522            }
     4523            else {
     4524                if( $this->label_dateformatstr !== '' ) {
     4525                    // Adjust the value to take daylight savings into account
     4526                    if (date("I",$aVal)==1 && $this->iAdjustForDST ) {
     4527                        // DST
     4528                        $aVal+=3600;
     4529                    }
     4530
     4531                    $l = date($this->label_dateformatstr,$aVal);
     4532                    if( $this->label_formatstr == 'W' ) {
     4533                        // If we use week formatting then add a single 'w' in front of the
     4534                        // week number to differentiate it from dates
     4535                        $l = 'w'.$l;
     4536                    }
     4537                }
     4538                else {
     4539                    $l = sprintf($this->label_formatstr,$aVal);
     4540                }
     4541            }
     4542        }
     4543        else {
     4544            $l = sprintf('%01.'.$precision.'f',round($aVal,$precision));
     4545        }
     4546
     4547        if( ($this->supress_zerolabel && $l==0) ||  ($this->supress_first && $aIdx==0) || ($this->supress_last  && $aIdx==$aNbrTicks-1) ) {
     4548            $l='';
     4549        }
     4550        return $l;
    41884551    }
    41894552
    41904553    // Stroke ticks on either X or Y axis
    41914554    function _StrokeTicks($aImg,$aScale,$aPos) {
    4192         $hor = $aScale->type == 'x';
    4193         $aImg->SetLineWeight($this->weight);
    4194 
    4195         // We need to make this an int since comparing it below
    4196         // with the result from round() can give wrong result, such that
    4197         // (40 < 40) == TRUE !!!       
    4198         $limit = (int)$aScale->scale_abs[1];
    4199                
    4200         // A text scale doesn't have any minor ticks
    4201         if( !$aScale->textscale ) {
    4202             // Stroke minor ticks
    4203             $yu = $aPos - $this->direction*$this->GetMinTickAbsSize();
    4204             $xr = $aPos + $this->direction*$this->GetMinTickAbsSize();
    4205             $n = count($this->ticks_pos);
    4206             for($i=0; $i < $n; ++$i ) {
    4207                 if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) {
    4208                     if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor);
    4209                     if( $hor ) {
    4210                         //if( $this->ticks_pos[$i] <= $limit )
    4211                         $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu);
    4212                     }
    4213                     else {
    4214                         //if( $this->ticks_pos[$i] >= $limit )
    4215                         $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]);
    4216                     }
    4217                     if( $this->mincolor!="" ) $aImg->PopColor();
    4218                 }
    4219             }
    4220         }
    4221 
    4222         // Stroke major ticks
    4223         $yu = $aPos - $this->direction*$this->GetMajTickAbsSize();
    4224         $xr = $aPos + $this->direction*$this->GetMajTickAbsSize();
    4225         $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
    4226         $n = count($this->maj_ticks_pos);
    4227         for($i=0; $i < $n ; ++$i ) {
    4228             if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) {
    4229                 if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor);
    4230                 if( $hor ) {
    4231                     //if( $this->maj_ticks_pos[$i] <= $limit )
    4232                     $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu);
    4233                 }
    4234                 else {
    4235                     //if( $this->maj_ticks_pos[$i] >= $limit )
    4236                     $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]);
    4237                 }
    4238                 if( $this->majcolor!="" ) $aImg->PopColor();
    4239             }
    4240         }
    4241        
     4555        $hor = $aScale->type == 'x';
     4556        $aImg->SetLineWeight($this->weight);
     4557
     4558        // We need to make this an int since comparing it below
     4559        // with the result from round() can give wrong result, such that
     4560        // (40 < 40) == TRUE !!!
     4561        $limit = (int)$aScale->scale_abs[1];
     4562
     4563        // A text scale doesn't have any minor ticks
     4564        if( !$aScale->textscale ) {
     4565            // Stroke minor ticks
     4566            $yu = $aPos - $this->direction*$this->GetMinTickAbsSize();
     4567            $xr = $aPos + $this->direction*$this->GetMinTickAbsSize();
     4568            $n = count($this->ticks_pos);
     4569            for($i=0; $i < $n; ++$i ) {
     4570                if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) {
     4571                    if( $this->mincolor != '') {
     4572                        $aImg->PushColor($this->mincolor);
     4573                    }
     4574                    if( $hor ) {
     4575                        //if( $this->ticks_pos[$i] <= $limit )
     4576                        $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu);
     4577                    }
     4578                    else {
     4579                        //if( $this->ticks_pos[$i] >= $limit )
     4580                        $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]);
     4581                    }
     4582                    if( $this->mincolor != '' ) {
     4583                        $aImg->PopColor();
     4584                    }
     4585                }
     4586            }
     4587        }
     4588
     4589        // Stroke major ticks
     4590        $yu = $aPos - $this->direction*$this->GetMajTickAbsSize();
     4591        $xr = $aPos + $this->direction*$this->GetMajTickAbsSize();
     4592        $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
     4593        $n = count($this->maj_ticks_pos);
     4594        for($i=0; $i < $n ; ++$i ) {
     4595            if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) {
     4596                if( $this->majcolor != '') {
     4597                    $aImg->PushColor($this->majcolor);
     4598                }
     4599                if( $hor ) {
     4600                    //if( $this->maj_ticks_pos[$i] <= $limit )
     4601                    $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu);
     4602                }
     4603                else {
     4604                    //if( $this->maj_ticks_pos[$i] >= $limit )
     4605                    $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]);
     4606                }
     4607                if( $this->majcolor != '') {
     4608                    $aImg->PopColor();
     4609                }
     4610            }
     4611        }
     4612
    42424613    }
    42434614
    42444615    // Draw linear ticks
    42454616    function Stroke($aImg,$aScale,$aPos) {
    4246         if( $this->iManualTickPos != NULL )
    4247             $this->_doManualTickPos($aScale);
    4248         else
    4249             $this->_doAutoTickPos($aScale);
    4250         $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' );
    4251     }
    4252 
    4253 //---------------
    4254 // PRIVATE METHODS
     4617        if( $this->iManualTickPos != NULL ) {
     4618            $this->_doManualTickPos($aScale);
     4619        }
     4620        else {
     4621            $this->_doAutoTickPos($aScale);
     4622        }
     4623        $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' );
     4624    }
     4625
     4626    //---------------
     4627    // PRIVATE METHODS
    42554628    // Spoecify the offset of the displayed tick mark with the tick "space"
    4256     // Legal values for $o is [0,1] used to adjust where the tick marks and label 
     4629    // Legal values for $o is [0,1] used to adjust where the tick marks and label
    42574630    // should be positioned within the major tick-size
    42584631    // $lo specifies the label offset and $to specifies the tick offset
     
    42604633    // tick but have the labels displayed halfway under the bars.
    42614634    function SetXLabelOffset($aLabelOff,$aTickOff=-1) {
    4262         $this->xlabel_offset=$aLabelOff;
    4263         if( $aTickOff==-1 )     // Same as label offset
    4264             $this->xtick_offset=$aLabelOff;
    4265         else
    4266             $this->xtick_offset=$aTickOff;
    4267         if( $aLabelOff>0 )
    4268             $this->SupressLast();       // The last tick wont fit
     4635        $this->xlabel_offset=$aLabelOff;
     4636        if( $aTickOff==-1 ) {
     4637            // Same as label offset
     4638            $this->xtick_offset=$aLabelOff;
     4639        }
     4640        else {
     4641            $this->xtick_offset=$aTickOff;
     4642        }
     4643        if( $aLabelOff>0 ) {
     4644            $this->SupressLast(); // The last tick wont fit
     4645        }
    42694646    }
    42704647
    42714648    // Which tick label should we start with?
    42724649    function SetTextLabelStart($aTextLabelOff) {
    4273         $this->text_label_start=$aTextLabelOff;
    4274     }
    4275        
     4650        $this->text_label_start=$aTextLabelOff;
     4651    }
     4652
    42764653} // Class
    42774654
    42784655//===================================================
    42794656// CLASS LinearScale
    4280 // Description: Handle linear scaling between screen and world 
     4657// Description: Handle linear scaling between screen and world
    42814658//===================================================
    42824659class LinearScale {
     
    42974674    public $auto_ticks=false; // When using manual scale should the ticks be automatically set?
    42984675    public $world_abs_size; // Plot area size in pixels (Needed public in jpgraph_radar.php)
    4299     public $world_size; // Plot area size in world coordinates
    43004676    public $intscale=false; // Restrict autoscale to integers
    43014677    protected $autoscale_min=false; // Forced minimum value, auto determine max
    43024678    protected $autoscale_max=false; // Forced maximum value, auto determine min
    43034679    private $gracetop=0,$gracebottom=0;
    4304 //---------------
    4305 // CONSTRUCTOR
    4306     function LinearScale($aMin=0,$aMax=0,$aType="y") {
    4307         assert($aType=="x" || $aType=="y" );
    4308         assert($aMin<=$aMax);
    4309                
    4310         $this->type=$aType;
    4311         $this->scale=array($aMin,$aMax);               
    4312         $this->world_size=$aMax-$aMin; 
    4313         $this->ticks = new LinearTicks();
    4314     }
    4315 
    4316 //---------------
    4317 // PUBLIC METHODS       
     4680
     4681    private $_world_size; // Plot area size in world coordinates
     4682
     4683    function __construct($aMin=0,$aMax=0,$aType='y') {
     4684        assert($aType=='x' || $aType=='y' );
     4685        assert($aMin<=$aMax);
     4686
     4687        $this->type=$aType;
     4688        $this->scale=array($aMin,$aMax);
     4689        $this->world_size=$aMax-$aMin;
     4690        $this->ticks = new LinearTicks();
     4691    }
     4692
    43184693    // Check if scale is set or if we should autoscale
    43194694    // We should do this is either scale or ticks has not been set
    43204695    function IsSpecified() {
    4321         if( $this->GetMinVal()==$this->GetMaxVal() ) {          // Scale not set
    4322             return false;
    4323         }
    4324         return true;
    4325     }
    4326        
    4327     // Set the minimum data value when the autoscaling is used. 
     4696        if( $this->GetMinVal()==$this->GetMaxVal() ) {  // Scale not set
     4697            return false;
     4698        }
     4699        return true;
     4700    }
     4701
     4702    // Set the minimum data value when the autoscaling is used.
    43284703    // Usefull if you want a fix minimum (like 0) but have an
    43294704    // automatic maximum
    43304705    function SetAutoMin($aMin) {
    4331         $this->autoscale_min=$aMin;
    4332     }
    4333 
    4334     // Set the minimum data value when the autoscaling is used. 
     4706        $this->autoscale_min=$aMin;
     4707    }
     4708
     4709    // Set the minimum data value when the autoscaling is used.
    43354710    // Usefull if you want a fix minimum (like 0) but have an
    43364711    // automatic maximum
    43374712    function SetAutoMax($aMax) {
    4338         $this->autoscale_max=$aMax;
     4713        $this->autoscale_max=$aMax;
    43394714    }
    43404715
     
    43424717    // still be set automatically?
    43434718    function SetAutoTicks($aFlag=true) {
    4344         $this->auto_ticks = $aFlag;
     4719        $this->auto_ticks = $aFlag;
    43454720    }
    43464721
    43474722    // Specify scale "grace" value (top and bottom)
    43484723    function SetGrace($aGraceTop,$aGraceBottom=0) {
    4349         if( $aGraceTop<0 || $aGraceBottom < 0  )
    4350             JpGraphError::RaiseL(25069);//(" Grace must be larger then 0");
    4351         $this->gracetop=$aGraceTop;
    4352         $this->gracebottom=$aGraceBottom;
    4353     }
    4354        
     4724        if( $aGraceTop<0 || $aGraceBottom < 0  ) {
     4725            JpGraphError::RaiseL(25069);//(" Grace must be larger then 0");
     4726        }
     4727        $this->gracetop=$aGraceTop;
     4728        $this->gracebottom=$aGraceBottom;
     4729    }
     4730
    43554731    // Get the minimum value in the scale
    43564732    function GetMinVal() {
    4357         return $this->scale[0];
    4358     }
    4359        
     4733        return $this->scale[0];
     4734    }
     4735
    43604736    // get maximum value for scale
    43614737    function GetMaxVal() {
    4362         return $this->scale[1];
    4363     }
    4364                
    4365     // Specify a new min/max value for sclae   
     4738        return $this->scale[1];
     4739    }
     4740
     4741    // Specify a new min/max value for sclae
    43664742    function Update($aImg,$aMin,$aMax) {
    4367         $this->scale=array($aMin,$aMax);               
    4368         $this->world_size=$aMax-$aMin;         
    4369         $this->InitConstants($aImg);                                   
    4370     }
    4371        
     4743        $this->scale=array($aMin,$aMax);
     4744        $this->world_size=$aMax-$aMin;
     4745        $this->InitConstants($aImg);
     4746    }
     4747
    43724748    // Translate between world and screen
    43734749    function Translate($aCoord) {
    4374         if( !is_numeric($aCoord) ) {
    4375             if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' )
    4376                 JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.');
    4377             return 0;
    4378         }
    4379         else {
    4380             return $this->off+($aCoord - $this->scale[0]) * $this->scale_factor;
    4381         }
    4382     }
    4383        
     4750        if( !is_numeric($aCoord) ) {
     4751            if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) {
     4752                JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.');
     4753            }
     4754            return 0;
     4755        }
     4756        else {
     4757            return round($this->off+($aCoord - $this->scale[0]) * $this->scale_factor);
     4758        }
     4759    }
     4760
    43844761    // Relative translate (don't include offset) usefull when we just want
    43854762    // to know the relative position (in pixels) on the axis
    43864763    function RelTranslate($aCoord) {
    4387         if( !is_numeric($aCoord) ) {
    4388             if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x'  )
    4389                 JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.');
    4390             return 0;
    4391         }
    4392         else {
    4393             return ($aCoord - $this->scale[0]) * $this->scale_factor;
    4394         }
    4395     }
    4396        
     4764        if( !is_numeric($aCoord) ) {
     4765            if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x'  ) {
     4766                JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.');
     4767            }
     4768            return 0;
     4769        }
     4770        else {
     4771            return ($aCoord - $this->scale[0]) * $this->scale_factor;
     4772        }
     4773    }
     4774
    43974775    // Restrict autoscaling to only use integers
    43984776    function SetIntScale($aIntScale=true) {
    4399         $this->intscale=$aIntScale;
    4400     }
    4401        
     4777        $this->intscale=$aIntScale;
     4778    }
     4779
    44024780    // Calculate an integer autoscale
    44034781    function IntAutoScale($img,$min,$max,$maxsteps,$majend=true) {
    4404         // Make sure limits are integers
    4405         $min=floor($min);
    4406         $max=ceil($max);
    4407         if( abs($min-$max)==0 ) {
    4408             --$min; ++$max;
    4409         }
    4410         $maxsteps = floor($maxsteps);
    4411                
    4412         $gracetop=round(($this->gracetop/100.0)*abs($max-$min));
    4413         $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min));
    4414         if( is_numeric($this->autoscale_min) ) {
    4415             $min = ceil($this->autoscale_min);
    4416             if( $min >= $max ) {
    4417                 JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');
    4418             }
    4419         }
    4420 
    4421         if( is_numeric($this->autoscale_max) ) {
    4422             $max = ceil($this->autoscale_max);
    4423             if( $min >= $max ) {
    4424                 JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');
    4425             }
    4426         }
    4427 
    4428         if( abs($min-$max ) == 0 ) {
    4429             ++$max;
    4430             --$min;
    4431         }
    4432                        
    4433         $min -= $gracebottom;
    4434         $max += $gracetop;             
    4435 
    4436         // First get tickmarks as multiples of 1, 10, ...       
    4437         if( $majend ) {
    4438             list($num1steps,$adj1min,$adj1max,$maj1step) =
    4439                 $this->IntCalcTicks($maxsteps,$min,$max,1);
    4440         }
    4441         else {
    4442             $adj1min = $min;
    4443             $adj1max = $max;
    4444             list($num1steps,$maj1step) =
    4445                 $this->IntCalcTicksFreeze($maxsteps,$min,$max,1);
    4446         }
    4447 
    4448         if( abs($min-$max) > 2 ) {
    4449             // Then get tick marks as 2:s 2, 20, ...
    4450             if( $majend ) {
    4451                 list($num2steps,$adj2min,$adj2max,$maj2step) =
    4452                     $this->IntCalcTicks($maxsteps,$min,$max,5);
    4453             }
    4454             else {
    4455                 $adj2min = $min;
    4456                 $adj2max = $max;
    4457                 list($num2steps,$maj2step) =
    4458                     $this->IntCalcTicksFreeze($maxsteps,$min,$max,5);
    4459             }
    4460         }
    4461         else {
    4462             $num2steps = 10000; // Dummy high value so we don't choose this
    4463         }
    4464        
    4465         if( abs($min-$max) > 5 ) {     
    4466             // Then get tickmarks as 5:s 5, 50, 500, ...
    4467             if( $majend ) {
    4468                 list($num5steps,$adj5min,$adj5max,$maj5step) =
    4469                     $this->IntCalcTicks($maxsteps,$min,$max,2);
    4470             }
    4471             else {
    4472                 $adj5min = $min;
    4473                 $adj5max = $max;
    4474                 list($num5steps,$maj5step) =
    4475                     $this->IntCalcTicksFreeze($maxsteps,$min,$max,2);
    4476             }
    4477         }
    4478         else {
    4479             $num5steps = 10000; // Dummy high value so we don't choose this             
    4480         }
    4481        
    4482         // Check to see whichof 1:s, 2:s or 5:s fit better with
    4483         // the requested number of major ticks         
    4484         $match1=abs($num1steps-$maxsteps);             
    4485         $match2=abs($num2steps-$maxsteps);
    4486         if( !empty($maj5step) && $maj5step > 1 )
    4487             $match5=abs($num5steps-$maxsteps);
    4488         else
    4489             $match5=10000;      // Dummy high value
    4490                
    4491         // Compare these three values and see which is the closest match
    4492         // We use a 0.6 weight to gravitate towards multiple of 5:s
    4493         if( $match1 < $match2 ) {
    4494             if( $match1 < $match5 )
    4495                 $r=1;                   
    4496             else
    4497                 $r=3;
    4498         }
    4499         else {
    4500             if( $match2 < $match5 )
    4501                 $r=2;                   
    4502             else
    4503                 $r=3;           
    4504         }       
    4505         // Minsteps are always the same as maxsteps for integer scale
    4506         switch( $r ) {
    4507             case 1:
    4508                 $this->ticks->Set($maj1step,$maj1step);
    4509                 $this->Update($img,$adj1min,$adj1max);
    4510                 break;                 
    4511             case 2:
    4512                 $this->ticks->Set($maj2step,$maj2step);
    4513                 $this->Update($img,$adj2min,$adj2max);         
    4514                 break;                                                                 
    4515             case 3:
    4516                 $this->ticks->Set($maj5step,$maj5step);         
    4517                 $this->Update($img,$adj5min,$adj5max);
    4518                 break;                 
    4519             default:
    4520                 JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)');
    4521         }               
    4522     }
    4523        
    4524        
     4782        // Make sure limits are integers
     4783        $min=floor($min);
     4784        $max=ceil($max);
     4785        if( abs($min-$max)==0 ) {
     4786            --$min; ++$max;
     4787        }
     4788        $maxsteps = floor($maxsteps);
     4789
     4790        $gracetop=round(($this->gracetop/100.0)*abs($max-$min));
     4791        $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min));
     4792        if( is_numeric($this->autoscale_min) ) {
     4793            $min = ceil($this->autoscale_min);
     4794            if( $min >= $max ) {
     4795                JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');
     4796            }
     4797        }
     4798
     4799        if( is_numeric($this->autoscale_max) ) {
     4800            $max = ceil($this->autoscale_max);
     4801            if( $min >= $max ) {
     4802                JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');
     4803            }
     4804        }
     4805
     4806        if( abs($min-$max ) == 0 ) {
     4807            ++$max;
     4808            --$min;
     4809        }
     4810
     4811        $min -= $gracebottom;
     4812        $max += $gracetop;
     4813
     4814        // First get tickmarks as multiples of 1, 10, ...
     4815        if( $majend ) {
     4816            list($num1steps,$adj1min,$adj1max,$maj1step) = $this->IntCalcTicks($maxsteps,$min,$max,1);
     4817        }
     4818        else {
     4819            $adj1min = $min;
     4820            $adj1max = $max;
     4821            list($num1steps,$maj1step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,1);
     4822        }
     4823
     4824        if( abs($min-$max) > 2 ) {
     4825            // Then get tick marks as 2:s 2, 20, ...
     4826            if( $majend ) {
     4827                list($num2steps,$adj2min,$adj2max,$maj2step) = $this->IntCalcTicks($maxsteps,$min,$max,5);
     4828            }
     4829            else {
     4830                $adj2min = $min;
     4831                $adj2max = $max;
     4832                list($num2steps,$maj2step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,5);
     4833            }
     4834        }
     4835        else {
     4836            $num2steps = 10000; // Dummy high value so we don't choose this
     4837        }
     4838
     4839        if( abs($min-$max) > 5 ) {
     4840            // Then get tickmarks as 5:s 5, 50, 500, ...
     4841            if( $majend ) {
     4842                list($num5steps,$adj5min,$adj5max,$maj5step) = $this->IntCalcTicks($maxsteps,$min,$max,2);
     4843            }
     4844            else {
     4845                $adj5min = $min;
     4846                $adj5max = $max;
     4847                list($num5steps,$maj5step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,2);
     4848            }
     4849        }
     4850        else {
     4851            $num5steps = 10000; // Dummy high value so we don't choose this
     4852        }
     4853
     4854        // Check to see whichof 1:s, 2:s or 5:s fit better with
     4855        // the requested number of major ticks
     4856        $match1=abs($num1steps-$maxsteps);
     4857        $match2=abs($num2steps-$maxsteps);
     4858        if( !empty($maj5step) && $maj5step > 1 ) {
     4859            $match5=abs($num5steps-$maxsteps);
     4860        }
     4861        else {
     4862            $match5=10000;  // Dummy high value
     4863        }
     4864
     4865        // Compare these three values and see which is the closest match
     4866        // We use a 0.6 weight to gravitate towards multiple of 5:s
     4867        if( $match1 < $match2 ) {
     4868            if( $match1 < $match5 ) $r=1;
     4869            else  $r=3;
     4870        }
     4871        else {
     4872            if( $match2 < $match5 ) $r=2;
     4873            else $r=3;
     4874        }
     4875        // Minsteps are always the same as maxsteps for integer scale
     4876        switch( $r ) {
     4877            case 1:
     4878                $this->ticks->Set($maj1step,$maj1step);
     4879                $this->Update($img,$adj1min,$adj1max);
     4880                break;
     4881            case 2:
     4882                $this->ticks->Set($maj2step,$maj2step);
     4883                $this->Update($img,$adj2min,$adj2max);
     4884                break;
     4885            case 3:
     4886                $this->ticks->Set($maj5step,$maj5step);
     4887                $this->Update($img,$adj5min,$adj5max);
     4888                break;
     4889            default:
     4890                JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)');
     4891        }
     4892    }
     4893
     4894
    45254895    // Calculate autoscale. Used if user hasn't given a scale and ticks
    45264896    // $maxsteps is the maximum number of major tickmarks allowed.
    45274897    function AutoScale($img,$min,$max,$maxsteps,$majend=true) {
    4528         if( $this->intscale ) {
    4529             $this->IntAutoScale($img,$min,$max,$maxsteps,$majend);
    4530             return;
    4531         }
    4532         if( abs($min-$max) < 0.00001 ) {
    4533             // We need some difference to be able to autoscale
    4534             // make it 5% above and 5% below value
    4535             if( $min==0 && $max==0 ) {          // Special case
    4536                 $min=-1; $max=1;
    4537             }
    4538             else {
    4539                 $delta = (abs($max)+abs($min))*0.005;
    4540                 $min -= $delta;
    4541                 $max += $delta;
    4542             }
    4543         }
    4544                
    4545         $gracetop=($this->gracetop/100.0)*abs($max-$min);
    4546         $gracebottom=($this->gracebottom/100.0)*abs($max-$min);
    4547         if( is_numeric($this->autoscale_min) ) {
    4548             $min = $this->autoscale_min;
    4549             if( $min >= $max ) {
    4550                 JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');
    4551             }
    4552             if( abs($min-$max ) < 0.00001 )
    4553                 $max *= 1.2;
    4554         }
    4555 
    4556         if( is_numeric($this->autoscale_max) ) {
    4557             $max = $this->autoscale_max;
    4558             if( $min >= $max ) {
    4559                 JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');
    4560             }
    4561             if( abs($min-$max ) < 0.00001 )
    4562                 $min *= 0.8;
    4563         }
    4564 
    4565         $min -= $gracebottom;
    4566         $max += $gracetop;
    4567 
    4568 
    4569         // First get tickmarks as multiples of 0.1, 1, 10, ... 
    4570         if( $majend ) {
    4571             list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) =
    4572                 $this->CalcTicks($maxsteps,$min,$max,1,2);
    4573         }
    4574         else {
    4575             $adj1min=$min;
    4576             $adj1max=$max;
    4577             list($num1steps,$min1step,$maj1step) =
    4578                 $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false);
    4579         }
    4580                
    4581         // Then get tick marks as 2:s 0.2, 2, 20, ...
    4582         if( $majend ) {
    4583             list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) =
    4584                 $this->CalcTicks($maxsteps,$min,$max,5,2);
    4585         }
    4586         else {
    4587             $adj2min=$min;
    4588             $adj2max=$max;
    4589             list($num2steps,$min2step,$maj2step) =
    4590                 $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false);
    4591         }
    4592                
    4593         // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ...
    4594         if( $majend ) {
    4595             list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) =
    4596                 $this->CalcTicks($maxsteps,$min,$max,2,5);             
    4597         }
    4598         else {
    4599             $adj5min=$min;
    4600             $adj5max=$max;
    4601             list($num5steps,$min5step,$maj5step) =
    4602                 $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false);
    4603         }
    4604 
    4605         // Check to see whichof 1:s, 2:s or 5:s fit better with
    4606         // the requested number of major ticks         
    4607         $match1=abs($num1steps-$maxsteps);             
    4608         $match2=abs($num2steps-$maxsteps);
    4609         $match5=abs($num5steps-$maxsteps);
    4610         // Compare these three values and see which is the closest match
    4611         // We use a 0.8 weight to gravitate towards multiple of 5:s
    4612         $r=$this->MatchMin3($match1,$match2,$match5,0.8);
    4613         switch( $r ) {
    4614             case 1:
    4615                 $this->Update($img,$adj1min,$adj1max);
    4616                 $this->ticks->Set($maj1step,$min1step);
    4617                 break;                 
    4618             case 2:
    4619                 $this->Update($img,$adj2min,$adj2max);         
    4620                 $this->ticks->Set($maj2step,$min2step);
    4621                 break;                                                                 
    4622             case 3:
    4623                 $this->Update($img,$adj5min,$adj5max);
    4624                 $this->ticks->Set($maj5step,$min5step);         
    4625                 break;                 
    4626         }
    4627     }
    4628 
    4629 //---------------
    4630 // PRIVATE METHODS     
     4898
     4899        if( !is_numeric($min) || !is_numeric($max) ) {
     4900            JpGraphError::Raise(25044);
     4901        }
     4902
     4903        if( $this->intscale ) {
     4904            $this->IntAutoScale($img,$min,$max,$maxsteps,$majend);
     4905            return;
     4906        }
     4907        if( abs($min-$max) < 0.00001 ) {
     4908            // We need some difference to be able to autoscale
     4909            // make it 5% above and 5% below value
     4910            if( $min==0 && $max==0 ) {  // Special case
     4911                $min=-1; $max=1;
     4912            }
     4913            else {
     4914                $delta = (abs($max)+abs($min))*0.005;
     4915                $min -= $delta;
     4916                $max += $delta;
     4917            }
     4918        }
     4919
     4920        $gracetop=($this->gracetop/100.0)*abs($max-$min);
     4921        $gracebottom=($this->gracebottom/100.0)*abs($max-$min);
     4922        if( is_numeric($this->autoscale_min) ) {
     4923            $min = $this->autoscale_min;
     4924            if( $min >= $max ) {
     4925                JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.');
     4926            }
     4927            if( abs($min-$max ) < 0.001 ) {
     4928                $max *= 1.2;
     4929            }
     4930        }
     4931
     4932        if( is_numeric($this->autoscale_max) ) {
     4933            $max = $this->autoscale_max;
     4934            if( $min >= $max ) {
     4935                JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.');
     4936            }
     4937            if( abs($min-$max ) < 0.001 ) {
     4938                $min *= 0.8;
     4939            }
     4940        }
     4941
     4942        $min -= $gracebottom;
     4943        $max += $gracetop;
     4944
     4945        // First get tickmarks as multiples of 0.1, 1, 10, ...
     4946        if( $majend ) {
     4947            list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = $this->CalcTicks($maxsteps,$min,$max,1,2);
     4948        }
     4949        else {
     4950            $adj1min=$min;
     4951            $adj1max=$max;
     4952            list($num1steps,$min1step,$maj1step) = $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false);
     4953        }
     4954
     4955        // Then get tick marks as 2:s 0.2, 2, 20, ...
     4956        if( $majend ) {
     4957            list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = $this->CalcTicks($maxsteps,$min,$max,5,2);
     4958        }
     4959        else {
     4960            $adj2min=$min;
     4961            $adj2max=$max;
     4962            list($num2steps,$min2step,$maj2step) = $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false);
     4963        }
     4964
     4965        // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ...
     4966        if( $majend ) {
     4967            list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = $this->CalcTicks($maxsteps,$min,$max,2,5);
     4968        }
     4969        else {
     4970            $adj5min=$min;
     4971            $adj5max=$max;
     4972            list($num5steps,$min5step,$maj5step) = $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false);
     4973        }
     4974
     4975        // Check to see whichof 1:s, 2:s or 5:s fit better with
     4976        // the requested number of major ticks
     4977        $match1=abs($num1steps-$maxsteps);
     4978        $match2=abs($num2steps-$maxsteps);
     4979        $match5=abs($num5steps-$maxsteps);
     4980
     4981        // Compare these three values and see which is the closest match
     4982        // We use a 0.8 weight to gravitate towards multiple of 5:s
     4983        $r=$this->MatchMin3($match1,$match2,$match5,0.8);
     4984        switch( $r ) {
     4985            case 1:
     4986                $this->Update($img,$adj1min,$adj1max);
     4987                $this->ticks->Set($maj1step,$min1step);
     4988                break;
     4989            case 2:
     4990                $this->Update($img,$adj2min,$adj2max);
     4991                $this->ticks->Set($maj2step,$min2step);
     4992                break;
     4993            case 3:
     4994                $this->Update($img,$adj5min,$adj5max);
     4995                $this->ticks->Set($maj5step,$min5step);
     4996                break;
     4997        }
     4998    }
     4999
     5000    //---------------
     5001    // PRIVATE METHODS
    46315002
    46325003    // This method recalculates all constants that are depending on the
     
    46355006    // that image. Should really be installed as an observer of that image.
    46365007    function InitConstants($img) {
    4637         if( $this->type=="x" ) {
    4638             $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin;
    4639             $this->off=$img->left_margin;
    4640             $this->scale_factor = 0;
    4641             if( $this->world_size > 0 )
    4642                 $this->scale_factor=$this->world_abs_size/($this->world_size*1.0);
    4643         }
    4644         else { // y scale
    4645             $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin;
    4646             $this->off=$img->top_margin+$this->world_abs_size;                 
    4647             $this->scale_factor = 0;                   
    4648             if( $this->world_size > 0 )                 
    4649                 $this->scale_factor=-$this->world_abs_size/($this->world_size*1.0);     
    4650         }
    4651         $size = $this->world_size * $this->scale_factor;
    4652         $this->scale_abs=array($this->off,$this->off + $size); 
    4653     }
    4654        
     5008        if( $this->type=='x' ) {
     5009            $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin;
     5010            $this->off=$img->left_margin;
     5011            $this->scale_factor = 0;
     5012            if( $this->world_size > 0 ) {
     5013                $this->scale_factor=$this->world_abs_size/($this->world_size*0.999999);
     5014            }
     5015        }
     5016        else { // y scale
     5017            $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin;
     5018            $this->off=$img->top_margin+$this->world_abs_size;
     5019            $this->scale_factor = 0;
     5020            if( $this->world_size > 0 ) {
     5021                $this->scale_factor=-$this->world_abs_size/($this->world_size*0.999999);
     5022            }
     5023        }
     5024        $size = $this->world_size * $this->scale_factor;
     5025        $this->scale_abs=array($this->off,$this->off + $size);
     5026    }
     5027
    46555028    // Initialize the conversion constants for this scale
    46565029    // This tries to pre-calculate as much as possible to speed up the
    46575030    // actual conversion (with Translate()) later on
    4658     // $start   =scale start in absolute pixels (for x-scale this is an y-position
    4659     //                          and for an y-scale this is an x-position
    4660     // $len             =absolute length in pixels of scale                     
     5031    // $start =scale start in absolute pixels (for x-scale this is an y-position
     5032    //    and for an y-scale this is an x-position
     5033    // $len   =absolute length in pixels of scale
    46615034    function SetConstants($aStart,$aLen) {
    4662         $this->world_abs_size=$aLen;
    4663         $this->off=$aStart;
    4664                
    4665         if( $this->world_size<=0 ) {
    4666             // This should never ever happen !!
    4667             JpGraphError::RaiseL(25074);
    4668 //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale] <br> Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail.");
    4669 
    4670         }
    4671                
    4672         // scale_factor = number of pixels per world unit
    4673         $this->scale_factor=$this->world_abs_size/($this->world_size*1.0);
    4674                
    4675         // scale_abs = start and end points of scale in absolute pixels
    4676         $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor);           
    4677     }
    4678        
    4679        
     5035        $this->world_abs_size=$aLen;
     5036        $this->off=$aStart;
     5037
     5038        if( $this->world_size<=0 ) {
     5039            // This should never ever happen !!
     5040            JpGraphError::RaiseL(25074);
     5041            //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale] <br> Please report Bug #01 to info@jpgraph.net and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail.");
     5042        }
     5043
     5044        // scale_factor = number of pixels per world unit
     5045        $this->scale_factor=$this->world_abs_size/($this->world_size*1.0);
     5046
     5047        // scale_abs = start and end points of scale in absolute pixels
     5048        $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor);
     5049    }
     5050
     5051
    46805052    // Calculate number of ticks steps with a specific division
    46815053    // $a is the divisor of 10**x to generate the first maj tick intervall
     
    46845056    // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,...
    46855057    // We return a vector of
    4686     //  [$numsteps,$adjmin,$adjmax,$minstep,$majstep]
     5058    //  [$numsteps,$adjmin,$adjmax,$minstep,$majstep]
    46875059    // If $majend==true then the first and last marks on the axis will be major
    46885060    // labeled tick marks otherwise it will be adjusted to the closest min tick mark
    46895061    function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) {
    4690         $diff=$max-$min;
    4691         if( $diff==0 )
    4692             $ld=0;
    4693         else
    4694             $ld=floor(log10($diff));
    4695 
    4696         // Gravitate min towards zero if we are close           
    4697         if( $min>0 && $min < pow(10,$ld) ) $min=0;
    4698                
    4699         //$majstep=pow(10,$ld-1)/$a;
    4700         $majstep=pow(10,$ld)/$a;
    4701         $minstep=$majstep/$b;
    4702        
    4703         $adjmax=ceil($max/$minstep)*$minstep;
    4704         $adjmin=floor($min/$minstep)*$minstep; 
    4705         $adjdiff = $adjmax-$adjmin;
    4706         $numsteps=$adjdiff/$majstep;
    4707        
    4708         while( $numsteps>$maxsteps ) {
    4709             $majstep=pow(10,$ld)/$a;
    4710             $numsteps=$adjdiff/$majstep;
    4711             ++$ld;
    4712         }
    4713 
    4714         $minstep=$majstep/$b;
    4715         $adjmin=floor($min/$minstep)*$minstep; 
    4716         $adjdiff = $adjmax-$adjmin;             
    4717         if( $majend ) {
    4718             $adjmin = floor($min/$majstep)*$majstep;   
    4719             $adjdiff = $adjmax-$adjmin;         
    4720             $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin;
    4721         }
    4722         else
    4723             $adjmax=ceil($max/$minstep)*$minstep;
    4724 
    4725         return array($numsteps,$adjmin,$adjmax,$minstep,$majstep);
     5062        $diff=$max-$min;
     5063        if( $diff==0 ) {
     5064            $ld=0;
     5065        }
     5066        else {
     5067            $ld=floor(log10($diff));
     5068        }
     5069
     5070        // Gravitate min towards zero if we are close
     5071        if( $min>0 && $min < pow(10,$ld) ) $min=0;
     5072
     5073        //$majstep=pow(10,$ld-1)/$a;
     5074        $majstep=pow(10,$ld)/$a;
     5075        $minstep=$majstep/$b;
     5076
     5077        $adjmax=ceil($max/$minstep)*$minstep;
     5078        $adjmin=floor($min/$minstep)*$minstep;
     5079        $adjdiff = $adjmax-$adjmin;
     5080        $numsteps=$adjdiff/$majstep;
     5081
     5082        while( $numsteps>$maxsteps ) {
     5083            $majstep=pow(10,$ld)/$a;
     5084            $numsteps=$adjdiff/$majstep;
     5085            ++$ld;
     5086        }
     5087
     5088        $minstep=$majstep/$b;
     5089        $adjmin=floor($min/$minstep)*$minstep;
     5090        $adjdiff = $adjmax-$adjmin;
     5091        if( $majend ) {
     5092            $adjmin = floor($min/$majstep)*$majstep;
     5093            $adjdiff = $adjmax-$adjmin;
     5094            $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin;
     5095        }
     5096        else {
     5097            $adjmax=ceil($max/$minstep)*$minstep;
     5098        }
     5099
     5100        return array($numsteps,$adjmin,$adjmax,$minstep,$majstep);
    47265101    }
    47275102
    47285103    function CalcTicksFreeze($maxsteps,$min,$max,$a,$b) {
    4729         // Same as CalcTicks but don't adjust min/max values
    4730         $diff=$max-$min;
    4731         if( $diff==0 )
    4732             $ld=0;
    4733         else
    4734             $ld=floor(log10($diff));
    4735 
    4736         //$majstep=pow(10,$ld-1)/$a;
    4737         $majstep=pow(10,$ld)/$a;
    4738         $minstep=$majstep/$b;
    4739         $numsteps=floor($diff/$majstep);
    4740        
    4741         while( $numsteps > $maxsteps ) {
    4742             $majstep=pow(10,$ld)/$a;
    4743             $numsteps=floor($diff/$majstep);
    4744             ++$ld;
    4745         }
    4746         $minstep=$majstep/$b;
    4747         return array($numsteps,$minstep,$majstep);
    4748     }
    4749 
    4750        
     5104        // Same as CalcTicks but don't adjust min/max values
     5105        $diff=$max-$min;
     5106        if( $diff==0 ) {
     5107            $ld=0;
     5108        }
     5109        else {
     5110            $ld=floor(log10($diff));
     5111        }
     5112
     5113        //$majstep=pow(10,$ld-1)/$a;
     5114        $majstep=pow(10,$ld)/$a;
     5115        $minstep=$majstep/$b;
     5116        $numsteps=floor($diff/$majstep);
     5117
     5118        while( $numsteps > $maxsteps ) {
     5119            $majstep=pow(10,$ld)/$a;
     5120            $numsteps=floor($diff/$majstep);
     5121            ++$ld;
     5122        }
     5123        $minstep=$majstep/$b;
     5124        return array($numsteps,$minstep,$majstep);
     5125    }
     5126
     5127
    47515128    function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) {
    4752         $diff=$max-$min;
    4753         if( $diff==0 )
    4754             JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.');
    4755         else
    4756             $ld=floor(log10($diff));
    4757                
    4758         // Gravitate min towards zero if we are close           
    4759         if( $min>0 && $min < pow(10,$ld) ) $min=0;
    4760                
    4761         if( $ld == 0 ) $ld=1;
    4762        
    4763         if( $a == 1 )
    4764             $majstep = 1;
    4765         else
    4766             $majstep=pow(10,$ld)/$a;
    4767         $adjmax=ceil($max/$majstep)*$majstep;
    4768 
    4769         $adjmin=floor($min/$majstep)*$majstep; 
    4770         $adjdiff = $adjmax-$adjmin;
    4771         $numsteps=$adjdiff/$majstep;
    4772         while( $numsteps>$maxsteps ) {
    4773             $majstep=pow(10,$ld)/$a;
    4774             $numsteps=$adjdiff/$majstep;
    4775             ++$ld;
    4776         }
    4777                
    4778         $adjmin=floor($min/$majstep)*$majstep; 
    4779         $adjdiff = $adjmax-$adjmin;             
    4780         if( $majend ) {
    4781             $adjmin = floor($min/$majstep)*$majstep;   
    4782             $adjdiff = $adjmax-$adjmin;         
    4783             $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin;
    4784         }
    4785         else
    4786             $adjmax=ceil($max/$majstep)*$majstep;
    4787                        
    4788         return array($numsteps,$adjmin,$adjmax,$majstep);               
     5129        $diff=$max-$min;
     5130        if( $diff==0 ) {
     5131            JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.');
     5132        }
     5133        else {
     5134            $ld=floor(log10($diff));
     5135        }
     5136
     5137        // Gravitate min towards zero if we are close
     5138        if( $min>0 && $min < pow(10,$ld) ) {
     5139            $min=0;
     5140        }
     5141        if( $ld == 0 ) {
     5142            $ld=1;
     5143        }
     5144        if( $a == 1 ) {
     5145            $majstep = 1;
     5146        }
     5147        else {
     5148            $majstep=pow(10,$ld)/$a;
     5149        }
     5150        $adjmax=ceil($max/$majstep)*$majstep;
     5151
     5152        $adjmin=floor($min/$majstep)*$majstep;
     5153        $adjdiff = $adjmax-$adjmin;
     5154        $numsteps=$adjdiff/$majstep;
     5155        while( $numsteps>$maxsteps ) {
     5156            $majstep=pow(10,$ld)/$a;
     5157            $numsteps=$adjdiff/$majstep;
     5158            ++$ld;
     5159        }
     5160
     5161        $adjmin=floor($min/$majstep)*$majstep;
     5162        $adjdiff = $adjmax-$adjmin;
     5163        if( $majend ) {
     5164            $adjmin = floor($min/$majstep)*$majstep;
     5165            $adjdiff = $adjmax-$adjmin;
     5166            $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin;
     5167        }
     5168        else {
     5169            $adjmax=ceil($max/$majstep)*$majstep;
     5170        }
     5171
     5172        return array($numsteps,$adjmin,$adjmax,$majstep);
    47895173    }
    47905174
    47915175
    47925176    function IntCalcTicksFreeze($maxsteps,$min,$max,$a) {
    4793         // Same as IntCalcTick but don't change min/max values
    4794         $diff=$max-$min;
    4795         if( $diff==0 )
    4796             JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.');
    4797         else
    4798             $ld=floor(log10($diff));
    4799                
    4800         if( $ld == 0 ) $ld=1;
    4801        
    4802         if( $a == 1 )
    4803             $majstep = 1;
    4804         else
    4805             $majstep=pow(10,$ld)/$a;
    4806 
    4807         $numsteps=floor($diff/$majstep);
    4808         while( $numsteps > $maxsteps ) {
    4809             $majstep=pow(10,$ld)/$a;
    4810             $numsteps=floor($diff/$majstep);
    4811             ++$ld;
    4812         }
    4813                                        
    4814         return array($numsteps,$majstep);               
    4815     }
    4816 
    4817 
    4818        
     5177        // Same as IntCalcTick but don't change min/max values
     5178        $diff=$max-$min;
     5179        if( $diff==0 ) {
     5180            JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.');
     5181        }
     5182        else {
     5183            $ld=floor(log10($diff));
     5184        }
     5185        if( $ld == 0 ) {
     5186            $ld=1;
     5187        }
     5188        if( $a == 1 ) {
     5189            $majstep = 1;
     5190        }
     5191        else {
     5192            $majstep=pow(10,$ld)/$a;
     5193        }
     5194
     5195        $numsteps=floor($diff/$majstep);
     5196        while( $numsteps > $maxsteps ) {
     5197            $majstep=pow(10,$ld)/$a;
     5198            $numsteps=floor($diff/$majstep);
     5199            ++$ld;
     5200        }
     5201
     5202        return array($numsteps,$majstep);
     5203    }
     5204
    48195205    // Determine the minimum of three values witha  weight for last value
    48205206    function MatchMin3($a,$b,$c,$weight) {
    4821         if( $a < $b ) {
    4822             if( $a < ($c*$weight) )
    4823                 return 1; // $a smallest
    4824             else
    4825                 return 3; // $c smallest
    4826         }
    4827         elseif( $b < ($c*$weight) )
    4828             return 2; // $b smallest
    4829         return 3; // $c smallest
     5207        if( $a < $b ) {
     5208            if( $a < ($c*$weight) ) {
     5209                return 1; // $a smallest
     5210            }
     5211            else {
     5212                return 3; // $c smallest
     5213            }
     5214        }
     5215        elseif( $b < ($c*$weight) ) {
     5216            return 2; // $b smallest
     5217        }
     5218        return 3; // $c smallest
     5219    }
     5220
     5221    function __get($name) {
     5222        $variable_name = '_' . $name;
     5223
     5224        if (isset($this->$variable_name)) {
     5225            return $this->$variable_name * SUPERSAMPLING_SCALE;
     5226        } else {
     5227            JpGraphError::RaiseL('25132', $name);
     5228        }
     5229    }
     5230
     5231    function __set($name, $value) {
     5232        $this->{'_'.$name} = $value;
    48305233    }
    48315234} // Class
     
    48395242    public $margin=5;
    48405243    public $show=false;
    4841     public $valign="",$halign="center";
    4842     public $format="%.1f",$negformat="";
    4843     private $ff=FF_FONT1,$fs=FS_NORMAL,$fsize=10;
     5244    public $valign='',$halign='center';
     5245    public $format='%.1f',$negformat='';
     5246    private $ff=FF_DEFAULT,$fs=FS_NORMAL,$fsize=8;
    48445247    private $iFormCallback='';
    48455248    private $angle=0;
    4846     private $color="navy",$negcolor="";
     5249    private $color='navy',$negcolor='';
    48475250    private $iHideZero=false;
     5251    public $txt=null;
     5252
     5253    function __construct() {
     5254                $this->txt = new Text();
     5255    }
    48485256
    48495257    function Show($aFlag=true) {
    4850         $this->show=$aFlag;
    4851     }
    4852 
    4853     function SetColor($aColor,$aNegcolor="") {
    4854         $this->color = $aColor;
    4855         $this->negcolor = $aNegcolor;
    4856     }
    4857 
    4858     function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=10) {
    4859         $this->ff=$aFontFamily;
    4860         $this->fs=$aFontStyle;
    4861         $this->fsize=$aFontSize;
     5258        $this->show=$aFlag;
     5259    }
     5260
     5261    function SetColor($aColor,$aNegcolor='') {
     5262        $this->color = $aColor;
     5263        $this->negcolor = $aNegcolor;
     5264    }
     5265
     5266    function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=8) {
     5267        $this->ff=$aFontFamily;
     5268        $this->fs=$aFontStyle;
     5269        $this->fsize=$aFontSize;
    48625270    }
    48635271
    48645272    function ApplyFont($aImg) {
    4865         $aImg->SetFont($this->ff,$this->fs,$this->fsize);
     5273        $aImg->SetFont($this->ff,$this->fs,$this->fsize);
    48665274    }
    48675275
    48685276    function SetMargin($aMargin) {
    4869         $this->margin = $aMargin;
     5277        $this->margin = $aMargin;
    48705278    }
    48715279
    48725280    function SetAngle($aAngle) {
    4873         $this->angle = $aAngle;
     5281        $this->angle = $aAngle;
    48745282    }
    48755283
    48765284    function SetAlign($aHAlign,$aVAlign='') {
    4877         $this->halign = $aHAlign;
    4878         $this->valign = $aVAlign;
    4879     }
    4880 
    4881     function SetFormat($aFormat,$aNegFormat="") {
    4882         $this->format= $aFormat;
    4883         $this->negformat= $aNegFormat;
     5285        $this->halign = $aHAlign;
     5286        $this->valign = $aVAlign;
     5287    }
     5288
     5289    function SetFormat($aFormat,$aNegFormat='') {
     5290        $this->format= $aFormat;
     5291        $this->negformat= $aNegFormat;
    48845292    }
    48855293
    48865294    function SetFormatCallback($aFunc) {
    4887         $this->iFormCallback = $aFunc;
     5295        $this->iFormCallback = $aFunc;
    48885296    }
    48895297
    48905298    function HideZero($aFlag=true) {
    4891         $this->iHideZero=$aFlag;
     5299        $this->iHideZero=$aFlag;
    48925300    }
    48935301
    48945302    function Stroke($img,$aVal,$x,$y) {
    4895        
    4896         if( $this->show )
    4897         {
    4898             if( $this->negformat=="" ) $this->negformat=$this->format;
    4899             if( $this->negcolor=="" ) $this->negcolor=$this->color;
    4900 
    4901             if( $aVal===NULL || (is_string($aVal) && ($aVal=="" || $aVal=="-" || $aVal=="x" ) ) )
    4902                 return;
    4903 
    4904             if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) {
    4905                 return;
    4906             }
    4907 
    4908             // Since the value is used in different cirumstances we need to check what
    4909             // kind of formatting we shall use. For example, to display values in a line
    4910             // graph we simply display the formatted value, but in the case where the user
    4911             // has already specified a text string we don't fo anything.
    4912             if( $this->iFormCallback != '' ) {
    4913                 $f = $this->iFormCallback;
    4914                 $sval = call_user_func($f,$aVal);
    4915             }
    4916             elseif( is_numeric($aVal) ) {
    4917                 if( $aVal >= 0 )
    4918                     $sval=sprintf($this->format,$aVal);
    4919                 else
    4920                     $sval=sprintf($this->negformat,$aVal);
    4921             }
    4922             else
    4923                 $sval=$aVal;
    4924 
    4925             $y = $y-sign($aVal)*$this->margin;
    4926 
    4927             $txt = new Text($sval,$x,$y);
    4928             $txt->SetFont($this->ff,$this->fs,$this->fsize);
    4929             if( $this->valign == "" ) {
    4930                 if( $aVal >= 0 )
    4931                     $valign = "bottom";
    4932                 else
    4933                     $valign = "top";
    4934             }
    4935             else
    4936                 $valign = $this->valign;
    4937             $txt->Align($this->halign,$valign);
    4938 
    4939             $txt->SetOrientation($this->angle);
    4940             if( $aVal > 0 )
    4941                 $txt->SetColor($this->color);
    4942             else
    4943                 $txt->SetColor($this->negcolor);
    4944             $txt->Stroke($img);
    4945         }
     5303
     5304        if( $this->show )
     5305        {
     5306            if( $this->negformat=='' ) {
     5307                $this->negformat=$this->format;
     5308            }
     5309            if( $this->negcolor=='' ) {
     5310                $this->negcolor=$this->color;
     5311            }
     5312
     5313            if( $aVal===NULL || (is_string($aVal) && ($aVal=='' || $aVal=='-' || $aVal=='x' ) ) ) {
     5314                return;
     5315            }
     5316
     5317            if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) {
     5318                return;
     5319            }
     5320
     5321            // Since the value is used in different cirumstances we need to check what
     5322            // kind of formatting we shall use. For example, to display values in a line
     5323            // graph we simply display the formatted value, but in the case where the user
     5324            // has already specified a text string we don't fo anything.
     5325            if( $this->iFormCallback != '' ) {
     5326                $f = $this->iFormCallback;
     5327                $sval = call_user_func($f,$aVal);
     5328            }
     5329            elseif( is_numeric($aVal) ) {
     5330                if( $aVal >= 0 ) {
     5331                    $sval=sprintf($this->format,$aVal);
     5332                }
     5333                else {
     5334                    $sval=sprintf($this->negformat,$aVal);
     5335                }
     5336            }
     5337            else {
     5338                $sval=$aVal;
     5339            }
     5340
     5341            $y = $y-sign($aVal)*$this->margin;
     5342
     5343            $this->txt->Set($sval);
     5344            $this->txt->SetPos($x,$y);
     5345            $this->txt->SetFont($this->ff,$this->fs,$this->fsize);
     5346            if( $this->valign == '' ) {
     5347                if( $aVal >= 0 ) {
     5348                    $valign = "bottom";
     5349                }
     5350                else {
     5351                    $valign = "top";
     5352                }
     5353            }
     5354            else {
     5355                $valign = $this->valign;
     5356            }
     5357            $this->txt->Align($this->halign,$valign);
     5358
     5359            $this->txt->SetOrientation($this->angle);
     5360            if( $aVal > 0 ) {
     5361                $this->txt->SetColor($this->color);
     5362            }
     5363            else {
     5364                $this->txt->SetColor($this->negcolor);
     5365            }
     5366            $this->txt->Stroke($img);
     5367        }
    49465368    }
    49475369}
     
    49565378    public $legend='';
    49575379    public $coords=array();
    4958     public $color="black";
     5380    public $color='black';
    49595381    public $hidelegend=false;
    49605382    public $line_weight=1;
    49615383    public $csimtargets=array(),$csimwintargets=array(); // Array of targets for CSIM
    4962     public $csimareas="";                       // Resultant CSIM area tags     
    4963     public $csimalts=null;                      // ALT:s for corresponding target
     5384    public $csimareas='';   // Resultant CSIM area tags
     5385    public $csimalts=null;   // ALT:s for corresponding target
    49645386    public $legendcsimtarget='',$legendcsimwintarget='';
    49655387    public $legendcsimalt='';
    4966     protected $weight=1;       
     5388    protected $weight=1;
    49675389    protected $center=false;
    4968 //---------------
    4969 // CONSTRUCTOR
    4970     function Plot($aDatay,$aDatax=false) {
    4971         $this->numpoints = count($aDatay);
    4972         if( $this->numpoints==0 )
    4973             JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point.");
    4974         $this->coords[0]=$aDatay;
    4975         if( is_array($aDatax) ) {
    4976             $this->coords[1]=$aDatax;
    4977             $n = count($aDatax);
    4978             for($i=0; $i < $n; ++$i ) {
    4979                 if( !is_numeric($aDatax[$i]) ) {
    4980                     JpGraphError::RaiseL(25070);
    4981                 }
    4982             }
    4983         }
    4984         $this->value = new DisplayValue();
    4985     }
    4986 
    4987 //---------------
    4988 // PUBLIC METHODS       
     5390
     5391    protected $inputValues;
     5392    protected $isRunningClear = false;
     5393
     5394    function __construct($aDatay,$aDatax=false) {
     5395        $this->numpoints = count($aDatay);
     5396        if( $this->numpoints==0 ) {
     5397            JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point.");
     5398        }
     5399
     5400        if (!$this->isRunningClear) {
     5401            $this->inputValues = array();
     5402            $this->inputValues['aDatay'] = $aDatay;
     5403            $this->inputValues['aDatax'] = $aDatax;
     5404        }
     5405
     5406        $this->coords[0]=$aDatay;
     5407        if( is_array($aDatax) ) {
     5408            $this->coords[1]=$aDatax;
     5409            $n = count($aDatax);
     5410            for( $i=0; $i < $n; ++$i ) {
     5411                if( !is_numeric($aDatax[$i]) ) {
     5412                    JpGraphError::RaiseL(25070);
     5413                }
     5414            }
     5415        }
     5416        $this->value = new DisplayValue();
     5417    }
    49895418
    49905419    // Stroke the plot
     
    49925421    // the subclasses
    49935422    function Stroke($aImg,$aXScale,$aYScale) {
    4994         JpGraphError::RaiseL(25122);//("JpGraph: Stroke() must be implemented by concrete subclass to class Plot");
     5423        JpGraphError::RaiseL(25122);//("JpGraph: Stroke() must be implemented by concrete subclass to class Plot");
    49955424    }
    49965425
    49975426    function HideLegend($f=true) {
    4998         $this->hidelegend = $f;
     5427        $this->hidelegend = $f;
    49995428    }
    50005429
    50015430    function DoLegend($graph) {
    5002         if( !$this->hidelegend )
    5003             $this->Legend($graph);
     5431        if( !$this->hidelegend )
     5432        $this->Legend($graph);
    50045433    }
    50055434
    50065435    function StrokeDataValue($img,$aVal,$x,$y) {
    5007         $this->value->Stroke($img,$aVal,$x,$y);
    5008     }
    5009        
    5010     // Set href targets for CSIM       
     5436        $this->value->Stroke($img,$aVal,$x,$y);
     5437    }
     5438
     5439    // Set href targets for CSIM
    50115440    function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') {
    5012         $this->csimtargets=$aTargets;
    5013         $this->csimwintargets=$aWinTargets;
    5014         $this->csimalts=$aAlts;         
    5015     }
    5016        
     5441        $this->csimtargets=$aTargets;
     5442        $this->csimwintargets=$aWinTargets;
     5443        $this->csimalts=$aAlts;
     5444    }
     5445
    50175446    // Get all created areas
    50185447    function GetCSIMareas() {
    5019         return $this->csimareas;
    5020     }   
    5021        
     5448        return $this->csimareas;
     5449    }
     5450
    50225451    // "Virtual" function which gets called before any scale
    50235452    // or axis are stroked used to do any plot specific adjustment
    50245453    function PreStrokeAdjust($aGraph) {
    5025         if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) )
    5026             JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead.");
    5027         return true;   
    5028     }
    5029        
     5454        if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) {
     5455            JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead.");
     5456        }
     5457        return true;
     5458    }
     5459
     5460    // Virtual function to the the concrete plot class to make any changes to the graph
     5461    // and scale before the stroke process begins
     5462    function PreScaleSetup($aGraph) {
     5463        // Empty
     5464    }
     5465
    50305466    // Get minimum values in plot
    50315467    function Min() {
    5032         if( isset($this->coords[1]) )
    5033             $x=$this->coords[1];
    5034         else
    5035             $x="";
    5036         if( $x != "" && count($x) > 0 ) {
    5037             $xm=min($x);
    5038         }
    5039         else
    5040             $xm=0;
    5041         $y=$this->coords[0];
    5042         $cnt = count($y);
    5043         if( $cnt > 0 ) {
    5044             /*
    5045             if( ! isset($y[0]) ) {
    5046                 JpGraphError('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)');
    5047             }
    5048             $ym = $y[0];
    5049             */
    5050             $i=0;
    5051             while( $i<$cnt && !is_numeric($ym=$y[$i]) )
    5052                 $i++;
    5053             while( $i < $cnt) {
    5054                 if( is_numeric($y[$i]) )
    5055                     $ym=min($ym,$y[$i]);
    5056                 ++$i;
    5057             }                   
    5058         }
    5059         else
    5060             $ym="";
    5061         return array($xm,$ym);
    5062     }
    5063        
     5468        if( isset($this->coords[1]) ) {
     5469            $x=$this->coords[1];
     5470        }
     5471        else {
     5472            $x='';
     5473        }
     5474        if( $x != '' && count($x) > 0 ) {
     5475            $xm=min($x);
     5476        }
     5477        else {
     5478            $xm=0;
     5479        }
     5480        $y=$this->coords[0];
     5481        $cnt = count($y);
     5482        if( $cnt > 0 ) {
     5483            $i=0;
     5484            while( $i<$cnt && !is_numeric($ym=$y[$i]) ) {
     5485                $i++;
     5486            }
     5487            while( $i < $cnt) {
     5488                if( is_numeric($y[$i]) ) {
     5489                    $ym=min($ym,$y[$i]);
     5490                }
     5491                ++$i;
     5492            }
     5493        }
     5494        else {
     5495            $ym='';
     5496        }
     5497        return array($xm,$ym);
     5498    }
     5499
    50645500    // Get maximum value in plot
    50655501    function Max() {
    5066         if( isset($this->coords[1]) )
    5067             $x=$this->coords[1];
    5068         else
    5069             $x="";
    5070 
    5071         if( $x!="" && count($x) > 0 )
    5072             $xm=max($x);
    5073         else {
    5074             $xm = $this->numpoints-1;
    5075         }
    5076         $y=$this->coords[0];
    5077         if( count($y) > 0 ) {
    5078             /*
    5079             if( !isset($y[0]) ) {
    5080                 JpGraphError::Raise('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)');
    5081 //              $y[0] = 0;
    5082 // Change in 1.5.1 Don't treat this as an error any more. Just silently convert to 0
    5083 // Change in 1.17 Treat his as an error again !! This is the right way to do !!
    5084             }
    5085             */
    5086             $cnt = count($y);
    5087             $i=0;
    5088             while( $i<$cnt && !is_numeric($ym=$y[$i]) )
    5089                 $i++;                           
    5090             while( $i < $cnt ) {
    5091                 if( is_numeric($y[$i]) )
    5092                     $ym=max($ym,$y[$i]);
    5093                 ++$i;
    5094             }
    5095         }
    5096         else
    5097             $ym="";
    5098         return array($xm,$ym);
    5099     }
    5100        
     5502        if( isset($this->coords[1]) ) {
     5503            $x=$this->coords[1];
     5504        }
     5505        else {
     5506            $x='';
     5507        }
     5508
     5509        if( $x!='' && count($x) > 0 ) {
     5510            $xm=max($x);
     5511        }
     5512        else {
     5513            $xm = $this->numpoints-1;
     5514        }
     5515        $y=$this->coords[0];
     5516        if( count($y) > 0 ) {
     5517            $cnt = count($y);
     5518            $i=0;
     5519            while( $i<$cnt && !is_numeric($ym=$y[$i]) ) {
     5520                $i++;
     5521            }
     5522            while( $i < $cnt ) {
     5523                if( is_numeric($y[$i]) ) {
     5524                    $ym=max($ym,$y[$i]);
     5525                }
     5526                ++$i;
     5527            }
     5528        }
     5529        else {
     5530            $ym='';
     5531        }
     5532        return array($xm,$ym);
     5533    }
     5534
    51015535    function SetColor($aColor) {
    5102         $this->color=$aColor;
    5103     }
    5104        
     5536        $this->color=$aColor;
     5537    }
     5538
    51055539    function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') {
    5106         $this->legend = $aLegend;
    5107         $this->legendcsimtarget = $aCSIM;
    5108         $this->legendcsimwintarget = $aCSIMWinTarget;
    5109         $this->legendcsimalt = $aCSIMAlt;
     5540        $this->legend = $aLegend;
     5541        $this->legendcsimtarget = $aCSIM;
     5542        $this->legendcsimwintarget = $aCSIMWinTarget;
     5543        $this->legendcsimalt = $aCSIMAlt;
    51105544    }
    51115545
    51125546    function SetWeight($aWeight) {
    5113         $this->weight=$aWeight;
    5114     }
    5115                
     5547        $this->weight=$aWeight;
     5548    }
     5549
    51165550    function SetLineWeight($aWeight=1) {
    5117         $this->line_weight=$aWeight;
    5118     }
    5119        
     5551        $this->line_weight=$aWeight;
     5552    }
     5553
    51205554    function SetCenter($aCenter=true) {
    5121         $this->center = $aCenter;
    5122     }
    5123        
     5555        $this->center = $aCenter;
     5556    }
     5557
    51245558    // This method gets called by Graph class to plot anything that should go
    51255559    // into the margin after the margin color has been set.
    51265560    function StrokeMargin($aImg) {
    5127         return true;
     5561        return true;
    51285562    }
    51295563
    51305564    // Framework function the chance for each plot class to set a legend
    51315565    function Legend($aGraph) {
    5132         if( $this->legend != "" )
    5133             $aGraph->legend->Add($this->legend,$this->color,"",0,$this->legendcsimtarget,
    5134                                  $this->legendcsimalt,$this->legendcsimwintarget);   
    5135     }
    5136        
     5566        if( $this->legend != '' ) {
     5567            $aGraph->legend->Add($this->legend,$this->color,'',0,$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
     5568        }
     5569    }
     5570
     5571    function Clear() {
     5572        $this->isRunningClear = true;
     5573        $this->__construct($this->inputValues['aDatay'], $this->inputValues['aDatax']);
     5574        $this->isRunningClear = false;
     5575    }
     5576
    51375577} // Class
    51385578
    51395579
    5140 //===================================================
    5141 // CLASS PlotLine
    5142 // Description:
    5143 // Data container class to hold properties for a static
    5144 // line that is drawn directly in the plot area.
    5145 // Usefull to add static borders inside a plot to show
    5146 // for example set-values
    5147 //===================================================
    5148 class PlotLine {
    5149     public $scaleposition, $direction=-1;
    5150     protected $weight=1;
    5151     protected $color="black";
    5152     private $legend='',$hidelegend=false, $legendcsimtarget='', $legendcsimalt='',$legendcsimwintarget='';
    5153     private $iLineStyle='solid';
    5154 
    5155 //---------------
    5156 // CONSTRUCTOR
    5157     function PlotLine($aDir=HORIZONTAL,$aPos=0,$aColor="black",$aWeight=1) {
    5158         $this->direction = $aDir;
    5159         $this->color=$aColor;
    5160         $this->weight=$aWeight;
    5161         $this->scaleposition=$aPos;
    5162     }
    5163        
    5164 //---------------
    5165 // PUBLIC METHODS       
    5166 
    5167     function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') {
    5168         $this->legend = $aLegend;
    5169         $this->legendcsimtarget = $aCSIM;
    5170         $this->legendcsimwintarget = $aCSIMWinTarget;
    5171         $this->legendcsimalt = $aCSIMAlt;
    5172     }
    5173 
    5174     function HideLegend($f=true) {
    5175         $this->hidelegend = $f;
    5176     }
    5177 
    5178     function SetPosition($aScalePosition) {
    5179         $this->scaleposition=$aScalePosition;
    5180     }
    5181        
    5182     function SetDirection($aDir) {
    5183         $this->direction = $aDir;
    5184     }
    5185        
    5186     function SetColor($aColor) {
    5187         $this->color=$aColor;
    5188     }
    5189        
    5190     function SetWeight($aWeight) {
    5191         $this->weight=$aWeight;
    5192     }
    5193 
    5194     function SetLineStyle($aStyle) {
    5195         $this->iLineStyle = $aStyle;
    5196     }
    5197 
    5198 //---------------
    5199 // PRIVATE METHODS
    5200 
    5201     function DoLegend(&$graph) {
    5202         if( !$this->hidelegend )
    5203             $this->Legend($graph);
    5204     }
    5205 
    5206     // Framework function the chance for each plot class to set a legend
    5207     function Legend(&$aGraph) {
    5208         if( $this->legend != "" ) {
    5209             $dummyPlotMark = new PlotMark();
    5210             $lineStyle = 1;
    5211             $aGraph->legend->Add($this->legend,$this->color,$dummyPlotMark,$lineStyle,
    5212                                  $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);   
    5213         }
    5214     }
    5215 
    5216     function PreStrokeAdjust($aGraph) {
    5217         // Nothing to do
    5218     }
    5219        
    5220     function Stroke($aImg,$aXScale,$aYScale) {
    5221         $aImg->SetColor($this->color);
    5222         $aImg->SetLineWeight($this->weight);   
    5223         $oldStyle = $aImg->SetLineStyle($this->iLineStyle);
    5224         if( $this->direction == VERTICAL ) {
    5225             $ymin_abs=$aYScale->Translate($aYScale->GetMinVal());
    5226             $ymax_abs=$aYScale->Translate($aYScale->GetMaxVal());
    5227             $xpos_abs=$aXScale->Translate($this->scaleposition);
    5228             $aImg->StyleLine($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs);
    5229         }
    5230         elseif( $this->direction == HORIZONTAL ) {
    5231             $xmin_abs=$aXScale->Translate($aXScale->GetMinVal());
    5232             $xmax_abs=$aXScale->Translate($aXScale->GetMaxVal());
    5233             $ypos_abs=$aYScale->Translate($this->scaleposition);
    5234             $aImg->StyleLine($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs);
    5235         }
    5236         else {
    5237             JpGraphError::RaiseL(25125);//(" Illegal direction for static line");
    5238         }
    5239         $aImg->SetLineStyle($oldStyle);
    5240     }
     5580// Provide a deterministic list of new colors whenever the getColor() method
     5581// is called. Used to automatically set colors of plots.
     5582class ColorFactory {
     5583
     5584    static private $iIdx = 0;
     5585    static private $iColorList = array(
     5586        'black',
     5587        'blue',
     5588        'orange',
     5589        'darkgreen',
     5590        'red',
     5591        'AntiqueWhite3',
     5592        'aquamarine3',
     5593        'azure4',
     5594        'brown',
     5595        'cadetblue3',
     5596        'chartreuse4',
     5597        'chocolate',
     5598        'darkblue',
     5599        'darkgoldenrod3',
     5600        'darkorchid3',
     5601        'darksalmon',
     5602        'darkseagreen4',
     5603        'deepskyblue2',
     5604        'dodgerblue4',
     5605        'gold3',
     5606        'hotpink',
     5607        'lawngreen',
     5608        'lightcoral',
     5609        'lightpink3',
     5610        'lightseagreen',
     5611        'lightslateblue',
     5612        'mediumpurple',
     5613        'olivedrab',
     5614        'orangered1',
     5615        'peru',
     5616        'slategray',
     5617        'yellow4',
     5618        'springgreen2');
     5619    static private $iNum = 33;
     5620
     5621    static function getColor() {
     5622        if( ColorFactory::$iIdx >= ColorFactory::$iNum )
     5623            ColorFactory::$iIdx = 0;
     5624        return ColorFactory::$iColorList[ColorFactory::$iIdx++];
     5625    }
     5626
    52415627}
    52425628
Note: See TracChangeset for help on using the changeset viewer.