]> git.sur5r.net Git - bacula/bacula/commitdiff
Apply bacula-web 1.2 updates
authorKern Sibbald <kern@sibbald.com>
Sun, 19 Jun 2005 08:52:45 +0000 (08:52 +0000)
committerKern Sibbald <kern@sibbald.com>
Sun, 19 Jun 2005 08:52:45 +0000 (08:52 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2143 91ce42f0-d328-0410-95d8-f526ca767f89

13 files changed:
gui/bacula-web/ChangeLog
gui/bacula-web/README
gui/bacula-web/classes.inc
gui/bacula-web/configs/bacula.conf
gui/bacula-web/external_packages/phplot/ChangeLog
gui/bacula-web/external_packages/phplot/doc/index.php
gui/bacula-web/external_packages/phplot/doc/quickstart.html
gui/bacula-web/external_packages/phplot/phplot.php
gui/bacula-web/index.php
gui/bacula-web/locale/fr/LC_MESSAGES/messages.po.fr
gui/bacula-web/report.php
gui/bacula-web/templates/generaldata.tpl
gui/bacula-web/templates/index.tpl

index fc6c64a846cbae039de0a5a38b44679a5660bbf8..6e34e7c9fd458dae30e33c65665cc1f16a0b50fa 100644 (file)
@@ -1,8 +1,14 @@
+- - - -  Bacula web 1.2
+       - Human redable Y-axis of graphs
+       - Updated French translation
+       - Initial support for PostgreSQL
+       - Upgrade Phplot to 5.0rc2 version.
+       
 25-10-2004 Bacula web 1.1
-       - Add array_fill function (as Mikael suggested)
-       - Fix url encode of links. (reported by Phil Stracchino)
+    - Add array_fill function (as Mikael suggested)
+       - Fix url encode of links. (reported by Phil Stracchino) 
        - Upgrade Smarty to 2.6.6 version.
-       - Add French translation
+       - Add French translation        
        
 04-08-2004 Bacula web 1.0
        - Add Italian translation
index 30e00570d403b2041eb3654f3960ec6ad0ba1f14..a66477e27e5d0d0932f87f0a1723b259af8b4b5e 100644 (file)
@@ -11,17 +11,17 @@ News and bugs: http://indpnday.com/bacula_stuff/bacula-web/mantisbt/login_page.p
 
 REQUERIMENTS:
 **************
-       
-       - Web server    (Tested with apache)
-       - PHP                   (Tested with php.4.3.4)
-               - Gettext       (Optional)
-               - GD 2.x
-               - TrueType (optional)
-               - Pear DB (http://pear.php.net/package/DB)
-               - MySQL,SQLite or PgSQL
-       - Bacula (Oh!, yes, you need this ;-) ) http://www.bacula.org
-
-               
+        
+        - Web server    (Tested with apache)
+        - PHP                   (Tested with php.4.3.4)
+                - Gettext       (Optional)
+                - GD 2.x
+                - TrueType (optional)
+                - Pear DB (http://pear.php.net/package/DB)
+                - MySQL or PostgreSQL
+        - Bacula (Oh!, yes, you need this ;-) ) http://www.bacula.org
+
+                
 INSTALL
 *******
 - Copy this distribution to root directory or a subdirectory of your webroot.
index 4f48e12567b1042f5934332938f9fbee20958504..c4ce70b872f217b1ed5b6e34c828421ff7df147c 100644 (file)
@@ -14,7 +14,7 @@
 | GNU General Public License for more details.                            |
 +-------------------------------------------------------------------------+ 
 */
-
+// Last Err: 11
 define('CONFIG_DIR', "configs");
 define('CONFIG_FILE', "bacula.conf");
 define('BACULA_TYPE_BYTES_FILES', 1);
@@ -22,195 +22,233 @@ define('BACULA_TYPE_FILES_JOBID', 2);
 define('BACULA_TYPE_BYTES_ENDTIME_ALLJOBS', 69);
 
 require_once "paths.php";
-require_once "DB.php";                                                                                                                 // Pear DB
+require_once "DB.php";                                                                                                                  // Pear DB
 require_once($smarty_path."Config_File.class.php");
 
-if (!function_exists('array_fill')) {                                                                                  // For PHP < 4.2.0 users 
+if (!function_exists('array_fill')) {                                                                                   // For PHP < 4.2.0 users 
     require_once('array_fill.func.php');
 }
 
 class Bweb extends DB {
 
-       var $StartDate;
-       var $EndDate;
-
-
-
-       function Bweb() {
-               
-               $conf = new Config_File (CONFIG_DIR);
-               
-               
-               $this->dsn[hostspec] = $conf->get(CONFIG_FILE,"DATABASE","host");
-               $this->dsn[username] = $conf->get(CONFIG_FILE,"DATABASE","login");
-               $this->dsn[password] = $conf->get(CONFIG_FILE,"DATABASE","pass");
-               $this->dsn[database] = $conf->get(CONFIG_FILE,"DATABASE","db_name");
-               $this->dsn[phptype] = $conf->get(CONFIG_FILE,"DATABASE","db_type");                     // mysql, (sqlite, pgsql) -->> Yet not checked
-               if (  $conf->get(CONFIG_FILE,"DATABASE","db_port") )
-                       $this->dsn[port] = $conf->get(CONFIG_FILE,"DATABASE","db_port");
-                       
-               $this->link =& $this->connect($this->dsn);
-               
-               if (DB::isError($this->link))
-                   die($this->link->getMessage());
-                               
-               register_shutdown_function(array(&$this,'close'));
-        }
-
-
-               
-       function close() {
-
-               $this->link->disconnect();
-        }      
-
-       
-        
-       function CalculateBytesPeriod($server,$StartDate,$EndPeriod) {                          // Bytes transferred in a period.
-
-               $result =& $this->link->query("select SUM(JobBytes) from Job WHERE EndTime < '$EndPeriod' and EndTime > '$StartDate' and Name='$server'")
-                       or die("Error query row 68");
-               $return =& $result->fetchRow(); 
-               return $return[0];
-        }//end function
-
-       
-        
-       function CalculateFilesPeriod($server,$StartDate,$EndPeriod) {                          // Number of files transferred in a period.
-
-               $result =& $this->link->query("select SUM(JobFiles) from Job WHERE EndTime < '$EndPeriod' and EndTime > '$StartDate' and Name='$server'")
-                       or die("Error query row 78");
-               $return =& $result->fetchRow();
-               return $return[0];
-        }//end function 
-
-                
-
-       function PrepareDate($StartDateMonth,$StartDateDay,$StartDateYear,$EndDateMonth,$EndDateDay,$EndDateYear) {  // Convert date for Smarty. Check if only works with Mysql.
-       
-               $this->StartDate=$StartDateYear."-".$StartDateMonth."-".$StartDateDay." 00:00:00";
-               $this->EndDate=$EndDateYear."-".$EndDateMonth."-".$EndDateDay." 23:59:59";  // last day full
-               
-       }//end function
+        var $StartDate;
+        var $EndDate;
+        var $driver;
+
+
+
+        function Bweb() {
+                
+                $conf = new Config_File (CONFIG_DIR);
+                
+                
+                $this->dsn[hostspec] = $conf->get(CONFIG_FILE,"DATABASE","host");
+                $this->dsn[username] = $conf->get(CONFIG_FILE,"DATABASE","login");
+                $this->dsn[password] = $conf->get(CONFIG_FILE,"DATABASE","pass");
+                $this->dsn[database] = $conf->get(CONFIG_FILE,"DATABASE","db_name");
+                $this->dsn[phptype] = $conf->get(CONFIG_FILE,"DATABASE","db_type");                     // mysql, (sqlite, pgsql) -->> Yet not checked
+                if (  $conf->get(CONFIG_FILE,"DATABASE","db_port") )
+                        $this->dsn[port] = $conf->get(CONFIG_FILE,"DATABASE","db_port");
+                        
+                $this->link =& $this->connect($this->dsn);
+                
+                if (DB::isError($this->link))
+                    die($this->link->getMessage());
+                $this->driver = $this->dsn[phptype];                            
+                register_shutdown_function(array(&$this,'close'));
+         }
+
+
+                
+        function close() {
+
+                $this->link->disconnect();
+         }      
+
+        
+         
+        function CalculateBytesPeriod($server,$StartDate,$EndPeriod) {                          // Bytes transferred in a period.
+
+                $result =& $this->link->query("select SUM(JobBytes) from Job WHERE EndTime < '$EndPeriod' and EndTime > '$StartDate' and Name='$server'")
+                        or die("classes.inc: Error query: 1");
+                $return =& $result->fetchRow(); 
+                return $return[0];
+         }//end function
+
+        
+         
+        function CalculateFilesPeriod($server,$StartDate,$EndPeriod) {                          // Number of files transferred in a period.
+
+                $result =& $this->link->query("select SUM(JobFiles) from Job WHERE EndTime < '$EndPeriod' and EndTime > '$StartDate' and Name='$server'")
+                        or die("classes.inc: Error query: 2");
+                $return =& $result->fetchRow();
+                return $return[0];
+         }//end function 
+
+                 
+
+        function PrepareDate($StartDateMonth,$StartDateDay,$StartDateYear,$EndDateMonth,$EndDateDay,$EndDateYear) {  // Convert date for Smarty. Check if only works with Mysql.
+        
+                $this->StartDate=$StartDateYear."-".$StartDateMonth."-".$StartDateDay." 00:00:00";
+                $this->EndDate=$EndDateYear."-".$EndDateMonth."-".$EndDateDay." 23:59:59";  // last day full
+                
+        }//end function
  
 
 
-       function GetDataVolumes() {
-
-               $volume = array();
-               $res = $this->link->query("SELECT Name FROM Pool");
-               while ( $tmp =& $res->fetchRow() ) {
-                       $result = $this->link->query("select Media.VolumeName, Media.VolBytes,Media.VolStatus,Pool.Name,Media.MediaType,Media.LastWritten,FROM_UNIXTIME(UNIX_TIMESTAMP(Media.LastWritten)+Media.VolRetention ) as expire from Pool LEFT JOIN Media ON Media.PoolId=Pool.PoolId where Name='$tmp[0]' order by Media.VolumeName");
-                       while ( $tmp1 = $result->fetchRow() ) {
-                               $pos = array_key_exists($tmp[0],$volume);
-                               if ($pos != FALSE)
-                                       array_push($volume["$tmp[0]"],$tmp1);
-                               else
-                                       $volume += array($tmp[0]=>array($tmp1));
-                       }
-               }
-               
-               $res->free();
-               $result->free();
-               return $volume;
-       }
-       
+        function GetDataVolumes() {
+
+                $volume = array();
+                $res = $this->link->query("SELECT Name FROM Pool");
+                while ( $tmp =& $res->fetchRow() ) {
+                        if ($this->driver == "mysql" )
+                                $result = $this->link->query("select Media.VolumeName, Media.VolBytes,Media.VolStatus,Pool.Name,Media.MediaType,Media.LastWritten,FROM_UNIXTIME(UNIX_TIMESTAMP(Media.LastWritten)+Media.VolRetention ) as expire from Pool LEFT JOIN Media ON Media.PoolId=Pool.PoolId where Name='$tmp[0]' order by Media.VolumeName");
+                        else if ($this->driver == "pgsql")
+                                $result = $this->link->query("select Media.VolumeName, Media.VolBytes,Media.VolStatus,Pool.Name,Media.MediaType,Media.LastWritten,FROM_UNIXTIME(Media.LastWritten::Timestamp without time zone + Media.VolRetention) as expire from Pool LEFT JOIN Media ON Media.PoolId=Pool.PoolId where Name='$tmp[0]' order by Media.VolumeName");                                                          
+                        while ( $tmp1 = $result->fetchRow() ) {
+                                $pos = array_key_exists($tmp[0],$volume);
+                                if ($pos != FALSE)
+                                        array_push($volume["$tmp[0]"],$tmp1);
+                                else
+                                        $volume += array($tmp[0]=>array($tmp1));
+                        }
+                }
+                
+                $res->free();
+                $result->free();
+                return $volume;
+        }
+        
+        function GetDbSize() {
+                if ( $this->driver == "mysql") {
+                        $dbsize = $this->link->query("show table status")
+                                or die ("classes.inc: Error query: 3");
+                        if ( $dbsize->numRows() ) {
+                                while ( $res = $dbsize->fetchRow() )
+                                        $database_size += $res[5];
+                        }
+                        else
+                                return 0;
+                }
+                else if ( $this->driver == "pgsql") {
+                        $dbsize = $this->link->query("select database_size('bacula')")
+                                or die ("classes.inc: Error query: 4");
+                        if ( $dbsize->numRows() ) {
+                                while ( $res = $dbsize->fetchRow() )
+                                        $database_size += $res[0];
+                        }
+                        else
+                                return 0;
+                }       
+        $dbsize->free();
+        return $database_size;  
+        }
+
 }
 
 class BGraph {
 
-       var $type;
-       var $sizex;
-       var $sizey;
-       var $MarginBottom;
-       var $MarginLeft;
-       var $Leg;
-
-
-       
-       function BShowGraph($datos,$title,$xlabel,$ylabel,$leyenda,$tipo="lines") {
-       
-               global $type;
-       
-               require_once ("external_packages/phplot/phplot.php");
-
-               if ( empty($this->sizex) || empty($this->sizey) ) {                                             //Default size
-                       $this->sizex = "600";
-                       $this->sizey = "400";
-               }
-               if ( empty($this->MarginBottom) ) {
-                       $this->MarginBottom = 120;
-               }
-               
-               $legend = $leyenda;
-//             $bgcolor = array(222,206,215);                                                                                  // Background color of graph
-               $bgcolor = array(207,231,231);
-               $fgcolor = array(110,41,57);
-               
-
-               
-               $graph = new PHPlot($this->sizex,$this->sizey,"","");
-
-               if ( !empty($type) )
-                       $graph->setDataType($type);
-
-               $graph->SetDataValues($datos);
-               $graph->SetPlotType($tipo);
-//             $graph->SetUseTTF(1);
-               $graph->SetBackgroundColor($bgcolor);
-
-               $graph->SetLegendPixels(1,20);
-               $graph->SetDataColors(array('SkyBlue','purple','PeachPuff','aquamarine1','#2CB04B','beige','#9F865F','#135568','orchid','navy','red', 'black', 'blue', 'green', 'brown', 'yellow','cyan','orange','#B9F5A7','#AFAFAF'));
-               $graph->SetTitle($title);
-               $graph->SetXLabel($xlabel);
-               $graph->SetYLabel($ylabel);
-               $graph->SetPlotAreaWorld("","","","");
-               
-               if ( count($datos) > 5 )
-                       $graph->SetXDataLabelAngle(90);
-               else
-                       $graph->SetXDataLabelAngle(0);
-//             $graph->SetNumXTicks(10);
-//             $graph->SetXDataLabelPos('none');
-//             $graph->SetXTickLabelPos('plotdown');
-               
-//             $graph->SetXGridLabelType("time");
-//             $graph->SetXTimeFormat("%b ") ;
-
-               if ( $this->Leg == 1 ) {
-                       $this->MarginLeftWithLegend($legend);
-                       $graph->SetMarginsPixels($this->MarginLeft,10,35,$this->MarginBottom);
-                       $graph->SetLegend($legend);                     
-               }
-               else
-                       $graph->SetMarginsPixels(90,35,35,$this->MarginBottom);
-//             $graph->SetDataColors(array($fgcolor),array( "black"));
-               $graph->SetFileFormat( "png");
-//             $graph->DoScaleData(1,1);
-//             $graph->DoMovingAverage(1,1,1);
-               $graph->DrawGraph();
-
-       }//end Crear
+        var $type;
+        var $sizex;
+        var $sizey;
+        var $MarginBottom;
+        var $MarginLeft;
+        var $Leg;
+
+
+        
+        function BShowGraph($datos,$title,$xlabel,$ylabel,$leyenda,$tipo="lines") {
+        
+                global $type;
+        
+                require_once ("external_packages/phplot/phplot.php");
+
+                if ( empty($this->sizex) || empty($this->sizey) ) {                                             //Default size
+                        $this->sizex = "600";
+                        $this->sizey = "400";
+                }
+                if ( empty($this->MarginBottom) ) {
+                        $this->MarginBottom = 120;
+                }
+                
+                $legend = $leyenda;
+//              $bgcolor = array(222,206,215);                                                                                  // Background color of graph
+                $bgcolor = array(207,231,231);
+                $fgcolor = array(110,41,57);
+                
+
+                
+                $graph = new PHPlot($this->sizex,$this->sizey,"","");
+
+                if ( !empty($type) )
+                        $graph->setDataType($type);
+
+                $graph->SetDataValues($datos);
+                $graph->SetPlotType($tipo);
+//              $graph->SetUseTTF(1);
+                $graph->SetBackgroundColor($bgcolor);
+
+                $graph->SetLegendPixels(1,20);
+                $graph->SetDataColors(array('SkyBlue','purple','PeachPuff','aquamarine1','#2CB04B','beige','#9F865F','#135568','orchid','navy','red', 'black', 'blue', 'green', 'brown', 'yellow','cyan','orange','#B9F5A7','#AFAFAF'));
+                $graph->SetTitle($title);
+                $graph->SetXLabel($xlabel);
+                $graph->SetYLabel($ylabel);
+                $graph->SetPlotAreaWorld("","","","");
+                
+                if ( count($datos) > 5 )
+                        $graph->SetXDataLabelAngle(90);
+                else
+                        $graph->SetXDataLabelAngle(0);
+//              $graph->SetNumXTicks(10);
+//              $graph->SetXDataLabelPos('none');
+//              $graph->SetXTickLabelPos('plotdown');
+                
+//              $graph->SetXGridLabelType("time");
+//              $graph->SetXTimeFormat("%b ") ;
+
+                if ( $this->Leg == 1 ) {
+                        $this->MarginLeftWithLegend($legend);
+                        $graph->SetMarginsPixels($this->MarginLeft,10,35,$this->MarginBottom);
+                        $graph->SetLegend($legend);                     
+                }
+                else
+                        $graph->SetMarginsPixels(90,35,35,$this->MarginBottom);
+//              $graph->SetDataColors(array($fgcolor),array( "black"));
+                $graph->SetFileFormat( "png");
+//              $graph->DoScaleData(1,1);
+//              $graph->DoMovingAverage(1,1,1);
+
+//              FIX ME -- to round y axis.
+                $vtick = strlen (round ($graph->max_y));
+                $res = 1;
+                for ($i=1;$i < $vtick; $i++)
+                        $res = $res*10;
+                if (strlen($graph->max_y-$res) != $vtick )
+                        $res = $res/10;
+                $graph->SetVertTickIncrement($res);
+                $graph->DrawGraph();
+
+        }//end Crear
 
 
 //Estupidez que tengo que cambiar. !!!!!!!!!!!
-       function SetDataType($typ) {
-               
-               global $type;
-               $type = $typ;
-       }
-
-       function MarginLeftWithLegend($clients) {
-               
-               $maxlen = 0;
-               
-               while (next($clients)) {
-                       $tmp = strlen (current($clients));
-                       if ( $tmp > $maxlen )
-                               $maxlen = $tmp;
-               }
-               $this->MarginLeft = $maxlen * 11;
-       }       
+        function SetDataType($typ) {
+                
+                global $type;
+                $type = $typ;
+        }
+
+        function MarginLeftWithLegend($clients) {
+                
+                $maxlen = 0;
+                
+                while (next($clients)) {
+                        $tmp = strlen (current($clients));
+                        if ( $tmp > $maxlen )
+                                $maxlen = $tmp;
+                }
+                $this->MarginLeft = $maxlen * 11;
+        }       
 
 }//end class
 
@@ -220,186 +258,212 @@ class BGraph {
 
 class BCreateGraph extends BGraph {
 
-       var $BD_bacula;
-       var $izquierda;
-       var $derecha;
-       var $StartDate;
-       var $EndDate;
-       var $elapsed;                                                                                                                           // Default elapsed time to show complex graphs
-       
-       
-       
-       function BCreateGraph() {
-       
-               $this->StartDate = "1900-01-01";
-               $this->EndDate = "4000-01-01";
-               $this->elapsed = "86400";                                                                                               // 24 hours in seconds.
-               
-        }              
-        
-        
-        
-       function BCreate($server,$tipo_dato,$title,$tipo="bars",$xlabel="",$ylabel="") {
-       
-               global $DB_bacula;
-               global $izquierda;
-               global $derecha;
-               global $clientes;
-       
-               $this->clientes=array();
-               $DB_bacula = new Bweb();
-               $datos = $this->SQLPrepareData($server,$tipo_dato);
-       
-               if ( empty($datos) ) {                                                                                                  //No data = No stats = Empty graph
-                       header("Content-type: image/png");
-                       $img= @ImageCreate(200,100) or die ("Cannot intialize GD stream");
-                       $bgc= ImageColorAllocate($img, 0, 255,255);
-                       $txc= ImageColorAllocate($img, 0,0,0);
-                       ImageString($img, 5, 4, 4, "None data to process", $txc);
-                       ImagePng($img);
-                       ImageDestroy($img);
-                       return; 
-               }
-       
-               if ( empty ($xlabel) ) {                                                                                                // If no label, table names like leyends
-                       $xlabel=$derecha; $ylabel=$izquierda; 
-               }                                                       
-                       
-               $this->SetDataType("text-data");
-               $this->BShowGraph($datos,$title,$xlabel,$ylabel,$this->clientes,$tipo);
-               
-       }
+        var $BD_bacula;
+        var $izquierda;
+        var $derecha;
+        var $StartDate;
+        var $EndDate;
+        var $elapsed;                                                                                                                           // Default elapsed time to show complex graphs
+        
+        
+        
+        function BCreateGraph() {
+        
+                $this->StartDate = "1900-01-01";
+                $this->EndDate = "4000-01-01";
+                $this->elapsed = "86400";                                                                                               // 24 hours in seconds.
+                
+         }              
+         
+         
+         
+        function BCreate($server,$tipo_dato,$title,$tipo="bars",$xlabel="",$ylabel="") {
+        
+                global $DB_bacula;
+                global $izquierda;
+                global $derecha;
+                global $clientes;
+        
+                $this->clientes=array();
+                $DB_bacula = new Bweb();
+                $datos = $this->SQLPrepareData($server,$tipo_dato);
+        
+                if ( empty($datos) ) {                                                                                                  //No data = No stats = Empty graph
+                        header("Content-type: image/png");
+                        $img= @ImageCreate(200,100) or die ("Cannot intialize GD stream");
+                        $bgc= ImageColorAllocate($img, 0, 255,255);
+                        $txc= ImageColorAllocate($img, 0,0,0);
+                        ImageString($img, 5, 4, 4, "None data to process", $txc);
+                        ImagePng($img);
+                        ImageDestroy($img);
+                        return; 
+                }
+        
+                if ( empty ($xlabel) ) {                                                                                                // If no label, table names like leyends
+                        $xlabel=$derecha; $ylabel=$izquierda; 
+                }                                                       
+                        
+                $this->SetDataType("text-data");
+                $this->BShowGraph($datos,$title,$xlabel,$ylabel,$this->clientes,$tipo);
+                
+        }
 
 
  
-       function SQLPrepareData($servidor,$tipo_dato=0) {                                                       // Prepare bytes data from database.
-
-               global $DB_bacula;
-               global $izquierda;
-               global $derecha;
-       
-               if ( $tipo_dato<30 ) {                                                                                                  // Simple graph. Only 2 data 
-       
-               switch ($tipo_dato)
-                               {
-                               case BACULA_TYPE_BYTES_FILES:
-                                       $izquierda="JobBytes";
-                                       $derecha="JobFiles";
-                                       break;
-                               case BACULA_TYPE_FILES_JOBID:
-                                       $izquierda="JobFiles";
-                                       $derecha="Jobid";
-                                       break;
-                               default:
-                                       $izquierda="JobBytes";
-                                       $derecha="EndTime";
-                                       break;
-                               }
-                       $result = $DB_bacula->link->query("select $derecha,$izquierda from Job where Name='$servidor' and EndTime < '$this->EndDate' and EndTime > '$this->StartDate' order by SchedTime asc")
-                               or die ("Ivalid query row 295");
-               while ( $row = $result->fetchRow(DB_FETCHMODE_ASSOC) ) {
-                       $whole_result[] = array_merge($row["$derecha"],$row[$izquierda]);
-               }
-               $result->free();
-        } else {                                                                                                                               // Complex graph. 3 or more data.
-               
-                       switch ( $tipo_dato )
-                               {
-                               case '30':                                                                                                              // Unused, at this time.
-                                       $result = $DB_bacula->link->query("select JobBytes,JobFiles,Jobid from Job where Name='$servidor' order by EndTime asc")
-                                               or die ("Invalid query row 306");
-                                       while ( $row = $result->fetchRow(DB_FETCHMODE_ASSOC) )
-                                               $whole_result[] = array_merge($row["Jobid"],$row["JobFiles"],$row["JobBytes"]);
-                                       $result->free();
-                                       break;
-                               case BACULA_TYPE_BYTES_ENDTIME_ALLJOBS:                                                 // Special: Generic graph from all clientes.
-                                       $i = -1;                                                                                                        // Counter of number of jobs of one cliente. SP: Contador del número de jobs totales de un cliente.
-                                       $i2 = 0;                                                                                                        // Counter of number of keys of array. SP: Contador del número de valores del array.
-                                       
-                                       $res = $DB_bacula->link->query("select Name from Job where UNIX_TIMESTAMP(EndTime) > UNIX_TIMESTAMP(NOW())-$this->elapsed  group by Name order by Name desc")
-                                               or die ("Invalid query row 316");
-                                       $resdata=$DB_bacula->link->query("select date_format(EndTime,\"%Y-%m-%d\") from Job where UNIX_TIMESTAMP(EndTime) > UNIX_TIMESTAMP(NOW())-$this->elapsed  group by date_format(EndTime,\"%Y-%m-%d\") order by EndTime")
-                                               or die ("Invalid query row 318");
-                                       
-                                       while ( $tmpdata = $res->fetchRow() )
-                                               array_push($this->clientes,$tmpdata[0]);
-                                               
-//                                     echo "<pre>";
-//                                     print_r ($this->clientes);
-//                                     echo "</pre>";
-                                       
-                                       
-                                       $spr = array();                                                                                         // Temporal array
-                                       $spr2 = array();                                                                                        // Temporal array
-                                       $whole_result = array();
-                                       
-                                       while ( $tmpdata = $resdata->fetchRow() ) {
-                                               $count++;
-                                               array_push($spr,$tmpdata[0]);
-                                               $result = $DB_bacula->link->query("select date_format(EndTime,\"%Y-%m-%d\"),SUM(JobBytes),Name,count(Name) as Nname from Job WHERE EndTime like '$tmpdata[0]%' group by Name order by Name desc")
-                                                       or die ("invalid query row 336");
-                                               while ( $row = $result->fetchRow(DB_FETCHMODE_ASSOC) ) {
-                                                       $spr2 = array_merge($spr2,array($row["Name"]=>$row["SUM(JobBytes)"]));
-                                                       $i = $result->numRows();
-                                               }
-
-                                       
-//                                             echo "<pre>";
-//                                             print_r ($spr2);
-//                                             echo "</pre>";
-                                               
-                                               reset ($this->clientes);                                                                
-                                               do { 
-                                                       if ( $spr2[current($this->clientes)] != NULL)
-                                                               array_push($spr,$spr2[current($this->clientes)]);
-                                                       else
-                                                               array_push($spr,0);
-                                               } while ( next($this->clientes) );
-                                               
-                                               if ( $i2 < $i )
-                                                       $i2 = $i;
-                                               
-                                               if ( $tmpdata[0] != $row["EndTime"] )   
-                                                       array_push($whole_result,$spr);
-                                               
-                                               $spr = array();
-                                               $spr2 = array();
-                                       }
-                               
-                                       for ( $i = 0; $i < count($whole_result); $i++ ) {                       // To equal the arrays so that the graph is not unsquared. SP:Igualamos las matrices para que la gráfica no se descuadre
-                                               $tmp = count($whole_result[$i]);
-                                               if ( $i2 < $tmp )                                                                               // Estupidez?. Check this code later...
-                                                       continue;
-                                               $tmp = $i2 - $tmp;
-                                               for ( $a = 0; $a <= $tmp; $a++ )
-                                                       array_push($whole_result[$i],"0");                                      // Fill the array
-                                       }
-                                       $resdata->free();       
-//                                     echo "DEBUG:<br>";
-//                                     echo "<pre>";
-//                                     print_r ($whole_result);
-//                                     echo "</pre>";  
-                                       break;
-                               
-                               default:
-                                       break;
-                       }
-               }
+        function SQLPrepareData($servidor,$tipo_dato=0) {                                                       // Prepare bytes data from database.
+
+                global $DB_bacula;
+                global $izquierda;
+                global $derecha;
+        
+                if ( $tipo_dato<30 ) {                                                                                                  // Simple graph. Only 2 data 
+        
+                switch ($tipo_dato)
+                                {
+                                case BACULA_TYPE_BYTES_FILES:
+                                        $izquierda="jobbytes";
+                                        $derecha="jobfiles";
+                                        break;
+                                case BACULA_TYPE_FILES_JOBID:
+                                        $izquierda="jobfiles";
+                                        $derecha="jobid";
+                                        break;
+                                default:
+                                        $izquierda="jobbytes";
+                                        $derecha="endtime";
+                                        break;
+                                }
+                        $result = $DB_bacula->link->query("select $derecha,$izquierda from Job where Name='$servidor' and EndTime < '$this->EndDate' and EndTime > '$this->StartDate' order by SchedTime asc")
+                                or die ("classes.inc: Error at query: 5");
+                while ( $row = $result->fetchRow(DB_FETCHMODE_ASSOC) ) {
+                        $whole_result[] = $this->array_merge_php4($row["$derecha"],$row[$izquierda]);
+                }
+                $result->free();
+        } else {                                                                                                                                // Complex graph. 3 or more data.
+                
+                        switch ( $tipo_dato )
+                                {
+                                case '30':                                                                                                              // Unused, at this time.
+                                        $result = $DB_bacula->link->query("select JobBytes,JobFiles,Jobid from Job where Name='$servidor' order by EndTime asc")
+                                                or die ("classes.inc: Error at query: 6");
+                                        while ( $row = $result->fetchRow(DB_FETCHMODE_ASSOC) )
+                                                $whole_result[] = array_merge($row["Jobid"],$row["JobFiles"],$row["JobBytes"]);
+                                        $result->free();
+                                        break;
+                                case BACULA_TYPE_BYTES_ENDTIME_ALLJOBS:                                                 // Special: Generic graph from all clientes.
+                                        $i = -1;                                                                                                        // Counter of number of jobs of one cliente. SP: Contador del número de jobs totales de un cliente.
+                                        $i2 = 0;                                                                                                        // Counter of number of keys of array. SP: Contador del número de valores del array.
+                                        
+                                        $res = $DB_bacula->link->query("select Name from Job where UNIX_TIMESTAMP(EndTime) > UNIX_TIMESTAMP(NOW())-$this->elapsed  group by Name order by Name desc")
+                                                or die ("classes.inc: Error at query: 7");
+                                        if ($DB_bacula->driver == "mysql")
+                                                $resdata = $DB_bacula->link->query("select date_format(EndTime,\"%Y-%m-%d\") from Job where UNIX_TIMESTAMP(EndTime) > UNIX_TIMESTAMP(NOW())-$this->elapsed  group by date_format(EndTime, \"%Y-%m-%d\") order by EndTime")
+                                                        or die ("classes.inc: Error at query: 8");
+                                        else if ($DB_bacula->driver == "pgsql")
+                                                $resdata = $DB_bacula->link->query("select date_format(EndTime,'%Y-%m-%d') from Job where UNIX_TIMESTAMP(EndTime) > UNIX_TIMESTAMP(NOW())-$this->elapsed  group by EndTime order by EndTime")                                                   
+                                                        or die ("classes.inc: Error at query: 9");
+                                        
+                                        while ( $tmpdata = $res->fetchRow() )
+                                                array_push($this->clientes,$tmpdata[0]);
+                                                
+//                                      echo "<pre>";
+//                                      print_r ($this->clientes);
+//                                      echo "</pre>";
+                                        
+                                        
+                                        $spr = array();                                                                                         // Temporal array
+                                        $spr2 = array();                                                                                        // Temporal array
+                                        $whole_result = array();
+                                        
+                                        while ( $tmpdata = $resdata->fetchRow() ) {
+                                                $count++;
+                                                array_push($spr,$tmpdata[0]);
+                                                if ($DB_bacula->driver == "mysql")
+                                                        $result = $DB_bacula->link->query("select date_format(EndTime,\"%Y-%m-%d\"),SUM(JobBytes),Name,count(Name) as Nname from Job WHERE EndTime like '$tmpdata[0]%' group by Name order by Name desc")
+                                                                or die ("classes.inc: Error at query: 10");
+                                                else if ($DB_bacula->driver == "pgsql")
+                                                        $result = $DB_bacula->link->query("select date_format(EndTime,'%Y-%m-%d'),SUM(JobBytes),Name,count(Name) as Nname from Job WHERE EndTime like '$tmpdata[0]%' group by EndTime,Name order by Name desc")
+                                                                or die ("classes.inc: Error at query: 11");
+                                                while ( $row = $result->fetchRow(DB_FETCHMODE_ASSOC) ) {
+                                                        $spr2 = array_merge($spr2,array($row["Name"]=>$row["SUM(JobBytes)"]));
+                                                        $i = $result->numRows();
+                                                }
+
+                                        
+//                                              echo "<pre>";
+//                                              print_r ($spr2);
+//                                              echo "</pre>";
+                                                
+                                                reset ($this->clientes);                                                                
+                                                do { 
+                                                        if ( $spr2[current($this->clientes)] != NULL)
+                                                                array_push($spr,$spr2[current($this->clientes)]);
+                                                        else
+                                                                array_push($spr,0);
+                                                } while ( next($this->clientes) );
+                                                
+                                                if ( $i2 < $i )
+                                                        $i2 = $i;
+                                                
+                                                if ( $tmpdata[0] != $row["EndTime"] )   
+                                                        array_push($whole_result,$spr);
+                                                
+                                                $spr = array();
+                                                $spr2 = array();
+                                        }
+                                
+                                        for ( $i = 0; $i < count($whole_result); $i++ ) {                       // To equal the arrays so that the graph is not unsquared. SP:Igualamos las matrices para que la gráfica no se descuadre
+                                                $tmp = count($whole_result[$i]);
+                                                if ( $i2 < $tmp )                                                                               // Estupidez?. Check this code later...
+                                                        continue;
+                                                $tmp = $i2 - $tmp;
+                                                for ( $a = 0; $a <= $tmp; $a++ )
+                                                        array_push($whole_result[$i],"0");                                      // Fill the array
+                                        }
+                                        $resdata->free();       
+//                                      echo "DEBUG:<br>";
+//                                      echo "<pre>";
+//                                      print_r ($whole_result);
+//                                      echo "</pre>";  
+                                        break;
+                                
+                                default:
+                                        break;
+                        }
+                }
 //      $result->free();
-         return $whole_result;
-       }//end function
-
-
-
-       //Conversión de la fecha a Mysql-format para Smarty.            THE SAME FUNCTION AT 2 CLASSES. THIS WAY IS BUGGY. TO SOLVE LATER.
-       function PrepareDate($StartDateMonth,$StartDateDay,$StartDateYear,$EndDateMonth,$EndDateDay,$EndDateYear){
-       
-               $this->StartDate = $StartDateYear."-".$StartDateMonth."-".$StartDateDay." 00:00:00";
-               $this->EndDate = $EndDateYear."-".$EndDateMonth."-".$EndDateDay." 23:59:00";
-               
-       }//end function
-
+          return $whole_result;
+        }//end function
+
+
+
+        //Conversión de la fecha a Mysql-format para Smarty.           THE SAME FUNCTION AT 2 CLASSES. THIS WAY IS BUGGY. TO SOLVE LATER.
+        function PrepareDate($StartDateMonth,$StartDateDay,$StartDateYear,$EndDateMonth,$EndDateDay,$EndDateYear){
+        
+                $this->StartDate = $StartDateYear."-".$StartDateMonth."-".$StartDateDay." 00:00:00";
+                $this->EndDate = $EndDateYear."-".$EndDateMonth."-".$EndDateDay." 23:59:00";
+                
+        }//end function
+
+
+        function array_merge_php4($array1,$array2) {
+            $return=array();
+
+            foreach(func_get_args() as $arg) {
+                if(!is_array($arg)){
+                $arg=array($arg);
+                }
+                    foreach($arg as $key=>$val){
+                            if(!is_int($key)){
+                                $return[$key]=$val;
+                            }else{
+                                $return[]=$val;
+                            }
+                    }
+            }
+        return $return;
+        }
 
 }//end class
 
-?>
\ No newline at end of file
+?>
index 85ad3748dd567176ed94e28f3c161b4e0b19af5e..68b7f1521dc168b1e39a7ef78e38e2d5378eacc8 100644 (file)
@@ -2,7 +2,7 @@
 # Please, modify with your preferences
 
 # Title of main window
-title = Bacula-Web 1.1
+title = Bacula-Web 1.2
 
 # If http://www.domain.com/bacula/
 # root = /bacula
index 9110149ff7d3dbcef7b9c29210d0cf5cdfa0e6b7..b1c6d91afb42818db008f67c7716016a8cf96008 100644 (file)
+2004-10-24 18:40  migueldb
+
+       * phplot.php:
+
+         + array_merge_php4(): added to cope with the bug introduced by
+         the change in array_merge() from PHP4 to PHP5 (I haven't verified
+         this)
+
+         + Fixed some divisions by zero, thanks to an old bug report.
+
+2004-10-24 17:44  migueldb
+
+       * README.txt, doc/quickstart.html, examples/create_chart.php,
+         examples/format_chart.php, examples/inline_image.php:
+
+         + Updated to the latest changes in phplot
+
+2004-10-24 17:40  migueldb
+
+       * doc/index.php:
+
+         + Minimal change
+
+2004-09-09 20:27  migueldb
+
+       * phplot.php:
+
+         + SetPointSize(): deprecated
+
+         + SetPointSizes(): added as replacement for SetPointSize().Now
+         able to set point sizes on a per line basis.
+
+         + SetPointShape(): deprecated.
+
+         + SetPointShapes(): added as replacement for SetPointShape(). Now
+         able to set point shape on a per line basis.
+
+         + DrawDot(): now needs record number to decide which dot shape
+         and size to draw.
+
+         + CalcMargins(): dirty fix for x data label placing.
+
+         + tile_img(): fixed tile placement.
+
+2004-06-14 14:19  migueldb
+
+       * phplot.php:
+
+         + SetXTickLabelPos() and others: more on the bug reported by Jo
+         Demol.
+
+2004-06-14 11:35  migueldb
+
+       * phplot.php:
+
+         + Fixed bug reported by Jo Demol.
+
+2004-05-11 14:14  migueldb
+
+       * phplot.php:
+
+         + SetBgImage(): added.
+
+         + SetPlotAreaBgImage(): added.
+
+         + SetInputFile(): deprecated.
+
+         + DrawBackground(): now accepts images as backgrounds.
+
+         + DrawPlotAreaBackground(): now accepts images as backgrounds.
+
+         + tile_img(): internal method added.
+
+2004-04-14 13:26  migueldb
+
+       * phplot.php:
+
+         + DrawXAxis(): No more horizontal tick nor label at X-axis'
+         sides.
+
+2004-03-21 18:01  migueldb
+
+       * phplot.php:
+
+         + x/y_label_type automaticaally set to 'data' when setting label
+         precision.
+
+         + minor corrections.
+
+2004-03-03 08:17  afan
+
+       * phplot.php: PlotAreaWorld - last fix
+
+2004-03-03 02:40  migueldb
+
+       * phplot.php:
+
+         + SetPlotAreaWorld(): fixed.
+
+2004-03-01 21:14  afan
+
+       * phplot.php: Needed one more = in  ($ymin === NULL)
+
+2004-02-29 11:21  afan
+
+       * phplot.php: phplot.php SetPlotAreaWorld - changed ($!ymin) to
+         ($ymin == NULL) for cases where $ymin = 0. (also done for ymax,
+         xmin, xmax) afan
+
+2004-02-23 10:34  migueldb
+
+       * phplot.php:
+
+         + SetPlotAreaWorld(): Fixed the calculation of max and min y.
+
+2004-02-14 12:29  migueldb
+
+       * phplot.php:
+
+         + SetPlotAreaWorld(): Fine grained control over which values are
+         auto-calculated. Should fix some trouble with y-scaling.
+
+         + DrawGraph(): yet another fix to drawing order...
+
+         + CheckOption(): fixes problems with mixedcase arguments.
+
+         + SetFileFormat(), FormatLabel(): typos fixed.
+
+2004-01-30 12:56  migueldb
+
+       * examples/data_sample1.php:
+
+         + Added "stacked bars" plot type.
+
+2004-01-30 12:50  migueldb
+
+       * phplot.php:
+
+         + DrawStackedBars(): added plot type.
+
+         + SetEqualXCoord(): renamed to more intuitive CalcBarWidths().
+         Modified for stacked bars.
+
+         + Changed graphing order. The grids are again at the background,
+         as they should. Added var $grid_at_foreground (bool) to alter
+         this.
+
+         + text-data-pie renamed to text-data-single.
+
+         + SetPlotAreaWorld(): fixed min_y bug.
+
+2004-01-29 17:10  migueldb
+
+       * phplot.php:
+
+         + SetPlotAreaWorld(): default behaviour is to adjust Y axis to Y
+         min/max.
+
+         + SetSkipLeftTick(), SetSkipRightTick(): added.
+
+         + SetFileFormat(): fixed silly bug that prevented selections from
+         being made.
+
+2004-01-28 20:00  migueldb
+
+       * phplot.php, doc/quickstart.html:
+
+         + Merged final changes to rel-5-0 into main trunk.
+
 2004-01-28 19:12  migueldb
 
-       * phplot.php (rel-5-0):
+       * phplot.php:
 
          + DrawGraph(): Fixed graph drawing order for default plots
-         (bars). Removed some redundant lines of code.
+         (bars). Removed some redundat lines of code.
 
 2004-01-28 18:58  migueldb
 
-       * doc/quickstart.html (rel-5-0):
+       * doc/quickstart.html:
 
          + More stuff...
 
 2004-01-28 18:49  migueldb
 
-       * phplot.php (rel-5-0):
+       * phplot.php:
 
          + DrawPieChart(): fixed use of old variable.
 
 
 2004-01-27 12:12  migueldb
 
-       * phplot.php (rel-5-0):
+       * phplot.php:
 
          + Added missing SetSkipTopTick()
 
 
 2004-01-27 00:03  migueldb
 
-       * doc/index.php (rel-5-0): [no log message]
+       * doc/index.php: [no log message]
 
 2004-01-25 20:28  migueldb
 
 
          + Doc by Afan. With slight corrections.
 
+2004-01-21 18:44  migueldb
+
+       * examples/rgb.inc.php, doc/index.html: [no log message]
+
 2004-01-21 18:43  migueldb
 
        * phplot.php:
 
          + DoExponentialMovingAverage(): added. Needs testing.
 
+2003-12-27 14:53  migueldb
+
+       * benjamingothic.ttf:
+
+         + The TTFont is only needed in 'examples/'.
+
 2003-12-27 14:52  migueldb
 
        * phplot.php:
 
          + Corrected some comments.
 
+2003-12-24 12:52  migueldb
+
+       * examples/example5.php:
+
+         + Now in format_chart.php
+
 2003-12-24 12:47  migueldb
 
        * examples/example4.php: Ooops! I deleted the wrong file!
 
          + Inserted example in example-o-matic as 'randfunction'
 
+2003-12-24 12:35  migueldb
+
+       * examples/test1.php: inserted example in example-o-matic as
+         'randfunction'
+
 2003-12-24 10:38  migueldb
 
        * phplot.php:
 
 2003-12-15 16:50  migueldb
 
-       * examples/: example4.php, example9.php:
+       * examples/: example4.php, example5.php, example9.php, test1.php:
 
          + Updated examples to work with new PHPlot.
 
 
          + Fixed a typo.
 
+2003-11-24 17:03  migueldb
+
+       * doc/: examples.html, function_reference.html, quick_start.php:
+
+         + Inserted into index.html (some time ago)
+
 2003-11-24 17:00  migueldb
 
        * doc/style.css:
 
          + Slight modifications to data label placement
 
+2003-11-24 11:30  migueldb
+
+       * doc/index.html:
+
+         + More reorganisation
+
 2003-11-23 23:53  migueldb
 
        * phplot.php:
          + When drawing pie charts (no axis titles nor labels), maximize
          plot area.
 
+2003-11-23 21:48  migueldb
+
+       * doc/index.html:
+
+         + Included function_reference.html links here.
+
 2003-11-23 21:42  migueldb
 
-       * doc/schema.html: [no log message]
+       * doc/: index.html, schema.html: [no log message]
+
+2003-11-23 21:39  migueldb
+
+       * doc/index.html:
+
+         + New welcome page, some text.
+
+         + Some features listed.
+
+         + Uses stylesheet
 
 2003-11-23 21:37  migueldb
 
index 4105dae22331fa4a7078981e76c979b2ac3d3ea8..a6482ec64a14a6fc0a79114989347684d353fd33 100644 (file)
@@ -53,7 +53,7 @@
    <p>
    Here goes a (incomplete) list, in no particular order.:
    <ul>
-    <li>Several different graph types: lines, bars, points, areas, pie, squared.</li>
+    <li>Several different graph types: lines, bars, stacked bars, points, areas, pie, squared.</li>
     <li>text-data, data only and data-error data types accepted.</li>
     <li>3D shading for pie and bar graphs.</li>
     <li>Different line types: solid and wholly customizable dashed ones.</li>
@@ -83,7 +83,7 @@
 
 <h3>Requirements</h3>
 <p>
-We are not sure about exact requirements, but at least PHP 4.1.0 and 
+We are not sure about exact requirements, but at least PHP 4.2.0 and 
 GD Lib 2 are necessary. Feedback is welcome.
 </p>
 
@@ -138,14 +138,13 @@ Description of the use and inner workings of PHPlot:
 </ul>
 </p>
 
-
 <h3>The Authors</h3>
 <p>
 <ul>
     <li>Original work by <a href="mailto:afan AT jeo DOT net">Afan Ottenheimer</a>.</li>
     <li>Recent work by <a href="mailto:nonick AT 8027 DOT org">Miguel de Benito</a>.</li>
     <li>Contributions by Thiemo Nagel, Marlin Viss and Remi Ricard.</li>
-</ul>    
+</ul>   
 </p>
 
 <p class="foot">$Id$</p>
index 8e4323a6a07d81078c02d62f225b4cc5819040f1..6f738c6c9c250c8a0b53e481266fc9a57b32b8a6 100644 (file)
@@ -93,18 +93,15 @@ and then defining the variable:</p>
 <div class="box">
 <pre>&lt;?php
 include('./phplot.php');  // here we include the PHPlot code 
-$graph = new PHPlot();   // here we define the variable graph 
+$graph =& new PHPlot();   // here we define the variable graph
 
 //Rest of code goes below
 ?&gt;</pre>
 </div>
 
-<p>The above code assigns the PHPlot object to the variable <code>$graph</code>.</p>
-
-<p>Now we have created a PHPlot graph object, we can access
-information about the object and manipulate the object. In these
-following examples, <code>$graph</code> is the variable/object we created
-above.</p>
+<p>The above code assigns the PHPlot object to the variable <code>$graph</code>. Please,
+use that '&' to create a reference, it is needed by phplot's approximation of a destructor,
+a facility unavailable in PHP4.</p>
 
 <p> <a href="#top">Back to top</a> </p>
 
@@ -119,7 +116,7 @@ above.</p>
 include('./PHPlot.php');
 
 //Define the object
-$graph = new PHPlot();
+$graph =& new PHPlot();
 
 //Define some data
 $example_data = array(
@@ -134,8 +131,8 @@ $example_data = array(
 $graph-&gt;SetDataValues($example_data);
 
 //Draw it
-$graph-&gt;DrawGraph(); // remember, since in this example we have one graph, PHPlot 
-                        // does the <i>PrintImage </i>part for you 
+$graph-&gt;DrawGraph(); // remember, since in this example we have one graph, PHPlot
+                        // does the <i>PrintImage </i>part for you
 ?&gt;</pre>
 </div>
 
@@ -146,7 +143,7 @@ $graph-&gt;DrawGraph(); // remember, since in this example we have one graph, PH
   <br />Figure 1
 </div>
 
-<p>That's a great start, but now we'd like to specify the width and height 
+<p>That's a great start, but now we'd like to specify the width and height
 of the image.</p>
 
 
@@ -154,57 +151,57 @@ of the image.</p>
 <p>
 Lets say we want it to have a width of 300 and a height of 250 pixels.
 So instead of having the line <br /><br />
-    <code>$graph = new PHPlot();</code> <br /><br />
+    <code>$graph =& new PHPlot();</code> <br /><br />
 we replace it with <br /><br />
-    <code>$graph = new PHPlot(300,250);</code><br /><br />
+    <code>$graph =& new PHPlot(300,250);</code><br /><br />
 and you have specified the size in pixels of the image to be created.
 A couple of things to note:
 </p>
 <ul>
   <li>The default is <em>not</em> to use TTF fonts. </li>
   <li>Since there was only one graph on the image we didn't have to
-       specify PrintImage, DrawGraph took care of it for us. 
+       specify PrintImage, DrawGraph took care of it for us.
   </li>
   <li>
        We did not specify the data type. If you do not specify the data
-       type PHPlot assumes <code>text-data</code>. 
+       type PHPlot assumes <code>text-data</code>.
   </li>
   <li>
        We did not specify the file type (gif, png, jpg, ...) .
-       PHPlot 5.0 assumes PNG image formats. 
+       PHPlot 5.0 assumes PNG image formats.
   </li>
   <li>
        The data is passed in as an array of arrays. This may seem awkward
-       now, but as we add functionality this will be beneficial. 
-  </li> 
+       now, but as we add functionality this will be beneficial.
+  </li>
 </ul>
 <p>Ok, now we're ready to add some customization to the plot. Let's change
-the size, the title and the x/y axis labels. All we need to do is modify 
+the size, the title and the x/y axis labels. All we need to do is modify
 the variable <code>$graph</code> before printing the image. We achieve this with:
 </p>
 <div class="box">
-<pre>&lt;?php            
+<pre>&lt;?php
 include ('./phplot.php');
 
 //create an graph object 300x250 pixels
-$graph = new PHPlot(300,250); 
+$graph =& new PHPlot(300,250);
 //Set titles
 $graph-&gt;SetTitle("Title\n\rSubtitle");
 $graph-&gt;SetXTitle('X data');
 $graph-&gt;SetYTitle('Y data');
 
-//...rest of code
+//...rest of the code
 
 
 ?&gt;</pre>
 </div>
 <div align=center>
  <img src="imgs/qstart_fig2.png" name="graphic1" align="bottom" border="0"><br />
- Figure 2 
+ Figure 2
 </div>
 
-<p>Note that in order for the "\n" and "\r " to be interpreted as 
-new line/new return characters for <code>SetTitle </code>you have to 
+<p>Note that in order for the "\n" and "\r " to be interpreted as
+new line/new return characters for <code>SetTitle </code>you have to
 enclose the string in <b>double </b>quotes.</p>
 
 <h3><a name="lines"></a>Case 2: Multiple Lines per Graph </h3>
@@ -223,7 +220,7 @@ Now our data will have three Y values for each position on the X axis
 include('./phplot.php');
 
 //Define the object
-$graph = new PHPlot(300,250);
+$graph =& new PHPlot(300,250);
 
 //Set titles
 $graph-&gt;SetTitle("Title\n\rSubtitle");
@@ -260,7 +257,7 @@ Also the missing data point is skipped, this behaviour can be adjusted with
 <p>
 This gives you the basics of how to create a graph in PHPlot.
 A nice start, but now we'd like to add some customization, namely different
-fonts, margins and types of graphs. 
+fonts, margins and types of graphs.
 </p>
 <p><a href="#top">Back to top</a> </p>
 
@@ -270,9 +267,9 @@ fonts, margins and types of graphs.
 <ul>
        <li><code>bars</code> (with optional shadows)</li>
        <li><code>lines</code></li>
-       <li><code>linepoints</code> (a faster way of plotting when 
+       <li><code>linepoints</code> (a faster way of plotting when
         you want both points and lines)</li>
-       <li><code>area</code></li> 
+       <li><code>area</code></li>
        <li><code>points</code> (lots of point types here)</li>
        <li><code>pie</code> (2D or 3D)</li>
        <li><code>thinbarline</code> (sometimes also called impulse) </li>
@@ -282,7 +279,7 @@ fonts, margins and types of graphs.
 </p>
 <p>You specify which type with the <code>SetPlotType</code> function.
 We'll look at that function with bars and lines in the next example when we look at
-multiple graphs per image. 
+multiple graphs per image.
 </p>
 <p>As we discussed before, there are several ways we can manipulate
 the look/feel of the graph object. Almost every parameter of ticks, grids and data labels
@@ -300,7 +297,7 @@ can be adjusted via (among many others):
   <li><code>SetNumYticks()</code></li>
   <li><code>SetSkipTopTick()</code></li>
   <li><code>SetSkipBottomTick()</code></li>
-  
+
   <li><code>SetDrawXGrid()</code></li>
   <li><code>SetDrawYGrid()</code></li>
   <li><code>SetDrawDashedGrid()</code></li>
@@ -312,7 +309,7 @@ can be adjusted via (among many others):
   <li><code>SetYLabelAngle()</code></li>
   <li><code>SetXLabelType()</code></li>
   <li><code>SetYLabelType()</code></li>
-</ul>  
+</ul>
 As we go further we will introduce some of these features of PHPlot.
 For more specialized examples, please go <a href="index.php">back to the index</a> and
 look in the examples section.
@@ -326,7 +323,7 @@ look in the examples section.
 on it is a straightforward process. As in the previous examples we
 first have to create an object (e.g. variable) but now we tell it to
 <i>not</i> print the image at the same time as the draw command. Now
-we want it to wait for the explicit <code>PrintImage</code> function call. 
+we want it to wait for the explicit <code>PrintImage</code> function call.
 To tell PHPlot this is the way we want to work, we use the
 <code>SetPrintImage</code> function.
 <code>SetPrintImage(TRUE)</code> is the default, and tells to draw the image
@@ -334,26 +331,26 @@ when <code>DrawGraph</code> is called. To turn this
 off we use <code>SetPrintImage(FALSE)</code>.</p>
 <p>Now we will draw several images entirely within one object. That
 means that if we set a value for one graph, there will be a couple of
-other commands we will need. 
+other commands we will need.
 </p>
 <p>To specify in pixels the placement of each graph we use
 <code>SetNewPlotAreaPixels</code>. The format is
 <code>SetNewPlotAreaPixels(upper_left_x, upper_left_y, lower_right_x,
 lower_right_y)</code> . Again we are using the GD coordinates where 0,0
-is the upper left corner of the image. 
+is the upper left corner of the image.
 </p>
 <p>In more detail:</p>
 <div class="box">
 <pre>&lt;?php
-include('./PHPlot.php');  // here we include the PHPlot code 
-$graph = new PHPlot(400,250);   // here we define the variable $graph 
+include('./PHPlot.php');  // here we include the PHPlot code
+$graph =& new PHPlot(400,250);   // here we define the variable $graph
 $graph-&gt;SetPrintImage(0); //Don't draw the image yet
 
 //....Data and Values for first graph here .....
 
 $graph-&gt;SetNewPlotAreaPixels(70,10,375,100);  // where to place it
 
-$graph-&gt;DrawGraph();   //Draw the first graph to the image. 
+$graph-&gt;DrawGraph();   //Draw the first graph to the image.
 
 //....Data and Values for second graph here .....
 
@@ -373,7 +370,7 @@ $graph-&gt;PrintImage();
 include('./phplot.php');
 
 //Define the object
-$graph = new PHPlot(400,250);
+$graph =& new PHPlot(400,250);
 
 $graph-&gt;SetPrintImage(0); //Don't draw the image until specified explicitly
 
@@ -399,10 +396,10 @@ $graph-&gt;SetPlotType("lines");
 $graph-&gt;SetLineWidth(1);
 
 $graph-&gt;SetNewPlotAreaPixels(70,10,375,100);  // where do we want the graph to go
-$graph-&gt;DrawGraph(); // remember, since we said not to draw yet, PHPlot 
+$graph-&gt;DrawGraph(); // remember, since we said not to draw yet, PHPlot
                      // still needs a <i>PrintImage </i>command to write an image.
 
-                     
+
 //Now do the second chart on the same image
 unset($example_data);  //we are re-using $example_data (to save memory), but you don't have to
 $example_data = array(
@@ -439,7 +436,7 @@ $graph-&gt;PrintImage();
 <div align="center">
   <img src="imgs/qstart_fig4.png" name="graphic3" align="top" border="0" /> <br />
   Figure 4 <br />
-</div>  
+</div>
 
 <p>
 You must remember that world Coordinates are the XY coordinates relative to the
index 3c2dae113f75fe5def255ea0cb3fc38587f5994f..4d4fe58c6c879bd1d7b02685ffc998bf1cb7ea05 100644 (file)
@@ -3,37 +3,35 @@
 /* $Id$ */
 
 /*
- * Copyright (C) 1998, 1999, 2000, 2001, 2002 Afan Ottenheimer.  Released under
- * the GPL and PHP licenses as stated in the the README file which
- * should have been included with this document.
+ * PHPLOT Version 5.0.rc1
+ * Copyright (C) 1998, 1999, 2000, 2001 Afan Ottenheimer.  Released under
+ * the GPL and PHP licenses as stated in the the README file which should
+ * have been included with this document.
  *
- * Recent (2003-2004) work by Miguel de Benito Delgado <nonick AT 8027 DOT org>
+ * Recent (2003-2004) work by Miguel de Benito Delgado <nonick AT vodafone DOT es>
  *
+ * Requires PHP 4.2.0 or later (CHECK THIS)
  */
 
-
-// PHPLOT Version 5.0.rc1
-// Requires PHP 4.1.0 or later (CHECK THIS)
-
 if (! defined(__FUNCTION__))
     define(__FUNCTION__, '__FUNCTION__ Requires at least PHP 4.3.0.');
 
 define ('MINY', -1);        // Indexes in $data (for DrawXDataLine())
 define ('MAXY', -2);
+define ('TOTY', -3);
 
 error_reporting(E_ALL);
 
-
 class PHPlot {
 
-    /* I have removed internal variable declarations, some isset() checking was required, 
+    /* I have removed internal variable declarations, some isset() checking was required,
      * but now the variables left are those which can be tweaked by the user. This is intended to
-     * be the first step towards moving most of the Set...() methods into a subclass which will be 
+     * be the first step towards moving most of the Set...() methods into a subclass which will be
      * used only when strictly necessary. Many users will be able to put default values here in the
      * class and thus avoid memory overhead and reduce parsing times.
      */
     //////////////// CONFIG PARAMETERS //////////////////////
-       var $reduction = 8;                                     // BW Patch
+
     var $is_inline = FALSE;             // FALSE = Sends headers, TRUE = sends just raw image data
     var $browser_cache = FALSE;         // FALSE = Sends headers for browser to not cache the image,
                                         // (only if is_inline = FALSE also)
@@ -48,7 +46,7 @@ class PHPlot {
 
 //Fonts
     var $use_ttf  = FALSE;                  // Use True Type Fonts?
-    var $ttf_path = '.';                    // Default path to look in for TT Fonts. 
+    var $ttf_path = '.';                    // Default path to look in for TT Fonts.
     var $default_ttfont = 'benjamingothic.ttf';
     var $line_spacing = 4;                  // Pixels between lines.
 
@@ -64,7 +62,7 @@ class PHPlot {
     var $output_file = '';                  // For output to a file instead of stdout
 
 //Data
-    var $data_type = 'text-data';           // text-data, data-data-error, data-data, text-data-pie
+    var $data_type = 'text-data';           // text-data, data-data-error, data-data, text-data-single
     var $plot_type= 'linepoints';           // bars, lines, linepoints, area, points, pie, thinbarline, squared
 
     var $label_scale_position = 0.5;        // Shifts data labes in pie charts. 1 = top, 0 = bottom
@@ -89,10 +87,10 @@ class PHPlot {
 //Labels
     // There are two types of labels in PHPlot:
     //    Tick labels: they follow the grid, next to ticks in axis.   (DONE)
-    //                 they are drawn at grid drawing time, by _DrawXTicks() and _DrawYTicks()
+    //                 they are drawn at grid drawing time, by DrawXTicks() and DrawYTicks()
     //    Data labels: they follow the data points, and can be placed on the axis or the plot (x/y)  (TODO)
-    //                 they are drawn at graph plotting time, by DrawDataLabel(), called by DrawLines(), etc.
-    //                 Draw*DataLabel() also draws H/V lines to datapoints depending on draw_*_data_label_line
+    //                 they are drawn at graph plotting time, by Draw*DataLabel(), called by DrawLines(), etc.
+    //                 Draw*DataLabel() also draws H/V lines to datapoints depending on draw_*_data_label_lines
 
     // Tick Labels
     var $x_tick_label_pos = 'plotdown';     // plotdown, plotup, both, xaxis, none
@@ -109,11 +107,12 @@ class PHPlot {
     var $x_label_type = '';                 // data, time. Leave blank for no formatting.
     var $y_label_type = '';                 // data, time. Leave blank for no formatting.
     var $x_time_format = '%H:%m:%s';        // See http://www.php.net/manual/html/function.strftime.html
-    var $y_time_format = '%H:%m:%s';        // SetYTimeFormat() too... 
+    var $y_time_format = '%H:%m:%s';        // SetYTimeFormat() too...
 
     // Skipping labels
     var $x_label_inc = 1;                   // Draw a label every this many (1 = all) (TODO)
     var $y_label_inc = 1;
+    var $_x_label_cnt = 0;                  // internal count FIXME: work in progress
 
     // Legend
     var $legend = '';                       // An array with legend titles
@@ -128,14 +127,14 @@ class PHPlot {
     var $x_tick_cross = 3;                  // ticks cross x axis this many pixels
     var $y_tick_cross = 3;                  // ticks cross y axis this many pixels
 
-    var $x_tick_pos = 'plotdown';           // plotdown, plotup, both, xaxis, none 
-    var $y_tick_pos = 'plotleft';           // plotright, plotleft, both, yaxis, none 
+    var $x_tick_pos = 'plotdown';           // plotdown, plotup, both, xaxis, none
+    var $y_tick_pos = 'plotleft';           // plotright, plotleft, both, yaxis, none
 
     var $num_x_ticks = '';
     var $num_y_ticks = '';
 
-    var $x_tick_increment = '';             // Set num_x_ticks or x_tick_increment, not both.
-    var $y_tick_increment = '';             // Set num_y_ticks or y_tick_increment, not both.
+    var $x_tick_inc = '';                   // Set num_x_ticks or x_tick_inc, not both.
+    var $y_tick_inc = '';                   // Set num_y_ticks or y_tick_inc, not both.
 
     var $skip_top_tick = FALSE;
     var $skip_bottom_tick = FALSE;
@@ -147,6 +146,7 @@ class PHPlot {
     var $draw_y_grid = TRUE;
 
     var $dashed_grid = TRUE;
+    var $grid_at_foreground = FALSE;        // Chooses whether to draw the grid below or above the graph
 
 //Colors and styles       (all colors can be array (R,G,B) or named color)
     var $color_array = 'small';             // 'small', 'large' or array (define your own colors)
@@ -168,8 +168,8 @@ class PHPlot {
     var $line_styles = array('solid', 'solid', 'dashed');   // single value or array
     var $dashed_style = '2-4';              // colored dots-transparent dots
 
-    var $point_size = 5;
-    var $point_shape = 'diamond';           // rect, circle, diamond, triangle, dot, line, halfline, cross
+    var $point_sizes = array(5,5,3);         // single value or array
+    var $point_shapes = array('diamond');   // rect, circle, diamond, triangle, dot, line, halfline, cross
 
     var $error_bar_size = 5;                // right and left size of tee
     var $error_bar_shape = 'tee';           // 'tee' or 'line'
@@ -190,13 +190,13 @@ class PHPlot {
 
     /*!
      * Constructor: Setup img resource, colors and size of the image, and font sizes.
-     * 
+     *
      * \param which_width       int    Image width in pixels.
      * \param which_height      int    Image height in pixels.
      * \param which_output_file string Filename for output.
      * \param which_input_fule  string Path to a file to be used as background.
      */
-    function PHPlot($which_width=600, $which_height=400, $which_output_file=NULL, $which_input_file=NULL) 
+    function PHPlot($which_width=600, $which_height=400, $which_output_file=NULL, $which_input_file=NULL)
     {
         /*
          * Please see http://www.php.net/register_shutdown_function
@@ -218,7 +218,7 @@ class PHPlot {
 
         $this->SetRGBArray($this->color_array);
 
-        $this->background_done = FALSE;     // Set to TRUE after background image first drawn
+        $this->background_done = FALSE;     // Set to TRUE after background image is drawn once
 
         if ($which_output_file)
             $this->SetOutputFile($which_output_file);
@@ -251,14 +251,14 @@ class PHPlot {
      * do it ourselves.
      * See notes in the constructor code.
      */
-    function _PHPlot () 
+    function _PHPlot ()
     {
         ImageDestroy($this->img);
         return;
     }
 
 
-/////////////////////////////////////////////    
+/////////////////////////////////////////////
 //////////////                         COLORS
 /////////////////////////////////////////////
 
@@ -306,13 +306,13 @@ class PHPlot {
      * FIXME Isn't this too slow?
      *
      */
-    function SetDefaultStyles() 
+    function SetDefaultStyles()
     {
         /* Some of the Set*() functions use default values when they get no parameters. */
 
         if (! isset($this->session_set)) {
             // If sessions are enabled, this variable will be preserved, so upon future executions, we
-            // will have it set, as well as color names (though not color indices, that's why we 
+            // will have it set, as well as color names (though not color indices, that's why we
             // need to rebuild them)
             $this->session_set = TRUE;
 
@@ -320,7 +320,7 @@ class PHPlot {
             $this->SetLineWidths();
             $this->SetLineStyles();
             $this->SetDefaultDashedStyle($this->dashed_style);
-            $this->SetPointSize($this->point_size);
+            $this->SetPointSizes($this->point_sizes);
         }
 
         $this->SetImageBorderColor($this->i_border);
@@ -341,7 +341,7 @@ class PHPlot {
     /*
      *
      */
-    function SetBackgroundColor($which_color) 
+    function SetBackgroundColor($which_color)
     {
         $this->bg_color= $which_color;
         $this->ndx_bg_color= $this->SetIndexColor($this->bg_color);
@@ -351,7 +351,7 @@ class PHPlot {
     /*
      *
      */
-    function SetPlotBgColor($which_color) 
+    function SetPlotBgColor($which_color)
     {
         $this->plot_bg_color= $which_color;
         $this->ndx_plot_bg_color= $this->SetIndexColor($this->plot_bg_color);
@@ -389,7 +389,7 @@ class PHPlot {
         return TRUE;
     }
 
-    
+
     /*
      *
      */
@@ -400,7 +400,7 @@ class PHPlot {
         return TRUE;
     }
 
-    
+
     /*
      *
      */
@@ -422,7 +422,7 @@ class PHPlot {
         return TRUE;
     }
 
-    
+
     /*
      *
      */
@@ -434,11 +434,11 @@ class PHPlot {
         return TRUE;
     }
 
-    
+
     /*
      *
      */   
-    function SetTransparentColor($which_color) 
+    function SetTransparentColor($which_color)
     { 
         ImageColorTransparent($this->img, $this->SetIndexColor($which_color));
         return TRUE;
@@ -651,7 +651,7 @@ class PHPlot {
     /*!
      * Sets line widths on a per-line basis.
      */
-    function SetLineWidths($which_lw=NULL) 
+    function SetLineWidths($which_lw=NULL)
     {
         if (is_null($which_lw)) {
             // Do nothing, use default value.
@@ -689,7 +689,7 @@ class PHPlot {
     /*!
      * Sets number of pixels between lines of the same text.
      */
-    function SetLineSpacing($which_spc) 
+    function SetLineSpacing($which_spc)
     {
         $this->line_spacing = $which_spc;
     }
@@ -728,7 +728,7 @@ class PHPlot {
     /*!
      * Sets the default TrueType font and updates all fonts to that.
      */
-    function SetDefaultTTFont($which_font) 
+    function SetDefaultTTFont($which_font)
     {
         if (is_file($which_font) && is_readable($which_font)) {
             $this->default_ttfont = $which_font;
@@ -742,7 +742,7 @@ class PHPlot {
     /*!
      * Sets fonts to their defaults
      */
-    function SetDefaultFonts() 
+    function SetDefaultFonts()
     {
         // TTF:
         if ($this->use_ttf) {
@@ -755,7 +755,7 @@ class PHPlot {
             $this->SetFont('y_label', $this->default_ttfont, 6);
             $this->SetFont('x_title', $this->default_ttfont, 10);
             $this->SetFont('y_title', $this->default_ttfont, 10);
-        } 
+        }
         // Fixed:
         else {
             $this->SetFont('generic', 2);
@@ -773,9 +773,9 @@ class PHPlot {
     /*!
      * Sets Fixed/Truetype font parameters.
      *  \param $which_elem Is the element whose font is to be changed.
-     *         It can be one of 'title', 'legend', 'generic', 
+     *         It can be one of 'title', 'legend', 'generic',
      *         'x_label', 'y_label', x_title' or 'y_title'
-     *  \param $which_font Can be a number (for fixed font sizes) or 
+     *  \param $which_font Can be a number (for fixed font sizes) or
      *         a string with the filename when using TTFonts.
      *  \param $which_size Point size (TTF only)
      * Calculates and updates internal height and width variables.
@@ -847,7 +847,7 @@ class PHPlot {
            break;
         case 'legend':
             $this->legend_font['font'] = $which_font;
-            $this->legend_font['height'] = ImageFontHeight($which_font)-$this->reduction;      // BW Patch
+            $this->legend_font['height'] = ImageFontHeight($which_font);
             $this->legend_font['width'] = ImageFontWidth($which_font);
             break;
         case 'x_label':
@@ -899,10 +899,10 @@ class PHPlot {
 
 
     /*!
-     * Draws a string of text. Horizontal and vertical alignment are relative to 
+     * Draws a string of text. Horizontal and vertical alignment are relative to
      * to the drawing. That is: vertical text (90 deg) gets centered along y-axis 
      * with v_align = 'center', and adjusted to the left of x-axis with h_align = 'right',
-     * 
+     *
      * \note Original multiple lines code submitted by Remi Ricard.
      * \note Original vertical code submitted by Marlin Viss.
      */
@@ -910,8 +910,8 @@ class PHPlot {
                       $which_halign = 'left', $which_valign = 'bottom') 
     {
         // TTF:
-        if ($this->use_ttf) { 
-            $size = $this->TTFBBoxSize($which_font['size'], $which_angle, $which_font['font'], $which_text); 
+        if ($this->use_ttf) {
+            $size = $this->TTFBBoxSize($which_font['size'], $which_angle, $which_font['font'], $which_text);
             $rads = deg2rad($which_angle);
 
             if ($which_valign == 'center')
@@ -930,10 +930,10 @@ class PHPlot {
                 $which_xpos -= $size[0] * cos($rads);
 
             ImageTTFText($this->img, $which_font['size'], $which_angle, 
-                         $which_xpos, $which_ypos, $which_color, $which_font['font'], $which_text); 
+                         $which_xpos, $which_ypos, $which_color, $which_font['font'], $which_text);
         }
         // Fixed fonts:
-        else { 
+        else {
             // Split the text by its lines, and count them
             $which_text = ereg_replace("\r", "", $which_text);
             $str = split("\n", $which_text);
@@ -944,7 +944,7 @@ class PHPlot {
             // (Remember the alignment convention with vertical text)
             if ($which_angle == 90) {
                 // The text goes around $which_xpos.
-                if ($which_halign == 'center') 
+                if ($which_halign == 'center')
                     $which_xpos -= ($nlines * ($which_font['height'] + $spacing))/2;
 
                 // Left alignment requires no modification to $xpos...
@@ -965,7 +965,7 @@ class PHPlot {
                                   $i * ($which_font['height'] + $spacing) + $which_xpos,
                                   $ypos, $str[$i], $which_color);
                 } 
-            } 
+            }
             // Horizontal text:
             else {
                 // The text goes above $which_ypos
@@ -977,7 +977,7 @@ class PHPlot {
                 // valign = 'bottom' requires no modification
 
                 $xpos = $which_xpos;
-                for($i = 0; $i < $nlines; $i++) { 
+                for($i = 0; $i < $nlines; $i++) {
                     // center the text around $which_xpos
                     if ($which_halign == 'center')
                         $xpos = $which_xpos - (strlen($str[$i]) * $which_font['width'])/2;
@@ -991,7 +991,7 @@ class PHPlot {
                 }                 
             }
         } 
-        return TRUE; 
+        return TRUE;
     } // function DrawText()
 
 
@@ -1000,103 +1000,81 @@ class PHPlot {
 /////////////////////////////////////////////
 
     /*!
-     * Sets output format.
-     * inline condition, cacheable, etc.
+     * Sets output file format.
      */
-    function SetFileFormat($which_file_format) 
+    function SetFileFormat($format)
     {
-        // I know rewriting this was unnecessary, but it didn't work for me, I don't
-        // understand why. 
-        $asked = strtolower($which_file_format);
+        $asked = $this->CheckOption($format, 'jpg, png, gif, wbmp', __FUNCTION__);
+
         switch ($asked) {
         case 'jpg':
             if (imagetypes() & IMG_JPG)
+                $this->file_format = 'jpg';
                 return TRUE;
             break;
         case 'png':
             if (imagetypes() & IMG_PNG)
+                $this->file_format = 'png';
                 return TRUE;
             break;
         case 'gif':
             if (imagetypes() & IMG_GIF)
+                $this->file_format = 'gif';
                 return TRUE;
             break;
         case 'wbmp':
             if (imagetypes() & IMG_WBMP)
+                $this->file_format = 'wbmp';
                 return TRUE;
             break;
         default:
-            $this->PrintError("SetFileFormat(): Unrecognized option '$which_file_format'");
+            $this->PrintError("SetFileFormat():File format '$format' not supported");
             return FALSE;
         }
-        $this->PrintError("SetFileFormat():File format '$which_file_format' not supported");
-        return FALSE;
-    }    
+    }
 
 
     /*!
-     * Selects an input file to be used as background for the whole graph.
+     * Selects an input file to be used as graph background and scales or tiles this image
+     * to fit the sizes.
+     *  \param input_file string Path to the file to be used (jpeg, png and gif accepted)
+     *  \param mode       string 'centeredtile', 'tile', 'scale' (the image to the graph's size)
      */
-    function SetInputFile($which_input_file) 
-    { 
-        $size = GetImageSize($which_input_file);
-        $input_type = $size[2]; 
-
-        switch($input_type) {
-        case 1:
-            $im = @ImageCreateFromGIF ($which_input_file);
-            if (!$im) { // See if it failed 
-                $this->PrintError("Unable to open $which_input_file as a GIF");
-                return FALSE;
-            }
-        break;
-        case 3:
-            $im = @ImageCreateFromPNG ($which_input_file); 
-            if (!$im) { // See if it failed 
-                $this->PrintError("Unable to open $which_input_file as a PNG");
-                return FALSE;
-            }
-        break;
-        case 2:
-            $im = @ImageCreateFromJPEG ($which_input_file); 
-            if (!$im) { // See if it failed 
-                $this->PrintError("Unable to open $which_input_file as a JPG");
-                return FALSE;
-            }
-        break;
-        default:
-            $this->PrintError('SetInputFile(): Please select gif, jpg, or png for image type!');
-            return FALSE;
-        break;
-        }
-
-        // Set Width and Height of Image
-        $this->image_width = $size[0];
-        $this->image_height = $size[1];
-
-        // Deallocate any resources previously allocated
-        if ($this->img)
-            imagedestroy($this->img);
-
-        $this->img = $im;
-
-        return TRUE;
+    function SetBgImage($input_file, $mode='centeredtile')
+    {
+        $this->bgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
+        $this->bgimg  = $input_file;
+    }
 
+    /*!
+     * Selects an input file to be used as plot area background and scales or tiles this image
+     * to fit the sizes.
+     *  \param input_file string Path to the file to be used (jpeg, png and gif accepted)
+     *  \param mode       string 'centeredtile', 'tile', 'scale' (the image to the graph's size)
+     */
+    function SetPlotAreaBgImage($input_file, $mode='tile')
+    {
+        $this->plotbgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
+        $this->plotbgimg  = $input_file;
     }
 
-    function SetOutputFile($which_output_file) 
-    { 
+
+    /*!
+     * Sets the name of the file to be used as output file.
+     */
+    function SetOutputFile($which_output_file)
+    {
         $this->output_file = $which_output_file;
         return TRUE;
     }
 
     /*!
-     * Sets the output image as 'inline', ie. no Content-Type headers are sent
-     * to the browser. Very useful if you want to embed the images.
+     * Sets the output image as 'inline', that is: no Content-Type headers are sent
+     * to the browser. Needed if you want to embed the images.
      */
-    function SetIsInline($which_ii) 
+    function SetIsInline($which_ii)
     {
-        $this->is_inline = $which_ii;
+        $this->is_inline = (bool)$which_ii;
         return TRUE;
     }
 
@@ -1105,7 +1083,7 @@ class PHPlot {
      * Performs the actual outputting of the generated graph, and
      * destroys the image resource.
      */
-    function PrintImage() 
+    function PrintImage()
     {
         // Browser cache stuff submitted by Thiemo Nagel
         if ( (! $this->browser_cache) && (! $this->is_inline)) {
@@ -1208,12 +1186,12 @@ class PHPlot {
     /*!
      * Sets position for X labels following data points.
      */
-    function SetXDataLabelPos($which_xdlp) 
+    function SetXDataLabelPos($which_xdlp)
     {
         $this->x_data_label_pos = $this->CheckOption($which_xdlp, 'plotdown, plotup, both, xaxis, all, none',
                                                       __FUNCTION__);
         if ($which_xdlp != 'none')
-            $this->x_tick_label_pos == 'none';
+            $this->x_tick_label_pos = 'none';
 
         return TRUE;
     }
@@ -1226,7 +1204,7 @@ class PHPlot {
         $this->y_data_label_pos = $this->CheckOption($which_ydlp, 'plotleft, plotright, both, yaxis, all, none',
                                                       __FUNCTION__);
         if ($which_ydlp != 'none')
-            $this->y_tick_label_pos == 'none';
+            $this->y_tick_label_pos = 'none';
 
         return TRUE;
     }
@@ -1240,7 +1218,7 @@ class PHPlot {
         $this->x_tick_label_pos = $this->CheckOption($which_xtlp, 'plotdown, plotup, both, xaxis, all, none',
                                                       __FUNCTION__);
         if ($which_xtlp != 'none')
-            $this->x_data_label_pos == 'none';
+            $this->x_data_label_pos = 'none';
 
         return TRUE;
     }
@@ -1253,7 +1231,7 @@ class PHPlot {
         $this->y_tick_label_pos = $this->CheckOption($which_ytlp, 'plotleft, plotright, both, yaxis, all, none',
                                                       __FUNCTION__);
         if ($which_ytlp != 'none')
-            $this->y_data_label_pos == 'none';
+            $this->y_data_label_pos = 'none';
 
         return TRUE;
     }
@@ -1305,10 +1283,6 @@ class PHPlot {
 /////////////////////////////////////////////
 
     /*!
-     * ON THE WORKS:        XXX XXX XXX XXX
-     *
-     *****************                       __FUNCTION__ needs PHP 4.3.0
-     *
      * Checks the valididy of an option.
      *  \param which_opt  String to check.
      *  \param which_acc  String of accepted choices.
@@ -1325,19 +1299,20 @@ class PHPlot {
         if ($asked == '')
             return '';
 
+        $asked = strtolower($asked);
         if (@ eregi($asked, $which_acc)) {
             return $asked;
         } else {
             $this->DrawError("$which_func(): '$which_opt' not in available choices: '$which_acc'.");
             return NULL;
-        } 
+        }
     }
 
 
     /*!
      *  \note Submitted by Thiemo Nagel
      */
-    function SetBrowserCache($which_browser_cache) 
+    function SetBrowserCache($which_browser_cache)
     {
         $this->browser_cache = $which_browser_cache;
         return TRUE;
@@ -1346,7 +1321,7 @@ class PHPlot {
     /*!
      * Whether to show the final image or not
      */
-    function SetPrintImage($which_pi) 
+    function SetPrintImage($which_pi)
     {
         $this->print_image = $which_pi;
         return TRUE;
@@ -1389,7 +1364,7 @@ class PHPlot {
      */
     function SetLegendWorld($which_x, $which_y, $which_type=NULL) 
     { 
-        if (! $this->scale_is_set) 
+        if (! isset($this->scale_is_set))
             $this->CalcTranslation();
 
         $this->legend_x_pos = $this->xtr($which_x);
@@ -1401,7 +1376,7 @@ class PHPlot {
     /*!
      * Accepted values are: left, sides, none, full
      */
-    function SetPlotBorderType($pbt) 
+    function SetPlotBorderType($pbt)
     {
         $this->plot_border_type = $this->CheckOption($pbt, 'left, sides, none, full', __FUNCTION__);
     }
@@ -1418,7 +1393,7 @@ class PHPlot {
     /*!
      * \param dpab bool
      */
-    function SetDrawPlotAreaBackground($dpab) 
+    function SetDrawPlotAreaBackground($dpab)
     {
         $this->draw_plot_area_background = (bool)$dpab;
     }
@@ -1473,8 +1448,10 @@ class PHPlot {
         $this->draw_y_data_label_lines = $dydl;
         return TRUE;
     }
+    
     /*!
      * Sets the graph's title.
+     * TODO: add parameter to choose title placement: left, right, centered=
      */
     function SetTitle($which_title) 
     {
@@ -1565,15 +1542,15 @@ class PHPlot {
     function SetPlotType($which_pt) 
     {
         $this->plot_type = $this->CheckOption($which_pt, 
-                                  'bars, lines, linepoints, area, points, pie, thinbarline, squared', 
-                                  __FUNCTION__);
+                           'bars, stackedbars, lines, linepoints, area, points, pie, thinbarline, squared', 
+                            __FUNCTION__);
     }
 
     /*!
      * Sets the position of Y axis.
-     * \param pos int Position in world coordinates. 
+     * \param pos int Position in world coordinates.
      */
-    function SetYAxisPosition($pos) 
+    function SetYAxisPosition($pos)
     {
         $this->y_axis_position = (int)$pos;
         if (isset($this->scale_is_set)) {
@@ -1586,7 +1563,7 @@ class PHPlot {
      * Sets the position of X axis.
      * \param pos int Position in world coordinates. 
      */
-    function SetXAxisPosition($pos) 
+    function SetXAxisPosition($pos)
     {
         $this->x_axis_position = (int)$pos;
         if (isset($this->scale_is_set)) {
@@ -1596,43 +1573,46 @@ class PHPlot {
     }
 
 
-    function SetXScaleType($which_xst) 
-    { 
+    function SetXScaleType($which_xst)
+    {
         $this->xscale_type = $this->CheckOption($which_xst, 'linear, log', __FUNCTION__);
         return TRUE;
     }
 
-    function SetYScaleType($which_yst) 
-    { 
+    function SetYScaleType($which_yst)
+    {
         $this->yscale_type = $this->CheckOption($which_yst, 'linear, log',  __FUNCTION__);
         return TRUE;
     }
 
-    function SetPrecisionX($which_prec) 
+    function SetPrecisionX($which_prec)
     {
         $this->x_precision = $which_prec;
+        $this->SetXLabelType('data');
         return TRUE;
     }
-    function SetPrecisionY($which_prec) 
+
+    function SetPrecisionY($which_prec)
     {
         $this->y_precision = $which_prec;
+        $this->SetYLabelType('data');
         return TRUE;
     }
 
-    function SetErrorBarLineWidth($which_seblw) 
+    function SetErrorBarLineWidth($which_seblw)
     {
         $this->error_bar_line_width = $which_seblw;
         return TRUE;
     }
 
-    function SetLabelScalePosition($which_blp) 
+    function SetLabelScalePosition($which_blp)
     {
         //0 to 1
         $this->label_scale_position = $which_blp;
         return TRUE;
     }
 
-    function SetErrorBarSize($which_ebs) 
+    function SetErrorBarSize($which_ebs)
     {
         //in pixels
         $this->error_bar_size = $which_ebs;
@@ -1642,33 +1622,81 @@ class PHPlot {
     /*!
      * Can be one of: 'tee', 'line'
      */
-    function SetErrorBarShape($which_ebs) 
+    function SetErrorBarShape($which_ebs)
     {
         $this->error_bar_shape = $this->CheckOption($which_ebs, 'tee, line', __FUNCTION__);
     }
 
     /*!
-     * Can be one of: 'halfline', 'line', 'plus', 'cross', 'rect', 'circle', 'dot',
+     * Sets point shape for each data set via an array.
+     * Shape can be one of: 'halfline', 'line', 'plus', 'cross', 'rect', 'circle', 'dot',
      * 'diamond', 'triangle', 'trianglemid'
      */
-    function SetPointShape($which_pt) 
+    function SetPointShapes($which_pt)
     {
-        $this->point_shape = $this->CheckOption($which_pt, 
-                              'halfline, line, plus, cross, rect, circle, dot, diamond, triangle, trianglemid',
-                              __FUNCTION__);
+        if (is_null($which_pt)) {
+            // Do nothing, use default value.
+        } else if (is_array($which_pt)) {
+            // Did we get an array with point shapes?
+            $this->point_shapes = $which_pt;
+        } else {
+            // Single value into array
+            $this->point_shapes = array($which_pt);
+        }
+
+        foreach ($this->point_shapes as $shape)
+        {
+            // TODO, better check, per element rectification
+            $this->CheckOption($shape,
+               'halfline, line, plus, cross, rect, circle, dot, diamond, triangle, trianglemid',
+                __FUNCTION__);
+        }
+
+        // Make both point_shapes and point_sizes same size.
+        $ps = count($this->point_sizes);
+        $pt = count($this->point_shapes);
+
+        if ($ps < $pt) {
+            array_pad_array($this->point_sizes, $pt);
+        } else if ($pt > $ps) {
+            array_pad_array($this->point_shapes, $ps);
+        }
+        return TRUE;
     }
 
     /*!
      * Sets the point size for point plots.
      * \param ps int Size in pixels.
+     * \note Test this more extensively
      */
-    function SetPointSize($ps) 
+    function SetPointSizes($which_ps)
     {
-        $this->point_size = (int)$ps;
+        if (is_null($which_ps)) {
+            // Do nothing, use default value.
+        } else if (is_array($which_ps)) {
+            // Did we get an array with point sizes?
+            $this->point_sizes = $which_ps;
+        } else {
+            // Single value into array
+            $this->point_sizes = array($which_ps);
+        }
+
+        // Make both point_shapes and point_sizes same size.
+        $ps = count($this->point_sizes);
+        $pt = count($this->point_shapes);
+
+        if ($ps < $pt) {
+            array_pad_array($this->point_sizes, $pt);
+        } else if ($pt > $ps) {
+            array_pad_array($this->point_shapes, $ps);
+        }
 
-        if ($this->point_shape == 'diamond' or $this->point_shape == 'triangle') {
-            if ($this->point_size % 2 != 0) {
-                $this->point_size++;
+        // Fix odd point sizes for point shapes which need it
+        for ($i = 0; $i < $pt; $i++) {
+            if ($this->point_shapes[$i] == 'diamond' or $this->point_shapes[$i] == 'triangle') {
+                if ($this->point_sizes[$i] % 2 != 0) {
+                    $this->point_sizes[$i]++;
+                }
             }
         }
         return TRUE;
@@ -1687,19 +1715,21 @@ class PHPlot {
 
     /*!
      *  text-data: ('label', y1, y2, y3, ...)
-     *  text-data-pie: ('label', y1), for pie charts. See DrawPieChart()
+     *  text-data-single: ('label', data), for some pie charts.
      *  data-data: ('label', x, y1, y2, y3, ...)
      *  data-data-error: ('label', x1, y1, e1+, e2-, y2, e2+, e2-, y3, e3+, e3-, ...)
      */
-    function SetDataType($which_dt) 
+    function SetDataType($which_dt)
     {
-        //The next three lines are for past compatibility.
+        //The next four lines are for past compatibility.
         if ($which_dt == 'text-linear') { $which_dt = 'text-data'; };
         if ($which_dt == 'linear-linear') { $which_dt = 'data-data'; };
         if ($which_dt == 'linear-linear-error') { $which_dt = 'data-data-error'; };
+        if ($which_dt == 'text-data-pie') { $which_dt = 'text-data-single'; }
+
 
-        $this->data_type = $this->CheckOption($which_dt, 'text-data, text-data-pie, data-data, data-data-error',
-                                              __FUNCTION__);
+        $this->data_type = $this->CheckOption($which_dt, 'text-data, text-data-single, '.
+                                                         'data-data, data-data-error', __FUNCTION__);
         return TRUE;
     }
 
@@ -1708,8 +1738,9 @@ class PHPlot {
      * use for (or while) loops, which sometimes are faster. Performance improvements
      * vary from 28% in DrawLines() to 49% in DrawArea() for plot drawing functions.
      */
-    function SetDataValues(&$which_dv) 
+    function SetDataValues(&$which_dv)
     {
+        unset ($this->data_limits_done);        // Reset this for every new data_set
         $this->num_data_rows = count($which_dv);
         $this->total_records = 0;               // Perform some useful calculations.
         $this->records_per_group = 1;           
@@ -1739,7 +1770,7 @@ class PHPlot {
         array_pad_array($this->line_styles, $this->records_per_group);
 
         array_pad_array($this->data_colors, $this->records_per_group);
-        array_pad_array($this->data_border_colors, $this->records_per_group); 
+        array_pad_array($this->data_border_colors, $this->records_per_group);
         array_pad_array($this->error_bar_colors, $this->records_per_group);
 
         $this->SetDataColors();
@@ -1760,9 +1791,9 @@ class PHPlot {
      *   Text-Data is different than data-data graphs. For them what
      *   we have, instead of X values, is # of records equally spaced on data.
      *   text-data is passed in as $data[] = (title, y1, y2, y3, y4, ...)
-     *   data-data is passed in as $data[] = (title, x, y1, y2, y3, y4, ...) 
+     *   data-data is passed in as $data[] = (title, x, y1, y2, y3, y4, ...)
      */
-    function FindDataLimits() 
+    function FindDataLimits()
     {
         // Set some default min and max values before running through the data
         switch ($this->data_type) {
@@ -1779,13 +1810,16 @@ class PHPlot {
             $maxy = $miny;
             break;
         }
-        
-        $mine = 0;  // Maximum value for the -error bar (assume error bars always > 0) 
-        $maxe = 0;  // Maximum value for the +error bar (assume error bars always > 0) 
+
+        $mine = 0;  // Maximum value for the -error bar (assume error bars always > 0)
+        $maxe = 0;  // Maximum value for the +error bar (assume error bars always > 0)
         $maxt = 0;  // Maximum number of characters in text labels
-        
+
         $minminy = $miny;
         $maxmaxy = $maxy;
+
+        if ($this->plot_type == 'stackedbars') { $maxmaxy = $minminy = 0; }
+
         // Process each row of data
         for ($i=0; $i < $this->num_data_rows; $i++) {
             $j=0;
@@ -1793,23 +1827,30 @@ class PHPlot {
             $val = @ strlen($this->data[$i][$j++]);
             $maxt = ($val > $maxt) ? $val : $maxt;
 
+
+            if ($this->plot_type == 'stackedbars') { $maxy = $miny = 0; }
+
             switch ($this->data_type) {
             case 'text-data':           // Data is passed in as (title, y1, y2, y3, ...)
-            case 'text-data-pie':       // This one is for some pie charts, see DrawPieChart()
+            case 'text-data-single':    // This one is for some pie charts
                 // $numrecs = @ count($this->data[$i]);
                 $miny = $maxy = (double)$this->data[$i][$j];
                 for (; $j < $this->num_recs[$i]; $j++) {
                     $val = (double)$this->data[$i][$j];
-                    $maxy = ($val > $maxy) ? $val : $maxy;
-                    $miny = ($val < $miny) ? $val : $miny;
+                    if ($this->plot_type == 'stackedbars') {
+                        $maxy += abs($val);      // only positive values for the moment
+                    } else {
+                        $maxy = ($val > $maxy) ? $val : $maxy;
+                        $miny = ($val < $miny) ? $val : $miny;
+                    }
                 }
                 break;
-            case 'data-data':           // Data is passed in as (title, x, y, y2, y3, ...) 
+            case 'data-data':           // Data is passed in as (title, x, y, y2, y3, ...)
                 // X value:
                 $val = (double)$this->data[$i][$j++];
                 $maxx = ($val > $maxx) ? $val : $maxx;
                 $minx = ($val < $minx) ? $val : $minx;
-                
+
                 $miny = $maxy = (double)$this->data[$i][$j];
                 // $numrecs = @ count($this->data[$i]);
                 for (; $j < $this->num_recs[$i]; $j++) {
@@ -1847,6 +1888,7 @@ class PHPlot {
             }
             $this->data[$i][MINY] = $miny;      // This row's min Y, for DrawXDataLine()
             $this->data[$i][MAXY] = $maxy;      // This row's max Y, for DrawXDataLine()
+
             $minminy = ($miny < $minminy) ? $miny : $minminy;   // global min
             $maxmaxy = ($maxy > $maxmaxy) ? $maxy : $maxmaxy;   // global max
         }
@@ -1858,7 +1900,7 @@ class PHPlot {
         $this->max_t = $maxt;
 
         $this->data_limits_done = TRUE;
-        
+
         return TRUE;
     }
 
@@ -1870,15 +1912,22 @@ class PHPlot {
      * FIXME: fix x_data_label_pos behaviour. Now we are leaving room for it AND x_tick_label_pos
      *        maybe it shouldn't be so...
      *
+     * FIXME: y_data_label_pos is not yet used...
+     *
      * TODO: add x_tick_label_width and y_tick_label_height and use them to calculate
-     *       max_x_labels and max_y_labels, to be used by drawing functions t avoid overlapping.
+     *       max_x_labels and max_y_labels, to be used by drawing functions to avoid overlapping.
      */
-    function CalcMargins() 
+    function CalcMargins()
     {
         // Temporary variables for label size calculation
         $xlab = $this->FormatLabel('x', $this->max_x);
         $ylab = $this->FormatLabel('y', $this->max_y);
 
+        // dirty fix:
+        // max_t is the maximum data label length (from column 0 of each data row).
+        if ($this->max_t > strlen ($xlab))
+            $xlab = sprintf ("%{$this->max_t}s","_");
+
         //////// Calculate maximum X/Y axis label height and width:
 
         // TTFonts:
@@ -1889,16 +1938,16 @@ class PHPlot {
             $this->x_tick_label_height = $size[1];
 
             // Maximum Y axis label width
-            $size = $this->TTFBBoxSize($this->y_label_font['size'], $this->y_label_angle, 
+            $size = $this->TTFBBoxSize($this->y_label_font['size'], $this->y_label_angle,
                                         $this->y_label_font['font'], $ylab);
             $this->y_tick_label_width = $size[0];
         }
         // Fixed fonts:
-        else { 
+        else {
             // Maximum X axis label height
             if ($this->x_label_angle == 90)
                 $this->x_tick_label_height = strlen($xlab) * $this->x_label_font['width'];
-            else 
+            else
                 $this->x_tick_label_height = $this->x_label_font['height'];
 
             // Maximum Y axis label width
@@ -1924,7 +1973,7 @@ class PHPlot {
             $this->y_top_margin += $this->x_tick_label_height;
 
         // Lower title, ticks and tick labels, and data labels:
-        $this->y_bot_margin = $this->safe_margin * 2; 
+        $this->y_bot_margin = $this->safe_margin * 2;
 
         if ($this->x_title_pos == 'plotdown' || $this->x_title_pos == 'both')
             $this->y_bot_margin += $this->x_title_height;
@@ -1979,7 +2028,7 @@ class PHPlot {
     /*!
      * Set the margins in pixels (left, right, top, bottom)
      */
-    function SetMarginsPixels($which_lm, $which_rm, $which_tm, $which_bm) 
+    function SetMarginsPixels($which_lm, $which_rm, $which_tm, $which_bm)
     { 
 
         $this->x_left_margin = $which_lm;
@@ -1998,7 +2047,7 @@ class PHPlot {
 
     /*!
      * Sets the limits for the plot area. If no arguments are supplied, uses
-     * values calculated from _CalcMargins();
+     * values calculated from CalcMargins();
      * Like in GD, (0,0) is upper left
      *
      * This resets the scale if SetPlotAreaWorld() was already called
@@ -2035,35 +2084,44 @@ class PHPlot {
      */
     function SetPlotAreaWorld($xmin=NULL, $ymin=NULL, $xmax=NULL, $ymax=NULL) 
     {
-        if ((! $xmin)  && (! $xmax) ) {
-            // For automatic setting of data we need data limits
-            if (! isset($this->data_limits_done)) {
-                $this->FindDataLimits() ;
-            }
-            if ($this->data_type == 'text-data') {
-                $xmax = $this->max_x + 1 ;  // valid for BAR CHART TYPE GRAPHS ONLY
-                $xmin = 0 ;                 // valid for BAR CHART TYPE GRAPHS ONLY
-            } else {
-                $xmax = $this->max_x;
+        if (! isset($this->data_limits_done)) { // For automatic setting of data we need data limits
+            $this->FindDataLimits() ;
+        }
+        if ($xmin === NULL || $xmin === '') {
+            if ($this->data_type == 'text-data')  // Valid for data without X values only.
+                $xmin = 0;
+            else
                 $xmin = $this->min_x;
-            }
-
-            $ymax = ceil($this->max_y * 1.1);
-            if ($this->min_y < 0) {
-                $ymin = floor($this->min_y * 1.1);
-            } else {
-                $ymin = 0;
-            }
+        }
+        if ($xmax === NULL || $xmax === '') {
+            if ($this->data_type == 'text-data')  // Valid for data without X values only.
+                $xmax = $this->max_x + 1;
+            else
+                $xmax = $this->max_x;
         }
 
-        $this->plot_min_x = $xmin;
-        $this->plot_max_x = $xmax;
-
-        if ($ymin == $ymax) {
-            $ymax += 1;
+        // Leave room above and below the highest and lowest data points.
+        
+        if ($ymin === NULL || $ymin === '') {
+            if ($this->min_y < 0)
+                $ymin = ceil($this->min_y * 1.1);
+            else
+                $ymin = floor($this->min_y * 0.9);
+        }    
+        if ($ymax === NULL || $ymax === '') {
+            if ($this->max_y < 0)
+                $ymax = floor($this->max_y * 0.9);
+            else
+                $ymax = ceil($this->max_y * 1.1);
         }
-        if ($this->yscale_type == 'log') { 
-            //extra error checking
+        
+        // Error checking
+        
+        if ($ymin == $ymax)     // Minimum height
+            $ymax += 1;
+
+        if ($this->yscale_type == 'log') {
             if ($ymin <= 0) { 
                 $ymin = 1;
             }
@@ -2072,16 +2130,20 @@ class PHPlot {
                 return FALSE;
             }
         }
-
-        $this->plot_min_y = $ymin;
-        $this->plot_max_y = $ymax;
-
+        
         if ($ymax <= $ymin) {
             $this->DrawError('SetPlotAreaWorld(): Error in data - max not greater than min');
             return FALSE;
         }
+       
+      
+        // Reset (if it was already set) the scale with the new maxs and mins
+      
+        $this->plot_min_x = $xmin;
+        $this->plot_max_x = $xmax;
+        $this->plot_min_y = $ymin;
+        $this->plot_max_y = $ymax;
 
-        // Reset the scale with the new maxs and mins
         if (isset($this->plot_area_width)) {
             $this->CalcTranslation();
         }
@@ -2091,43 +2153,52 @@ class PHPlot {
 
 
     /*!
-     * For plots that have equally spaced x variables and multiple bars per x-point.
+     * For bar plots, which have equally spaced x variables.
      */
-    function SetEqualXCoord() 
+    function CalcBarWidths() 
     {
-        $space = ($this->plot_area[2] - $this->plot_area[0]) / 
-                 ($this->num_data_rows * 2) * $this->group_frac_width;
-        $group_width = $space * 2;
-        $bar_width = $group_width / $this->records_per_group;
-        //I think that eventually this space variable will be replaced by just graphing x.
-        $this->data_group_space = $space;
-        $this->record_bar_width = $bar_width;
+        $group_width = ($this->plot_area[2] - $this->plot_area[0]) /
+                      $this->num_data_rows * $this->group_frac_width;
+        if ($this->plot_type == 'bars') {
+            $this->record_bar_width = $group_width / $this->records_per_group;
+        } else if ($this->plot_type == 'stackedbars') {
+            $this->record_bar_width = $group_width;
+        }            
+        $this->data_group_space = $group_width / 2;
         return TRUE;
     }
 
     /*!
      * Calculates scaling stuff...
      */
-    function CalcTranslation() 
+    function CalcTranslation()
     {
-        if ($this->xscale_type == 'log') { 
-            $this->xscale = ($this->plot_area_width)/(log10($this->plot_max_x) - log10($this->plot_min_x));
-        } else { 
-            $this->xscale = ($this->plot_area_width)/($this->plot_max_x - $this->plot_min_x);
-        }
-        if ($this->yscale_type == 'log') { 
-            $this->yscale = ($this->plot_area_height)/(log10($this->plot_max_y) - log10($this->plot_min_y));
-        } else { 
-            $this->yscale = ($this->plot_area_height)/($this->plot_max_y - $this->plot_min_y);
+        if ($this->plot_max_x - $this->plot_min_x == 0) { // Check for div by 0
+            $this->xscale = 0;
+        } else {
+            if ($this->xscale_type == 'log') {
+                $this->xscale = ($this->plot_area_width)/(log10($this->plot_max_x) - log10($this->plot_min_x));
+            } else {
+                $this->xscale = ($this->plot_area_width)/($this->plot_max_x - $this->plot_min_x);
+            }
         }
 
+        if ($this->plot_max_y - $this->plot_min_y == 0) { // Check for div by 0
+            $this->yscale = 0;
+        } else {
+            if ($this->yscale_type == 'log') {
+                $this->yscale = ($this->plot_area_height)/(log10($this->plot_max_y) - log10($this->plot_min_y));
+            } else {
+                $this->yscale = ($this->plot_area_height)/($this->plot_max_y - $this->plot_min_y);
+            }
+        }
         // GD defines x = 0 at left and y = 0 at TOP so -/+ respectively
-        if ($this->xscale_type == 'log') { 
+        if ($this->xscale_type == 'log') {
             $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * log10($this->plot_min_x) );
-        } else { 
+        } else {
             $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * $this->plot_min_x);
         }
-        if ($this->yscale_type == 'log') { 
+        if ($this->yscale_type == 'log') {
             $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * log10($this->plot_min_y));
         } else { 
             $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * $this->plot_min_y);
@@ -2139,29 +2210,29 @@ class PHPlot {
         // There should be a better place for this.
 
         // User provided y axis position?
-        if ($this->y_axis_position != '') { 
+        if ($this->y_axis_position != '') {
             // Make sure we draw our axis inside the plot
-            $this->y_axis_position = ($this->y_axis_position < $this->plot_min_x) 
+            $this->y_axis_position = ($this->y_axis_position < $this->plot_min_x)
                                      ? $this->plot_min_x : $this->y_axis_position;
-            $this->y_axis_position = ($this->y_axis_position > $this->plot_max_x) 
+            $this->y_axis_position = ($this->y_axis_position > $this->plot_max_x)
                                      ? $this->plot_max_x : $this->y_axis_position;
             $this->y_axis_x_pixels = $this->xtr($this->y_axis_position);
-        } else { 
+        } else {
             // Default to left axis
             $this->y_axis_x_pixels = $this->xtr($this->plot_min_x);
         }
         // User provided x axis position?
-        if ($this->x_axis_position != '') { 
+        if ($this->x_axis_position != '') {
             // Make sure we draw our axis inside the plot
-            $this->x_axis_position = ($this->x_axis_position < $this->plot_min_y) 
+            $this->x_axis_position = ($this->x_axis_position < $this->plot_min_y)
                                      ? $this->plot_min_y : $this->x_axis_position;
-            $this->x_axis_position = ($this->x_axis_position > $this->plot_max_y) 
+            $this->x_axis_position = ($this->x_axis_position > $this->plot_max_y)
                                      ? $this->plot_max_y : $this->x_axis_position;
             $this->x_axis_y_pixels = $this->ytr($this->x_axis_position);
         } else { 
             if ($this->yscale_type == 'log')
                 $this->x_axis_y_pixels = $this->ytr(1);
-            else 
+            else
                 // Default to axis at 0 or plot_min_y (should be 0 anyway, from SetPlotAreaWorld())
                 $this->x_axis_y_pixels = ($this->plot_min_y <= 0) && (0 <= $this->plot_max_y) 
                                          ? $this->ytr(0) : $this->ytr($this->plot_min_y);
@@ -2194,9 +2265,9 @@ class PHPlot {
      */
     function ytr($y_world) 
     {
-        if ($this->yscale_type == 'log') { 
+        if ($this->yscale_type == 'log') {
             //minus because GD defines y = 0 at top. doh!
-            $y_pixels =  $this->plot_origin_y - log10($y_world) * $this->yscale ;  
+            $y_pixels =  $this->plot_origin_y - log10($y_world) * $this->yscale ;
         } else { 
             $y_pixels =  $this->plot_origin_y - $y_world * $this->yscale ;  
         }
@@ -2208,17 +2279,17 @@ class PHPlot {
      *
      * \note Time formatting suggested by Marlin Viss
      */
-    function FormatLabel($which_pos, $which_lab) 
-    { 
+    function FormatLabel($which_pos, $which_lab)
+    {
         switch ($which_pos) {
         case 'x':
         case 'plotx':
             switch ($this->x_label_type) {
             case 'title':
-                $lab = $this->data[$which_lab][0];
+                $lab = $this->data[$which_lab][0];
                 break;
             case 'data':
-                $lab = number_format($which_lab, $this->x_precision, '.', ', ').$this->data_units_text;
+                $lab = number_format($which_lab, $this->x_precision, '.', ',').$this->data_units_text;
                 break;
             case 'time':
                 $lab = strftime($this->x_time_format, $which_lab);
@@ -2227,13 +2298,13 @@ class PHPlot {
                 // Unchanged from whatever format it is passed in
                 $lab = $which_lab;
             break;
-            }    
+            }
             break;
         case 'y':
         case 'ploty':
             switch ($this->y_label_type) {
             case 'data':
-                $lab = number_format($which_lab, $this->y_precision, '.', ', ').$this->data_units_text;
+                $lab = number_format($which_lab, $this->y_precision, '.', ',').$this->data_units_text;
                 break;
             case 'time':
                 $lab = strftime($this->y_time_format, $which_lab);
@@ -2247,7 +2318,7 @@ class PHPlot {
         default:
             $this->PrintError("FormatLabel(): Unknown label type $which_type");
             return NULL;
-        } 
+        }
 
         return $lab;
     } //function FormatLabel
@@ -2261,28 +2332,27 @@ class PHPlot {
     /*!
      * Use either this or SetNumXTicks() to set where to place x tick marks
      */
-    function SetXTickIncrement($which_ti=NULL) 
+    function SetXTickIncrement($which_ti=NULL)
     {
         if ($which_ti) {
-            $this->x_tick_increment = $which_ti;  //world coordinates
+            $this->x_tick_inc = $which_ti;  //world coordinates
         } else {
             if (! isset($this->data_limits_done)) {
                 $this->FindDataLimits();  //Get maxima and minima for scaling
             }
-            //$this->x_tick_increment = ( ceil($this->max_x * 1.2) - floor($this->min_x * 1.2) )/10;
-            $this->x_tick_increment =  ($this->plot_max_x  - $this->plot_min_x  )/10;
+            $this->x_tick_inc =  ($this->plot_max_x  - $this->plot_min_x  )/10;
         }
-        $this->num_x_ticks = ''; //either use num_y_ticks or y_tick_increment, not both
+        $this->num_x_ticks = ''; //either use num_y_ticks or y_tick_inc, not both
         return TRUE;
     }
 
     /*!
      * Use either this or SetNumYTicks() to set where to place y tick marks
      */
-    function SetYTickIncrement($which_ti=NULL) 
+    function SetYTickIncrement($which_ti=NULL)
     {
         if ($which_ti) {
-            $this->y_tick_increment = $which_ti;  //world coordinates
+            $this->y_tick_inc = $which_ti;  //world coordinates
         } else {
             if (! isset($this->data_limits_done)) {
                 $this->FindDataLimits();  //Get maxima and minima for scaling
@@ -2290,10 +2360,9 @@ class PHPlot {
             if (! isset($this->plot_max_y))
                 $this->SetPlotAreaWorld();
 
-            //$this->y_tick_increment = ( ceil($this->max_y * 1.2) - floor($this->min_y * 1.2) )/10;
-            $this->y_tick_increment =  ($this->plot_max_y  - $this->plot_min_y  )/10;
+            $this->y_tick_inc =  ($this->plot_max_y  - $this->plot_min_y  )/10;
         }
-        $this->num_y_ticks = ''; //either use num_y_ticks or y_tick_increment, not both
+        $this->num_y_ticks = ''; //either use num_y_ticks or y_tick_inc, not both
         return TRUE;
     }
 
@@ -2301,14 +2370,14 @@ class PHPlot {
     function SetNumXTicks($which_nt) 
     {
         $this->num_x_ticks = $which_nt;
-        $this->x_tick_increment = '';  //either use num_x_ticks or x_tick_increment, not both
+        $this->x_tick_inc = '';  //either use num_x_ticks or x_tick_inc, not both
         return TRUE;
     }
 
     function SetNumYTicks($which_nt) 
     {
         $this->num_y_ticks = $which_nt;
-        $this->y_tick_increment = '';  //either use num_y_ticks or y_tick_increment, not both
+        $this->y_tick_inc = '';  //either use num_y_ticks or y_tick_inc, not both
         return TRUE;
     }
 
@@ -2323,9 +2392,9 @@ class PHPlot {
     /*!
      *
      */
-    function SetXTickPos($which_tp) 
+    function SetXTickPos($which_tp)
     { 
-        $this->x_tick_pos = $this->CheckOption($which_tp, 'plotdown, plotup, both, xaxis, none', __FUNCTION__); 
+        $this->x_tick_pos = $this->CheckOption($which_tp, 'plotdown, plotup, both, xaxis, none', __FUNCTION__);
         return TRUE;
     }
 
@@ -2347,25 +2416,43 @@ class PHPlot {
         return TRUE;
     }
 
-    function SetXTickLength($which_xln) 
+    /*!
+     * \param skip bool
+     */ 
+    function SetSkipLeftTick($skip)
+    {
+        $this->skip_left_tick = (bool)$skip;
+        return TRUE;
+    }
+
+    /*!
+     * \param skip bool
+     */
+    function SetSkipRightTick($skip)
+    {
+        $this->skip_right_tick = (bool)$skip;
+        return TRUE;
+    }
+
+    function SetXTickLength($which_xln)
     {
         $this->x_tick_length = $which_xln;
         return TRUE;
     }
 
-    function SetYTickLength($which_yln) 
+    function SetYTickLength($which_yln)
     {
         $this->y_tick_length = $which_yln;
         return TRUE;
     }
 
-    function SetXTickCrossing($which_xc) 
+    function SetXTickCrossing($which_xc)
     {
         $this->x_tick_cross = $which_xc;
         return TRUE;
     }
 
-    function SetYTickCrossing($which_yc) 
+    function SetYTickCrossing($which_yc)
     {
         $this->y_tick_cross = $which_yc;
         return TRUE;
@@ -2377,22 +2464,126 @@ class PHPlot {
 /////////////////////////////////////////////
 
     /*!
-     * Fills the background of the image with a solid color
+     * Fills the background.
      */
-    function DrawBackground() 
+    function DrawBackground()
     {
-        if (! $this->background_done) {     //Don't draw it twice if drawing two plots on one image
-            ImageFilledRectangle($this->img, 0, 0, $this->image_width, $this->image_height, 
-                                 $this->ndx_bg_color);
+        // Don't draw this twice if drawing two plots on one image
+        if (! $this->background_done) {
+            if (isset($this->bgimg)) {    // If bgimg is defined, use it
+                $this->tile_img($this->bgimg, 0, 0, $this->image_width, $this->image_height, $this->bgmode);
+            } else {                        // Else use solid color
+                ImageFilledRectangle($this->img, 0, 0, $this->image_width, $this->image_height,
+                                     $this->ndx_bg_color);
+            }
             $this->background_done = TRUE;
+            return TRUE;        // Done
+        }
+        return FALSE;           // Nothing done
+    }
+
+
+    /*!
+     * Fills the plot area background.
+     */
+    function DrawPlotAreaBackground()
+    {
+        if (isset($this->plotbgimg)) {
+            $this->tile_img($this->plotbgimg, $this->plot_area[0], $this->plot_area[1],
+                            $this->plot_area_width, $this->plot_area_height, $this->plotbgmode);
         }
+        else {
+            if ($this->draw_plot_area_background) {
+                ImageFilledRectangle($this->img, $this->plot_area[0], $this->plot_area[1],
+                                     $this->plot_area[2], $this->plot_area[3], $this->ndx_plot_bg_color);
+            }
+        }
+
         return TRUE;
     }
 
+
+    /*!
+     * Tiles an image at some given coordinates.
+     *
+     * \param $file   string Filename of the picture to be used as tile.
+     * \param $xorig  int    X coordinate of the plot where the tile is to begin.
+     * \param $yorig  int    Y coordinate of the plot where the tile is to begin.
+     * \param $width  int    Width of the area to be tiled.
+     * \param $height int    Height of the area to be tiled.
+     * \param $mode   string One of 'centeredtile', 'tile', 'scale'.
+     */
+    function tile_img($file, $xorig, $yorig, $width, $height, $mode)
+    {
+        $size = getimagesize($file);
+        $input_format = $size[2];
+
+        switch($input_format) {
+        case 1:
+            $im = @ imagecreatefromGIF ($file);
+            if (! $im) {
+                $this->PrintError("tile_img:() Unable to open $file as a GIF.");
+                return FALSE;
+            }
+            break;
+        case 2:
+            $im = @ imagecreatefromJPEG ($file);
+            if (! $im) {
+                $this->PrintError("tile_img(): Unable to open $file as a JPG.");
+                return FALSE;
+            }
+            break;
+        case 3:
+            $im = @ imagecreatefromPNG ($file);
+            if (! $im) {
+                $this->PrintError("tile_img(): Unable to open $file as a PNG.");
+                return FALSE;
+            }
+            break;
+        default:
+            $this->PrintError('tile_img(): Please select a gif, jpg, or png image.');
+            return FALSE;
+            break;
+        }
+
+
+        if ($mode == 'scale') {
+            imagecopyresized($this->img, $im, $xorig, $yorig, 0, 0, $width, $height, $size[0],$size[1]);
+            return TRUE;
+        } else if ($mode == 'centeredtile') {
+            $x0 = - floor($size[0]/2);   // Make the tile look better
+            $y0 = - floor($size[1]/2);
+        } else if ($mode = 'tile') {
+            $x0 = 0;
+            $y0 = 0;
+        }
+
+        // Actually draw the tile
+
+        // But first on a temporal image.
+        $tmp = ImageCreate($width, $height);
+        if (! $tmp)
+            $this->PrintError('tile_img(): Could not create image resource.');
+
+        for ($x = $x0; $x < $width; $x += $size[0])
+            for ($y = $y0; $y < $height; $y += $size[1])
+                imagecopy($tmp, $im, $x, $y, 0, 0, $size[0], $size[1]);
+
+        // Copy the temporal image onto the final one.
+        imagecopy($this->img, $tmp, $xorig, $yorig, 0,0, $width, $height);
+
+        // Free resources
+        imagedestroy($tmp);
+        imagedestroy($im);
+
+        return TRUE;
+    }  // function tile_img
+
+
     /*!
      * Draws a border around the final image.
      */
-    function DrawImageBorder() 
+    function DrawImageBorder()
     {
         switch ($this->image_border_type) {
         case 'raised':
@@ -2452,7 +2643,7 @@ class PHPlot {
     /*!
      * Draws the X-Axis Title
      */
-    function DrawXTitle() 
+    function DrawXTitle()
     {
         if ($this->x_title_pos == 'none')
             return;
@@ -2471,14 +2662,14 @@ class PHPlot {
             $ypos = $this->image_height - $this->x_title_height - $this->safe_margin;
             $this->DrawText($this->x_title_font, $this->x_title_angle,
                             $xpos, $ypos, $this->ndx_title_color, $this->x_title_txt, 'center');
-        } 
+        }
         return TRUE;
     }
 
     /*!
      * Draws the Y-Axis Title
      */
-    function DrawYTitle() 
+    function DrawYTitle()
     {
         if ($this->y_title_pos == 'none')
             return;
@@ -2488,12 +2679,12 @@ class PHPlot {
 
         if ($this->y_title_pos == 'plotleft' || $this->y_title_pos == 'both') {
             $xpos = $this->safe_margin;
-            $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color, 
+            $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color,
                             $this->y_title_txt, 'left', 'center');
         }
         if ($this->y_title_pos == 'plotright' || $this->y_title_pos == 'both') {
             $xpos = $this->image_width - $this->safe_margin - $this->y_title_width - $this->safe_margin;
-            $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color, 
+            $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color,
                             $this->y_title_txt, 'left', 'center');
         }
 
@@ -2501,46 +2692,38 @@ class PHPlot {
     }
 
 
-    /*!
-     * Fills the plot area with a solid color
-     */
-    function DrawPlotAreaBackground() 
-    {
-        ImageFilledRectangle($this->img, $this->plot_area[0], $this->plot_area[1], 
-                             $this->plot_area[2], $this->plot_area[3],
-                             $this->ndx_plot_bg_color);
-        return TRUE;
-    }
-
     /*
      * \note Horizontal grid lines overwrite horizontal axis with y=0, so call this first, then DrawXAxis()
      */
-    function DrawYAxis() 
+    function DrawYAxis()
     {
         // Draw ticks, labels and grid, if any
         $this->DrawYTicks();
 
         // Draw Y axis at X = y_axis_x_pixels
-        ImageLine($this->img, $this->y_axis_x_pixels, $this->plot_area[1], 
+        ImageLine($this->img, $this->y_axis_x_pixels, $this->plot_area[1],
                   $this->y_axis_x_pixels, $this->plot_area[3], $this->ndx_grid_color);
-                  
+
         return TRUE;
     }
 
     /*
      *
      */
-    function DrawXAxis() 
+    function DrawXAxis()
     {
         // Draw ticks, labels and grid
         $this->DrawXTicks();
 
-        //Draw Tick and Label for Y axis
-        if (! $this->skip_bottom_tick) { 
+        /* This tick and label tend to overlap with regular Y Axis labels,
+         * as Mike Pullen pointed out.
+         *
+        //Draw Tick and Label for X axis
+        if (! $this->skip_bottom_tick) {
             $ylab =$this->FormatLabel('y', $this->x_axis_position);
             $this->DrawYTick($ylab, $this->x_axis_y_pixels);
         }
-
+        */
         //Draw X Axis at Y = x_axis_y_pixels
         ImageLine($this->img, $this->plot_area[0]+1, $this->x_axis_y_pixels,
                   $this->plot_area[2]-1, $this->x_axis_y_pixels, $this->ndx_grid_color);
@@ -2552,31 +2735,31 @@ class PHPlot {
      * Draw Just one Tick, called from DrawYTicks() and DrawXAxis()
      * TODO? Move this inside DrawYTicks() and Modify DrawXAxis() ?
      */
-    function DrawYTick($which_ylab, $which_ypix) 
+    function DrawYTick($which_ylab, $which_ypix)
     {
-        // Ticks on Y axis 
-        if ($this->y_tick_pos == 'yaxis') { 
-            ImageLine($this->img, $this->y_axis_x_pixels - $this->y_tick_length, $which_ypix, 
-                      $this->y_axis_x_pixels + $this->y_tick_cross, $which_ypix, 
+        // Ticks on Y axis
+        if ($this->y_tick_pos == 'yaxis') {
+            ImageLine($this->img, $this->y_axis_x_pixels - $this->y_tick_length, $which_ypix,
+                      $this->y_axis_x_pixels + $this->y_tick_cross, $which_ypix,
                       $this->ndx_tick_color);
         }
 
         // Labels on Y axis
         if ($this->y_tick_label_pos == 'yaxis') {
             $this->DrawText($this->y_label_font, $this->y_label_angle,
-                            $this->y_axis_x_pixels - $this->y_tick_length * 1.5, $which_ypix, 
+                            $this->y_axis_x_pixels - $this->y_tick_length * 1.5, $which_ypix,
                             $this->ndx_text_color, $which_ylab, 'right', 'center');
         }
 
         // Ticks to the left of the Plot Area
-        if (($this->y_tick_pos == 'plotleft') || ($this->y_tick_pos == 'both') ) { 
+        if (($this->y_tick_pos == 'plotleft') || ($this->y_tick_pos == 'both') ) {
             ImageLine($this->img, $this->plot_area[0] - $this->y_tick_length,
                       $which_ypix, $this->plot_area[0] + $this->y_tick_cross,
                       $which_ypix, $this->ndx_tick_color);
         }
 
         // Ticks to the right of the Plot Area
-        if (($this->y_tick_pos == 'plotright') || ($this->y_tick_pos == 'both') ) { 
+        if (($this->y_tick_pos == 'plotright') || ($this->y_tick_pos == 'both') ) {
             ImageLine($this->img, ($this->plot_area[2] + $this->y_tick_length),
                       $which_ypix, $this->plot_area[2] - $this->y_tick_cross,
                       $which_ypix, $this->ndx_tick_color);
@@ -2584,14 +2767,14 @@ class PHPlot {
 
         // Labels to the left of the plot area
         if ($this->y_tick_label_pos == 'plotleft' || $this->y_tick_label_pos == 'both') {
-            $this->DrawText($this->y_label_font, $this->y_label_angle, 
-                            $this->plot_area[0] - $this->y_tick_length * 1.5, $which_ypix, 
+            $this->DrawText($this->y_label_font, $this->y_label_angle,
+                            $this->plot_area[0] - $this->y_tick_length * 1.5, $which_ypix,
                             $this->ndx_text_color, $which_ylab, 'right', 'center');
         }
         // Labels to the right of the plot area
         if ($this->y_tick_label_pos == 'plotright' || $this->y_tick_label_pos == 'both') {
-            $this->DrawText($this->y_label_font, $this->y_label_angle, 
-                            $this->plot_area[2] + $this->y_tick_length * 1.5, $which_ypix, 
+            $this->DrawText($this->y_label_font, $this->y_label_angle,
+                            $this->plot_area[2] + $this->y_tick_length * 1.5, $which_ypix,
                             $this->ndx_text_color, $which_ylab, 'left', 'center');
         }
    } // Function DrawYTick()
@@ -2599,10 +2782,11 @@ class PHPlot {
 
     /*!
      * Draws Grid, Ticks and Tick Labels along Y-Axis
-     * Ticks and ticklabels can be left of plot only, right of plot only, 
+     * Ticks and ticklabels can be left of plot only, right of plot only,
      * both on the left and right of plot, or crossing a user defined Y-axis
+     * TODO: marks at whole numbers (-10, 10, 20, 30 ...) no matter where the plot begins (-3, 4.7, etc.)
      */
-    function DrawYTicks() 
+    function DrawYTicks()
     {
         // Sets the line style for IMG_COLOR_STYLED lines (grid)
         if ($this->dashed_grid) {
@@ -2613,16 +2797,16 @@ class PHPlot {
         }
 
         // maxy is always > miny so delta_y is always positive
-        if ($this->y_tick_increment) {
-            $delta_y = $this->y_tick_increment;
+        if ($this->y_tick_inc) {
+            $delta_y = $this->y_tick_inc;
         } elseif ($this->num_y_ticks) {
             $delta_y = ($this->plot_max_y - $this->plot_min_y) / $this->num_y_ticks;
         } else {
             $delta_y = ($this->plot_max_y - $this->plot_min_y) / 10 ;
         }
 
-        // NOTE: When working with floats, because of approximations when adding $delta_y, 
-        // $y_tmp never equals $y_end  at the for loop, so one spurious line would  get drawn where 
+        // NOTE: When working with floats, because of approximations when adding $delta_y,
+        // $y_tmp never equals $y_end  at the for loop, so one spurious line would  get drawn where
         // not for the substraction to $y_end here.
         $y_tmp = (double)$this->plot_min_y;
         $y_end = (double)$this->plot_max_y - ($delta_y/2);
@@ -2651,7 +2835,7 @@ class PHPlot {
 
     /*!
      * Draws Grid, Ticks and Tick Labels along X-Axis
-     * Ticks and tick labels can be down of plot only, up of plot only, 
+     * Ticks and tick labels can be down of plot only, up of plot only,
      * both on up and down of plot, or crossing a user defined X-axis 
      *
      * \note Original vertical code submitted by Marlin Viss
@@ -2667,16 +2851,16 @@ class PHPlot {
         }
 
         // Calculate x increment between ticks
-        if ($this->x_tick_increment) {
-            $delta_x = $this->x_tick_increment;
+        if ($this->x_tick_inc) {
+            $delta_x = $this->x_tick_inc;
         } elseif ($this->num_x_ticks) {
             $delta_x = ($this->plot_max_x - $this->plot_min_x) / $this->num_x_ticks;
         } else {
             $delta_x =($this->plot_max_x - $this->plot_min_x) / 10 ;
         }
 
-        // NOTE: When working with decimals, because of approximations when adding $delta_x, 
-        // $x_tmp never equals $x_end  at the for loop, so one spurious line would  get drawn where 
+        // NOTE: When working with decimals, because of approximations when adding $delta_x,
+        // $x_tmp never equals $x_end  at the for loop, so one spurious line would  get drawn where
         // not for the substraction to $x_end here.
         $x_tmp = (double)$this->plot_min_x;
         $x_end = (double)$this->plot_max_x - ($delta_x/2);
@@ -2689,7 +2873,7 @@ class PHPlot {
         if (! $this->skip_right_tick)
             $x_end += $delta_x;
 
-        for (;$x_tmp < $x_end; $x_tmp += $delta_x) { 
+        for (;$x_tmp < $x_end; $x_tmp += $delta_x) {
             $xlab = $this->FormatLabel('x', $x_tmp);
             $x_pixels = $this->xtr($x_tmp);
 
@@ -2698,15 +2882,16 @@ class PHPlot {
                 ImageLine($this->img, $x_pixels, $this->plot_area[1], $x_pixels, $this->plot_area[3], $style);
             }
 
-            // Tick on X Axis 
-            if ($this->x_tick_pos == 'xaxis') { 
-                ImageLine($this->img, $x_pixels, $this->x_axis_y_pixels - $this->x_tick_cross, 
+            // Tick on X Axis
+            if ($this->x_tick_pos == 'xaxis') {
+
+                ImageLine($this->img, $x_pixels, $this->x_axis_y_pixels - $this->x_tick_cross,
                           $x_pixels, $this->x_axis_y_pixels + $this->x_tick_length, $this->ndx_tick_color);
             }
 
             // Label on X axis
             if ($this->x_tick_label_pos == 'xaxis') {
-                 $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels, 
+                 $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels,
                                 $this->x_axis_y_pixels + $this->x_tick_length*1.5, $this->ndx_text_color, 
                                 $xlab, 'center', 'bottom');
             }              
@@ -2731,8 +2916,8 @@ class PHPlot {
 
             // Bottom of the plot area tick label
             if ($this->x_tick_label_pos == 'plotdown' || $this->x_tick_label_pos == 'both') {
-                $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels, 
-                                $this->plot_area[3] + $this->x_tick_length*1.5, $this->ndx_text_color, 
+                $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels,
+                                $this->plot_area[3] + $this->x_tick_length*1.5, $this->ndx_text_color,
                                 $xlab, 'center', 'bottom');
             }
         }
@@ -2743,7 +2928,7 @@ class PHPlot {
     /*!
      * 
      */
-    function DrawPlotBorder() 
+    function DrawPlotBorder()
     {
         switch ($this->plot_border_type) {
         case 'left':    // for past compatibility
@@ -2784,26 +2969,30 @@ class PHPlot {
      * Leave the last parameter out, to avoid the drawing of vertical lines, no matter
      * what the setting is (for plots that need it, like DrawSquared())
      */
-    function DrawXDataLabel($xlab, $xpos, $row=FALSE) 
+    function DrawXDataLabel($xlab, $xpos, $row=FALSE)
     {
+        // FIXME!! not working...
+        if (($this->_x_label_cnt++ % $this->x_label_inc) != 0)
+            return;
+
         $xlab = $this->FormatLabel('x', $xlab);
-   
+
         // Labels below the plot area
         if ($this->x_data_label_pos == 'plotdown' || $this->x_data_label_pos == 'both')
-            $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos, 
-                            $this->plot_area[3] + $this->x_tick_length, 
+            $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos,
+                            $this->plot_area[3] + $this->x_tick_length,
                             $this->ndx_text_color, $xlab, 'center', 'bottom');
-        
+
         // Labels above the plot area
         if ($this->x_data_label_pos == 'plotup' || $this->x_data_label_pos == 'both')
-            $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos, 
-                            $this->plot_area[1] - $this->x_tick_length , 
+            $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos,
+                            $this->plot_area[1] - $this->x_tick_length ,
                             $this->ndx_text_color, $xlab, 'center', 'top');
 
         if ($row && $this->draw_x_data_label_lines)
             $this->DrawXDataLine($xpos, $row);
     }
-    
+
     /*!
      * Draws Vertical lines from data points up and down.
      * Which lines are drawn depends on the value of x_data_label_pos,
@@ -2812,7 +3001,7 @@ class PHPlot {
      * \param xpos int position in pixels of the line.
      * \param row int index of the data row being drawn.
      */
-    function DrawXDataLine($xpos, $row) 
+    function DrawXDataLine($xpos, $row)
     {
         // Sets the line style for IMG_COLOR_STYLED lines (grid)
         if($this->dashed_grid) {
@@ -2825,7 +3014,7 @@ class PHPlot {
         // Lines from the bottom up
         if ($this->x_data_label_pos == 'both') {
             ImageLine($this->img, $xpos, $this->plot_area[3], $xpos, $this->plot_area[1], $style);
-        }         
+        }
         // Lines coming from the bottom of the plot
         else if ($this->x_data_label_pos == 'plotdown') {
             // See FindDataLimits() to see why 'MAXY' index.
@@ -2853,7 +3042,7 @@ class PHPlot {
      * FIXME: maximum label length should be calculated more accurately for TT fonts
      *        Performing a BBox calculation for every legend element, for example.
      */
-    function DrawLegend($which_x1, $which_y1, $which_boxtype) 
+    function DrawLegend($which_x1, $which_y1, $which_boxtype)
     {
         // Find maximum legend label length
         $max_len = 0;
@@ -2948,15 +3137,15 @@ class PHPlot {
 
     /*!
      * Draws a pie chart. Data has to be 'text-data' type.
-     * 
-     *  This can work in two ways: the classical, with a column for each sector 
-     *  (computes the column totals and draws the pie with that) 
+     *
+     *  This can work in two ways: the classical, with a column for each sector
+     *  (computes the column totals and draws the pie with that)
      *  OR
      *  Takes each row as a sector and uses it's first value. This has the added
      *  advantage of using the labels provided, which is not the case with the
      *  former method. This might prove useful for pie charts from GROUP BY sql queries
      */
-    function DrawPieChart() 
+    function DrawPieChart()
     {
         $xpos = $this->plot_area[0] + $this->plot_area_width/2;
         $ypos = $this->plot_area[1] + $this->plot_area_height/2;
@@ -2972,7 +3161,7 @@ class PHPlot {
             }
         }
         // Or only one column per row, one pie slice per row?
-        else if ($this->data_type == 'text-data-pie') {
+        else if ($this->data_type == 'text-data-single') {
             for ($i = 0; $i < $this->num_data_rows; $i++) {
                 $legend[$i] = $this->data[$i][0];                   // Set the legend to column labels
                 $sumarr[$i] = $this->data[$i][1];
@@ -2984,7 +3173,7 @@ class PHPlot {
                     @ $sumarr[$j] += abs($this->data[$i][$j]);
                 }
             }
-        }            
+        }
         else {
             $this->DrawError("DrawPieChart(): Data type '$this->data_type' not supported.");
             return FALSE;
@@ -3012,7 +3201,7 @@ class PHPlot {
                 // For shaded pies: the last one (at the top of the "stack") has a brighter color:
                 if ($h == 0)
                     $slicecol = $this->ndx_data_colors[$color_index];
-                else                
+                else
                     $slicecol = $this->ndx_data_dark_colors[$color_index];
 
                 $label_txt = number_format(($val / $total * 100), $this->y_precision, '.', ', ') . '%';
@@ -3025,8 +3214,8 @@ class PHPlot {
                 $end_angle += $val;
                 $mid_angle = deg2rad($end_angle - ($val / 2));
 
-                // Draw the slice       
-                ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2, 
+                // Draw the slice
+                ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2,
                                360-$end_angle, 360-$start_angle,
                                $slicecol, IMG_ARC_PIE);
 
@@ -3034,19 +3223,19 @@ class PHPlot {
                 if ($h == 0) {
                     // Draw the outline
                     if (! $this->shading)
-                        ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2, 
+                        ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2,
                                        360-$end_angle, 360-$start_angle,
                                        $this->ndx_grid_color, IMG_ARC_PIE | IMG_ARC_EDGED |IMG_ARC_NOFILL);
 
 
-                    // The '* 1.2' trick is to get labels out of the pie chart so there are more 
+                    // The '* 1.2' trick is to get labels out of the pie chart so there are more
                     // chances they can be seen in small sectors.
                     $label_x = $xpos + ($diameter * 1.2 * cos($mid_angle)) * $this->label_scale_position;
                     $label_y = $ypos+$h - ($diam2 * 1.2 * sin($mid_angle)) * $this->label_scale_position;
 
                     $this->DrawText($this->generic_font, 0, $label_x, $label_y, $this->ndx_grid_color,
-                                    $label_txt, 'center', 'center');           
-                }                                
+                                    $label_txt, 'center', 'center');
+                }
                 $color_index++;
                 $color_index = $color_index % $max_data_colors;
             }   // end for
@@ -3058,7 +3247,7 @@ class PHPlot {
      * Supported data formats: data-data-error, text-data-error (doesn't exist yet)
      * ( data comes in as array("title", x, y, error+, error-, y2, error2+, error2-, ...) )
      */
-    function DrawDotsError() 
+    function DrawDotsError()
     {
         $this->CheckOption($this->data_type, 'data-data-error', __FUNCTION__);
 
@@ -3070,20 +3259,20 @@ class PHPlot {
                 $x_now = $this->data[$row][$record++];  // Read it, advance record index
             else
                 $x_now = 0.5 + $cnt++;                  // Place text-data at X = 0.5, 1.5, 2.5, etc...
-                
+
             // Draw X Data labels?
             if ($this->x_data_label_pos != 'none')
                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
 
             while ($record < $this->num_recs[$row]) {
                     // Y:
-                    $y_now = $this->data[$row][$record++];
-                    $this->DrawDot($x_now, $y_now, $this->point_shape, $this->ndx_data_colors[$record]);
+                    $y_now = $this->data[$row][$record];
+                    $this->DrawDot($x_now, $y_now, $record, $this->ndx_data_colors[$record++]);
 
                     // Error +
-                    $val = $this->data[$row][$record++];
+                    $val = $this->data[$row][$record];
                     $this->DrawYErrorBar($x_now, $y_now, $val, $this->error_bar_shape,
-                                         $this->ndx_error_bar_colors[$record]);
+                                         $this->ndx_error_bar_colors[$record++]);
                     // Error -
                     $val = $this->data[$row][$record];
                     $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape,
@@ -3094,11 +3283,11 @@ class PHPlot {
 
 
     /*
-     * Supported data types: 
+     * Supported data types:
      *  - data-data ("title", x, y1, y2, y3, ...)
      *  - text-data ("title", y1, y2, y3, ...)
      */
-    function DrawDots() 
+    function DrawDots()
     {
         $this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__);
 
@@ -3119,9 +3308,9 @@ class PHPlot {
 
             // Proceed with Y values
             for($idx = 0;$rec < $this->num_recs[$row]; $rec++, $idx++) {
-                if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data 
-                    $this->DrawDot($x_now, $this->data[$row][$rec], 
-                                   $this->point_shape, $this->ndx_data_colors[$idx]);
+                if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data
+                    $this->DrawDot($x_now, $this->data[$row][$rec],
+                                   $rec, $this->ndx_data_colors[$idx]);
                 }
             }
         }
@@ -3131,7 +3320,7 @@ class PHPlot {
     /*!
      * A clean, fast routine for when you just want charts like stock volume charts
      */
-    function DrawThinBarLines() 
+    function DrawThinBarLines()
     {
         $this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__);
 
@@ -3157,7 +3346,7 @@ class PHPlot {
                     // Draws a line from user defined x axis position up to ytr($val)
                     ImageLine($this->img, $x_now_pixels, $this->x_axis_y_pixels, $x_now_pixels, 
                               $this->ytr($this->data[$row][$rec]), $this->ndx_data_colors[$idx]);
-                }                              
+                }
             }
         }
 
@@ -3167,7 +3356,7 @@ class PHPlot {
     /*!
      *
      */
-    function DrawYErrorBar($x_world, $y_world, $error_height, $error_bar_type, $color) 
+    function DrawYErrorBar($x_world, $y_world, $error_height, $error_bar_type, $color)
     {
         /* 
         // TODO: add a parameter to show datalabels next to error bars?
@@ -3204,9 +3393,12 @@ class PHPlot {
      * Supported types: 'halfline', 'line', 'plus', 'cross', 'rect', 'circle', 'dot',
      * 'diamond', 'triangle', 'trianglemid'
      */
-    function DrawDot($x_world, $y_world, $dot_type, $color) 
+    function DrawDot($x_world, $y_world, $record, $color)
     {
-        $half_point = $this->point_size / 2;
+        // TODO: optimize, avoid counting every time we are called.
+        $record = $record % count ($this->point_shapes);
+
+        $half_point = $this->point_sizes[$record] / 2;
 
         $x_mid = $this->xtr($x_world);
         $y_mid = $this->ytr($y_world);
@@ -3216,7 +3408,7 @@ class PHPlot {
         $y1 = $y_mid - $half_point;
         $y2 = $y_mid + $half_point;
 
-        switch ($dot_type) {
+        switch ($this->point_shapes[$record]) {
         case 'halfline':
             ImageLine($this->img, $x1, $y_mid, $x_mid, $y_mid, $color);
             break;
@@ -3235,10 +3427,10 @@ class PHPlot {
             ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color);
             break;
         case 'circle':
-            ImageArc($this->img, $x_mid, $y_mid, $this->point_size, $this->point_size, 0, 360, $color);
+            ImageArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record], $this->point_sizes[$record], 0, 360, $color);
             break;
         case 'dot':
-            ImageFilledArc($this->img, $x_mid, $y_mid, $this->point_size, $this->point_size, 0, 360, 
+            ImageFilledArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record], $this->point_sizes[$record], 0, 360,
                            $color, IMG_ARC_PIE);
             break;
         case 'diamond':
@@ -3265,13 +3457,13 @@ class PHPlot {
      *      'text-data'
      *      'data-data'
      * NOTE: This function used to add first and last data values even on incomplete
-     *       sets. That is not the behaviour now. As for missing data in between, 
+     *       sets. That is not the behaviour now. As for missing data in between,
      *       there are two posibilities: replace the point with one on the X axis (previous
      *       way), or forget about it and use the preceding and following ones to draw the polygon.
      *       There is the possibility to use both, we just need to add the method to set
      *       it. Something like SetMissingDataBehaviour(), for example.
      */
-    function DrawArea() 
+    function DrawArea()
     {
         $incomplete_data_defaults_to_x_axis = FALSE;        // TODO: make this configurable
 
@@ -3287,7 +3479,7 @@ class PHPlot {
 
 
             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
-                $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);                   
+                $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
 
             // Proceed with Y values
             // Create array of points for imagefilledpolygon()
@@ -3415,7 +3607,7 @@ class PHPlot {
             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates.
             
 
-            if ($this->x_data_label_pos != 'none')          // Draw X Data labels? 
+            if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
 
             // Now go for Y, E+, E-
@@ -3447,7 +3639,7 @@ class PHPlot {
                 $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape, 
                                      $this->ndx_error_bar_colors[$idx]);
 
-                // Update indices:
+                // Update indexes:
                 $start_lines[$idx] = TRUE;   // Tells us if we already drew the first column of points, 
                                              // thus having $lastx and $lasty ready for the next column.
                 $lastx[$idx] = $x_now_pixels;
@@ -3456,7 +3648,7 @@ class PHPlot {
         }   // end for
 
         ImageSetThickness($this->img, 1);   // Revert to original state for lines to be drawn later.
-    }   // function DrawErrorLines()
+    }   // function DrawLinesError()
 
 
 
@@ -3499,7 +3691,7 @@ class PHPlot {
 
                         if ($this->line_styles[$idx] == 'dashed') {
                             $this->SetDashedStyle($this->ndx_data_colors[$idx]);
-                            ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx], 
+                            ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx],
                                       IMG_COLOR_STYLED);
                             ImageLine($this->img, $x_now_pixels, $lasty[$idx], $x_now_pixels, $y_now_pixels, 
                                       IMG_COLOR_STYLED);
@@ -3528,9 +3720,9 @@ class PHPlot {
     /*!    
      * Data comes in as array("title", x, y, y2, y3, ...)
      */
-    function DrawBars() 
+    function DrawBars()
     {
-        if ($this->data_type != 'text-data') { 
+        if ($this->data_type != 'text-data') {
             $this->DrawError('DrawBars(): Bar plots must be text-data: use function SetDataType("text-data")');
             return FALSE;
         }
@@ -3540,14 +3732,14 @@ class PHPlot {
 
             $x_now_pixels = $this->xtr(0.5 + $row);         // Place text-data at X = 0.5, 1.5, 2.5, etc...
 
-            if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
+            if ($this->x_data_label_pos != 'none')          // Draw X Data labels? TODO:labels on top of bars.
                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
 
             // Draw the bar
             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
-                if (is_numeric($this->data[$row][$record])) {       // Allow for missing Y data 
+                if (is_numeric($this->data[$row][$record])) {       // Allow for missing Y data
                     $x1 = $x_now_pixels - $this->data_group_space + ($idx * $this->record_bar_width);
-                    $x2 = $x1 + ($this->bar_width_adjust * $this->record_bar_width); 
+                    $x2 = $x1 + ($this->bar_width_adjust * $this->record_bar_width);
 
                     if ($this->data[$row][$record] < $this->x_axis_position) {
                         $y1 = $this->x_axis_y_pixels;
@@ -3557,6 +3749,57 @@ class PHPlot {
                         $y2 = $this->x_axis_y_pixels;
                     }
 
+                    if ($this->shading) {                           // Draw the shade?
+                        ImageFilledPolygon($this->img, array($x1, $y1,
+                                                       $x1 + $this->shading, $y1 - $this->shading,
+                                                       $x2 + $this->shading, $y1 - $this->shading,
+                                                       $x2 + $this->shading, $y2 - $this->shading,
+                                                       $x2, $y2,
+                                                       $x2, $y1),
+                                           6, $this->ndx_data_dark_colors[$idx]);
+                    }
+                    // Or draw a border?
+                    else {
+                        ImageRectangle($this->img, $x1, $y1, $x2,$y2, $this->ndx_data_border_colors[$idx]);
+                    }
+                    // Draw the bar
+                    ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]);
+                }
+            }   // end for
+        }   // end for
+    } //function DrawBars
+
+
+    /*!
+     * Data comes in as array("title", x, y, y2, y3, ...)
+     * \note Original stacked bars idea by Laurent Kruk < lolok at users.sourceforge.net >
+     */
+    function DrawStackedBars()
+    {
+        if ($this->data_type != 'text-data') {
+            $this->DrawError('DrawStackedBars(): Bar plots must be text-data: use SetDataType("text-data")');
+            return FALSE;
+        }
+
+        for ($row = 0; $row < $this->num_data_rows; $row++) {
+            $record = 1;                                    // Skip record #0 (data label)
+
+            $x_now_pixels = $this->xtr(0.5 + $row);         // Place text-data at X = 0.5, 1.5, 2.5, etc...
+
+            if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
+                $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
+
+            // Draw the bars
+            $oldv = 0;
+            for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
+                if (is_numeric($this->data[$row][$record])) {       // Allow for missing Y data 
+                    $x1 = $x_now_pixels - $this->data_group_space;
+                    $x2 = $x_now_pixels + $this->data_group_space; 
+
+                    $y1 = $this->ytr(abs($this->data[$row][$record]) + $oldv);
+                    $y2 = $this->ytr($this->x_axis_position + $oldv);
+                    $oldv += abs($this->data[$row][$record]);
+
                     if ($this->shading) {                           // Draw the shade?
                         ImageFilledPolygon($this->img, array($x1, $y1, 
                                                        $x1 + $this->shading, $y1 - $this->shading,
@@ -3572,16 +3815,17 @@ class PHPlot {
                     }
                     // Draw the bar
                     ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]);
+                    
                 } 
             }   // end for
         }   // end for
-    } //function DrawBars    
-
+    } //function DrawStackedBars 
 
+    
     /*!
      *
      */
-    function DrawGraph() 
+    function DrawGraph()
     {
         if (! $this->img) {
             $this->DrawError('DrawGraph(): No image resource allocated');
@@ -3593,7 +3837,7 @@ class PHPlot {
             return FALSE;
         }
 
-        if (! isset($this->data_limits_done)) 
+        if (! isset($this->data_limits_done))
             $this->FindDataLimits();                // Get maxima and minima for scaling
 
         if ($this->total_records == 0) {            // Check for empty data sets
@@ -3609,27 +3853,50 @@ class PHPlot {
         if (! isset($this->plot_max_y))             // Set plot area world values (plot_max_x, etc.)
             $this->SetPlotAreaWorld();
 
-        if ($this->data_type == 'text-data')
-            $this->SetEqualXCoord();
-
-        if ($this->x_data_label_pos != 'none') {    // Default: do not draw tick stuff if 
+        if ($this->plot_type == 'bars' || $this->plot_type == 'stackedbars') // Calculate bar widths
+            $this->CalcBarWidths();
+/* FIXME!!  this sort of thing should not be done without user's consent
+        if ($this->x_data_label_pos != 'none') {    // Default: do not draw tick stuff if
             $this->x_tick_label_pos = 'none';       // there are data labels.
             $this->x_tick_pos = 'none';
         }
-
+*/
         $this->PadArrays();                         // Pad color and style arrays to fit records per group.
 
         $this->DrawBackground();
 
         $this->DrawImageBorder();
 
-        if ($this->draw_plot_area_background)
-            $this->DrawPlotAreaBackground();
+        $this->DrawPlotAreaBackground();
 
         $this->DrawTitle();
         $this->DrawXTitle();
         $this->DrawYTitle();
 
+        // Pie charts are drawn differently, handle them first
+        if ($this->plot_type == 'pie') {
+            // Pie charts can maximize image space usage.
+            $this->SetPlotAreaPixels($this->safe_margin, $this->title_height,
+                                     $this->image_width - $this->safe_margin,
+                                     $this->image_height - $this->safe_margin);
+            $this->DrawPieChart();
+
+            if ($this->legend)
+                $this->DrawLegend($this->legend_x_pos, $this->legend_y_pos, '');
+
+            if ($this->print_image)
+                $this->PrintImage();
+                
+            return;
+        }
+
+        ////// All other chart types:
+        
+        if (! $this->grid_at_foreground) {         // Usually one wants grids to go back, but...
+            $this->DrawYAxis();     // Y axis must be drawn before X axis (see DrawYAxis()) 
+            $this->DrawXAxis();
+        }
+
         switch ($this->plot_type) {
         case 'thinbarline':
             $this->DrawThinBarLines();
@@ -3663,28 +3930,25 @@ class PHPlot {
                 $this->DrawDots();
             }
             break;
-        case 'pie':
-            // Pie charts can maximize image space usage.
-            $this->SetPlotAreaPixels($this->safe_margin, $this->title_height,
-                                     $this->image_width - $this->safe_margin,
-                                     $this->image_height - $this->safe_margin);
-            $this->DrawPieChart();
-            break;
+        case 'stackedbars':
+            $this->DrawStackedBars();
+            break; 
         case 'bars':
+            $this->DrawBars();
+            break;
         default:
             $this->plot_type = 'bars';  // Set it if it wasn't already set.
-            $this->DrawYAxis();     // We don't want the grid to overwrite bar charts
-            $this->DrawXAxis();     // so we draw it first. Also, Y must be drawn before X (see DrawYAxis())
             $this->DrawBars();
-            $this->DrawPlotBorder();
             break;
         }   // end switch
 
-        if ($this->plot_type != 'pie' && $this->plot_type != 'bars') {
-            $this->DrawYAxis();
+        if ($this->grid_at_foreground) {         // Usually one wants grids to go back, but...
+            $this->DrawYAxis();     // Y axis must be drawn before X axis (see DrawYAxis()) 
             $this->DrawXAxis();
-            $this->DrawPlotBorder();
         }
+
+        $this->DrawPlotBorder();
+        
         if ($this->legend)
             $this->DrawLegend($this->legend_x_pos, $this->legend_y_pos, '');
 
@@ -3763,7 +4027,7 @@ class PHPlot {
      */
     function SetHorizTickPosition($which_tp) 
     { 
-        return $this->SetXTickPos($which_tp); 
+        return $this->SetXTickPos($which_tp);
     }
 
     /*!
@@ -3794,7 +4058,7 @@ class PHPlot {
     /*!
      * \deprecated Use SetFont()
      */
-    function SetXLabelFontSize($which_size) 
+    function SetXLabelFontSize($which_size)
     {
         return $this->SetFont('x_title', $which_size);
     }
@@ -3809,7 +4073,7 @@ class PHPlot {
 
     /*!
      * \deprecated Use SetXTitle()
-     */ 
+     */
     function SetXLabel($which_xlab) 
     {
         return $this->SetXTitle($which_xlab);
@@ -3905,7 +4169,7 @@ class PHPlot {
     /*!
      * \deprecated Use SetXLabelAngle()
      */
-    function SetXDataLabelAngle($which_xdla) 
+    function SetXDataLabelAngle($which_xdla)
     {
         return $this->SetXLabelAngle($which_xdla);
     }
@@ -3916,7 +4180,7 @@ class PHPlot {
      *
      * \deprecated Use SetXDataLabelPos()
      */
-    function SetDrawXDataLabels($which_dxdl) 
+    function SetDrawXDataLabels($which_dxdl)
     {
         if ($which_dxdl == '1' )
             $this->SetXDataLabelPos('plotdown');
@@ -3934,7 +4198,7 @@ class PHPlot {
     }
 
     /*!
-     * \deprecated Calculates maximum X-Axis label height. Now inside _CalcMargins()
+     * \deprecated Calculates maximum X-Axis label height. Now inside CalcMargins()
      */
     function CalcXHeights() 
     {
@@ -3949,7 +4213,7 @@ class PHPlot {
         else { // For Non-TTF fonts we can have only angles 0 or 90
             if ($this->x_label_angle == 90)
                 $this->x_tick_label_height = $this->max_t * $this->x_label_font['width'];
-            else 
+            else
                 $this->x_tick_label_height = $this->x_label_font['height'];
         }
 
@@ -3995,7 +4259,7 @@ class PHPlot {
      * Set up the image resource 'img'
      * \deprecated The constructor should init 'img'
      */
-    function InitImage() 
+    function InitImage()
     {
         $this->img = ImageCreate($this->image_width, $this->image_height);
 
@@ -4024,28 +4288,28 @@ class PHPlot {
     /*!
      * \deprecated Use _SetRGBColor()
      */
-    function SetColor($which_color) 
-    { 
+    function SetColor($which_color)
+    {
         $this->SetRGBColor($which_color);
         return TRUE;
     }
 
-    /* 
+    /*
      * \deprecated Use SetLineWidths().
      */
-    function SetLineWidth($which_lw) 
+    function SetLineWidth($which_lw)
     {
 
         $this->SetLineWidths($which_lw);
 
-        if (!$this->error_bar_line_width) { 
+        if (!$this->error_bar_line_width) {
             $this->SetErrorBarLineWidth($which_lw);
         }
         return TRUE;
     }
 
     /*!
-     * \deprecated 
+     * \deprecated
      */
     function DrawDashedLine($x1, $y1, $x2, $y2 , $dash_length, $dash_space, $color)
     {
@@ -4061,12 +4325,82 @@ class PHPlot {
         $style = array_merge($dashes, $spaces);
         ImageSetStyle($this->img, $style);
         ImageLine($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
-    }        
+    }
+
+    /*!
+     * \deprecated Selects an input file to be used as background for the whole graph.
+     * This resizes the graph to the image's size.
+     */
+    function SetInputFile($which_input_file)
+    {
+        $size = GetImageSize($which_input_file);
+        $input_type = $size[2];
+
+        switch($input_type) {
+        case 1:
+            $im = @ ImageCreateFromGIF ($which_input_file);
+            if (!$im) { // See if it failed
+                $this->PrintError("Unable to open $which_input_file as a GIF");
+                return FALSE;
+            }
+        break;
+        case 3:
+            $im = @ ImageCreateFromPNG ($which_input_file);
+            if (!$im) { // See if it failed
+                $this->PrintError("Unable to open $which_input_file as a PNG");
+                return FALSE;
+            }
+        break;
+        case 2:
+            $im = @ ImageCreateFromJPEG ($which_input_file);
+            if (!$im) { // See if it failed
+                $this->PrintError("Unable to open $which_input_file as a JPG");
+                return FALSE;
+            }
+        break;
+        default:
+            $this->PrintError('SetInputFile(): Please select gif, jpg, or png for image type!');
+            return FALSE;
+        break;
+        }
+
+        // Set Width and Height of Image
+        $this->image_width = $size[0];
+        $this->image_height = $size[1];
+
+        // Deallocate any resources previously allocated
+        if ($this->img)
+            imagedestroy($this->img);
+
+        $this->img = $im;
+
+        return TRUE;
+
+    }
+
+
+    /*
+     * \deprecated Use SetPointShapes().
+     */
+    function SetPointShape($which_pt)
+    {
+        $this->SetPointShapes($which_pt);
+        return TRUE;
+    }
+
+    /*
+     * \deprecated Use SetPointSizes().
+     */
+    function SetPointSize($which_ps)
+    {
+        $this->SetPointSizes($which_ps);
+        return TRUE;
+    }
 }  // class PHPlot
 
 
 
-//////////////////////// 
+////////////////////////
 
 
 /*!
@@ -4081,6 +4415,34 @@ function array_pad_array(&$arr, $size, $arr2=NULL)
         $arr2 = $arr;                           // copy the original array
     }
     while (count($arr) < $size)
-        $arr = array_merge($arr, $arr2);        // append until done
+        $arr = array_merge_php4($arr, $arr2);        // append until done
 }
+
+/*!
+ * Fixes problem with array_merge() in PHP5.
+ * \note I simply copied this from a bug report. I am not running php5 yet, so
+ *       I cannot reproduce it, which is why I trust the reporter.
+ */
+function array_merge_php4($array1,$array2)
+{
+    $return=array();
+
+    foreach(func_get_args() as $arg){
+        if(!is_array($arg)){
+        $arg=array($arg);
+        }
+        foreach($arg as $key=>$val){
+            if(!is_int($key)){
+                $return[$key]=$val;
+            }else{
+                $return[]=$val;
+            }
+        }
+    }
+    return $return;
+ }
+
+
 ?>
index 4d1800f38818acc0cc8a573c0c21fb3d6af7125a..a9bcb72adf22c1880c6292d56f1df5bab6228c58 100644 (file)
@@ -14,6 +14,7 @@
 | GNU General Public License for more details.                            |
 +-------------------------------------------------------------------------+ 
 */
+// Last Err: 
 require ("paths.php");
 require($smarty_path."Smarty.class.php");
 include "classes.inc";
@@ -34,14 +35,15 @@ require("lang.php");
 
 // generaldata.tpl & last_run_report.tpl (last24bytes)
 $client = $dbSql->link->query("select count(*) from Client")
-       or die ("Error query at row 37");
+       or die ("Error query: 1");
 $totalfiles = $dbSql->link->query("select count(FilenameId) from Filename")
-       or die ("Error query at row 39");
+       or die ("Error query: 2");
 $last24bytes = $dbSql->link->query("select sum(JobBytes),count(*) from Job where Endtime <= NOW() and UNIX_TIMESTAMP(EndTime) > UNIX_TIMESTAMP(NOW())-86400")
-       or die ("Error query at row 41");
+       or die ("Error query: 3");
 $bytes_stored =& $dbSql->link->getOne("select SUM(VolBytes) from Media")
-       or die ("Error query at row 43");
+       or die ("Error query: 4");
 
+$smarty->assign('database_size', $dbSql->GetDbSize());
 $smarty->assign('bytes_stored',$bytes_stored);
 
 $tmp = $client->fetchRow();
@@ -81,7 +83,7 @@ $smarty->assign('volumes',$volumes);
 // last_run_report.tpl
 if ($mode == "Lite" && $_GET['Full_popup'] != "yes") {
        $tmp = array();
-       $status = $dbSql->link->query("select JobId,Name,EndTime,JobStatus from Job where EndTime <= NOW() and UNIX_TIMESTAMP(EndTime) >UNIX_TIMESTAMP(NOW())-86400 and JobStatus!=\"T\"" )             
+       $status = $dbSql->link->query("select JobId,Name,EndTime,JobStatus from Job where EndTime <= NOW() and UNIX_TIMESTAMP(EndTime) >UNIX_TIMESTAMP(NOW())-86400 and JobStatus!='T'" )               
                or die ("Error: query at row 85");
        $smarty->assign('status', $status->numRows());
        if ( $status->numRows() ) {
@@ -107,12 +109,15 @@ if ($mode == "Lite" && $_GET['Full_popup'] != "yes") {
 }
 else if ($mode == "Full" || $_GET['Full_popup'] == "yes" ){
        $tmp1 = array();
-       $query = "select SEC_TO_TIME( UNIX_TIMESTAMP(Job.EndTime)-UNIX_TIMESTAMP(Job.StartTime) )
-                       as elapsed,Job.Name,Job.StartTime,Job.EndTime,Job.Level,Pool.Name,Job.JobStatus from Job 
-                       LEFT JOIN Pool ON Job.PoolId=Pool.PoolId where EndTime <= NOW() and UNIX_TIMESTAMP(EndTime) >UNIX_TIMESTAMP(NOW())-86400 
-                       order by elapsed ";                                                                                                     // Full report array            
+       if ( $dbSql->driver == "mysql")
+               $query = "select SEC_TO_TIME( UNIX_TIMESTAMP(Job.EndTime)-UNIX_TIMESTAMP(Job.StartTime) )
+                               as elapsed,Job.Name,Job.StartTime,Job.EndTime,Job.Level,Pool.Name,Job.JobStatus from Job 
+                               LEFT JOIN Pool ON Job.PoolId=Pool.PoolId where EndTime <= NOW() and UNIX_TIMESTAMP(EndTime) >UNIX_TIMESTAMP(NOW())-86400 
+                               order by elapsed ";                                                                                                     // Full report array
+       if ( $dbSql->driver == "pgsql")
+               $query = "select Job.EndTime::timestamp-Job.StartTime::timestamp as elapsed,Job.Name,Job.StartTime,Job.EndTime,Job.Level,Pool.Name,Job.JobStatus from Job LEFT JOIN Pool ON Job.PoolId=Pool.PoolId where EndTime <= NOW() and UNIX_TIMESTAMP(EndTime) >UNIX_TIMESTAMP(NOW())-86400 order by elapsed ";
        $status = $dbSql->link->query($query)
-               or die ("Error: query at row 115");
+               or die ("Error: query at row 118");
        while ( $tmp = $status->fetchRow() ) {
                $tdate = explode (":",$tmp[0]);
                if ( $tdate[0] > 300000 )                                                                                               // Temporal "workaround" ;) Fix later
index 0082d9710b7a783203d1e10147da6179d37896b3..8ce5b7a291c61639ddebeec8a8c05deba2fb070b 100644 (file)
@@ -1,18 +1,18 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR Free Software Foundation, Inc.
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+# Translation of messages.po to french
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Morgan LEFIEUX <comete@archlinuxfr.org>, 2004.
+#
 #
-#, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
+"Project-Id-Version: messages_fr.po\n"
 "POT-Creation-Date: 2004-06-11 13:02+0200\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"PO-Revision-Date: 2004-11-25 HO:MI+ZONE\n"
+"Last-Translator: Morgan LEFIEUX <comete@archlinuxfr.org>\n"
+"Language-Team: FRENCH <LL@li.org>\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=CHARSET\n"
-"Content-Transfer-Encoding: ENCODING\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bits\n"
 
 #: lang.c:1 lang.c:2
 msgid "Bytes transferred last 30 days from ALL clients"
@@ -92,7 +92,7 @@ msgstr "Rapport d
 
 #: lang.c:21 lang.c:42
 msgid "Select a job:"
-msgstr "Sélectionnez un job:"
+msgstr "Sélectionnez un travail:"
 
 #: lang.c:22
 msgid "go"
@@ -104,7 +104,7 @@ msgstr "Temps 
 
 #: lang.c:24
 msgid "Job"
-msgstr ""
+msgstr "Travail"
 
 #: lang.c:25
 msgid "Start Time"
@@ -116,11 +116,11 @@ msgstr "Heure de fin"
 
 #: lang.c:27
 msgid "Type"
-msgstr ""
+msgstr "Type"
 
 #: lang.c:28
 msgid "Pool"
-msgstr ""
+msgstr "Pool"
 
 #: lang.c:29 lang.c:40
 msgid "Status"
@@ -132,7 +132,7 @@ msgstr "Statistiques Bacula: Job"
 
 #: lang.c:31
 msgid "Client:"
-msgstr ""
+msgstr "Client:"
 
 #: lang.c:32
 msgid "Period: From"
@@ -152,7 +152,7 @@ msgstr "Fichiers transf
 
 #: lang.c:36
 msgid "Date"
-msgstr ""
+msgstr "Date"
 
 #: lang.c:37
 msgid "Elapsed"
@@ -184,7 +184,7 @@ msgstr "lignes de points"
 
 #: lang.c:46
 msgid "points"
-msgstr ""
+msgstr "points"
 
 #: lang.c:47
 msgid "bars"
index 83eb921531b838abc8df75ac252ca42a981503fb..9958ee62970ddaccdb6a46c61e75b85e51fee8c5 100644 (file)
@@ -48,9 +48,13 @@ $smarty->assign('filesperiod',$files);
 
 // Array with jobs data
 $a_jobs = array();
-$res_jobs = $dbSql->link->query("select *,SEC_TO_TIME( UNIX_TIMESTAMP(Job.EndTime)-UNIX_TIMESTAMP(Job.StartTime) ) as elapsed from Job where EndTime < '$dbSql->EndDate' and EndTime > '$dbSql->StartDate' and Name='$_GET[server]' order by EndTime")
-       or die("Error query row 50");
-       
+if ($dbSql->driver == "mysql")
+       $res_jobs = $dbSql->link->query("select *,SEC_TO_TIME( UNIX_TIMESTAMP(Job.EndTime)-UNIX_TIMESTAMP(Job.StartTime) ) as elapsed from Job where EndTime < '$dbSql->EndDate' and EndTime > '$dbSql->StartDate' and Name='$_GET[server]' order by EndTime")
+               or die("Error query row 50");
+else if ($dbSql->driver == "pgsql")
+       $res_jobs = $dbSql->link->query("select jobid as \"JobId\",job as \"Job\",name as \"Name\",type as \"Type\",level as \"Level\",clientid as \"ClientId\",jobstatus as \"JobStatus\",schedtime as \"SchedTime\",starttime as \"StartTime\",endtime as \"EndTime\",jobtdate as \"JobtDate\",volsessionid as \"VolSessionId\",volsessiontime as \"VolSessionTime\",jobfiles as \"JobFiles\",jobbytes as \"JobBytes\",joberrors as \"JobErrors\",jobmissingfiles as \"JobMissingFiles\",poolid as \"PoolId\",filesetid as \"FilesetId\",purgedfiles as \"PurgedFiles\",hasbase,Job.EndTime::timestamp-Job.StartTime::timestamp as elapsed from Job where EndTime < '$dbSql->EndDate' and EndTime > '$dbSql->StartDate' and Name='$_GET[server]' order by EndTime")
+               or die("Error query row 56");
+
 while ( $tmp = $res_jobs->fetchRow(DB_FETCHMODE_ASSOC) ) {
        $tdate = explode (":",$tmp[elapsed]);                                                                           // Temporal "workaround" ;) Fix later
        if ( $tdate[0] > 300000 )
index 9fb3501f3d5c1e4f0b48a8e1a184f9c611a42847..b44775388a2af2177e66cf0ebbebc443db62b975 100644 (file)
        <td>
        <font color=red>{$files_totales}</font>
        </td>
+       
+       <td width=35%>
+       {t}Database size{/t}:
+       </td>
+       
+       <td>
+       <font color=red>{$database_size|fsize_format}</font>
+       </td>
 </tr>
 
 <tr>
index d7d3432745b141fc3b6ea59beeec9d04d6fe6072..f70d8d5a4d04476d2065c6b5ae0d57ef201b1241 100644 (file)
@@ -17,7 +17,7 @@
                        <table class=genmed cellspacing="1" cellpadding="3" border=0 align="center">
                                <tr><td>
                                                {if $server==""}
-                                                       <img src=stats.php?server={$server}&tipo_dato=69&title={t}General%20report{/t}&modo_graph=bars&sizex=400&sizey=250&MBottom=20&legend=1>
+                                                       <img src=stats.php?server={$server}&tipo_dato=69&title={t}General%20report{/t}&modo_graph=bars&sizex=420&sizey=250&MBottom=20&legend=1>
                                                {else}
                                                        <img src=stats.php?server={$server}&tipo_dato=3&title={$server}&modo_graph=bars>
                                                {/if}