Added support for different types of graphs; added a last 60 minutes line graph
authorDan
Sun, 04 Jan 2009 16:40:36 -0500
changeset 43 ce2e9caf2dfa
parent 42 c24a2311f232
child 44 73f74d395f95
child 45 53a50ba4d690
Added support for different types of graphs; added a last 60 minutes line graph
graphing/class.3dbargraph.php
graphing/class.graph.php
graphing/class.linegraph.php
graphing/class.piegraph.php
graphs.php
htdocs/graph.php
stats-fe.php
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphing/class.3dbargraph.php	Sun Jan 04 16:40:36 2009 -0500
@@ -0,0 +1,243 @@
+<?php
+  require_once dirname(__FILE__) . "/class.graph.php";
+
+  class BarGraph extends CGraph {
+    var $bar_width = 32;
+    var $bar_height = 8;
+    var $bar_padding = 5;
+    var $bar_bordercolor = array(39, 78, 120);
+    var $bar_bgcolor = array(69, 129, 194);
+    var $bar_textfont = 2;
+
+    function BarGraph() {
+      $this->axis_deepness = $this->bar_height;
+      $this->graph_height = $this->graph_padding['top'] + $this->graph_areaheight + $this->graph_padding['bottom'];
+    }
+
+    /**
+     * Graph::SetBarBorderColor()
+     * Sets border color for bars
+     **/
+    function SetBarBorderColor($red, $green, $blue) {
+      $this->bar_bordercolor = array($red, $green, $blue);
+    }
+
+    /**
+     * Graph::SetBarBackgroundColor()
+     * Sets background color for bars
+     **/
+    function SetBarBackgroundColor($red, $green, $blue) {
+      $this->bar_bgcolor = array($red, $green, $blue);
+    }
+
+    /**
+     * Graph::SetBarDimensions()
+     * Sets with and height of each bar
+     **/
+    function SetBarDimensions($width, $height) {
+      if ($width > 0) $this->bar_width = $width;
+      if ($height >= 0) {
+        $this->bar_height = $height;
+        $this->axis_deepness = $height;
+      }
+    }
+
+    /**
+     * Graph::SetBarPadding()
+     * Sets padding (border) around each bar
+     **/
+    function SetBarPadding($padding) {
+      if ($padding > 0) $this->bar_padding = $padding;
+    }
+    function SetBarFont($font) {
+      $this->bar_textfont = 0;
+      switch ($font) {
+        case 'x-large': $this->bar_textfont++;
+        case 'large':   $this->bar_textfont++;
+        case 'medium':  $this->bar_textfont++;
+        case 'small':   $this->bar_textfont++;
+        case 'x-small': $this->bar_textfont++; break;
+        default:
+          $this->bar_textfont = $font;
+      }
+    }
+    function DrawGraph($file = "") {
+      $this->graph_width = $this->graph_padding['left'] +
+                           (count($this->data) * ($this->bar_width + ($this->bar_padding * 2))) +
+                           $this->graph_padding['right'];
+      $this->axis_deepness = $this->bar_height;
+
+      $this->im = imagecreatetruecolor($this->graph_width, $this->graph_height);
+
+      $this->axis_frontgridlines = 0;
+      $this->axis_xscalevisible = 0;
+      $this->axis_positions = array($this->axis_positions[0], 0, 0, 0);
+
+      CGraph::DrawGraph();
+      
+      if ($this->axis_minY > 0) $this->axis_minY = 0;
+      if ($this->axis_maxY < 0) $this->axis_maxY = 0;
+
+      $this->__Draw_LeftBottom_Axis();
+      
+      $p = 0;
+      foreach ($this->data as $name => $value) {
+        $p++;
+        $this->__DrawBarText($p, $name);
+        $this->__DrawBar($p, $value);
+      }
+      
+      $this->__Draw_TopRight_Axis();
+
+      CGraph::DrawGraph2();
+
+      if (strlen($file)) {
+        $ret = imagepng($this->im, $file);
+      } else {
+        header("Content-Type: image/png"); // thanks to Marcin G. :)
+        imagepng($this->im);
+        $ret = true;
+      }
+      imagedestroy($this->im);
+      return $ret;
+    }
+
+    /**
+     * Graph::__DrawBarText()
+     * Determines top and left to draw text to a choosen bar
+     **/
+    function __DrawBarText($bar, $text) {
+      $this->__DrawText($text,
+                        $this->graph_padding['left'] + (($this->bar_width + ($this->bar_padding * 2)) * ($bar - 0.5)),
+                        $this->graph_height - $this->graph_padding['bottom'] + 1,
+                        $this->im_axis_scalecolor,
+                        $this->bar_textfont,
+                        1);
+    }
+
+    /**
+     * Graph::__DrawBar()
+     * Draws a choosen bar with it's value
+     **/
+    function __DrawBar($bar, $value) {
+      $x = $this->graph_padding['left'] +
+           (($this->bar_width + ($this->bar_padding * 2)) * ($bar - 1)) +
+           $this->bar_padding;
+      $y = $this->graph_areaheight / ($this->axis_maxY - $this->axis_minY);
+      if ($value >= 0) {
+        $this->____DrawBar($x,
+                           $this->graph_height - $this->graph_padding['bottom'] - abs(floor($this->axis_minY * $y)) - floor($y * $value),
+                           $x + $this->bar_width,
+                           $this->graph_height - $this->graph_padding['bottom'] - abs(floor($this->axis_minY * $y)));
+      } else {
+        $this->____DrawBar($x,
+                           $this->graph_height - $this->graph_padding['bottom'] - abs(floor($this->axis_minY * $y)),
+                           $x + $this->bar_width,
+                           $this->graph_height - $this->graph_padding['bottom'] - floor($this->axis_minY * -$y) + floor($y * -$value));
+      }
+    }
+    
+    /**
+     * Graph::____DrawBar()
+     * Draws the actual rectangles that form a bar
+     **/
+    function ____DrawBar($x1, $y1, $x2, $y2) {
+      $this->__AllocateColor("im_bar_bordercolor",
+                             $this->bar_bordercolor,
+                             ( $this->graph_transparencylevel * 1.5));
+      $this->__AllocateColor("im_bar_bgcolor",
+                             $this->bar_bgcolor,
+                             ( $this->graph_transparencylevel * 1.5));
+                             
+      // base square
+      $this->__DrawPolygon(array($x1, $y2, $x2, $y2, $x2 + $this->bar_height,
+                                 $y2 - $this->bar_height, $x1 + $this->bar_height,
+                                 $y2 - $this->bar_height),
+                           $this->im_bar_bgcolor,
+                           true);
+      $this->__DrawPolygon(array($x1, $y2, $x2, $y2, $x2 + $this->bar_height,
+                                 $y2 - $this->bar_height, $x1 + $this->bar_height,
+                                 $y2 - $this->bar_height),
+                           $this->im_bar_bordercolor);
+
+      // back square
+      $this->__DrawPolygon(array($x1 + $this->bar_height, $y1 - $this->bar_height,
+                                 $x2 + $this->bar_height, $y1 - $this->bar_height,
+                                 $x2 + $this->bar_height, $y2 - $this->bar_height,
+                                 $x1 + $this->bar_height, $y2 - $this->bar_height),
+                           $this->im_bar_bgcolor,
+                           true);
+      $this->__DrawPolygon(array($x1 + $this->bar_height, $y1 - $this->bar_height,
+                                 $x2 + $this->bar_height, $y1 - $this->bar_height,
+                                 $x2 + $this->bar_height, $y2 - $this->bar_height,
+                                 $x1 + $this->bar_height, $y2 - $this->bar_height),
+                           $this->im_bar_bordercolor);
+
+      // left square
+      $this->__DrawPolygon(array($x1, $y1, $x1 + $this->bar_height, $y1 - $this->bar_height,
+                                 $x1 + $this->bar_height, $y2 - $this->bar_height,
+                                 $x1, $y2),
+                           $this->im_bar_bgcolor,
+                           true);
+      $this->__DrawPolygon(array($x1, $y1, $x2, $y1, $x2, $y2, $x1, $y2),
+                           $this->im_bar_bordercolor);
+
+      // front square
+      $this->__DrawPolygon(array($x1, $y1, $x2, $y1, $x2, $y2, $x1, $y2),
+                           $this->im_bar_bgcolor,
+                           true);
+      $this->__DrawPolygon(array($x1, $y1, $x2, $y1, $x2, $y2, $x1, $y2),
+                           $this->im_bar_bordercolor);
+                           
+      // right square
+      $this->__DrawPolygon(array($x2, $y2, $x2, $y1, $x2 + $this->bar_height,
+                                 $y1 - $this->bar_height, $x2 + $this->bar_height,
+                                 $y2 - $this->bar_height),
+                           $this->im_bar_bgcolor,
+                           true);
+      $this->__DrawPolygon(array($x2, $y2, $x2, $y1, $x2 + $this->bar_height,
+                                 $y1 - $this->bar_height, $x2 + $this->bar_height,
+                                 $y2 - $this->bar_height),
+                           $this->im_bar_bordercolor);
+
+      // top square
+      $this->__DrawPolygon(array($x1, $y1, $x2, $y1, $x2 + $this->bar_height,
+                                 $y1 - $this->bar_height, $x1 + $this->bar_height,
+                                 $y1 - $this->bar_height),
+                           $this->im_bar_bgcolor,
+                           true);
+      $this->__DrawPolygon(array($x1, $y1, $x2, $y1, $x2 + $this->bar_height,
+                                 $y1 - $this->bar_height, $x1 + $this->bar_height,
+                                 $y1 - $this->bar_height),
+                           $this->im_bar_bordercolor);
+    }
+    
+    /**
+     * Graph::__Load3dbarValues()
+     * Loads definitions to 3d bar settings
+     **/
+    function __Load3dbarValues($data) {
+      foreach ($data as $name => $value) {
+        $name = strtolower($name);
+        switch ($name) {
+          case 'background-color':
+            $this->__SetColorToValue("bar_bgcolor", $value);
+            break;
+          case 'border-color':
+            $this->__SetColorToValue("bar_bordercolor", $value);
+            break;
+          case 'padding':
+            $this->bar_padding = $value;
+            break;
+          case 'width':
+            $this->bar_width = (int) $value;
+            break;
+          case 'height':
+            $this->bar_height = (int) $value;
+            $this->axis_deepness = (int) $value;
+            break;
+        }
+      }
+    }
+  }
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphing/class.graph.php	Sun Jan 04 16:40:36 2009 -0500
@@ -0,0 +1,1016 @@
+<?php
+  class CGraph {
+    var $data = array();
+    //---------------------------------------------
+    var $graph_areaheight = 100;
+    var $graph_areawidth = 50;
+    var $graph_padding = array('left' => 50, 'top' => 20, 'right'  => 20, 'bottom' => 20);
+    var $graph_title = "";
+    var $graph_titlefont = 3;
+    var $graph_bgcolor = array(255, 255, 255);
+    var $graph_bgtransparent = false;
+    var $graph_transparencylevel = 0;
+    var $graph_borderwidth = 1;
+    var $graph_bordercolor = array(218, 218, 239);
+    var $graph_titlecolor = array(99, 88, 78);
+    //---------------------------------------------
+    var $axis_stepX = 1;
+    var $axis_stepY = 1;
+    var $axis_stepSize = 3;
+    var $axis_deepness = 0;
+    var $axis_maxX = 0;
+    var $axis_minX = 0;
+    var $axis_maxY = 0;
+    var $axis_minY = 0;
+    var $axis_bordercolor = array(99, 88, 78);
+    var $axis_bgcolor = array(152, 137, 124);
+    var $axis_scalefont = 2;
+    var $axis_scalecolor = array(0, 0, 255);
+    var $axis_xscalevisible = true;
+    var $axis_yscalevisible = true;
+    var $axis_gridlines = true;
+    var $axis_frontgridlines = true;
+    var $axis_positions = array(true, false, false, true);
+    var $axis_modeX = 0; // 0=diference between steps 1=number of steps
+    var $axis_modeY = 0; // 0=diference between steps 1=number of steps
+    //---------------------------------------------
+    var $scale_roundX = 1;
+    var $scale_roundY = 1;
+    var $scale_funX = "";
+    var $scale_funY = "";
+    //---------------------------------------------
+    var $legend_visible = false;
+    var $legend_floating = false;
+    var $legend_borderwidth = 1;
+    var $legend_bgcolor = array(255, 255, 255);
+    var $legend_bordercolor = array(0, 0, 0);
+    var $legend_width = 0;
+    var $legend_height = 0;
+    var $legend_padding = 30;
+    var $legend_insidepadding = 3;
+    var $legend_font = 1;
+    var $legend_position = 3; // 1=bottom left | 2=top left | 3=top right | 4=bottom right
+    var $legend_color = array(array(0, 0, 255));
+    var $legend_data = array("Item 1");
+
+    function CGraph() {
+      //nothing @ the moment.. maybe later will set image at startup
+    }
+
+    /****************************************************************
+                                GRAPH
+    ****************************************************************/
+    function SetGraphAreaHeight($height) {
+      if ($height > 0) {
+        $this->graph_areaheight = $height;
+        $this->graph_height = $this->graph_padding['top'] + $height + $this->graph_padding['bottom'];
+      }
+    }
+    function SetGraphAreaWidth($width) {
+      if ($width > 0) {
+        $this->graph_areawidth = $width;
+        $this->graph_width = $this->graph_padding['left'] + $width + $this->graph_padding['right'];
+      }
+    }
+    function SetGraphPadding($left, $top, $right, $bottom) {
+      $this->graph_padding = array('left' => (int)$left, 'top' => (int)$top, 'right' => (int)$right, 'bottom' => (int)$bottom);
+    }
+    function SetGraphTitle($title) {
+      $this->graph_title = $title;
+    }
+    function SetGraphTitleFont($font) {
+      $this->graph_titlefont = 0;
+      switch ($font) {
+        case 'x-large': $this->graph_titlefont++;
+        case 'large':   $this->graph_titlefont++;
+        case 'medium':  $this->graph_titlefont++;
+        case 'small':   $this->graph_titlefont++;
+        case 'x-small': $this->graph_titlefont++; break;
+        default:
+          $this->graph_titlefont = $font;
+      }
+    }
+    function SetGraphTitleColor($red, $green, $blue) {
+      $this->graph_titlecolor = array($red, $green, $blue);
+    }
+    function SetGraphBorderColor($red, $green, $blue) {
+      $this->graph_bordercolor = array($red, $green, $blue);
+    }
+    function SetGraphBorderWidth($width = 0) {
+      $this->graph_borderwidth = $width;
+    }
+    function SetGraphBackgroundColor($red, $green, $blue) {
+      $this->graph_bgcolor = array($red, $green, $blue);
+    }
+    function SetGraphBackgroundTransparent($addtransparency = true, $red = 255, $green = 0, $blue = 255) {
+      $this->graph_bgcolor = array($red, $green, $blue);
+      $this->graph_bgtransparent = ($addtransparency ? true : false);
+    }
+    function SetGraphTransparency($percent) {
+      if ($percent < 0) $percent = 0;
+      elseif ($percent > 100) $percent = 127;
+      else $percent = $percent * 1.27;
+      $this->graph_transparencylevel = $percent;
+    }
+
+    /****************************************************************
+                                 AXIS
+    ****************************************************************/
+    function SetAxisBorderColor($red, $green, $blue) {
+      $this->axis_bordercolor = array($red, $green, $blue);
+    }
+    function SetAxisBackgroundColor($red, $green, $blue) {
+      $this->axis_bgcolor = array($red, $green, $blue);
+    }
+    function SetAxisScaleColor($red, $green, $blue) {
+      $this->axis_scalecolor = array($red, $green, $blue);
+    }
+    function SetAxisStepX($step) {
+      if ($step > 0) $this->axis_stepX = $step;
+    }
+    function SetAxisStepY($step) {
+      if ($step > 0) $this->axis_stepY = $step;
+    }
+    function SetAxisStepSize($size) {
+      $this->axis_stepSize = (int) $size;
+    }
+    function SetAxisScaleXVisibility($state) {
+      $this->axis_xscalevisible = ($state ? true : false);
+    }
+    function SetAxisScaleYVisibility($state) {
+      $this->axis_yscalevisible = ($state ? true : false);
+    }
+    function SetAxisModeX($mode) {
+      switch ($mode) {
+        case '0':
+        case 'value':
+          $this->axis_modeX = 0; break;
+        case '1':
+        case 'dynamic':
+          $this->axis_modeX = 1; break;
+        case '2':
+        case 'pixel':
+          $this->axis_modeX = 2; break;
+      }
+    }
+    function SetAxisModeY($mode) {
+      switch ($mode) {
+        case '0':
+        case 'value':
+          $this->axis_modeY = 0; break;
+        case '1':
+        case 'dynamic':
+          $this->axis_modeY = 1; break;
+        case '2':
+        case 'pixel':
+          $this->axis_modeY = 2; break;
+      }
+    }
+    function SetAxisDeepness($deepness) {
+      $this->axis_deepness = (int) $deepness;
+    }
+    function SetAxisScaleFont($font) {
+      $this->axis_scalefont = 0;
+      switch ($font) {
+        case 'x-large': $this->axis_scalefont++;
+        case 'large':   $this->axis_scalefont++;
+        case 'medium':  $this->axis_scalefont++;
+        case 'small':   $this->axis_scalefont++;
+        case 'x-small': $this->axis_scalefont++; break;
+        default:
+          $this->axis_scalefont = $font;
+      }
+    }
+    function SetAxisPositions($positions) {
+      $positions = explode(",", strtolower($positions));
+      $this->axis_positions = array(0, 0, 0, 0);
+      for ($i = 0; $i < count($positions); $i++) {
+        if ($positions[$i][0] == '-') {
+          $v = false;
+          $positions[$i] = substr($positions[$i], 1);
+        } else $v = true;
+        switch ($positions[$i]) {
+          case 'all':    $this->axis_positions = array($v, $v, $v, $v); break;
+          case 'left':   $this->axis_positions[0] = $v; break;
+          case 'top':    $this->axis_positions[1] = $v; break;
+          case 'right':  $this->axis_positions[2] = $v; break;
+          case 'bottom': $this->axis_positions[3] = $v; break;
+        }
+      }
+    }
+    function SetAxisGridlines($state) {
+      $this->axis_gridlines = ($state ? true : false);
+    }
+    function SetAxisFrontGridlines($state) {
+      $this->axis_frontgridlines = ($state ? true : false);
+    }
+    /****************************************************************
+                                 SCALE
+    ****************************************************************/
+    function SetScaleRoundX($number) {
+      if ($number < 0) $number = 0;
+      $this->scale_roundX = (int) $number;
+    }
+    function SetScaleRoundY($number) {
+      if ($number < 0) $number = 0;
+      $this->scale_roundY = (int) $number;
+    }
+    function SetScaleFunctionX($name) {
+      $this->scale_funX = $name;
+    }
+    function SetScaleFunctionY($name) {
+      $this->scale_funY = $name;
+    }
+    
+    /****************************************************************
+                                LEGEND
+    ****************************************************************/
+    function SetLegendVisible($visible) {
+      $this->legend_visible = ($visible ? true : false);
+    }
+    function SetLegendFloating($floating) {
+      $this->legend_floating = ($floating ? true : false);
+    }
+    function SetLegendBackgroundColor($red, $green, $blue) {
+      $this->legend_bgcolor = array($red, $green, $blue);
+    }
+    function SetLegendBorderColor($red, $green, $blue) {
+      $this->legend_bordercolor = array($red, $green, $blue);
+    }
+    function SetLegendBorderWidth($width = 0) {
+      $this->legend_borderwidth = $width;
+    }
+    function SetLegendColors($colors) {
+      $this->__SetColorToValue("legend_color", $colors);
+    }
+    function SetLegendPadding($padding = 0) {
+      $this->legend_padding = $padding;
+    }
+    function SetLegendInsidePadding($padding = 0) {
+      $this->legend_insidepadding = $padding;
+    }
+    function SetLegendPosition($position) {
+      switch ($position) {
+        case 1:
+        case 'bottom left':
+          $this->legend_position = 1; break;
+        case 2:
+        case 'top left':
+          $this->legend_position = 2; break;
+        case 3:
+        case 'top right':
+          $this->legend_position = 3; break;
+        case 4:
+        case 'bottom right':
+          $this->legend_position = 4; break;
+
+      }
+    }
+    function SetLegendData($data) {
+      if (is_array($data)) {
+        $this->legend_data = $data;
+      }
+    }
+    function SetLegentFont($font) {
+      $this->legend_font = 0;
+      switch ($font) {
+        case 'x-large': $this->legend_font++;
+        case 'large':   $this->legend_font++;
+        case 'medium':  $this->legend_font++;
+        case 'small':   $this->legend_font++;
+        case 'x-small': $this->legend_font++; break;
+        default:
+          $this->legend_font = $font;
+      }
+    }
+
+    /****************************************************************
+                                 DATA
+    ****************************************************************/
+    function SetData($data) {
+      if (is_array($data)) {
+        $this->data = $data;
+      }
+    }
+
+    function LoadGraph($path) {
+      if (($fp = @fopen($path, "r")) !== false) {
+        $content = "";
+        while (!feof($fp)) {              // I do not use filesize() here
+          $content .= fread($fp, 4096);   // because of remote files. If
+        }                                 // there is no problem with them
+        fclose($fp);                      // please let me know
+        $this->__LoadGraphDefinitions($content);
+        return true;
+      } else return false;
+    }
+
+    function DrawGraph() {
+      if ($this->graph_transparencylevel) {
+        imagealphablending($this->im, true);
+      }
+      
+      if ($this->legend_visible) {
+        $maxlength = 0;
+        for ($i = 0; $i < count($this->legend_data); $i++) {
+          if (strlen($this->legend_data[$i]) > $maxlength) $maxlength = strlen($this->legend_data[$i]);
+        }
+        $this->legend_width = ($this->legend_insidepadding * 4) + ($maxlength * imagefontwidth($this->legend_font));
+
+        if (!$this->legend_floating) {
+          $this->graph_padding[($this->legend_position < 3 ? 'left' : 'right')] += $this->legend_padding + $this->legend_width;
+          $this->graph_areawidth -= ($this->legend_padding + $this->legend_width);
+        }
+      }
+
+      $this->__PaintBackground();
+
+      $this->__DrawAxis();
+    }
+    
+    function DrawGraph2() {
+      if (strlen($this->graph_title)) {
+        $this->__AllocateColor("im_graph_titlecolor",
+                               $this->graph_titlecolor,
+                               $this->graph_transparencylevel);
+        $this->__DrawText($this->graph_title,
+                          floor($this->graph_width / 2),
+                          floor(($this->graph_padding['top'] - $this->axis_deepness - imagefontwidth($this->graph_titlefont)) / 2),
+                          $this->im_graph_titlecolor,
+                          $this->graph_titlefont,
+                          1);
+      }
+
+      $this->__DrawLegend();
+    }
+
+    function __PaintBackground() {
+      $this->__AllocateColor("im_graph_bgcolor",
+                             $this->graph_bgcolor,
+                             0);
+      if ($this->graph_bgtransparent) {
+        imagecolortransparent($this->im, $this->im_graph_bgcolor);
+      }
+      imagefilledrectangle($this->im, 0, 0, $this->graph_width, $this->graph_height, $this->im_graph_bgcolor);
+      if ($this->graph_borderwidth) {
+        $this->__AllocateColor("im_graph_bordercolor",
+                               $this->graph_bordercolor,
+                               $this->graph_transparencylevel);
+        for ($i = 0; $i < $this->graph_borderwidth; $i++) {
+          imagerectangle($this->im,
+                         $i,
+                         $i,
+                         $this->graph_width - 1 - $i,
+                         $this->graph_height - 1 - $i,
+                         $this->im_graph_bordercolor);
+        }
+      }
+    }
+
+    function __DrawAxis() {
+      $this->__AllocateColor("im_axis_bordercolor",
+                             $this->axis_bordercolor,
+                             $this->graph_transparencylevel);
+      $this->__AllocateColor("im_axis_bgcolor",
+                             $this->axis_bgcolor,
+                             $this->graph_transparencylevel);
+      $this->__AllocateColor("im_axis_scalecolor",
+                             $this->axis_scalecolor,
+                             $this->graph_transparencylevel);
+
+      list($this->axis_minX,
+           $this->axis_maxX,
+           $this->axis_minY,
+           $this->axis_maxY) = $this->__GetMinMaxGraphValue();
+
+      if ($this->axis_gridlines) {
+        $style = array($this->im_axis_bordercolor, $this->im_graph_bgcolor);
+        imagesetstyle($this->im, $style);
+      }
+
+      if ($this->axis_modeX == 1) {
+        $this->axis_stepX = ($this->axis_maxX - $this->axis_minX) / $this->axis_stepX;
+      } elseif ($this->axis_modeX == 2) {
+        $this->axis_stepX = $this->axis_stepX * ($this->axis_maxX - $this->axis_minX) / $this->graph_areawidth;
+      }
+
+      if ($this->axis_modeY == 1) {
+        $this->axis_stepY = ($this->axis_maxY - $this->axis_minY) / $this->axis_stepY;
+      } elseif ($this->axis_modeY == 2) {
+        $this->axis_stepY = $this->axis_stepY * ($this->axis_maxY - $this->axis_minY) / $this->graph_areaheight;
+        $rest = abs($this->axis_maxY) % $this->axis_stepY;
+          // need to center a step on coord 0
+          
+      }
+      
+      if (!$this->axis_deepness) {
+        $this->axis_frontgridlines = 1;
+      }
+
+      if (!$this->axis_xscalevisible) {
+        $this->axis_positions[1] = 0;
+        $this->axis_positions[3] = 0;
+      }
+      if (!$this->axis_yscalevisible) {
+        $this->axis_positions[0] = 0;
+        $this->axis_positions[2] = 0;
+      }
+      $this->__CorrectMinMax($this->axis_minX, $this->axis_maxX, $this->axis_stepX);
+      $this->__CorrectMinMax($this->axis_minY, $this->axis_maxY, $this->axis_stepY);
+      if ($this->axis_yscalevisible) {
+        $this->__DrawHorizontalGridlines();
+      }
+      $this->__DrawHorizontalGideGridlines();
+      if ($this->axis_xscalevisible) {
+        $this->__DrawVerticalGridlines();
+      }
+      $this->__DrawVerticalGideGridlines();
+      
+      // draw lines that separate bars
+      $total_bars = count($this->data);
+      if ( min($this->data) >= 0 && get_class($this) == 'BarGraph' )
+      {
+        $totalbarwidth = $this->bar_width + ($this->bar_padding * 2);
+        for ($i = 0; $i < $total_bars; $i++) {
+          $offset = $this->graph_padding['left'] +
+                    ($totalbarwidth * $i);
+          
+          $this->__DrawPolygon(
+                    array(
+                          $offset + $totalbarwidth,                     $this->graph_height - $this->graph_padding['bottom'],                      // top right
+                          $offset,                                      $this->graph_height - $this->graph_padding['bottom'],                      // top left
+                          $offset + $this->bar_height,                  $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height,  // bottom left
+                          $offset + $this->bar_height + $totalbarwidth, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height), // bottom right
+                    $this->im_axis_bgcolor, true);
+          
+          imageline($this->im,
+                    $offset,                         $this->graph_height - $this->graph_padding['bottom'],
+                    $offset + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
+                    $this->im_axis_bordercolor);
+        }
+      }
+    }
+    
+    function __Draw_LeftBottom_Axis() {
+      $w = $this->graph_width;
+      $h = $this->graph_height;
+      $p = $this->graph_padding;
+      if ($this->axis_positions[3]) {
+        $this->__DrawAxisPart($p['left'], $h - $p['bottom'], $w - $p['right'], $h - $p['bottom'],
+                              $this->axis_minX, $this->axis_maxX, $this->axis_stepX,
+                              "right", "bottom");
+      }
+      if ($this->axis_positions[0]) {
+        $this->__DrawAxisPart($p['left'], $p['top'], $p['left'], $h - $p['bottom'],
+                              $this->axis_minY, $this->axis_maxY, $this->axis_stepY,
+                              "up", "left");
+      }
+    }
+    
+    function __Draw_TopRight_Axis() {
+      $w = $this->graph_width;
+      $h = $this->graph_height;
+      $p = $this->graph_padding;
+      if ($this->axis_positions[1]) {
+        $this->__DrawAxisPart($p['left'], $p['top'], $w - $p['right'], $p['top'],
+                              $this->axis_minX, $this->axis_maxX, $this->axis_stepX,
+                              "right", "top");
+      }
+      if ($this->axis_positions[2]) {
+        $this->__DrawAxisPart($w - $p['right'], $p['top'], $w - $p['right'], $h - $p['bottom'],
+                              $this->axis_minY, $this->axis_maxY, $this->axis_stepY,
+                              "up", "right");
+      }
+    }
+    
+    function __CorrectMinMax(&$min, &$max, &$step) {
+      if (($max % $step) != 0) $max += ($step - abs($max % $step));
+      if (($min % $step) != 0) $min -= abs($min % $step);
+    }
+    
+    function __DrawHorizontalGridlines() {
+      $maxy = $this->graph_height - $this->graph_padding['bottom'];
+      $miny = $this->graph_padding['top'];
+      $maxx = $this->graph_width - $this->graph_padding['right'];
+      $minx = $this->graph_padding['left'];
+      $offset = ($maxy - $miny) / ($this->axis_maxY - $this->axis_minY) * $this->axis_stepY;
+      $v = $miny + $offset;
+
+      $deep = $this->axis_deepness;
+      if (!$deep) $grid_offset = $this->axis_stepSize;
+      else $grid_offset = 1;
+      while ($v < $maxy) {
+        imageline($this->im, $minx + $deep + (!$this->axis_positions[0] ? 0 : $grid_offset),
+                             floor($v) - $deep,
+                             $maxx + $deep - (!$this->axis_positions[2] ? 0 : $grid_offset),
+                             floor($v) - $deep, IMG_COLOR_STYLED);
+        $v += $offset;
+      }
+    }
+    
+    function __DrawHorizontalGideGridlines() {
+      $maxy = $this->graph_height - $this->graph_padding['bottom'];
+      $miny = $this->graph_padding['top'];
+      $maxx = $this->graph_width - $this->graph_padding['right'];
+      $minx = $this->graph_padding['left'];
+
+      $deep = $this->axis_deepness;
+      if (!$deep) $grid_offset = $this->axis_stepSize;
+      else $grid_offset = 1;
+      
+      if (!$this->axis_positions[1]) {
+        if ($deep) {
+          imageline($this->im, $minx + $deep + $grid_offset, $miny - $deep,
+                    $maxx + $deep + $grid_offset, $miny - $deep, IMG_COLOR_STYLED);
+        }
+        if ($this->axis_frontgridlines) {
+          imageline($this->im, $minx, $miny, $maxx, $miny, IMG_COLOR_STYLED);
+        }
+      }
+      if (!$this->axis_positions[3]) {
+        if ($deep) {
+          imageline($this->im, $minx + $deep + $grid_offset, $maxy - $deep,
+                    $maxx + $deep + $grid_offset, $maxy - $deep, IMG_COLOR_STYLED);
+        }
+        if ($this->axis_frontgridlines) {
+          imageline($this->im, $minx, $maxy, $maxx, $maxy, IMG_COLOR_STYLED);
+        }
+      }
+    }
+    
+    function __DrawVerticalGridlines() {
+      $maxy = $this->graph_height - $this->graph_padding['bottom'];
+      $miny = $this->graph_padding['top'];
+      $maxx = $this->graph_width - $this->graph_padding['right'];
+      $minx = $this->graph_padding['left'];
+      if ( $this->axis_maxX == 0 )
+        $this->axis_maxX = 1;
+      $offset = ($maxx - $minx) / ($this->axis_maxX - $this->axis_minX) * $this->axis_stepX;
+      $v = $minx + $offset;
+
+      $deep = $this->axis_deepness;
+      if (!$deep) $grid_offset = $this->axis_stepSize;
+      else $grid_offset = 1;
+      
+      while ($v < $maxx) {
+        imageline($this->im, floor($v) + $deep,
+                             $miny - $deep + (!$this->axis_positions[1] ? 0 : $grid_offset),
+                             floor($v) + $deep,
+                             $maxy - $deep - (!$this->axis_positions[3] ? 0 : $grid_offset),
+                             IMG_COLOR_STYLED);
+        $v += $offset;
+      }
+    }
+    
+    function __DrawVerticalGideGridlines() {
+      $maxy = $this->graph_height - $this->graph_padding['bottom'];
+      $miny = $this->graph_padding['top'];
+      $maxx = $this->graph_width - $this->graph_padding['right'];
+      $minx = $this->graph_padding['left'];
+
+      $deep = $this->axis_deepness;
+      if (!$deep) $grid_offset = $this->axis_stepSize;
+      else $grid_offset = 1;
+      
+      if (!$this->axis_positions[0]) {
+        if ($deep) {
+          imageline($this->im, $minx + $deep + $grid_offset, $miny - $deep,
+                    $minx + $deep + $grid_offset, $maxy - $deep, IMG_COLOR_STYLED);
+        }
+        if ($this->axis_frontgridlines) {
+          imageline($this->im, $minx, $miny, $minx, $maxy, IMG_COLOR_STYLED);
+        }
+      }
+      if (!$this->axis_positions[2]) {
+        if ($deep) {
+          imageline($this->im, $maxx + $deep + $grid_offset, $miny - $deep,
+                    $maxx + $deep + $grid_offset, $maxy - $deep, IMG_COLOR_STYLED);
+        }
+        if ($this->axis_frontgridlines) {
+          imageline($this->im, $maxx, $miny, $maxx, $maxy, IMG_COLOR_STYLED);
+        }
+      }
+    }
+    
+    function __DrawAxisPart($x1, $y1, $x2, $y2, $scale_start, $scale_end, $scale_step, $scale_direction, $scaletext_side) {
+      $deep = $this->axis_deepness;
+      if ($deep > 0) {
+        $this->__DrawPolygon(array($x1, $y1, $x1 + $deep, $y1 - $deep, $x2 + $deep, $y2 - $deep, $x2, $y2), $this->im_axis_bgcolor, true);
+        $this->__DrawPolygon(array($x1, $y1, $x1 + $deep, $y1 - $deep, $x2 + $deep, $y2 - $deep, $x2, $y2), $this->im_axis_bordercolor);
+      } else {
+        imageline($this->im, $x1, $y1, $x2, $y2, $this->im_axis_bordercolor);
+      }
+      
+      // reverse order if needed
+      if ($x1 == $x2) {
+        if ($scale_direction == "up") {
+          $scale_direction = "down";
+          $v = $scale_start;
+          $scale_start = $scale_end;
+          $scale_end = $v;
+          $scale_step = -$scale_step;
+        } else $scale_direction = "down";
+        if ($scaletext_side != "left") $scaletext_side = "right";
+      } else {
+        if ($scale_direction == "left") {
+          $scale_direction = "right";
+          $v = $scale_start;
+          $scale_start = $scale_end;
+          $scale_end = $v;
+          $scale_step = -$scale_step;
+        } else $scale_direction = "right";
+        if ($scaletext_side != "top") $scaletext_side = "bottom";
+      }
+      
+      $v = $scale_start;
+      $total = $scale_end - $v;
+      if ($x1 == $x2) {
+        $totalarea = $this->graph_areaheight;
+      } else {
+        $totalarea = $this->graph_areawidth;
+      }
+      
+      $akeys = array_keys($this->data);
+      
+      while (($v <= $scale_end && $scale_step > 0) || ($v >= $scale_end && $scale_step < 0)) {
+        if ($x1 == $x2) {
+          $offset = ceil($y1 + (($v - $scale_start) * $totalarea / $total));
+          if (strlen($this->scale_funY)) {
+            $fun = str_replace("%d", $v, $this->scale_funY);
+            eval("\$scale_value = " . $fun . ";");
+          } else {
+            $scale_value = $this->__RoundNumber($v, $this->scale_roundY);
+          }
+          // vertical axis scale text
+          $this->__DrawText($scale_value, $x1 + ($scaletext_side == "left" ? -6 : 6 + $deep),
+                            $offset, $this->im_axis_scalecolor, $this->axis_scalefont,
+                            ($scaletext_side == "left" ? 2 : 0), 1);
+          if ($v != $scale_start && $v != $scale_end) {
+            // vertical axis scale line
+            imageline($this->im, $x1 + ($scaletext_side == "left" ? 1 : -1), $offset,
+                      $x1 + ($scaletext_side == "left" ? $this->axis_stepSize : -$this->axis_stepSize),
+                      $offset - $this->axis_stepSize + ($scaletext_side == "left" ? 1 : -1), $this->im_axis_bordercolor);
+          }
+        } else {
+          $offset = floor($x1 + (($v - $scale_start) * $totalarea / $total));
+          if (function_exists($this->scale_funX)) {
+            $fun = $this->scale_funX;
+            $scale_value = $fun($v, $this);
+          } else {
+            $use_int = true;
+            if ( isset($akeys[$v]) )
+              if ( is_string($akeys[$v]) && !ctype_digit($akeys[$v]) )
+                $use_int = false;
+            $scale_value = $use_int ? $this->__RoundNumber($v, $this->scale_roundX) : $akeys[$v];
+          }
+          // horizontal axis scale text
+          $this->__DrawText($scale_value, $offset, $y1 + ($scaletext_side == "top" ? -6 - $deep : 6),
+                            $this->im_axis_scalecolor, $this->axis_scalefont, 1,
+                            ($scaletext_side == "top" ? 2 : 0));
+          if ($v != $scale_start && $v != $scale_end) {
+            // horizontal axis scale line
+            imageline($this->im, $offset, $y1 + ($scaletext_side == "top" ? 1 : -1),
+                      $offset,
+                      $y1 + ($scaletext_side == "top" ? $this->axis_stepSize : -$this->axis_stepSize),
+                      $this->im_axis_bordercolor);
+          }
+        }
+        $v += $scale_step;
+      }
+    }
+    
+    function __DrawText($text, $x, $y, $color, $size = 1, $align = 0, $valign = 0) {
+      /* Align: 0=left | 1=center | 2=right */
+      if ($align == 1) $x -= floor(strlen($text) * imagefontwidth($size) / 2);
+      elseif ($align == 2) $x -= (strlen($text) * imagefontwidth($size));
+      if ($valign == 1) $y -= floor(imagefontheight($size) / 2);
+      elseif ($valign == 2) $y -= imagefontheight($size);
+      imagestring($this->im, $size, $x, $y, $text, $color);
+    }
+
+    function __GetMinMaxGraphValue() {
+      $arrki = array_keys($this->data);
+      if (is_array($this->data[$arrki[0]])) {
+        for ($i = 0; $i < count($arrki); $i++) {
+          $arrkj = array_keys($this->data[$arrki[$i]]);
+          if ($i == 0) {
+            $maxX = $minX = (int) $arrkj[0];
+            $maxY = $minY = (int) $this->data[$arrki[0]][$arrkj[0]];
+          }
+          for ($j = 0; $j < count($arrkj); $j++) {
+            if ($arrkj[$j] > $maxX) $maxX = $arrkj[$j];
+            elseif ($arrkj[$j] < $minX) $minX = $arrkj[$j];
+            if ($this->data[$arrki[$i]][$arrkj[$j]] > $maxY) $maxY = $this->data[$arrki[$i]][$arrkj[$j]];
+            elseif ($this->data[$arrki[$i]][$arrkj[$j]] < $minY) $minY = $this->data[$arrki[$i]][$arrkj[$j]];
+          }
+        }
+      } else {
+        $maxY = $minY = (int) $this->data[$arrki[0]];
+        foreach ($this->data as $x => $y) {
+          if ($y > $maxY) $maxY = $y;
+          elseif ($y < $minY) $minY = $y;
+        }
+        $minX = 0;
+        $maxX = count($this->data);
+      }
+      if ( $maxY == 0 )
+      {
+        $maxY = 10;
+      }
+      return array($minX, $maxX, $minY, $maxY);
+    }
+
+    function __DrawPolygon($points, $color, $filled = false) {
+      if ($filled) {
+        imagefilledpolygon($this->im, $points, 4, $color);
+      } else {
+        imagepolygon($this->im, $points, 4, $color);
+      }
+    }
+
+    function __LoadGraphDefinitions($text) {
+      $text = preg_split("/\r?\n/", $text);
+      $data = array();
+      $section = '';
+      for ($i = 0; $i < count($text); $i++) {
+        if (preg_match("/^\s*#/", $text[$i])) {
+          //ignore.. it's just a comment
+        } elseif (preg_match("/^\s*\}\s*/", $text[$i])) {
+          $section = '';
+        } elseif (preg_match("/^\s*(\w+)\s*\{\s*$/", $text[$i], $r)) {
+          $section = $r[1];
+          $index = -1;
+        } elseif (preg_match("/^\s*\-\s*$/", $text[$i]) && strlen($section)) {
+          $index++;
+        } else {
+          $p = strpos($text[$i], "=");
+          if ($p !== false) {
+            $k = trim(substr($text[$i], 0, $p));
+            $v = trim(substr($text[$i], $p + 1));
+            if ($index >= 0) {
+              $data[$section][$index][$k] = $v;
+            } else {
+              if (preg_match("/^\s*\[(.*)\]\s*$/", $v, $r)) {
+                // array
+                $data[$section][$k] = explode(";", $r[1]);
+              } else {
+                $data[$section][$k] = $v;
+              }
+            }
+          }
+        }
+      }
+      foreach ($data as $key => $settings) {
+        $func = "__Load" . ucfirst($key) . "Values";
+        if (method_exists($this, $func)) {
+          $this->$func($settings);
+        }
+      }
+      if (is_array($data['data'])) {
+        $this->data = $data['data'];
+      }
+    }
+
+    function __LoadGraphValues($data) {
+      foreach ($data as $name => $value) {
+        $name = strtolower($name);
+        switch ($name) {
+          case 'background-color':
+            $this->__SetColorToValue("graph_bgcolor", $value);
+            break;
+          case 'border-color':
+            $this->__SetColorToValue("graph_bordercolor", $value);
+            break;
+          case 'title-color':
+            $this->__SetColorToValue("graph_titlecolor", $value);
+            break;
+          case 'background-transparent':
+            $this->graph_bgtransparent = ($value == 1 || $value == 'yes' ? 1 : 0);
+            break;
+          case 'transparency':
+            $this->SetGraphTransparency(str_replace('%', '', $value));
+            break;
+          case 'title':
+            $this->graph_title = $value;
+            break;
+          case 'title-font':
+            $this->SetGraphTitleFont($value);
+            break;
+          case 'border-width':
+            $this->graph_borderwidth = (int) $value;
+            break;
+          case 'area-height':
+            $this->graph_areaheight = (int) $value;
+            $this->graph_height = $this->graph_padding['top'] + (int)$value + $this->graph_padding['bottom'];
+            break;
+          case 'area-width':
+            $this->graph_areawidth = (int) $value;
+            $this->graph_width = $this->graph_padding['left'] + (int)$value + $this->graph_padding['right'];
+            break;
+          default:
+            if (substr($name, 0, 8) == 'padding-' && strlen($name) > 8) {
+              $this->graph_padding[substr($name, 8)] = $value;
+            }
+        }
+      }
+    }
+
+    function __LoadAxisValues($data) {
+      foreach ($data as $name => $value) {
+        $name = strtolower($name);
+        switch ($name) {
+          case 'x-step':
+            $this->SetAxisStepX($value);
+            break;
+          case 'y-step':
+            $this->SetAxisStepY($value);
+            break;
+          case 'step-size':
+            $this->axis_stepSize = (int) $value;
+            break;
+          case 'x-step-mode':
+            $this->SetAxisModeX($value);
+            break;
+          case 'y-step-mode':
+            $this->SetAxisModeY($value);
+            break;
+          case 'background-color':
+          case 'border-color':
+          case 'scale-color':
+            $this->__SetColorToValue("axis_" . str_replace(array("ackground", "-"),
+                                                           array("g", ""),
+                                                           $name),
+                                     $value);
+            break;
+          case 'scale-font':
+            $this->SetAxisScaleFont($value);
+            break;
+          case 'show-xscale':
+            $this->axis_xscalevisible = ($value == 1 || $value == 'yes' ? 1 : 0);
+            break;
+          case 'show-yscale':
+            $this->axis_yscalevisible = ($value == 1 || $value == 'yes' ? 1 : 0);
+            break;
+          case 'gridlines':
+            $this->axis_gridlines = ($value == 1 || $value == 'yes' ? 1 : 0);
+            break;
+          case 'position':
+            $this->SetAxisPositions($value);
+            break;
+          case 'deepness':
+            $this->axis_deepness = (int) $value;
+            break;
+        }
+      }
+    }
+
+    function __LoadScaleValues($data) {
+      foreach ($data as $name => $value) {
+        $name = strtolower($name);
+        switch ($name) {
+          case 'x-round':
+            $this->SetScaleRoundX($value);
+            break;
+          case 'y-round':
+            $this->SetScaleRoundY($value);
+            break;
+          case 'x-fun':
+            $this->SetScaleFunctionX($value);
+            break;
+          case 'y-fun':
+            $this->SetScaleFunctionY($value);
+            break;
+        }
+      }
+    }
+    
+    function __LoadLegendValues($data) {
+      foreach ($data as $name => $value) {
+        $name = strtolower($name);
+        switch ($name) {
+          case 'background-color':
+          case 'border-color':
+          case 'color':
+            $this->__SetColorToValue("legend_" . str_replace(array("ackground", "-"),
+                                                             array("g", ""),
+                                                             $name),
+                                     $value);
+            break;
+          case 'visible':
+            $this->SetLegendVisible($value);
+            break;
+          case 'floating':
+            $this->SetLegendFloating($value);
+            break;
+          case 'position':
+            $this->SetLegendPosition($value);
+            break;
+          case 'borderwidth':
+            $this->SetLegendBorderWidth($value);
+            break;
+          case 'padding':
+            $this->SetLegendPadding($value);
+            break;
+          case 'inside-padding':
+            $this->SetLegendInsidePadding($value);
+            break;
+          case 'data':
+            $this->SetLegendData($value);
+            break;
+        }
+      }
+    }
+
+    function __SetColorToValue($varname, $color, $index = false) {
+      if (is_array($color)) {
+        for ($i = 0; $i < count($color); $i++) {
+          $this->__SetColorToValue($varname, $color[$i], $i);
+        }
+      } else {
+        if ($color[0] == "#") { // if it's hex (html format), change to rgb array
+          if (strlen($color) == 4) {
+            // if only 3 hex values (I assume it's a shade of grey: #ddd)
+            $color .= substr($color, -3);
+          }
+          $color = array(hexdec($color[1].$color[2]),
+                         hexdec($color[3].$color[4]),
+                         hexdec($color[5].$color[6]));
+        }
+        if ($index !== false) $this->{$varname}[$index] = $color;
+        else $this->$varname = $color;
+      }
+    }
+    
+    function __AllocateColor($varname, $color, $alpha, $index = false) {
+      if ($index !== false) {
+        $this->{$varname}[$index] = imagecolorallocatealpha($this->im, $color[0], $color[1], $color[2], $alpha);
+      } else {
+        $this->$varname = imagecolorallocatealpha($this->im, $color[0], $color[1], $color[2], $alpha);
+      }
+    }
+    
+    function __DrawLegend() {
+      if (!$this->legend_visible) return;
+      
+      $this->legend_height = $this->legend_insidepadding + (count($this->legend_data) * (imagefontheight($this->legend_font) + $this->legend_insidepadding));
+
+      switch ($this->legend_position) {
+        case 1:
+          $x = $this->legend_padding;
+          $y = $this->graph_height - $this->legend_padding - $this->legend_height;
+          break;
+        case 2:
+          $x = $y = $this->legend_padding;
+          break;
+        case 3:
+          $x = $this->graph_width - $this->legend_padding - $this->legend_width;
+          $y = $this->legend_padding;
+          break;
+        case 4:
+          $x = $this->graph_width - $this->legend_padding - $this->legend_width;
+          $y = $this->graph_height - $this->legend_padding - $this->legend_height;
+          break;
+      }
+      if ($this->legend_floating) {
+        $x = $x + ($this->legend_position < 3 ? $this->graph_padding['left'] : -$this->graph_padding['right']);
+        $y = $y + ($this->legend_position == 2 || $this->legend_position == 3 ? $this->graph_padding['top'] : -$this->graph_padding['bottom']);
+      }
+      $this->__AllocateColor("im_legend_bordercolor",
+                             $this->legend_bordercolor,
+                             $this->graph_transparencylevel);
+      $this->__AllocateColor("im_legend_bgcolor",
+                             $this->legend_bgcolor,
+                             $this->graph_transparencylevel);
+
+      imagefilledrectangle($this->im, $x + 1, $y + 1, $x + $this->legend_width - 1, $y + $this->legend_height - 1, $this->im_legend_bgcolor);
+      imagerectangle($this->im, $x, $y, $x + $this->legend_width, $y + $this->legend_height, $this->im_legend_bordercolor);
+      for ($i = 0; $i < count($this->legend_data); $i++) {
+        $this->__AllocateColor("im_legend_color", $this->legend_color[$i], $this->graph_transparencylevel, $i);
+        $this->__DrawLegendItem($x, $y, $i, $this->legend_data[$i], $this->im_legend_color[$i]);
+      }
+    }
+    
+    function __DrawLegendItem($legendx, $legendy, $position, $text, $color) {
+      $x = $legendx + $this->legend_insidepadding * 3;
+      $y = $legendy + $this->legend_insidepadding + (($this->legend_insidepadding + imagefontheight($this->legend_font)) * $position);
+      imagefilledrectangle($this->im, $legendx + $this->legend_insidepadding,
+                                      $y + ((imagefontheight($this->legend_font) - $this->legend_insidepadding) / 2),
+                                      $legendx + $this->legend_insidepadding * 2,
+                                      $y + ((imagefontheight($this->legend_font) - $this->legend_insidepadding) / 2) + $this->legend_insidepadding,
+                                      $color);
+      $this->__DrawText($text, $x, $y, $color, $this->legend_font, 0, 0);
+    }
+    
+    function __RoundNumber($n, $round = 1) {
+      if (is_numeric($n)) {
+        $weights = " KMG";
+        $p = 0;
+        while (abs($n) >= 1000) {
+          $n = $n / 1000;
+          $p++;
+        }
+        return number_format($n, $round) . trim($weights[$p]);
+      } else return $n;
+    }
+  }
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphing/class.linegraph.php	Sun Jan 04 16:40:36 2009 -0500
@@ -0,0 +1,174 @@
+<?php
+  require_once dirname(__FILE__) . "/class.graph.php";
+
+  class LineGraph extends CGraph {
+    var $line_color = array(39, 78, 120);
+    var $line_bgcolor = array(69, 129, 194);
+
+    function LineGraph() {
+      $this->graph_width = $this->graph_padding['left'] + $this->graph_areawidth + $this->graph_padding['right'];
+      $this->graph_height = $this->graph_padding['top'] + $this->graph_areaheight + $this->graph_padding['bottom'];
+    }
+    
+    /**
+     * Graph::SetLineColor()
+     * Sets line color
+     **/
+    function SetLineColor($red, $green, $blue) {
+      $this->line_color = array($red, $green, $blue);
+    }
+
+    /**
+     * Graph::AddLineColor()
+     * Sets line color
+     **/
+    function AddLineColor($red, $green, $blue) {
+      if (!is_array($this->line_color[0])) {
+        $this->line_color = array($this->line_color);
+      }
+      $this->line_color[] = array($red, $green, $blue);
+    }
+
+    /**
+     * Graph::SetLineBackgroundColor()
+     * Sets background color for line (when 3D)
+     **/
+    function SetLineBackgroundColor($red, $green, $blue) {
+      $this->line_bgcolor = array($red, $green, $blue);
+    }
+    
+    /**
+     * Graph::AddLineBackgroundColor()
+     * Sets line background color
+     **/
+    function AddLineBackgroundColor($red, $green, $blue) {
+      if (!is_array($this->line_bgcolor[0])) {
+        $this->line_bgcolor = array($this->line_bgcolor);
+      }
+      $this->line_bgcolor[] = array($red, $green, $blue);
+    }
+    
+    /**
+     * Graph::DrawGraph()
+     * Draw all the graph: bg, axis, bars, text.. and output it
+     * Optional file parameter turns output to file, and bool on success
+     **/
+    function DrawGraph($file = "") {
+      $this->im = imagecreatetruecolor($this->graph_width, $this->graph_height);
+      
+      CGraph::DrawGraph();
+      
+      $this->__Draw_LeftBottom_Axis();
+      
+      $arrki = array_keys($this->data);
+      if (is_array($this->data[$arrki[0]])) { // more than 1 line
+        if (!is_array($this->line_color)) {
+          $this->line_color = array($this->line_color);
+        }
+        if (!is_array($this->line_bgcolor)) {
+          $this->line_bgcolor = array($this->line_bgcolor);
+        }
+        for ($i = 0; $i < count($arrki); $i++) {
+          $this->__AllocateColor("im_line_color",
+                                 $this->line_color[$i],
+                                 $this->graph_transparencylevel,
+                                 $i);
+          if ($this->axis_deepness > 0) {
+            $this->__AllocateColor("im_line_bgcolor",
+                                   $this->line_bgcolor[$i],
+                                   $this->graph_transparencylevel,
+                                   $i);
+          }
+          $arrkj = array_keys($this->data[$arrki[$i]]);
+          for ($j = 1; $j < count($arrkj); $j++) {
+            $this->__DrawLine(array($arrkj[$j - 1],
+                                    $arrkj[$j],
+                                    $this->data[$arrki[$i]][$arrkj[$j - 1]],
+                                    $this->data[$arrki[$i]][$arrkj[$j]]),
+                              $this->im_line_color[$i],
+                              $this->im_line_bgcolor[$i]);
+          }
+        }
+      } else {
+        $this->__AllocateColor("im_line_color",
+                               $this->line_color,
+                               $this->graph_transparencylevel);
+        $this->__AllocateColor("im_line_bgcolor",
+                               $this->line_bgcolor,
+                               $this->graph_transparencylevel);
+        for ($i = 1; $i < count($arrki); $i++) {
+          $this->__DrawLine(array($i - 1, // x1
+                                  $i,     // x2
+                                  $this->data[$arrki[$i - 1]], // y1
+                                  $this->data[$arrki[$i]]),    // y2
+                            $this->im_line_color,
+                            $this->im_line_bgcolor);
+        }
+        // exit;
+      }
+      
+      $this->__Draw_TopRight_Axis();
+      
+      CGraph::DrawGraph2();
+
+      if (strlen($file)) {
+        $ret = imagepng($this->im, $file);
+      } else {
+        header("Content-Type: image/png"); // thanks to Marcin G. :)
+        imagepng($this->im);
+        $ret = true;
+      }
+      imagedestroy($this->im);
+      return $ret;
+    }
+
+    /**
+     * Graph::__DrawLine()
+     * Draws a line between 2 points
+     **/
+    function __DrawLine($points, $color, $bgcolor) {
+      if (!isset($this->line_unitX) || !isset($this->line_unitY)) {
+        $this->line_unitX = ($this->graph_width - $this->graph_padding['left'] - $this->graph_padding['right']) / ($this->axis_maxX - $this->axis_minX);
+        $this->line_unitY = $this->graph_areaheight / ($this->axis_maxY - $this->axis_minY);
+      }
+      $x1 = $this->graph_padding['left'] + floor(($points[0] - $this->axis_minX) * $this->line_unitX) + $this->line_unitX;
+      $x2 = $this->graph_padding['left'] + floor(($points[1] - $this->axis_minX) * $this->line_unitX) + $this->line_unitX;
+      $y1 = $this->graph_height - $this->graph_padding['bottom'] - floor(($points[2] - $this->axis_minY) * $this->line_unitY);
+      $y2 = $this->graph_height - $this->graph_padding['bottom'] - floor(($points[3] - $this->axis_minY) * $this->line_unitY);
+      // echo "drawing line from ($x1, $y1) to ($x2, $y2)<br />";
+      if ($this->axis_deepness > 0) {
+        $this->__DrawPolygon(array($x1, $y1,
+                                   $x1 + $this->axis_deepness, $y1 - $this->axis_deepness,
+                                   $x2 + $this->axis_deepness, $y2 - $this->axis_deepness,
+                                   $x2, $y2),
+                             $bgcolor,
+                             true);
+        $this->__DrawPolygon(array($x1, $y1,
+                                   $x1 + $this->axis_deepness, $y1 - $this->axis_deepness,
+                                   $x2 + $this->axis_deepness, $y2 - $this->axis_deepness,
+                                   $x2, $y2),
+                             $color);
+      } else {
+        imageline($this->im, $x1, $y1, $x2, $y2, $color);
+      }
+    }
+
+    /**
+     * Graph::__LoadLineValues()
+     * Loads definitions to line settings
+     **/
+    function __LoadLineValues($data) {
+      foreach ($data as $name => $value) {
+        $name = strtolower($name);
+        switch ($name) {
+          case 'background-color':
+            $this->__SetColorToValue("line_bgcolor", $value);
+            break;
+          case 'color':
+            $this->__SetColorToValue("line_color", $value);
+            break;
+        }
+      }
+    }
+  }
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graphing/class.piegraph.php	Sun Jan 04 16:40:36 2009 -0500
@@ -0,0 +1,159 @@
+<?php
+  require_once dirname(__FILE__) . "/class.graph.php";
+
+  class PieGraph extends CGraph {
+    var $pie_color = array(array(39, 78, 120));
+    var $pie_deepnesscolor = array(array(9, 48, 90));
+    var $pie_bgcolor = array(array(69, 129, 194));
+    var $pie_deepness = 10;
+    var $pie_total = 0;
+    var $pie_startoffset = 0;
+
+    function Graph() {
+      $this->graph_width = $this->graph_padding['left'] + $this->graph_areawidth + $this->graph_padding['right'];
+      $this->graph_height = $this->graph_padding['top'] + $this->graph_areaheight + $this->graph_padding['bottom'];
+    }
+    
+    function SetPieColor($red, $green, $blue) {
+      $this->pie_color = array($red, $green, $blue);
+    }
+    function AddPieColor($red, $green, $blue) {
+      if (!is_array($this->pie_color[0])) {
+        $this->pie_color = array($this->pie_color);
+      }
+      $this->pie_color[] = array($red, $green, $blue);
+    }
+    function SetPieBackgroundColor($red, $green, $blue) {
+      $this->pie_bgcolor = array($red, $green, $blue);
+    }
+    function AddPieBackgroundColor($red, $green, $blue) {
+      if (!is_array($this->pie_bgcolor[0])) {
+        $this->pie_bgcolor = array($this->pie_bgcolor);
+      }
+      $this->pie_bgcolor[] = array($red, $green, $blue);
+    }
+    function SetPieDeepnessColor($red, $green, $blue) {
+      $this->pie_deepnesscolor = array($red, $green, $blue);
+    }
+    function AddPieDeepnessColor($red, $green, $blue) {
+      if (!is_array($this->pie_deepnesscolor[0])) {
+        $this->pie_deepnesscolor = array($this->pie_deepnesscolor);
+      }
+      $this->pie_deepnesscolor[] = array($red, $green, $blue);
+    }
+    function SetPieTotalValue($total) {
+      $this->pie_total = $total;
+    }
+    function SetPieStartOffset($offset) {
+      if ($offset < 0 || $offset > 359) $offset = 0;
+      $this->pie_startoffset = $offset;
+    }
+    function SetPieData($data) {
+      CGraph::SetData($data);
+    }
+    function DrawGraph($file = "") {
+      $this->im = imagecreatetruecolor($this->graph_width, $this->graph_height);
+
+      $this->axis_positions = array(0, 0, 0, 0);
+      $this->axis_xscalevisible = 0;
+      $this->axis_yscalevisible = 0;
+      $this->axis_gridlines = 0;
+      
+      CGraph::DrawGraph();
+      
+      if ($this->pie_total == 0) {
+        foreach ($this->data as $name => $value) {
+          $this->pie_total += $value;
+        }
+      }
+      // deepness
+      for ($i = $this->pie_deepness; $i > 0; $i--) {
+        $offset = 0;
+        $p = 0;
+        foreach ($this->data as $n => $value) {
+          if (!$this->pie_deepnesscolor[$p]) {
+            $this->__AllocateColor("im_pie_deepnesscolor", $this->pie_deepnesscolor[$p], 0, $p);
+          }
+          $from = round($this->pie_startoffset - ($offset * 360 / $this->pie_total));
+          $to = round($this->pie_startoffset - (($value + $offset) * 360 / $this->pie_total));
+          if ($from < 0) $from += 360;
+          if ($to < 0) $to += 360;
+          imagefilledarc($this->im, round($this->graph_width / 2), round($this->graph_height / 2) + $i,
+                                    $this->graph_areawidth, $this->graph_areaheight,
+                                    $to, $from, $this->pie_deepnesscolor[$p], IMG_ARC_PIE);
+          $offset += $value;
+          $p++;
+        }
+      }
+      $offset = 0;
+      $p = 0;
+      foreach ($this->data as $n => $value) {
+        $this->__AllocateColor("im_pie_color", $this->pie_color[$p], 0, $p);
+
+        $from = round($this->pie_startoffset - ($offset * 360 / $this->pie_total));
+        $to = round($this->pie_startoffset - (($value + $offset) * 360 / $this->pie_total));
+        if ($from < 0) $from += 360;
+        if ($to < 0) $to += 360;
+        imagefilledarc($this->im, round($this->graph_width / 2), round($this->graph_height / 2),
+                                  $this->graph_areawidth, $this->graph_areaheight,
+                                  $to, $from, $this->im_pie_color[$p], IMG_ARC_PIE);
+        $offset += $value;
+        $p++;
+      }
+
+      CGraph::DrawGraph2();
+
+      if (strlen($file)) {
+        $ret = imagepng($this->im, $file);
+      } else {
+        header("Content-Type: image/png"); // thanks to Marcin G. :)
+        imagepng($this->im);
+        $ret = true;
+      }
+      imagedestroy($this->im);
+      return $ret;
+    }
+    
+    function __DrawPieSlice($frompercent, $topercent, $color, $deepcolor) {
+      $from = round(270 - ($frompercent * 3.6));
+      $to = round(270 - ($topercent * 3.6));
+      if ($from < 0) $from += 360;
+      if ($to < 0) $to += 360;
+      //echo "FROM:" . $from . " TO:" . $to . "<br>\n";
+      for ($i = $this->pie_deepness; $i > 0; $i--) {
+        imagefilledarc($this->im, round($this->graph_width / 2), round($this->graph_height / 2) + $i,
+                                  round($this->graph_areawidth / 2), round($this->graph_areaheight / 2),
+                                  $to, $from, $deepcolor, IMG_ARC_PIE);
+      }
+      imagefilledarc($this->im, round($this->graph_width / 2), round($this->graph_height / 2),
+                                round($this->graph_areawidth / 2), round($this->graph_areaheight / 2),
+                                $to, $from, $color, IMG_ARC_PIE);
+    }
+
+    /**
+     * Graph::__LoadPieValues()
+     * Loads definitions to pie settings
+     **/
+    function __LoadPieValues($data) {
+      foreach ($data as $name => $value) {
+        $name = strtolower($name);
+        switch ($name) {
+          case 'background-color':
+            $this->__SetColorToValue("pie_bgcolor", $value);
+            break;
+          case 'color':
+            $this->__SetColorToValue("pie_color", $value);
+            break;
+          case 'deepness-color':
+            $this->__SetColorToValue("pie_depnesscolor", $value);
+            break;
+          case 'offset':
+            $this->SetPieStartOffset($value);
+            break;
+          case 'total':
+            $this->SetPieTotalValue($value);
+        }
+      }
+    }
+  }
+?>
--- a/graphs.php	Sun Jan 04 12:19:27 2009 -0500
+++ b/graphs.php	Sun Jan 04 16:40:36 2009 -0500
@@ -1,1051 +1,6 @@
 <?php
 
-/*
- * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.5 (Caoineag alpha 5)
- * Copyright (C) 2006-2008 Dan Fuhry
- *
- * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
- */
-
-// BarGraph for PHP
-// Source: http://www.phpclasses.org/browse/package/1567.html
-// License: PHP license, see licenses/phplic.html included with this package
-
-class GraphMaker {
-  /**
-   * GraphMaker::bar_width
-   * Width of bars
-   */
-  var $bar_width = 32;
-  /**
-   * GraphMaker::bar_height
-   * Height of bars
-   */
-  var $bar_height = 8;
-  /**
-   * GraphMaker::bar_data
-   * Data of all bars
-   */
-  var $bar_data = array('a' => 7, 'b' => 3, 'c' => 6, 'd' => 0, 'e' => 2);
-  /**
-   * GraphMaker::bar_padding
-   * Padding of bars
-   */
-  var $bar_padding = 5;
-  /**
-   * GraphMaker::bar_bordercolor
-   * Border color of bars
-   */
-  var $bar_bordercolor = array(39, 78, 120);
-  /**
-   * GraphMaker::bar_bgcolor
-   * Background color of bars
-   */
-  var $bar_bgcolor = array(69, 129, 194);
-  //---------------------------------------------
-  /**
-   * GraphMaker::graph_areaheight
-   * Height of graphic area
-   */
-  var $graph_areaheight = 100;
-  /**
-   * GraphMaker::graph_padding
-   * Paddings of graph
-   */
-  var $graph_padding = array('left' => 50, 'top' => 20, 'right'  => 20, 'bottom' => 20);
-  /**
-   * GraphMaker::graph_title
-   * Title text of graph
-   */
-  var $graph_title = "";
-  /**
-   * GraphMaker::graph_bgcolor
-   * Background color of graph
-   */
-  var $graph_bgcolor = array(255, 255, 255);
-  /**
-   * GraphMaker::graph_bgtransparent
-   * Boolean for background transparency
-   */
-  var $graph_bgtransparent = 0;
-  /**
-   * GraphMaker::graph_transparencylevel
-   * Transparency level (0=opaque, 127=transparent)
-   */
-  var $graph_transparencylevel = 0;
-  /**
-   * GraphMaker::graph_borderwidth
-   * Width of graph border
-   */
-  var $graph_borderwidth = 1;
-  /**
-   * GraphMaker::graph_bordercolor
-   * Border color of graph
-   */
-  var $graph_bordercolor = array(218, 218, 239);
-  /**
-   * GraphMaker::graph_titlecolor
-   * Color of title text of graph
-   */
-  var $graph_titlecolor = array(99, 88, 78);
-  //---------------------------------------------
-  /**
-   * GraphMaker::axis_step
-   * Scale step of axis
-   */
-  var $axis_step = 2;
-  /**
-   * GraphMaker::axis_bordercolor
-   * Border color of axis
-   */
-  var $axis_bordercolor = array(99, 88, 78);
-  /**
-   * GraphMaker::axis_bgcolor
-   * Background color of axis
-   */
-  var $axis_bgcolor = array(152, 137, 124);
-
-  /****************************************************************
-                              GRAPH
-  ****************************************************************/
-
-  /**
-   * GraphMaker::SetGraphAreaHeight()
-   * Sets graph height (not counting top and bottom margins)
-   **/
-  function SetGraphAreaHeight($height) {
-    if ($height > 0) $this->graph_areaheight = $height;
-  }
-
-  /**
-   * GraphMaker::SetGraphPadding()
-   * Sets graph padding (margins)
-   **/
-  function SetGraphPadding($left, $top, $right, $bottom) {
-    $this->graph_padding = array('left'   => (int) $left,
-                                 'top'    => (int) $top,
-                                 'right'  => (int) $right,
-                                 'bottom' => (int) $bottom);
-  }
-
-  /**
-   * GraphMaker::SetGraphTitle()
-   * Set title text
-   **/
-  function SetGraphTitle($title) {
-    $this->graph_title = $title;
-  }
-
-  /**
-   * GraphMaker::SetGraphBorderColor()
-   * Sets border color for graph
-   **/
-  function SetGraphBorderColor($red, $green, $blue) {
-    $this->graph_bordercolor = array($red, $green, $blue);
-  }
-
-  /**
-   * GraphMaker::SetGraphBorderWidth()
-   * Set width of border. 0 disables border
-   **/
-  function SetGraphBorderWidth($width = 0) {
-    $this->graph_borderwidth = $width;
-  }
-
-  /**
-   * GraphMaker::SetGraphBackgroundColor()
-   * Sets background color for graph
-   **/
-  function SetGraphBackgroundColor($red, $green, $blue) {
-    $this->graph_bgcolor = array($red, $green, $blue);
-  }
-
-  /**
-   * GraphMaker::SetGraphBackgroundTransparent()
-   * Sets background color for graph (and set it transparent)
-   **/
-  function SetGraphBackgroundTransparent($red, $green, $blue, $addtransparency = 1) {
-    $this->graph_bgcolor = array($red, $green, $blue);
-    $this->graph_bgtransparent = ($addtransparency ? 1 : 0);
-  }
-
-  /**
-   * GraphMaker::SetGraphTitleColor()
-   * Sets title color for graph
-   **/
-  function SetGraphTitleColor($red, $green, $blue) {
-    $this->graph_titlecolor = array($red, $green, $blue);
-  }
-
-  /**
-   * GraphMaker::SetGraphTransparency()
-   * Sets transparency for graph
-   **/
-  function SetGraphTransparency($percent) {
-    if ($percent < 0) $percent = 0;
-    elseif ($percent > 100) $percent = 127;
-    else $percent = $percent * 1.27;
-    $this->graph_transparencylevel = $percent;
-  }
-
-  /****************************************************************
-                               BAR
-  ****************************************************************/
-
-  /**
-   * GraphMaker::SetBarBorderColor()
-   * Sets border color for bars
-   **/
-  function SetBarBorderColor($red, $green, $blue) {
-    $this->bar_bordercolor = array($red, $green, $blue);
-  }
-
-  /**
-   * GraphMaker::SetBarBackgroundColor()
-   * Sets background color for bars
-   **/
-  function SetBarBackgroundColor($red, $green, $blue) {
-    $this->bar_bgcolor = array($red, $green, $blue);
-  }
-
-  /**
-   * GraphMaker::SetBarData()
-   * Sets data of graph (parameter should be an array with key
-   * being the name of the bar and the value the value of the bar.
-   **/
-  function SetBarData($data) {
-    if (is_array($data)) $this->bar_data = $data;
-  }
-
-  /**
-   * GraphMaker::SetBarDimensions()
-   * Sets with and height of each bar
-   **/
-  function SetBarDimensions($width, $height) {
-    if ($width > 0) $this->bar_width = $width;
-    if ($height > 0) $this->bar_height = $height;
-  }
-
-  /**
-   * GraphMaker::SetBarPadding()
-   * Sets padding (border) around each bar
-   **/
-  function SetBarPadding($padding) {
-    if ($padding > 0) $this->bar_padding = $padding;
-  }
-
-  /****************************************************************
-                               AXIS
-  ****************************************************************/
-
-  /**
-   * GraphMaker::SetAxisBorderColor()
-   * Sets border color for axis
-   **/
-  function SetAxisBorderColor($red, $green, $blue) {
-    $this->axis_bordercolor = array($red, $green, $blue);
-  }
-
-  /**
-   * GraphMaker::SetAxisBackgroundColor()
-   * Sets background color for axis
-   **/
-  function SetAxisBackgroundColor($red, $green, $blue) {
-    $this->axis_bgcolor = array($red, $green, $blue);
-  }
-
-  /**
-   * GraphMaker::SetAxisStep()
-   * Sets axis scale step
-   **/
-  function SetAxisStep($step) {
-    if ($step > 0) $this->axis_step = $step;
-  }
-
-  /**
-   * GraphMaker::GetFinalGraphDimensions()
-   * From the values already setted, it calculates image
-   * width and height
-   **/
-  function GetFinalGraphDimensions() {
-    $w = $this->graph_padding['left'] +
-         (count($this->bar_data) * ($this->bar_width + ($this->bar_padding * 2))) +
-         $this->graph_padding['right'];
-    $h = $this->graph_padding['top'] +
-         $this->graph_areaheight +
-         $this->graph_padding['bottom'];
-    return array($w, $h);
-  }
-
-  /**
-   * GraphMaker::LoadGraph()
-   * Loads definitions from a file
-   **/
-  function LoadGraph($path) {
-    if (($fp = @fopen($path, "r")) !== false) {
-      $content = "";
-      while (!feof($fp)) {              // I do not use filesize() here
-        $content .= fread($fp, 4096);   // because of remote files. If
-      }                                 // there is no problem with them
-      fclose($fp);                      // please let me know
-      $this->__LoadGraphDefinitions($content);
-      return true;
-    } else return false;
-  }
-
-  /**
-   * GraphMaker::DrawGraph()
-   * Draw all the graph: bg, axis, bars, text.. and output it
-   * Optional file parameter turns output to file, and bool on success
-   **/
-  function DrawGraph($file = "") {
-    list($w, $h) = $this->GetFinalGraphDimensions();
-    $this->graph_width = $w;
-    $this->graph_height = $h;
-
-    $this->im = imagecreatetruecolor($w, $h);
-    if ($this->graph_transparencylevel) {
-      imagealphablending($this->im, true);
-    }
-
-    $this->__PaintBackground();
-    $this->__DrawAxis();
-
-    $p = 0;
-    foreach ($this->bar_data as $name => $value) {
-      $p++;
-      $this->__DrawBarText($p, $name);
-      $this->__DrawBar($p, $value);
-    }
-
-    if (strlen($this->graph_title)) {
-      $this->__AllocateColor("im_graph_titlecolor",
-                             $this->graph_titlecolor,
-                             $this->graph_transparencylevel);
-      $this->__DrawText($this->graph_title,
-                        floor($this->graph_width / 2),
-                        $this->graph_borderwidth + 2,
-                        $this->im_graph_titlecolor,
-                        2,
-                        1);
-    }
-
-    if (strlen($file)) {
-      $ret = imagepng($this->im, $file);
-    } else {
-      header('Content-Type: image/png');
-      imagepng($this->im);
-      $ret = true;
-    }
-    imagedestroy($this->im);
-    return $ret;
-  }
-
-  /**
-   * GraphMaker::PaintBackground()
-   * Draw all the graph: bg, axis, bars, text.. and output it
-   * Optional file parameter turns output to file, and bool on success
-   **/
-  function __PaintBackground() {
-    $this->__AllocateColor("im_graph_bgcolor",
-                           $this->graph_bgcolor,
-                           0);
-    imagefilledrectangle($this->im,
-                         0,
-                         0,
-                         $this->graph_width,
-                         $this->graph_height,
-                         $this->im_graph_bgcolor);
-    if ($this->graph_bgtransparent) {
-      imagecolortransparent($this->im, $this->im_graph_bgcolor);
-    }
-    if ($this->graph_borderwidth) {
-      $this->__AllocateColor("im_graph_bordercolor",
-                             $this->graph_bordercolor,
-                             $this->graph_transparencylevel);
-      for ($i = 0; $i < $this->graph_borderwidth; $i++) {
-        imagerectangle($this->im,
-                       $i,
-                       $i,
-                       $this->graph_width - 1 - $i,
-                       $this->graph_height - 1 - $i,
-                       $this->im_graph_bordercolor);
-      }
-    }
-  }
-
-  /**
-   * GraphMaker::__DrawAxis()
-   * Draws all the axis stuff (and scale steps)
-   **/
-  function __DrawAxis() {
-    $this->__AllocateColor("im_axis_bordercolor",
-                           $this->axis_bordercolor,
-                           $this->graph_transparencylevel);
-    $this->__AllocateColor("im_axis_bgcolor",
-                           $this->axis_bgcolor,
-                           $this->graph_transparencylevel);
-    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
-                         $this->graph_padding['left'], $this->graph_padding['top'],
-                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_padding['top'] - $this->bar_height + 1,
-                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
-                         $this->im_axis_bgcolor, true);
-    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
-                         $this->graph_padding['left'], $this->graph_padding['top'],
-                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_padding['top'] - $this->bar_height + 1,
-                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
-                         $this->im_axis_bordercolor);
-
-    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
-                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
-                         $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
-                         $this->graph_width - $this->graph_padding['right'], $this->graph_height - $this->graph_padding['bottom'],
-                         $this->im_axis_bgcolor, true);
-    $this->__DrawPolygon($this->graph_padding['left'], $this->graph_height - $this->graph_padding['bottom'],
-                         $this->graph_padding['left'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
-                         $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1, $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
-                         $this->graph_width - $this->graph_padding['right'], $this->graph_height - $this->graph_padding['bottom'],
-                         $this->im_axis_bordercolor);
-
-    // draw lines that separate bars
-    $total_bars = count($this->bar_data);
-    for ($i = 1; $i < $total_bars; $i++) {
-      $offset = $this->graph_padding['left'] +
-                (($this->bar_width + ($this->bar_padding * 2)) * $i);
-      imageline($this->im,
-                $offset,
-                $this->graph_height - $this->graph_padding['bottom'],
-                $offset + $this->bar_height - 1,
-                $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height + 1,
-                $this->im_axis_bordercolor);
-    }
-
-    // draw scale steps
-    $max_value = $this->__GetMaxGraphValue();
-    if (($max_value % 10) > 0) {
-      $max_value = $max_value + (10 - ($max_value % 10));
-    }
-    $this->axis_max = $max_value;
-    $y = 0;
-    $style = array($this->im_axis_bordercolor, $this->im_graph_bgcolor);
-    imagesetstyle($this->im, $style);
-    while ($y <= $max_value) {
-      if ($max_value == 0) { $max_value=1; } // corrected by Marcelo Trenkenchu
-      $offset = floor($this->graph_height - $this->graph_padding['bottom'] -
-                ($y * $this->graph_areaheight / $max_value));
-      imageline($this->im,
-                $this->graph_padding['left'],
-                $offset,
-                $this->graph_padding['left'] + $this->bar_height - 1,
-                $offset - $this->bar_height + 1,
-                $this->im_axis_bordercolor);
-      $this->__DrawText($y,
-                        $this->graph_padding['left'],
-                        $offset,
-                        $this->im_axis_bordercolor,
-                        1,
-                        2,
-                        1);
-      // gridline
-      if ($y > 0) {
-        imageline($this->im,
-                  $this->graph_padding['left'] + $this->bar_height,
-                  $offset - $this->bar_height + 1,
-                  $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1,
-                  $offset - $this->bar_height + 1,
-                  IMG_COLOR_STYLED);
-      }
-      $y += $this->axis_step;
-    }
-
-    imageline($this->im,
-              $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1,
-              $this->graph_padding['top'] - $this->bar_height + 1,
-              $this->graph_width - $this->graph_padding['right'] + $this->bar_height - 1,
-              $this->graph_height - $this->graph_padding['bottom'] - $this->bar_height,
-              IMG_COLOR_STYLED);
-  }
-
-  /**
-   * GraphMaker::__DrawText()
-   * Draws text on image with color, size and alignment options
-   **/
-  function __DrawText($text, $x, $y, $color, $size = 1, $align = 0, $valign = 0) {
-    /*
-     * Align: 0=left | 1=center | 2=right
-     */
-    if ($align == 1) $x -= floor(strlen($text) * imagefontwidth($size) / 2);
-    elseif ($align == 2) $x -= (strlen($text) * imagefontwidth($size));
-    if ($valign == 1) $y -= floor(imagefontheight($size) / 2);
-    elseif ($valign == 2) $y -= imagefontheight($size);
-    imagestring($this->im,
-                $size,
-                $x,
-                $y,
-                $text,
-                $color);
-  }
-
-  /**
-   * GraphMaker::__GetMaxGraphValue()
-   * Returns max bar value
-   **/
-  function __GetMaxGraphValue() {
-    $max_value = 0;
-    foreach ($this->bar_data as $name => $value) {
-      if ($value > $max_value) $max_value = $value;
-    }
-    return $max_value;
-  }
-
-  /**
-   * GraphMaker::__DrawBarText()
-   * Determines top and left to draw text to a choosen bar
-   **/
-  function __DrawBarText($bar, $text) {
-    $this->__DrawText($text,
-                      $this->graph_padding['left'] + (($this->bar_width + ($this->bar_padding * 2)) * ($bar - 0.5)),
-                      $this->graph_height - $this->graph_padding['bottom'] + 1,
-                      $this->axis_bordercolor,
-                      1,
-                      1);
-  }
+require(dirname(__FILE__) . '/graphing/class.3dbargraph.php');
+require(dirname(__FILE__) . '/graphing/class.linegraph.php');
+require(dirname(__FILE__) . '/graphing/class.piegraph.php');
 
-  /**
-   * GraphMaker::__DrawBar()
-   * Draws a choosen bar with it's value
-   **/
-  function __DrawBar($bar, $value) {
-    $x = $this->graph_padding['left'] +
-         (($this->bar_width + ($this->bar_padding * 2)) * ($bar - 1)) +
-         $this->bar_padding;
-    if ($this->axis_max == 0) { $this->axis_max = 1; } // corrected by Marcelo Trenkenchu
-    $y = $value * $this->graph_areaheight / $this->axis_max;
-    $this->____DrawBar($x,
-                       $this->graph_height - $this->graph_padding['bottom'] - $y,
-                       $x + $this->bar_width,
-                       $this->graph_height - $this->graph_padding['bottom']);
-  }
-
-  /**
-   * GraphMaker::____DrawBar()
-   * Draws the actual rectangles that form a bar
-   **/
-  function ____DrawBar($x1, $y1, $x2, $y2) {
-    $this->__AllocateColor("im_bar_bordercolor",
-                           $this->bar_bordercolor,
-                           $this->graph_transparencylevel);
-    $this->__AllocateColor("im_bar_bgcolor",
-                           $this->bar_bgcolor,
-                           $this->graph_transparencylevel);
-    $this->__DrawPolygon($x1,                         $y1,
-                         $x2,                         $y1,
-                         $x2,                         $y2,
-                         $x1,                         $y2,
-                         $this->im_bar_bgcolor,       true);
-    $this->__DrawPolygon($x1,                         $y1,
-                         $x2,                         $y1,
-                         $x2,                         $y2,
-                         $x1,                         $y2,
-                         $this->im_bar_bordercolor);
-    $this->__DrawPolygon($x1,                         $y1,
-                         $x2,                         $y1,
-                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
-                         $x1 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
-                         $this->im_bar_bgcolor,       true);
-    $this->__DrawPolygon($x1,                         $y1,
-                         $x2,                         $y1,
-                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
-                         $x1 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
-                         $this->im_bar_bordercolor);
-    $this->__DrawPolygon($x2,                         $y2,
-                         $x2,                         $y1,
-                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
-                         $x2 + $this->bar_height - 1, $y2 - $this->bar_height + 1,
-                         $this->im_bar_bgcolor,       true);
-    $this->__DrawPolygon($x2,                         $y2,
-                         $x2,                         $y1,
-                         $x2 + $this->bar_height - 1, $y1 - $this->bar_height + 1,
-                         $x2 + $this->bar_height - 1, $y2 - $this->bar_height + 1,
-                         $this->im_bar_bordercolor);
-  }
-
-  /**
-   * GraphMaker::__DrawPolygon()
-   * Draws a (filled) (ir)regular polygon
-   **/
-  function __DrawPolygon($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4, $color, $filled = false) {
-    if ($filled) {
-      imagefilledpolygon($this->im, array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4), 4, $color);
-    } else {
-      imagepolygon($this->im, array($x1, $y1, $x2, $y2, $x3, $y3, $x4, $y4), 4, $color);
-    }
-  }
-
-  /**
-   * GraphMaker::__LoadGraphDefinitions()
-   * Loads definitions to a graph from text lines (normaly
-   * they come from a file). This function is called by
-   * GraphMaker::LoadGraph()
-   **/
-  function __LoadGraphDefinitions($text) {
-    $text = preg_split("/\r?\n/", $text);
-    $data = array();
-    $section = '';
-    for ($i = 0; $i < count($text); $i++) {
-      if (preg_match("/^\s*#/", $text[$i])) {
-        //ignore.. it's just a comment
-      } elseif (preg_match("/^\s*\}\s*/", $text[$i])) {
-        $section = '';
-      } elseif (preg_match("/^\s*(\w+)\s*\{\s*$/", $text[$i], $r)) {
-        $section = $r[1];
-      } else {
-        $p = strpos($text[$i], "=");
-        if ($p !== false) {
-          $data[$section][trim(substr($text[$i], 0, $p))] = trim(substr($text[$i], $p + 1));
-        }
-      }
-    }
-    if (is_array($data['graph'])) {
-      $this->__LoadGraphValues($data['graph']);
-    }
-    if (is_array($data['bar'])) {
-      $this->__LoadBarValues($data['bar']);
-    }
-    if (is_array($data['axis'])) {
-      $this->__LoadAxisValues($data['axis']);
-    }
-    if (is_array($data['data'])) {
-      $this->bar_data = $data['data'];
-    }
-  }
-
-  /**
-   * GraphMaker::__LoadGraphValues()
-   * Loads definitions to main graph settings
-   **/
-  function __LoadGraphValues($data) {
-    foreach ($data as $name => $value) {
-      $name = strtolower($name);
-      switch ($name) {
-        case 'background-color':
-          $this->__SetColorToValue("graph_bgcolor", $value);
-          break;
-        case 'border-color':
-          $this->__SetColorToValue("graph_bordercolor", $value);
-          break;
-        case 'title-color':
-          $this->__SetColorToValue("graph_titlecolor", $value);
-          break;
-        case 'background-transparent':
-          $this->graph_bgtransparent = ($value == 1 || $value == 'yes' ? 1 : 0);
-          break;
-        case 'transparency':
-          $this->SetGraphTransparency(str_replace('%', '', $value));
-          break;
-        case 'title':
-          $this->graph_title = $value;
-          break;
-        case 'border-width':
-          $this->graph_borderwidth = (int) $value;
-          break;
-        case 'area-height':
-          $this->graph_areaheight = (int) $value;
-          break;
-        default:
-          if (substr($name, 0, 8) == 'padding-' && strlen($name) > 8) {
-            $this->graph_padding[substr($name, 8)] = $value;
-          }
-      }
-    }
-  }
-
-  /**
-   * GraphMaker::__LoadBarValues()
-   * Loads definitions to bar settings
-   **/
-  function __LoadBarValues($data) {
-    foreach ($data as $name => $value) {
-      $name = strtolower($name);
-      switch ($name) {
-        case 'background-color':
-          $this->__SetColorToValue("bar_bgcolor", $value);
-          break;
-        case 'border-color':
-          $this->__SetColorToValue("bar_bordercolor", $value);
-          break;
-        case 'padding':
-          $this->bar_padding = $value;
-          break;
-        case 'width':
-          $this->bar_width = (int) $value;
-          break;
-        case 'height':
-          $this->bar_height = (int) $value;
-          break;
-      }
-    }
-  }
-
-  /**
-   * GraphMaker::__LoadAxisValues()
-   * Loads definitions to axis settings
-   **/
-  function __LoadAxisValues($data) {
-    foreach ($data as $name => $value) {
-      switch (strtolower($name)) {
-        case 'step':
-          $this->SetAxisStep($value);
-          break;
-        case 'background-color':
-          $this->__SetColorToValue("axis_bgcolor", $value);
-          break;
-        case 'border-color':
-          $this->__SetColorToValue("axis_bordercolor", $value);
-      }
-    }
-  }
-
-  /**
-   * GraphMaker::__SetColorToValue()
-   * Sets a color (rgb or in html format) to a variable
-   **/
-  function __SetColorToValue($varname, $color) {
-    if ($color[0] == "#") { // if it's hex (html format), change to rgb array
-      if (strlen($color) == 4) {
-        // if only 3 hex values (I assume it's a shade of grey: #ddd)
-        $color .= substr($color, -3);
-      }
-      $color = array(hexdec($color[1].$color[2]),
-                     hexdec($color[3].$color[4]),
-                     hexdec($color[5].$color[6]));
-    }
-    $this->$varname = $color;
-  }
-
-  function __AllocateColor($varname, $color, $alpha) {
-    $this->$varname = imagecolorallocatealpha($this->im,
-                                              $color[0],
-                                              $color[1],
-                                              $color[2],
-                                              $alpha);
-  }
-}
-
-// Graph Generator for PHP
-// Originally located at http://szewo.com/php/graph, but link was broken, so this file was retrieved from:
-// http://web.archive.org/web/20030130065944/szewo.com/php/graph/graph.class.php3.txt
-// License unknown, however sources on the web have shown this to be either GPL or public domain.
-
-// At this point this class has been very nearly rewritten for Enano.
-
-class GraphMaker_compat {
-  var $_values;
-  var $_ShowLabels;
-  var $_ShowCounts;
-  var $_ShowCountsMode;
-
-  var $_BarWidth;
-  var $_GraphWidth;
-  var $_BarImg;
-  var $_BarBorderWidth;
-  var $_BarBorderColor;
-  var $_BarBackgroundColor;
-  var $_RowSortMode;
-  var $_TDClassHead;
-  var $_TDClassLabel;
-  var $_TDClassCount;
-  var $_GraphTitle;
-
-  function __construct() {
-    $this->_values = array();
-    $this->_ShowLabels = true;
-    $this->_BarWidth = 32;
-    $this->_GraphWidth = 360;
-    $this->_BarImg = scriptPath . "/images/graphbit.png";
-    $this->_BarBorderWidth = 0;
-    $this->_BarBorderColor = "red";
-    $this->_ShowCountsMode = 2;
-    $this->_RowSortMode = 1;
-    $this->_TDClassHead = "graph-title";
-    $this->_TDClassLabel = "graph-label";
-    $this->_TDClassCount = "graph-count";
-    $this->_GraphTitle="Graph title";
-    $this->_BarBackgroundColor = "#456798";
-  }
-
-  function GraphMaker_compat() {
-    $this->__construct();
-  }
-
-  function SetBarBorderWidth($width) {
-    $this->_BarBorderWidth = $width;
-  }
-  function SetBorderColor($color) {
-    $this->_BarBorderColor = $color;
-  }
-  
-  function SetBarBackgroundColor($color)
-  {
-    $this->_BarBackgroundColor = $color;
-  }
-
-//  mode = 1 labels asc, 2 label desc
-  function SetSortMode($mode) {
-    switch ($mode) {
-      case 1:
-        asort($this->_values);
-        break;
-      case 2:
-        arsort($this->_values);
-        break;
-      default:
-        break;
-      }
-
-  }
-
-  function AddValue($labelName, $theValue) {
-    array_push($this->_values, array("label" => $labelName, "value" => $theValue));
-  }
-
-  function SetBarData($data)
-  {
-      foreach ( $data as $name => $value )
-      {
-          $this->AddValue($name, $value);
-      }
-  }
-  function DrawGraph()
-  {
-      $this->BarGraphVert();
-  }
-  function SetBarWidth($width)
-  {
-    $this->_BarWidth = $width;
-  }
-  function SetBarImg($img)
-  {
-    $this->_BarImg = $img;
-  }
-  function SetShowLabels($lables)
-  {
-    $this->_ShowLabels = $labels;
-  }
-  function SetGraphWidth($width)
-  {
-    $this->_GraphWidth = $width;
-  }
-  function SetGraphTitle($title)
-  {
-    $this->_GraphTitle = $title;
-  }
-  //mode = percentage or counts
-  function SetShowCountsMode($mode)
-  {
-    $this->_ShowCountsMode = $mode;
-  }
-  //mode = none(0) label(1) or count(2)
-  function SetRowSortMode($sortmode)
-  {
-    $this->_RowSortMode = $sortmode;
-  }
-
-  function SetTDClassHead($class)
-  {
-    $this->_TDClassHead = $class;
-  }
-  function SetTDClassLabel($class)
-  {
-    $this->_TDClassLabel = $class;
-  }
-  function SetTDClassCount($class)
-  {
-    $this->_TDClassCount = $class;
-  }
-  function GetMaxVal()
-  {
-    $maxval = 0;
-    foreach ( $this->_values as $value )
-    {
-      if ( $maxval < $value["value"] )
-      {
-        $maxval = $value["value"];
-      }
-    }
-    return $maxval;
-  }
-  function BarGraphVert()
-  {
-    $maxval = $this->GetMaxVal();
-    foreach($this->_values as $value)
-    {
-      $sumval += $value["value"];
-    }
-    
-    $this->SetSortMode($this->_RowSortMode);
-    
-    echo "\n<!-- ----------------------------------------- -->\n<div class=\"tblholder\" style=\"width: 100%; clip: rect(0px,auto,auto,0px); overflow: auto;\">\n<table border=\"0\" cellspacing=\"1\" cellpadding=\"4\">\n  ";
-    
-    if ( strlen($this->_GraphTitle) > 0 )
-    {
-      echo "<tr>\n    <th colspan=\"".count($this->_values)."\" class=\"".$this->_TDClassHead."\">".$this->_GraphTitle."</th>\n  </tr>\n  ";
-    }
-    
-    echo "<tr>\n  ";
-    $css_class = 'row1';
-    
-    foreach($this->_values as $value)
-    {
-      $css_class = ( $css_class == 'row1' ) ? 'row3' : 'row1';
-      echo "  <td valign=\"bottom\" align=\"center\" class=\"$css_class\">\n      ";
-      $width = $this->_BarWidth;
-      $height = ceil( $value["value"] * $this->_GraphWidth / $maxval );
-
-      echo "<div style=\"width: {$width}px; height: {$height}px; background-color: {$this->_BarBackgroundColor}; border: ".$this->_BarBorderWidth."px solid ".$this->_BarBorderColor."\">\n      ";
-      echo "</div>\n    ";
-      
-      // echo "<img src=\"".$this->_BarImg."\" height=\"$width\" width=\"$height\" ";
-      // echo "  style=\"border: ".$this->_BarBorderWidth."px solid ".$this->_BarBorderColor."\"";
-      // echo ">";
-
-      echo "</td>\n  ";
-    }
-    echo "</tr>\n  ";
-    if ( $this->_ShowCountsMode > 0 )
-    {
-      $css_class = 'row1';
-      echo "<tr>\n  ";
-      foreach($this->_values as $value)
-      {
-        $css_class = ( $css_class == 'row1' ) ? 'row3' : 'row1';
-        switch ($this->_ShowCountsMode)
-        {
-          case 1:
-            $count = round ( 100 * $value["value"] / $sumval ) . "%";
-            break;
-          case 2:
-            $count = $value["value"];
-            break;
-          default:
-            break;
-        }
-        echo "  <td align=\"center\" class=\"$css_class ".$this->_TDClassCount."\">$count</td>\n  ";
-      }
-      echo "</tr>\n";
-    }
-
-    if ($this->_ShowLabels)
-    {
-      $css_class = 'row1';
-      echo "  <tr>\n  ";
-      foreach($this->_values as $value)
-      {
-        $css_class = ( $css_class == 'row1' ) ? 'row3' : 'row1';
-        echo "  <td align=\"center\" class=\"$css_class ".$this->_TDClassLabel."\"";
-        echo ">".$value["label"]."</td>\n  ";
-      }
-      echo "</tr>\n";
-    }
-
-    echo "</table>";
-  }
-
-  function BarGraphHoriz()
-  {
-    $maxval = $this->GetMaxVal();
-    
-    foreach($this->_values as $value)
-    {
-      $sumval += $value["value"];
-    }
-    
-    $this->SetSortMode($this->_RowSortMode);
-    
-    echo "<table border=\"0\">";
-    
-    if ( strlen($this->_GraphTitle) > 0 )
-    {
-      echo "<tr><td ";
-      if ( $this->_ShowCountsMode > 0 )
-      {
-        echo " colspan=\"2\"";
-      }
-      echo " class=\"".$this->_TDClassHead."\">".$this->_GraphTitle."</td></tr>";
-    }
-    foreach($this->_values as $value)
-    {
-      if ($this->_ShowLabels)
-      {
-        echo "<tr>";
-        echo "<td class=\"".$this->_TDClassLabel."\"";
-        if ( $this->_ShowCountsMode > 0 )
-        {
-          echo " colspan=\"2\"";
-        }
-        echo ">".$value["label"]."</td></tr>";
-      }
-      echo "<tr>";
-      if ( $this->_ShowCountsMode > 0 )
-      {
-        switch ($this->_ShowCountsMode)
-        {
-          case 1:
-            $count = round(100 * $value["value"] / $sumval )."%";
-            break;
-          case 2:
-            $count = $value["value"];
-            break;  /* Exit the switch and the while. */
-          default:
-            break;
-        }
-        echo "<td class=\"".$this->_TDClassCount."\">$count</TD>";
-      }
-      echo "<td>";
-      $height = $this->_BarWidth;
-      $width = ceil( $value["value"] * $this->_GraphWidth / $maxval );
-      echo "<div style=\"width: {$width}px; height: {$height}px; background-color: #456798; border: ".$this->_BarBorderWidth."px solid ".$this->_BarBorderColor."\">\n      ";
-      echo "</div>\n    ";
-      //echo "<img SRC=\"".$this->_BarImg."\" height=$height width=$width ";
-      //echo "  style=\"border: ".$this->_BarBorderWidth."px solid ".$this->_BarBorderColor."\"";
-      //echo ">";
-      echo "</td></tr>";
-    }
-    echo "</table>";
-  }
-  /**
-   * Dummy functions for compatibility with the GD version of the class
-   */
-  
-  function SetGraphPadding($a, $b, $c, $d)
-  {
-    return true;
-  }
-  function SetBarPadding($a)
-  {
-    return true;
-  }
-  function SetAxisStep($a)
-  {
-    return true;
-  }
-  function SetGraphBackgroundTransparent($r, $g, $b, $a)
-  {
-    return true;
-  }
-  function SetGraphTransparency($a)
-  {
-    return true;
-  }
-  function SetGraphAreaHeight($a)
-  {
-    return true;
-  }
-}
-
-
--- a/htdocs/graph.php	Sun Jan 04 12:19:27 2009 -0500
+++ b/htdocs/graph.php	Sun Jan 04 16:40:36 2009 -0500
@@ -7,14 +7,34 @@
 $first_channel = $channel_list[0];
 $channel = ( isset($_REQUEST['channel']) && in_array($_REQUEST['channel'], $channel_list) ) ? $_REQUEST['channel'] : $first_channel;
 
-$g = new GraphMaker(); // _Compat();
-
-$g->SetGraphPadding(20, 30, 20, 15);
-$g->SetGraphAreaHeight(200);
-$g->SetBarDimensions(26, 0);
-$g->SetBarPadding(7);
-$g->SetGraphBackgroundTransparent(240, 250, 255, 0);
-$g->SetGraphTransparency(25);
+function makeGraph($type = 'bar')
+{
+  $class = ( $type == 'line' ) ? 'LineGraph' : 'BarGraph';
+  $g = new $class(); // _Compat();
+  
+  $g->SetGraphAreaHeight(200);
+  $g->SetGraphPadding(30, 30, 20, 15);
+  if ( get_class($g) == 'BarGraph' )
+  {
+    $g->SetBarPadding(7);
+    $g->SetBarFont(1);
+    $g->SetBarDimensions(25, 7);
+  }
+  else if ( get_class($g) == 'LineGraph' )
+  {
+    $g->SetGraphAreaWidth(800);
+  }
+  $g->SetAxisDeepness(7);
+  $g->SetGraphTitleFont(2);
+  $g->SetGraphBackgroundTransparent(false, 240, 250, 255);
+  $g->SetGraphTransparency(25);
+  $g->SetAxisScaleColor(90, 90, 90);
+  $g->SetAxisScaleFont(1);
+  $g->SetScaleRoundY(0);
+  $g->SetScaleRoundX(0);
+  $g->SetAxisStepSize(7);
+  return $g;
+}
 
 // generate the data
 // we're doing this by absolute hours, not by strictly "24 hours ago", e.g. on-the-hour stats
@@ -23,6 +43,7 @@
 {
   case 'lastday':
   default:
+    $g = makeGraph();
     $graph_title = $channel . ' message count - last 24 hours';
     $this_hour = gmmktime(gmdate('H'), 0, 0);
     $graphdata = array();
@@ -36,6 +57,7 @@
     }
     break;
   case 'lastweek':
+    $g = makeGraph();
     $graph_title = $channel . ' activity - last 14 days';
     $this_day = gmmktime(0, 0, 0);
     $graphdata = array();
@@ -50,6 +72,7 @@
     $g->SetBarPadding(12);
     break;
   case 'lastmonth':
+    $g = makeGraph();
     $graph_title = $channel . ' activity - last 30 days';
     $this_day = gmmktime(0, 0, 0);
     $graphdata = array();
@@ -63,6 +86,41 @@
     }
     $g->SetBarPadding(15);
     break;
+  case 'lasthour':
+    $g = makeGraph('line');
+    $g->SetAxisStepX(5);
+    $g->SetScaleFunctionX('lasthour_scaler');
+    function lasthour_scaler($v, $g)
+    {
+      $k = array_keys($g->data);
+      return ( isset($k[$v]) ) ? $k[$v] : 'now';
+    }
+    $graph_title = $channel . ' activity - last hour';
+    $data = stats_raw_data($channel, 59);
+    $agg = array();
+    foreach ( $data as $message )
+    {
+      $tid = intval(ltrim(date('i', $message['time']), '0'));
+      if ( !isset($agg[$tid]) )
+        $agg[$tid] = 0;
+      $agg[$tid]++;
+    }
+    $graphdata = array();
+    $minutenow = intval(ltrim(date('i', NOW), '0'));
+    $hournow = intval(ltrim(date('H', NOW), '0'));
+    $hourthen = intval(ltrim(date('H', NOW-3600), '0'));
+    for ( $i = $minutenow + 1; $i < 60; $i++ )
+    {
+      $istr = ( $i < 10 ) ? "0$i" : "$i";
+      $graphdata["$hourthen:$istr"] = ( isset($agg[$i]) ) ? $agg[$i] : 0;
+    }
+    for ( $i = 0; $i <= $minutenow; $i++ )
+    {
+      $istr = ( $i < 10 ) ? "0$i" : "$i";
+      $graphdata["$hournow:$istr"] = ( isset($agg[$i]) ) ? $agg[$i] : 0;
+    }
+    
+    break;
 }
 
 $max = max($graphdata);
@@ -94,9 +152,10 @@
 if ( $max > 30000 )
   $interval = round($max / 10);
 
-$g->SetBarData($graphdata);
-$g->SetAxisStep($interval);
+$g->data = $graphdata;
+
 $g->SetGraphTitle($graph_title);
+$g->SetAxisStepY($interval);
 
 $g->DrawGraph();
 
--- a/stats-fe.php	Sun Jan 04 12:19:27 2009 -0500
+++ b/stats-fe.php	Sun Jan 04 16:40:36 2009 -0500
@@ -106,6 +106,33 @@
 }
 
 /**
+ * Raw data.
+ * @param string Channel name
+ * @param int How many minutes, defaults to 60
+ * @param int Base time, defaults to right now
+ * @return array MySQL rows.
+ */
+
+function stats_raw_data($channel, $mins = 60, $base = NOW)
+{
+  $channel = db_escape($channel);
+  $time_min = $base - ( $mins * 60 );
+  $time_max =& $base;
+  $total = 0;
+  
+  if ( $q = eb_mysql_query("SELECT * FROM stats_messages WHERE channel = '$channel' AND time >= $time_min AND time <= $time_max ORDER BY message_id ASC;") )
+  {
+    $userdata = array();
+    while ( $row = @mysql_fetch_assoc($q) )
+    {
+      $userdata[] = $row;
+    }
+    return $userdata;
+  }
+  return false;
+}
+
+/**
  * Return the time that the stats DB was last updated.
  * @return int
  */