[Piwik-svn] r208 - in trunk: libs libs/sparkline libs/sparkline/lib modules modules/ViewDataTable plugins/Home plugins/Home/templates plugins/VisitsSummary

svnmaster at piwik.org svnmaster at piwik.org
Sun Jan 20 07:57:21 CET 2008


Author: matt
Date: 2008-01-20 07:57:20 +0100 (Sun, 20 Jan 2008)
New Revision: 208

Added:
   trunk/libs/sparkline/
   trunk/libs/sparkline/CHANGES
   trunk/libs/sparkline/DESIGN
   trunk/libs/sparkline/LICENSE
   trunk/libs/sparkline/README
   trunk/libs/sparkline/lib/
   trunk/libs/sparkline/lib/Object.php
   trunk/libs/sparkline/lib/Sparkline.php
   trunk/libs/sparkline/lib/Sparkline_Bar.php
   trunk/libs/sparkline/lib/Sparkline_Line.php
   trunk/modules/ViewDataTable/Sparkline.php
Modified:
   trunk/modules/ViewDataTable.php
   trunk/modules/ViewDataTable/GenerateGraphData.php
   trunk/modules/ViewDataTable/Graph.php
   trunk/plugins/Home/Controller.php
   trunk/plugins/Home/templates/datatable.css
   trunk/plugins/Home/templates/index.tpl
   trunk/plugins/VisitsSummary/API.php
Log:
- adding sparklines: http://piwik.org/demo/ 
first shot still lot of work

Added: trunk/libs/sparkline/CHANGES
===================================================================
--- trunk/libs/sparkline/CHANGES	                        (rev 0)
+++ trunk/libs/sparkline/CHANGES	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,22 @@
+#
+# Sparkline PHP Graphing Library
+# Copyright 2004 James Byers <jbyers at users.sf.net>
+# http://sparkline.org
+#
+# Sparkline is distributed under a BSD License.  See LICENSE for details.
+#
+# $Id: CHANGES,v 1.2 2005/06/02 20:57:51 jbyers Exp $
+#
+
+2005-06-02  James Byers  <jbyers at users.sf.net>
+
+        * Version 0.2  released
+	* Corrected line chart behavior for small data sets [1096890]
+	* Library will create log file if possible [1163412]
+	* Fixed error message on bad log file [1096895]
+	* Corrected bitmask on DEBUG_ALL
+	* Revised structure of SetFeature
+
+2004-11-08  James Byers  <jbyers at users.sf.net>
+
+        * Version 0.1 released

Added: trunk/libs/sparkline/DESIGN
===================================================================
--- trunk/libs/sparkline/DESIGN	                        (rev 0)
+++ trunk/libs/sparkline/DESIGN	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,27 @@
+#
+# Sparkline PHP Graphing Library
+# Copyright 2004 James Byers <jbyers at users.sf.net>
+# http://sparkline.org
+#
+# Sparkline is distributed under a BSD License.  See LICENSE for details.
+#
+# $Id: DESIGN,v 1.3 2004/11/09 07:10:42 jbyers Exp $
+#
+
+Not much to see.  It's 0.1, after all.
+
+Flow
+------------------------------------------------------------------------------
+
+Instantiate appropriate Sparkline subclass
+Load data, set parameters, all Set* calls
+Render
+  convert coordinates
+  calculate image size
+  create image handle
+  set colors
+  fill background
+  draw graph
+  draw features
+Optionally call Draw* functions
+Output / OutputFile

Added: trunk/libs/sparkline/LICENSE
===================================================================
--- trunk/libs/sparkline/LICENSE	                        (rev 0)
+++ trunk/libs/sparkline/LICENSE	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,29 @@
+Copyright (c) 2004 James Byers <jbyers at users.sf.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+ * Neither the name of James Byers nor the names of its contributors
+   may be used to endorse or promote products derived from this
+   software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Added: trunk/libs/sparkline/README
===================================================================
--- trunk/libs/sparkline/README	                        (rev 0)
+++ trunk/libs/sparkline/README	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,37 @@
+#
+# Sparkline PHP Graphing Library
+# Copyright 2004 James Byers <jbyers at users.sf.net>
+# http://sparkline.org
+#
+# Sparkline is distributed under a BSD License.  See LICENSE for details.
+#
+# $Id: README,v 1.2 2004/11/09 07:10:42 jbyers Exp $
+#
+
+Installation:
+-------------
+
+Sparkline does not have any installation requirements.  See the
+samples directory for usage ideas.
+
+Requirements:
+-------------
+
+Sparkline requires PHP 4.0.6 or newer and GD 2.0 built as a PHP
+module.
+
+Troubleshooting and Support:
+----------------------------
+
+See http://sparkline.org for troubleshooting advice and support.
+
+Bugs, Features:
+---------------
+
+Please submit bugs to the bug tracker:
+
+  http://sourceforge.net/tracker/?group_id=122936&atid=694962
+
+Please submit feature requests to the RFE tracker:
+
+  http://sourceforge.net/tracker/?group_id=122936&atid=694965

Added: trunk/libs/sparkline/lib/Object.php
===================================================================
--- trunk/libs/sparkline/lib/Object.php	                        (rev 0)
+++ trunk/libs/sparkline/lib/Object.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,158 @@
+<?php
+/*
+ * Sparkline PHP Graphing Library
+ * Copyright 2004 James Byers <jbyers at users.sf.net>
+ * http://sparkline.org
+ *
+ * Sparkline is distributed under a BSD License.  See LICENSE for details.
+ *
+ * $Id: Object.php,v 1.8 2005/06/02 21:01:42 jbyers Exp $
+ *
+ */
+
+define('DEBUG_NONE',     0); // nothing
+define('DEBUG_ERROR',    1); // major errors
+define('DEBUG_WARNING',  2); // warnings
+define('DEBUG_STATS',    4); // dataset, rendering statistics
+define('DEBUG_CALLS',    8); // major function calls
+define('DEBUG_SET',     16); // all Set methods
+define('DEBUG_DRAW',    32); // all Draw methods
+define('DEBUG_ALL',   2047); // everything
+
+function error_handler($errno, $errstr, $errfile, $errline) {
+  switch ($errno) {
+  case E_ERROR:
+    $message = "ERROR:    ";
+    break;
+  case E_WARNING:
+    $message = "WARNING:  ";
+    break;
+  case E_PARSE:
+    $message = "PARSE:    ";
+    break;
+  case E_NOTICE:
+    $message = "NOTICE:   ";		
+    break;
+  case E_USER_ERROR:
+    $message = "UERROR:   ";
+    break;
+  case E_USER_WARNING:
+    $message = "UWARNING: ";
+    break;
+  case E_USER_NOTICE:
+    $message = "UNOTICE:  ";		
+    break;
+  default:
+    $message = "UNKNOWN:  ";
+    break;
+  } // switch
+  
+  $message .= "$errstr in $errfile at line $errline\n";
+  
+  if (($errno != E_NOTICE) &&     // suppress notices
+      (error_reporting() != 0)) { // respect supressed errors (@)
+    log_write($message, 'PHP');
+  }
+} // function error_handler
+
+function log_write($string, $type = '', $date = false) {
+  global $LOGFILE;
+
+  if (isset($LOGFILE)) {
+    if ($date == false) {
+      $date = time();
+    }
+    
+    $message = date('d/m/Y:H:i:s', $date) . " $type: $string \n";
+    error_log($message, 3, $LOGFILE);
+  }
+} // function log_write
+
+class Object {
+
+  var $isError;
+  var $logFile;
+  var $errorList;
+  var $debugList;
+  var $debugLevel;
+  var $startTime;
+
+  ////////////////////////////////////////////////////////////////////////////
+  // constructor
+  //
+  function Object($catch_errors = true) {
+    $this->isError         = false;
+    $this->logFile         = null;
+    $this->logDate         = '';
+    $this->errorList       = array();
+    $this->debugList       = array();
+    $this->debugLevel      = DEBUG_NONE;
+    $this->startTime       = $this->microTimer();
+
+    //    if ($catch_errors) {
+      set_error_handler('error_handler');
+      //}
+  } // function Object
+
+  ////////////////////////////////////////////////////////////////////////////
+  // utility
+  //
+  function microTimer() {
+    list($usec, $sec) = explode(" ", microtime());
+    return ((float)$usec + (float)$sec); 
+  } // function microTimer
+
+  ////////////////////////////////////////////////////////////////////////////
+  // error handling
+  //
+  function SetDebugLevel($level, $file = null) {
+    global $LOGFILE;
+
+    if ($level >= DEBUG_NONE &&
+        $level <= DEBUG_ALL) {
+      $this->debugLevel = $level;
+    }
+
+    if ($file != null) {
+      if ((!file_exists($file) && !touch($file)) ||
+          !is_writable($file)) {
+        die("error log file '$file' is not writable to the web server user");
+      } else {
+        $this->logFile = $file;
+        $LOGFILE       = $file;
+      }
+    }
+  } // function SetDebugLevel
+  
+  function Debug($string, $level = DEBUG_WARNING) {
+    $this->debugList[] = $string;
+    if ($this->debugLevel & $level &&
+        $this->logFile != null) {
+      log_write($string, 'DEBUG');
+    }
+  } // function Debug
+
+  function Error($string) {
+    $this->isError = true;
+    $this->errorList[] = $string;
+    if ($this->debugLevel & DEBUG_ERROR &&
+        $this->logFile != null) {
+      log_write($string, 'ERROR');
+    }
+  } // function Error
+
+  function GetDebug() {
+    return $this->debugList;
+  } // function GetDebug
+
+  function GetError() {
+    return $this->errorList;
+  } // function GetError
+
+  function IsError() {
+    return $this->isError;
+  } // function IsError
+
+} // class Object
+
+?>

Added: trunk/libs/sparkline/lib/Sparkline.php
===================================================================
--- trunk/libs/sparkline/lib/Sparkline.php	                        (rev 0)
+++ trunk/libs/sparkline/lib/Sparkline.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,496 @@
+<?php
+/*
+ * Sparkline PHP Graphing Library
+ * Copyright 2004 James Byers <jbyers at users.sf.net>
+ * http://sparkline.org
+ *
+ * Sparkline is distributed under a BSD License.  See LICENSE for details.
+ *
+ * $Id: Sparkline.php,v 1.8 2005/05/02 20:25:47 jbyers Exp $
+ *
+ */
+
+define('TEXT_TOP',    1);
+define('TEXT_RIGHT',  2);
+define('TEXT_BOTTOM', 3);
+define('TEXT_LEFT',   4);
+
+define('FONT_1', 1);
+define('FONT_2', 2);
+define('FONT_3', 3);
+define('FONT_4', 4);
+define('FONT_5', 5);
+
+require_once('Object.php');
+
+class Sparkline extends Object {
+
+  var $imageX;
+  var $imageY;
+  var $imageHandle;
+  var $graphAreaPx;
+  var $graphAreaPt;
+  var $colorList;
+  var $colorBackground;
+  var $lineSize;
+
+  ////////////////////////////////////////////////////////////////////////////
+  // constructor
+  //
+  function Sparkline($catch_errors = true) {
+    parent::Object($catch_errors);
+
+    $this->colorList       = array();
+    $this->colorBackground = 'white';
+    $this->lineSize        = 1;
+    $this->graphAreaPx = array(array(0, 0), array(0, 0)); // px(L, B), px(R, T)
+  } // function Sparkline
+
+  ////////////////////////////////////////////////////////////////////////////
+  // init
+  //
+  function Init($x, $y) {
+    $this->Debug("Sparkline :: Init($x, $y)", DEBUG_CALLS);
+
+    $this->imageX    = $x;
+    $this->imageY    = $y;
+
+    // Set functions may have already set graphAreaPx offsets; add image dimensions
+    //
+    $this->graphAreaPx = array(array($this->graphAreaPx[0][0],
+                                   $this->graphAreaPx[0][1]),
+                             array($this->graphAreaPx[1][0] + $x - 1,
+                                   $this->graphAreaPx[1][1] + $y - 1));
+    
+    $this->imageHandle = $this->CreateImageHandle($x, $y);
+
+    // load default colors; set all color handles
+    //
+    $this->SetColorDefaults();
+    while (list($k, $v) = each($this->colorList)) {
+      $this->SetColorHandle($k, $this->DrawColorAllocate($k, $this->imageHandle));
+    }
+    reset($this->colorList);
+
+    if ($this->IsError()) {
+      return false;
+    } else {
+      return true;
+    }
+  } // function Init
+
+  ////////////////////////////////////////////////////////////////////////////
+  // color, drawing setup functions
+  //
+  function SetColor($name, $r, $g, $b) {
+    $this->Debug("Sparkline :: SetColor('$name', $r, $g, $b)", DEBUG_SET);
+    $name = strtolower($name);
+    $this->colorList[$name] = array('rgb' => array($r, $g, $b));
+  } // function SetDecColor
+
+  function SetColorHandle($name, $handle) {
+    $this->Debug("Sparkline :: SetColorHandle('$name', $handle)", DEBUG_SET);
+    $name = strtolower($name);
+    if (array_key_exists($name, $this->colorList)) {
+      $this->colorList[$name]['handle'] = $handle;
+      return true;
+    } else {
+      return false;
+    }
+  } // function SetColorHandle
+
+  function SetColorHex($name, $r, $g, $b) {
+    $this->Debug("Sparkline :: SetColorHex('$name', $r, $g, $b)", DEBUG_SET);
+    $this->SetColor($name, hexdec($r), hexdec($g), hexdec($b));
+  } // function SetHexColor
+
+  function SetColorHtml($name, $rgb) {
+    $this->Debug("Sparkline :: SetColorHtml('$name', '$rgb')", DEBUG_SET);
+    $rgb = trim($rgb, '#');
+    $this->SetColor($name, hexdec(substr($rgb, 0, 2)), hexdec(substr($rgb, 2, 2)), hexdec(substr($rgb, 4, 2)));
+  } // function SetHexColor
+
+  function SetColorBackground($name) {
+    $this->Debug("Sparkline :: SetColorBackground('$name')", DEBUG_SET);
+    $this->colorBackground = $name;
+  } // function SetColorBackground
+
+  function GetColor($name) {
+    if (array_key_exists($name, $this->colorList)) {
+      return $this->colorList[$name]['rgb'];
+    } else {
+      return false;
+    }
+  } // function GetColor
+
+  function GetColorHandle($name) {
+    $name = strtolower($name);
+    if (array_key_exists($name, $this->colorList)) {
+      return $this->colorList[$name]['handle'];
+    } else {
+      $this->Debug("Sparkline :: GetColorHandle color '$name' not set", DEBUG_WARNING);
+      return false;
+    }
+  } // function GetColorHandle
+
+  function SetColorDefaults() {
+    $this->Debug("Sparkline :: SetColorDefaults()", DEBUG_SET);
+    $colorDefaults = array(array('aqua',   '#00FFFF'),
+                           array('black',  '#010101'), // TODO failure if 000000?
+                           array('blue',   '#0000FF'),
+                           array('fuscia', '#FF00FF'),
+                           array('gray',   '#808080'),
+                           array('grey',   '#808080'),
+                           array('green',  '#008000'),
+                           array('lime',   '#00FF00'),
+                           array('maroon', '#800000'),
+                           array('navy',   '#000080'),
+                           array('olive',  '#808000'),
+                           array('purple', '#800080'),
+                           array('red',    '#FF0000'),
+                           array('silver', '#C0C0C0'),
+                           array('teal',   '#008080'),
+                           array('white',  '#FFFFFF'),
+                           array('yellow', '#FFFF00'));
+    while (list(, $v) = each($colorDefaults)) {
+      if (!array_key_exists($v[0], $this->colorList)) {
+        $this->SetColorHtml($v[0], $v[1]);
+      }
+    }
+  } // function SetColorDefaults
+
+  function SetLineSize($size) {
+    $this->Debug("Sparkline :: SetLineSize($size)", DEBUG_CALLS);
+
+    $this->lineSize = $size;
+  } // function SetLineSize
+
+  function GetLineSize() {
+    return($this->lineSize);
+  } // function GetLineSize
+
+  function SetPadding($T, $R = null, $B = null, $L = null) {
+    $this->Debug("Sparkline :: SetPadding($T, $R, $B, $L)", DEBUG_CALLS);
+
+    if (null == $R &&
+        null == $B &&
+        null == $L) {
+      $this->graphAreaPx = array(array($this->graphAreaPx[0][0] + $T,
+                                       $this->graphAreaPx[0][1] + $T),
+                                 array($this->graphAreaPx[1][0] - $T,
+                                       $this->graphAreaPx[1][1] - $T));
+    } else {
+      $this->graphAreaPx = array(array($this->graphAreaPx[0][0] + $L,
+                                       $this->graphAreaPx[0][1] + $B),
+                                 array($this->graphAreaPx[1][0] - $R,
+                                       $this->graphAreaPx[1][1] - $T));
+    }
+  } // function SetPadding
+
+  ////////////////////////////////////////////////////////////////////////////
+  // canvas setup
+  //
+  function CreateImageHandle($x, $y) {
+    $this->Debug("Sparkline :: CreateImageHandle($x, $y)", DEBUG_CALLS);
+
+    $handle = @imagecreatetruecolor($x, $y);
+    if (!is_resource($handle)) {
+      $handle = imagecreate($x, $y);
+      $this->Debug('imagecreatetruecolor unavailable', DEBUG_WARNING);
+    }
+
+    if (!is_resource($handle)) {
+      $this->Debug('imagecreate unavailable', DEBUG_WARNING);
+      $this->Error('could not create image; GD imagecreate functions unavailable');
+    }
+
+    return $handle;
+  } // function CreateImageHandle
+
+  ////////////////////////////////////////////////////////////////////////////
+  // drawing primitives
+  //
+  // NB: all drawing primitives use the coordinate system where (0,0) 
+  //     corresponds to the bottom left of the image, unlike y-inverted 
+  //     PHP gd functions
+  //
+  function DrawBackground($handle = false) {
+    $this->Debug("Sparkline :: DrawBackground()", DEBUG_DRAW);
+
+    if (!$this->IsError()) {
+      if ($handle === false) $handle = $this->imageHandle;
+      return $this->DrawRectangleFilled(0, 
+                                        0, 
+                                        imagesx($handle) - 1,
+                                        imagesy($handle) - 1,
+                                        $this->colorBackground,
+                                        $handle);
+    }
+  } // function DrawBackground
+
+  function DrawColorAllocate($color, $handle = false) {
+    $this->Debug("Sparkline :: DrawColorAllocate('$color')", DEBUG_DRAW);
+
+    if (!$this->IsError() &&
+        $colorRGB = $this->GetColor($color)) {
+      if ($handle === false) $handle = $this->imageHandle;
+      return imagecolorallocate($handle,
+                                $colorRGB[0], 
+                                $colorRGB[1], 
+                                $colorRGB[2]);
+    }
+  } // function DrawColorAllocate
+
+  function DrawFill($x, $y, $color, $handle = false) {
+    $this->Debug("Sparkline :: DrawFill($x, $y, '$color')", DEBUG_DRAW);
+
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      if ($handle === false) $handle = $this->imageHandle;
+      return imagefill($handle,
+                       $x, 
+                       $this->TxGDYToSLY($y, $handle), 
+                       $colorHandle);
+    }
+  } // function DrawFill
+
+  function DrawLine($x1, $y1, $x2, $y2, $color, $thickness = 1, $handle = false) {
+    $this->Debug("Sparkline :: DrawLine($x1, $y1, $x2, $y2, '$color', $thickness)", DEBUG_DRAW);
+
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      if ($handle === false) $handle = $this->imageHandle;
+
+      imagesetthickness($handle, $thickness);
+      $result = imageline($handle, 
+                          $x1,
+                          $this->TxGDYToSLY($y1, $handle),
+                          $x2,
+                          $this->TxGDYToSLY($y2, $handle),
+                          $colorHandle);
+      imagesetthickness($handle, 1);
+      return $result;
+    }
+  } // function DrawLine
+
+  function DrawPoint($x, $y, $color, $handle = false) {
+    $this->Debug("Sparkline :: DrawPoint($x, $y, '$color')", DEBUG_DRAW);
+
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      if ($handle === false) $handle = $this->imageHandle;
+      return imagesetpixel($handle, 
+                           $x, 
+                           $this->TxGDYToSLY($y, $handle), 
+                           $colorHandle);
+    }
+  } // function DrawPoint
+
+  function DrawRectangle($x1, $y1, $x2, $y2, $color, $handle = false) {
+    $this->Debug("Sparkline :: DrawRectangle($x1, $y1, $x2, $y2 '$color')", DEBUG_DRAW);
+
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      if ($handle === false) $handle = $this->imageHandle;
+      return imagerectangle($handle, 
+                            $x1, 
+                            $this->TxGDYToSLY($y1, $handle), 
+                            $x2, 
+                            $this->TxGDYToSLY($y2, $handle), 
+                            $colorHandle);
+    }
+  } // function DrawRectangle
+
+  function DrawRectangleFilled($x1, $y1, $x2, $y2, $color, $handle = false) {
+    $this->Debug("Sparkline :: DrawRectangleFilled($x1, $y1, $x2, $y2 '$color')", DEBUG_DRAW);
+
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      // NB: switch y1, y2 post conversion
+      //
+      if ($y1 < $y2) {
+        $yt = $y1;
+        $y1 = $y2;
+        $y2 = $yt;
+      }
+
+      if ($handle === false) $handle = $this->imageHandle;
+      return imagefilledrectangle($handle, 
+                                  $x1,
+                                  $this->TxGDYToSLY($y1, $handle),
+                                  $x2,
+                                  $this->TxGDYToSLY($y2, $handle),
+                                  $colorHandle);
+    }
+  } // function DrawRectangleFilled
+
+  function DrawCircleFilled($x, $y, $diameter, $color, $handle = false) {
+    $this->Debug("Sparkline :: DrawCircleFilled($x, $y, $diameter, '$color')", DEBUG_DRAW);
+
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      if ($handle === false) $handle = $this->imageHandle;
+      return imagefilledellipse($handle, 
+                                $x,
+                                $this->TxGDYToSLY($y, $handle),
+                                $diameter,
+                                $diameter,
+                                $colorHandle);
+    }
+  } // function DrawCircleFilled
+
+  function DrawText($string, $x, $y, $color, $font = FONT_1, $handle = false) {
+    $this->Debug("Sparkline :: DrawText('$string', $x, $y, '$color', $font)", DEBUG_DRAW);
+      
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      // adjust for font height so x,y corresponds to bottom left of font
+      //
+      if ($handle === false) $handle = $this->imageHandle;
+      return imagestring($handle, 
+                         $font, 
+                         $x,
+                         $this->TxGDYToSLY($y + imagefontheight($font), $handle),
+                         $string,
+                         $colorHandle);
+    }
+  } // function DrawText
+
+  function DrawTextRelative($string, $x, $y, $color, $position, $padding = 2, $font = FONT_1, $handle = false) {
+    $this->Debug("Sparkline :: DrawTextRelative('$string', $x, $y, '$color', $position, $font, $padding)", DEBUG_DRAW);
+      
+    if (!$this->IsError() &&
+        $colorHandle = $this->GetColorHandle($color)) {
+      if ($handle === false) $handle = $this->imageHandle;
+
+      // rendered text width, height
+      //
+      $textHeight = imagefontheight($font);
+      $textWidth  = imagefontwidth($font) * strlen($string);
+
+      // set (pxX, pxY) based on position and point
+      //
+      switch($position) {
+      case TEXT_TOP:
+        $x = $x - round($textWidth / 2);
+        $y = $y + $padding;
+        break;
+        
+      case TEXT_RIGHT:
+        $x = $x + $padding;
+        $y = $y - round($textHeight / 2);
+        break;
+        
+      case TEXT_BOTTOM:
+        $x = $x - round($textWidth / 2);
+        $y = $y - $padding - $textHeight;
+        break;
+        
+      case TEXT_LEFT:
+      default:
+        $x = $x - $padding - $textWidth;
+        $y = $y - round($textHeight / 2);
+        break;
+      }
+
+      // truncate bounds based on string size in pixels, image bounds
+      // order: TRBL
+      //
+      $y = min($y, $this->GetImageHeight() - $textHeight);
+      $x = min($x, $this->GetImageWidth() - $textWidth);
+      $y = max($y, 0);
+      $x = max($x, 0);
+
+      return $this->DrawText($string,
+                             $x,
+                             $y,
+                             $color,
+                             $font,
+                             $handle);
+    }
+  } // function DrawTextRelative
+
+  function DrawImageCopyResampled($dhandle, $shandle, $dx, $dy, $sx, $sy, $dw, $dh, $sw, $sh) {
+    $this->Debug("Sparkline :: DrawImageCopyResampled($dhhandle, $shandle, $dx, $dy, $sx, $sy, $dw, $dh, $sw, $sh)", DEBUG_DRAW);
+    if (!$this->IsError()) {
+      return imagecopyresampled($dhandle,  // dest handle
+                                $shandle,  // src  handle
+                                $dx, $dy,  // dest x, y
+                                $sx, $sy,  // src  x, y
+                                $dw, $dh,  // dest w, h
+                                $sw, $sh); // src  w, h
+    }
+  } // function DrawImageCopyResampled
+  
+  ////////////////////////////////////////////////////////////////////////////
+  // coordinate system functions
+  //   world coordinates are referenced as points or pt
+  //   graph coordinates are referenced as pixels or px
+  //   sparkline inverts GD Y pixel coordinates; the bottom left of the 
+  //     image rendering area is px(0,0)
+  //   all coordinate transformation functions are prefixed with Tx
+  //   all coordinate transformation functions depend on a valid image handle
+  //     and will only return valid results after all Set* calls are performed
+  //
+  function TxGDYToSLY($gdY, $handle) {
+    return imagesy($handle) - 1 - $gdY;
+  } // function TxGDYToSLY
+
+  function TxPxToPt($pxX, $pxY, $handle) {
+    // TODO;  must occur after data series conversion
+  } // function TxPxToPt
+
+  function TxPtToPx($ptX, $ptY, $handle) {
+    // TODO;  must occur after data series conversion
+  } // function TxPtToPx
+
+  function GetGraphWidth() {
+    return $this->graphAreaPx[1][0] - $this->graphAreaPx[0][0];
+  } // function GetGraphWidth
+
+  function GetGraphHeight() {
+    return $this->graphAreaPx[1][1] - $this->graphAreaPx[0][1];
+  } // function GetGraphHeight
+
+  function GetImageWidth() {
+    return $this->imageX;
+  } // function GetImageWidth
+
+  function GetImageHeight() {
+    return $this->imageY;
+  } // function GetImageHeight
+
+  ////////////////////////////////////////////////////////////////////////////
+  // image output
+  //
+  function Output($file = '') {
+
+    $this->Debug("Sparkline :: Output($file)", DEBUG_CALLS);
+
+    if ($this->IsError()) {
+      $colorError = imagecolorallocate($this->imageHandle, 0xFF, 0x00, 0x00);
+      imagestring($this->imageHandle, 
+                  1, 
+                  ($this->imageX / 2) - (5 * imagefontwidth(1) / 2), 
+                  ($this->imageY / 2) - (imagefontheight(1) / 2), 
+                  "ERROR", 
+                  $colorError);
+    }
+
+    if ($file == '') {
+      header('Content-type: image/png');
+      imagepng($this->imageHandle);
+    } else {
+      imagepng($this->imageHandle, $file);
+    }
+
+    $this->Debug('Sparkline :: Output - total execution time: ' . round($this->microTimer() - $this->startTime, 4) . ' seconds', DEBUG_STATS);
+  } // function Output
+
+  function OutputToFile($file) {
+    $this->Output($file);
+  } // function OutputToFile
+
+} // class Sparkline
+
+?>

Added: trunk/libs/sparkline/lib/Sparkline_Bar.php
===================================================================
--- trunk/libs/sparkline/lib/Sparkline_Bar.php	                        (rev 0)
+++ trunk/libs/sparkline/lib/Sparkline_Bar.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,191 @@
+<?php
+/*
+ * Sparkline PHP Graphing Library
+ * Copyright 2004 James Byers <jbyers at users.sf.net>
+ * http://sparkline.org
+ *
+ * Sparkline is distributed under a BSD License.  See LICENSE for details.
+ *
+ * $Id: Sparkline_Bar.php,v 1.2 2004/11/09 06:18:52 jbyers Exp $
+ *
+ */
+
+require_once('Sparkline.php');
+
+class Sparkline_Bar extends Sparkline {
+
+  var $dataSeries;
+  var $dataSeriesStats;
+  var $dataSeriesConverted;
+  var $yMin;
+  var $yMax;
+  var $barWidth;
+  var $barSpacing;
+  var $barColorDefault;
+  var $barColorUnderscoreDefault;
+
+  ////////////////////////////////////////////////////////////////////////////
+  // constructor
+  //
+  function Sparkline_Bar($catch_errors = true) {
+    parent::Sparkline($catch_errors);
+
+    $this->dataSeries                = array();
+    $this->dataSeriesStats           = array();
+    $this->dataSeriesConverted       = array();
+    $this->barWidth                  = 1;
+    $this->barSpacing                = 1;
+    $this->barColorDefault           = 'black';
+    $this->barColorUnderscoreDefault = 'black';
+  } // function Sparkline
+
+  ////////////////////////////////////////////////////////////////////////////
+  // color, image property setting
+  //
+  function SetBarWidth($value) {
+    $this->Debug("Sparkline_Bar :: SetBarWidth($value)", DEBUG_SET);
+    $this->barWidth = $value;
+  } // function SetBarWidth
+
+  function SetBarSpacing($value) {
+    $this->Debug("Sparkline_Bar :: SetBarSpacing($value)", DEBUG_SET);
+    $this->barSpacing = $value;
+  } // function SetBarSpacing
+
+  function SetBarColorDefault($value) {
+    $this->Debug("Sparkline_Bar :: SetBarColorDefault($value)", DEBUG_SET);
+    $this->barColorDefault = $value;
+  } // function SetBarColorDefault
+
+  function SetBarColorUnderscoreDefault($value) {
+    $this->Debug("Sparkline_Bar :: SetBarColorUnderscoreDefault($value)", DEBUG_SET);
+    $this->barColorUnderscoreDefault = $value;
+  } // function SetBarColorUnderscoreDefault
+
+  ////////////////////////////////////////////////////////////////////////////
+  // data setting
+  //
+  function SetData($x, $y, $color = null, $underscore = false, $series = 1) {
+    $x = trim($x);
+    $y = trim($y);
+
+    $this->Debug("Sparkline_Bar :: SetData($x, $y, $series)", DEBUG_SET);
+
+    if (!is_numeric($x) || 
+        !is_numeric($y)) {
+      $this->Debug("Sparkline_Bar :: SetData rejected values($x, $y) in series $series", DEBUG_WARNING);
+      return false;
+    } // if
+
+    if ($color == null) {
+      $color = $this->barColorDefault;
+    }
+
+    $this->dataSeries[$series][$x] = array('value'      => $y,
+                                           'color'      => $color,
+                                           'underscore' => $underscore);
+
+    if (!isset($this->dataSeriesStats[$series]['min']) ||
+        $y < $this->dataSeriesStats[$series]['min']) {
+      $this->dataSeriesStats[$series]['min'] = $y;
+    }
+
+    if (!isset($this->dataSeriesStats[$series]['max']) ||
+        abs($y) > $this->dataSeriesStats[$series]['max']) {
+      $this->dataSeriesStats[$series]['max'] = abs($y);
+    }
+  } // function SetData
+
+  function SetYMin($value) {
+    $this->Debug("Sparkline_Bar :: SetYMin($value)", DEBUG_SET);
+    $this->yMin = $value;
+  }
+
+  function SetYMax($value) {
+    $this->Debug("Sparkline_Bar :: SetYMax($value)", DEBUG_SET);
+    $this->yMax = $value;
+  }
+  
+  function ConvertDataSeries($series, $xBound, $yBound) {
+    $this->Debug("Sparkline_Bar :: ConvertDataSeries($series, $xBound, $yBound)", DEBUG_CALLS);
+
+    if (!isset($this->yMin)) {
+      $this->yMin = $this->dataSeriesStats[$series]['min'];
+    }
+
+    if (!isset($this->yMax)) {
+      $this->yMax = $this->dataSeriesStats[$series]['max'];
+    }
+
+    while (list(, $v) = each($this->dataSeries[$series])) {
+      $y = floor($v['value'] * ($yBound / (abs($this->yMax) + abs($this->yMin))));
+      $this->dataSeriesConverted[$series][] = array('value'      => $y,
+                                                    'color'      => $v['color'],
+                                                    'underscore' => $v['underscore']);
+
+      if (!isset($this->dataSeriesStats[$series]['min_converted']) ||
+          $y < $this->dataSeriesStats[$series]['min_converted']) {
+        $this->dataSeriesStats[$series]['min_converted'] = $y;
+      }
+      
+      if (!isset($this->dataSeriesStats[$series]['max_converted']) ||
+          abs($y) > $this->dataSeriesStats[$series]['max_converted']) {
+        $this->dataSeriesStats[$series]['max_converted'] = abs($y);
+      }
+    }
+    reset($this->dataSeries[$series]);
+
+  } // function ConvertDataSeries
+
+  function CalculateImageWidth() {
+    $this->Debug("Sparkline_Bar :: CalculateImageWidth()", DEBUG_CALLS);
+
+    $count = sizeof($this->dataSeries[1]); 
+    return (($count - 1) * $this->barSpacing) + ($count * $this->barWidth);
+  } // function CalculateImageWidth
+  
+  ////////////////////////////////////////////////////////////////////////////
+  // rendering
+  //
+  function Render($y) {
+    $this->Debug("Sparkline_Bar :: Render($y)", DEBUG_CALLS);
+
+    // calculate size based on sets for init
+    //
+    if (!parent::Init($this->CalculateImageWidth(), $y)) {
+      return false;
+    }
+
+    // convert based on actual canvas size
+    //
+    $this->ConvertDataSeries(1, $this->GetGraphWidth(), $this->GetGraphHeight());
+
+    // stats debugging
+    //
+    $this->Debug('Sparkline_Bar :: Draw' . 
+                 ' series: 1 min: ' . $this->dataSeriesStats[1]['min'] . 
+                 ' max: ' . $this->dataSeriesStats[1]['max'] . 
+                 ' height: ' . $this->GetGraphHeight() . 
+                 ' yfactor: ' . ($this->GetGraphHeight() / (abs($this->dataSeriesStats[1]['max']) + abs($this->dataSeriesStats[1]['min']))));
+
+    $this->DrawBackground();
+
+    $yAxis = abs(min($this->dataSeriesStats[1]['min_converted'], 0));
+    for ($i = 0; $i < sizeof($this->dataSeriesConverted[1]); $i++) {
+      $this->DrawRectangleFilled($i * ($this->barWidth + $this->barSpacing), 
+                                 $yAxis, 
+                                 $i * ($this->barWidth + $this->barSpacing) + $this->barWidth - 1, 
+                                 $yAxis + $this->dataSeriesConverted[1][$i]['value'], 
+                                 $this->dataSeriesConverted[1][$i]['color']);
+      if ($this->dataSeriesConverted[1][$i]['underscore']) {
+        $this->DrawLine(max(0, $i * ($this->barWidth + $this->barSpacing) - ($this->barSpacing / 2)),
+                        $yAxis,
+                        min($this->GetGraphWidth(), $i * ($this->barWidth + $this->barSpacing) + ($this->barSpacing / 2)),
+                        $yAxis,
+                        $this->barColorUnderscoreDefault);
+      }
+    }
+  } // function Render
+} // class Sparkline_Bar
+
+?>

Added: trunk/libs/sparkline/lib/Sparkline_Line.php
===================================================================
--- trunk/libs/sparkline/lib/Sparkline_Line.php	                        (rev 0)
+++ trunk/libs/sparkline/lib/Sparkline_Line.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,279 @@
+<?php
+/*
+ * Sparkline PHP Graphing Library
+ * Copyright 2004 James Byers <jbyers at users.sf.net>
+ * http://sparkline.org
+ *
+ * Sparkline is distributed under a BSD License.  See LICENSE for details.
+ *
+ * $Id: Sparkline_Line.php,v 1.7 2005/01/06 02:40:46 jbyers Exp $
+ *
+ */
+
+require_once('Sparkline.php');
+
+class Sparkline_Line extends Sparkline {
+
+  var $dataSeries;
+  var $dataSeriesStats;
+  var $dataSeriesConverted;
+  var $yMin;
+  var $yMax;
+  var $featurePoint;
+
+  ////////////////////////////////////////////////////////////////////////////
+  // constructor
+  //
+  function Sparkline_Line($catch_errors = true) {
+    parent::Sparkline($catch_errors);
+
+    $this->dataSeries          = array();
+    $this->dataSeriesStats     = array();
+    $this->dataSeriesConverted = array();
+
+    $this->featurePoint        = array();
+  } // function Sparkline
+
+  ////////////////////////////////////////////////////////////////////////////
+  // data setting
+  //
+  function SetData($x, $y, $series = 1) {
+    $x = trim($x);
+    $y = trim($y);
+
+    $this->Debug("Sparkline_Line :: SetData($x, $y, $series)", DEBUG_SET);
+
+    if (!is_numeric($x) || 
+        !is_numeric($y)) {
+      $this->Debug("Sparkline_Line :: SetData rejected values($x, $y) in series $series", DEBUG_WARNING);
+      return false;
+    } // if
+
+    $this->dataSeries[$series][$x] = $y;
+   
+    if (!isset($this->dataSeriesStats[$series]['yMin']) ||
+        $y < $this->dataSeriesStats[$series]['yMin']) {
+      $this->dataSeriesStats[$series]['yMin'] = $y;
+    }
+
+    if (!isset($this->dataSeriesStats[$series]['xMin']) ||
+        $x < $this->dataSeriesStats[$series]['xMin']) {
+      $this->dataSeriesStats[$series]['xMin'] = $x;
+    }
+
+    if (!isset($this->dataSeriesStats[$series]['yMax']) ||
+        $y > $this->dataSeriesStats[$series]['yMax']) {
+      $this->dataSeriesStats[$series]['yMax'] = $y;
+    }
+
+    if (!isset($this->dataSeriesStats[$series]['xMax']) ||
+        $x > $this->dataSeriesStats[$series]['xMax']) {
+      $this->dataSeriesStats[$series]['xMax'] = $x;
+    }
+  } // function SetData
+
+  function SetYMin($value) {
+    $this->Debug("Sparkline_Line :: SetYMin($value)", DEBUG_SET);
+    $this->yMin = $value;
+  } // function SetYMin
+
+  function SetYMax($value) {
+    $this->Debug("Sparkline_Line :: SetYMax($value)", DEBUG_SET);
+    $this->yMax = $value;
+  } // function SetYMin
+
+  function ConvertDataSeries($series, $xBound, $yBound) {
+    $this->Debug("Sparkline_Line :: ConvertDataSeries($series, $xBound, $yBound)", DEBUG_CALLS);
+
+    if (!isset($this->yMin)) {
+      $this->yMin = $this->dataSeriesStats[$series]['yMin'];
+    }
+
+    if (!isset($this->yMin)) {
+      $this->xMin = $this->dataSeriesStats[$series]['XMin'];
+    }
+
+    if (!isset($this->yMax)) {
+      $this->yMax = $this->dataSeriesStats[$series]['yMax'] + ($this->yMin * -1);
+    }
+
+    if (!isset($this->xMax)) {
+      $this->xMax = $this->dataSeriesStats[$series]['xMax'];
+    }
+
+    for ($i = 0; $i < sizeof($this->dataSeries[$series]); $i ++) {
+      $y = round(($this->dataSeries[$series][$i] + ($this->yMin * -1)) * ($yBound / $this->yMax));
+      $x = round($i * $xBound / sizeof($this->dataSeries[$series]));
+      $this->dataSeriesConverted[$series][] = array($x, $y);
+      $this->Debug("Sparkline :: ConvertDataSeries series $series value $i ($x, $y)", DEBUG_SET);
+    }
+  } // function ConvertDataSeries
+
+  ////////////////////////////////////////////////////////////////////////////
+  // features
+  // 
+  function SetFeaturePoint($x, $y, $color, $diameter, $text = '', $position = TEXT_TOP, $font = FONT_1) {
+    $this->Debug("Sparkline_Line :: SetFeaturePoint($x, $y, '$color', $diameter, '$text')", DEBUG_CALLS);
+
+    $this->featurePoint[] = array('ptX'      => $x,
+                                  'ptY'      => $y,
+                                  'color'    => $color,
+                                  'diameter' => $diameter,
+                                  'text'     => $text,
+                                  'textpos'  => $position,
+                                  'font'     => $font);
+  } // function SetFeaturePoint
+
+  ////////////////////////////////////////////////////////////////////////////
+  // low quality rendering
+  //
+  function Render($x, $y) {
+    $this->Debug("Sparkline_Line :: Render($x, $y)", DEBUG_CALLS);
+
+    if (!parent::Init($x, $y)) {
+      return false;
+    }
+
+    // convert based on graphAreaPx bounds
+    //
+    $this->ConvertDataSeries(1, $this->GetGraphWidth(), $this->GetGraphHeight());
+
+    // stats debugging
+    //
+    $this->Debug('Sparkline_Line :: Draw' . 
+                 ' series: 1 min: ' . $this->dataSeriesStats[1]['yMin'] . 
+                 ' max: ' .           $this->dataSeriesStats[1]['yMax'] . 
+                 ' offset: ' .        ($this->dataSeriesStats[1]['yMin'] * -1) . 
+                 ' height: ' .        $this->GetGraphHeight() + 1 . 
+                 ' yfactor: ' .       ($this->GetGraphHeight() / ($this->dataSeriesStats[1]['yMax'] + ($this->dataSeriesStats[1]['yMin'] * -1))));
+    $this->Debug('Sparkline_Line :: Draw' .
+                 ' drawing area:' . 
+                 ' (' . $this->graphAreaPx[0][0] . ',' . $this->graphAreaPx[0][1] .  '), ' . 
+                 ' (' . $this->graphAreaPx[1][0] . ',' . $this->graphAreaPx[1][1] .  ')');
+
+    $this->DrawBackground();
+
+    // draw graph
+    //
+    for ($i = 0; $i < sizeof($this->dataSeriesConverted[1]) - 1; $i++) {
+//      $this->DrawLine($this->dataSeriesConverted[1][$i][0] + $this->graphAreaPx[0][0], 
+//                      $this->dataSeriesConverted[1][$i][1] + $this->graphAreaPx[0][1], 
+//                      $this->dataSeriesConverted[1][$i+1][0] + $this->graphAreaPx[0][0], 
+//                      $this->dataSeriesConverted[1][$i+1][1] + $this->graphAreaPx[0][1],  
+//                      'black');
+    }
+
+    // draw features
+    //
+    while (list(, $v) = each($this->featurePoint)) {
+      $pxY = round(($v['ptY'] + ($this->yMin * -1)) * ($this->GetGraphHeight() / $this->yMax));
+      $pxX = round($v['ptX'] * $this->GetGraphWidth() / $this->dataSeriesStats[1]['xMax']);
+
+      $this->DrawCircleFilled($pxX + $this->graphAreaPx[0][0], 
+                              $pxY + $this->graphAreaPx[0][1], 
+                              $v['diameter'], 
+                              $v['color'], 
+                              $this->imageHandle);
+      $this->DrawTextRelative($v['text'],
+                              $pxX + $this->graphAreaPx[0][0], 
+                              $pxY + $this->graphAreaPx[0][1], 
+                              $v['color'], 
+                              $v['textpos'], 
+                              round($v['diameter'] / 2),
+                              $v['font'],
+                              $this->imageHandle);
+    }
+  } // function Render
+
+  ////////////////////////////////////////////////////////////////////////////
+  // high quality rendering
+  //
+  function RenderResampled($x, $y, $colorLineName = 'black') {
+    $this->Debug("Sparkline_Line :: RenderResampled($x, $y)", DEBUG_CALLS);
+
+    if (!parent::Init($x, $y)) {
+      return false;
+    }
+
+    // draw background on standard image in case of resample blit miss
+    //
+    $this->DrawBackground($this->imageHandle);
+
+    // convert based on virtual canvas: x based on size of dataset, y scaled proportionately
+    // if size of data set is small, default to 4X target canvas size
+    //
+    $xVC = max(sizeof($this->dataSeries[1]), 4 * $x);
+    $yVC = floor($xVC * ($this->GetGraphHeight() / $this->GetGraphWidth()));
+    $this->ConvertDataSeries(1, $xVC, $yVC);
+
+    // stats debugging
+    //
+    $this->Debug('Sparkline_Line :: DrawResampled' . 
+                 ' series: 1 min: ' . $this->dataSeriesStats[1]['yMin'] . 
+                 ' max: ' . $this->dataSeriesStats[1]['yMax'] . 
+                 ' offset: ' . ($this->dataSeriesStats[1]['yMin'] * -1) . 
+                 ' height: ' . $this->GetGraphHeight() . 
+                 ' yfactor: ' . ($this->GetGraphHeight() / ($this->dataSeriesStats[1]['yMax'] + ($this->dataSeriesStats[1]['yMin'] * -1))), DEBUG_STATS);
+    $this->Debug('Sparkline_Line :: DrawResampled' .
+                 ' drawing area:' . 
+                 ' (' . $this->graphAreaPx[0][0] . ',' . $this->graphAreaPx[0][1] .  '), ' . 
+                 ' (' . $this->graphAreaPx[1][0] . ',' . $this->graphAreaPx[1][1] .  ')');
+
+    // create virtual image
+    // allocate colors
+    // draw background, graph
+    // resample and blit onto original graph
+    //
+    $imageVCHandle = $this->CreateImageHandle($xVC, $yVC);
+
+    while (list($k, $v) = each($this->colorList)) {
+      $this->SetColorHandle($k, $this->DrawColorAllocate($k, $imageVCHandle));
+    }
+    reset($this->colorList);
+
+    $this->DrawBackground($imageVCHandle);
+
+    for ($i = 0; $i < sizeof($this->dataSeriesConverted[1]) - 1; $i++) {
+      $this->DrawLine($this->dataSeriesConverted[1][$i][0],
+                      $this->dataSeriesConverted[1][$i][1],
+                      $this->dataSeriesConverted[1][$i+1][0],
+                      $this->dataSeriesConverted[1][$i+1][1],
+                      $colorLineName, 
+                      $this->GetLineSize(), 
+                      $imageVCHandle);
+    }
+
+    $this->DrawImageCopyResampled($this->imageHandle, 
+                                  $imageVCHandle, 
+                                  $this->graphAreaPx[0][0], // dest x
+                                  $this->GetImageHeight() - $this->graphAreaPx[1][1], // dest y
+                                  0, 0,                     // src x, y
+                                  $this->GetGraphWidth(),   // dest width
+                                  $this->GetGraphHeight(),  // dest height
+                                  $xVC,                     // src  width
+                                  $yVC);                    // src  height
+
+    // draw features
+    //
+    while (list(, $v) = each($this->featurePoint)) {
+      $pxY = round(($v['ptY'] + ($this->yMin * -1)) * ($this->GetGraphHeight() / $this->yMax));
+      $pxX = round($v['ptX'] * $this->GetGraphWidth() / $this->dataSeriesStats[1]['xMax']);
+
+      $this->DrawCircleFilled($pxX + $this->graphAreaPx[0][0], 
+                              $pxY + $this->graphAreaPx[0][1], 
+                              $v['diameter'], 
+                              $v['color'], 
+                              $this->imageHandle);
+      $this->DrawTextRelative($v['text'],
+                              $pxX + $this->graphAreaPx[0][0], 
+                              $pxY + $this->graphAreaPx[0][1], 
+                              $v['color'], 
+                              $v['textpos'], 
+                              round($v['diameter'] / 2),
+                              $v['font'],
+                              $this->imageHandle);
+    }
+  } // function RenderResampled
+} // class Sparkline_Line
+
+?>

Modified: trunk/modules/ViewDataTable/GenerateGraphData.php
===================================================================
--- trunk/modules/ViewDataTable/GenerateGraphData.php	2008-01-20 04:19:48 UTC (rev 207)
+++ trunk/modules/ViewDataTable/GenerateGraphData.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -110,29 +110,7 @@
 	
 	protected function generateDataFromDataTable()
 	{
-		// we have to fill a $data array with each row = array('label' => X, 'value' => y)
-	
-		$data = array();
-		foreach($this->dataTable->getArray() as $keyName => $table)
-		{
-			$value = false;
-			
-			$onlyRow = $table->getRowFromId(0);
-			if($onlyRow !== false)
-			{
-				$value = $onlyRow->getColumn('value');
-			}
-		
-			if($value === false)
-			{
-				$value = 0;
-			}
-			$data[] = array(
-					'label' => $keyName,
-					'value' => $value
-				);
-		}
-		return $data;
+		return $this->generateDataFromDataTableArray($this->dataTable);
 	}
 }
 /**

Modified: trunk/modules/ViewDataTable/Graph.php
===================================================================
--- trunk/modules/ViewDataTable/Graph.php	2008-01-20 04:19:48 UTC (rev 207)
+++ trunk/modules/ViewDataTable/Graph.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -64,7 +64,7 @@
 	//TODO change $use_swfobject = true
 	public function getFlashInvocationCode(
 			$url = 'libs/open-flash-chart/data-files/nodata.txt',
-			$use_swfobject = false  )
+			$use_swfobject = true  )
 	{ 
 		$width = $this->width; 
 		$height = $this->height; 
@@ -82,8 +82,7 @@
 	    // I think we may use swfobject for all browsers, not JUST for IE...
 	    //
 	    //$ie = strstr(getenv('HTTP_USER_AGENT'), 'MSIE');
-	    
-	   
+	    	   
 	    $return = ''; 
 	    if( $use_swfobject )
 	    {
@@ -91,7 +90,7 @@
 		    $return .=  '
 				<div id="'. $div_name .'"></div>
 				<script type="text/javascript">
-				var so = new SWFObject("'.$pathToLibraryOpenChart.'open-flash-chart.swf", "chart", "'. $width . '", "' . $height . '", "9", "#FFFFFF");
+				var so = new SWFObject("'.$pathToLibraryOpenChart.'open-flash-chart.swf", "'.$obj_id.'_swf", "'. $width . '", "' . $height . '", "9", "#FFFFFF");
 				so.addVariable("data", "'. $url . '");
 				so.addParam("allowScriptAccess", "sameDomain");
 				so.write("'. $div_name .'");

Added: trunk/modules/ViewDataTable/Sparkline.php
===================================================================
--- trunk/modules/ViewDataTable/Sparkline.php	                        (rev 0)
+++ trunk/modules/ViewDataTable/Sparkline.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -0,0 +1,113 @@
+<?php
+class Piwik_ViewDataTable_Sparkline extends Piwik_ViewDataTable
+{
+	
+	function init($currentControllerName,
+						$currentControllerAction, 
+						$moduleNameAndMethod )
+	{
+		parent::init($currentControllerName, 
+						$currentControllerAction, 
+						$moduleNameAndMethod );
+	}
+	public function main()
+	{
+		if($this->mainAlreadyExecuted)
+		{
+			return;
+		}
+		$this->mainAlreadyExecuted = true;
+	
+		// we load the data with the filters applied
+		$this->loadDataTableFromAPI();
+		
+		$this->dataAvailable = $this->dataTable->getRowsCount() != 0;
+		
+		if(!$this->dataAvailable)
+		{
+			$this->view->title("No data for this graph", '{font-size: 25px;}');
+		}
+		else
+		{
+			$data = $this->generateDataFromDataTableArray($this->dataTable);
+			
+			$graph = new Piwik_Sparkline_Graph;
+			$graph->setData($data);
+			$graph->main();
+//			var_dump($data);
+			$this->view = $graph;
+		}
+	}
+	
+}
+
+require_once 'sparkline/lib/Sparkline_Line.php';
+
+class Piwik_Sparkline_Graph
+{
+	function setData($data)
+	{
+		$this->data = $data;
+	}
+	
+	function main()
+	{
+		$data = $this->data;
+		$sparkline = new Sparkline_Line();
+		
+//		$sparkline->SetColorHtml('lineColor', '000000');
+		$sparkline->SetColor('lineColor', 0,0,0);
+		$sparkline->SetColorHtml('red', '#FF7F7F');
+		$sparkline->SetColorHtml('blue', '#55AAFF');
+		$sparkline->SetColorHtml('green', '#75BF7C');
+		$sparkline->SetDebugLevel(DEBUG_NONE);
+//		$sparkline->SetDebugLevel(DEBUG_ERROR | DEBUG_WARNING | DEBUG_STATS | DEBUG_CALLS, '../log.txt');
+		
+		$data = array_reverse($data);
+		$min = $max= $last = null;
+		$i = 0;
+		foreach($this->data as $row)
+		{
+		
+			$value = $row['value'];
+			$sparkline->SetData($i, $value);
+			if(	null == $min || $value <= $min[1]) 
+			{
+				$min = array($i, $value);
+			}
+		
+			if(null == $max || $value >= $max[1]) 
+			{
+				$max = array($i, $value);
+			}
+		
+			$last = array($i, $value);
+			
+			$i++;			
+		}
+		
+		// set y-bound, min and max extent lines
+		//
+		$sparkline->SetYMin(0);
+		$sparkline->SetPadding(2); // setpadding is additive
+		$sparkline->SetPadding(imagefontheight(FONT_2), 
+					imagefontwidth(FONT_2) * strlen(" $last[1]"), 
+					0, //imagefontheight(FONT_2), 
+					0);
+		$sparkline->SetFeaturePoint($min[0]-1,$min[1]+2,'red', 5, $min[1], TEXT_TOP,FONT_2);
+		$sparkline->SetFeaturePoint($max[0]-1,$max[1],'green', 5, $max[1], TEXT_TOP,FONT_2);
+		$sparkline->SetFeaturePoint($last[0]-1, $last[1], 'blue',5, " $last[1]", TEXT_RIGHT,FONT_2);
+		
+		$sparkline->SetLineSize(3); // for renderresampled, linesize is on virtual image
+		$sparkline->RenderResampled(130, 30, 'black');
+		
+		$this->sparkline = $sparkline;
+	}
+	
+	function render()
+	{
+		$this->sparkline->Output();
+	}
+}
+
+?>
\ No newline at end of file

Modified: trunk/modules/ViewDataTable.php
===================================================================
--- trunk/modules/ViewDataTable.php	2008-01-20 04:19:48 UTC (rev 207)
+++ trunk/modules/ViewDataTable.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -72,6 +72,11 @@
 			case 'graphEvolution':
 				require_once "ViewDataTable/Graph.php";
 				return new Piwik_ViewDataTable_Graph_ChartEvolution();
+			break;	
+			
+			case 'sparkline':
+				require_once "ViewDataTable/Sparkline.php";
+				return new Piwik_ViewDataTable_Sparkline();
 			break;	
 			
 			case 'generateDataChartVerticalBar':
@@ -133,6 +138,36 @@
 	 */
 	public function __call($function, $args)
 	{
+	}
+	
+	
+	
+	// given a DataTable_Array made of DataTable_Simple
+	// returns PHP array containing rows of array( label => X, value => Y)
+	protected function generateDataFromDataTableArray( $dataTableArray)
+	{
+		// we have to fill a $data array with each row = array('label' => X, 'value' => y)
+		$data = array();
+		foreach($dataTableArray->getArray() as $keyName => $table)
+		{
+			$value = false;
+			
+			$onlyRow = $table->getRowFromId(0);
+			if($onlyRow !== false)
+			{
+				$value = $onlyRow->getColumn('value');
+			}
+		
+			if($value === false)
+			{
+				$value = 0;
+			}
+			$data[] = array(
+					'label' => $keyName,
+					'value' => $value
+				);
+		}
+		return $data;
 	}
 	
 	public function getView()

Modified: trunk/plugins/Home/Controller.php
===================================================================
--- trunk/plugins/Home/Controller.php	2008-01-20 04:19:48 UTC (rev 207)
+++ trunk/plugins/Home/Controller.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -41,6 +41,57 @@
 		echo $view->render();
 	}
 	
+	function getUrlSparkline( $action )
+	{
+		$params = array('action' => $action, 'date' => 'last30', 'viewDataTable' => 'sparkline');
+		$url = Piwik_Url::getCurrentQueryStringWithParametersModified($params);
+		return $url;
+	}
+	
+	function getLastUnitGraph($currentControllerAction, $apiMethod)
+	{
+		require_once "ViewDataTable/Graph.php";
+		$view = Piwik_ViewDataTable::factory(null, 'graphEvolution');
+		$view->init( $this->currentControllerName, $currentControllerAction, $apiMethod );
+		return $view;
+	}
+	
+	function getLastVisitsGraph( $fetch = false )
+	{
+		$view = $this->getLastUnitGraph(__FUNCTION__, "VisitsSummary.getVisits");
+		return $this->renderView($view, $fetch);
+	}
+	
+	function getLastUniqueVisitorsGraph( $fetch = false )
+	{
+		$view = $this->getLastUnitGraph(__FUNCTION__, "VisitsSummary.getUniqueVisitors");
+		return $this->renderView($view, $fetch);
+	}
+	
+	function getLastActionsGraph( $fetch = false )
+	{
+		$view = $this->getLastUnitGraph(__FUNCTION__, "VisitsSummary.getActions");
+		return $this->renderView($view, $fetch);
+	}
+	
+	function getLastSumVisitsLengthGraph( $fetch = false )
+	{
+		$view = $this->getLastUnitGraph(__FUNCTION__, "VisitsSummary.getSumVisitsLength");
+		return $this->renderView($view, $fetch);
+	}
+	
+	function getLastMaxActionsGraph( $fetch = false )
+	{
+		$view = $this->getLastUnitGraph(__FUNCTION__, "VisitsSummary.getMaxActions");
+		return $this->renderView($view, $fetch);
+	}
+	
+	function getLastBounceCountGraph( $fetch = false )
+	{
+		$view = $this->getLastUnitGraph(__FUNCTION__, "VisitsSummary.getBounceCount");
+		return $this->renderView($view, $fetch);
+	}
+	
 	function index()
 	{
 		$view = new Piwik_View('Home/templates/index.tpl');
@@ -70,6 +121,14 @@
 		/* General visits */
 		$view->graphLastVisits = $this->getLastVisitsGraph( true );
 		
+		$view->urlSparklineNbVisits 		= $this->getUrlSparkline( 'getLastVisitsGraph');
+		$view->urlSparklineNbUniqVisitors 	= $this->getUrlSparkline( 'getLastUniqueVisitorsGraph');
+		$view->urlSparklineNbActions 		= $this->getUrlSparkline( 'getLastActionsGraph');
+		$view->urlSparklineSumVisitLength 	= $this->getUrlSparkline( 'getLastSumVisitsLengthGraph');
+		$view->urlSparklineMaxActions 		= $this->getUrlSparkline( 'getLastMaxActionsGraph');
+		$view->urlSparklineBounceCount 		= $this->getUrlSparkline( 'getLastBounceCountGraph');
+	
+	
 		$dataTableVisit = $this->getVisitsSummary();
 		$view->nbUniqVisitors = $dataTableVisit->getColumn('nb_uniq_visitors');
 		$view->nbVisits = $dataTableVisit->getColumn('nb_visits');
@@ -312,14 +371,7 @@
 		$request = new Piwik_API_Request($requestString);
 		return $request->process();
 	}
-
-	function getLastVisitsGraph( $fetch = false )
-	{
-		require_once "ViewDataTable/Graph.php";
-		$view = Piwik_ViewDataTable::factory(null, 'graphEvolution');
-		$view->init( $this->currentControllerName, __FUNCTION__, "VisitsSummary.getVisits" );
-		return $this->renderView($view, $fetch);
-	}
+	
 	function getLastDistinctKeywordsGraph( $fetch = false )
 	{
 		require_once "ViewDataTable/Graph.php";

Modified: trunk/plugins/Home/templates/datatable.css
===================================================================
--- trunk/plugins/Home/templates/datatable.css	2008-01-20 04:19:48 UTC (rev 207)
+++ trunk/plugins/Home/templates/datatable.css	2008-01-20 06:57:20 UTC (rev 208)
@@ -193,7 +193,7 @@
 
 #loadingDataTable {
 	font-size: 1em;
-	font-decoration:bold;
+	font-weight:bold;
 	color:#193B6C;
 	padding:0.5em;
 }
\ No newline at end of file

Modified: trunk/plugins/Home/templates/index.tpl
===================================================================
--- trunk/plugins/Home/templates/index.tpl	2008-01-20 04:19:48 UTC (rev 207)
+++ trunk/plugins/Home/templates/index.tpl	2008-01-20 06:57:20 UTC (rev 208)
@@ -206,14 +206,35 @@
 	{$graphLastVisits}
 	
 	<h3>Report</h3>
-	<p>{$nbUniqVisitors} unique visitors</p>
-	<p>{$nbVisits} visits</p>
-	<p>{$nbActions} actions (page views)</p>
-	<p>{$sumVisitLength|sumtime} total time spent by the visitors</p>
-	<p>{$maxActions} max actions</p>
-	<p>{$bounceCount} visitors have bounced (left the site directly)</p>
 	
+	{literal}
+<script type="text/javascript">
 	
+	function findSWF(movieName) {
+  if (navigator.appName.indexOf("Microsoft")!= -1) {
+    return window[movieName];
+  } else {
+    return document[movieName];
+  }
+}
+function reload()
+{
+  tmp = findSWF("getLastVisitsGraphChart_swf");
+  x = tmp.reload();
+}
+
+</script>
+	{/literal}
+	
+	<p><a href="javascript:reload();">test</a>
+	<p><img align="absmiddle" src="{$urlSparklineNbVisits}" /><strong>{$nbVisits} </strong>visits</p>
+	<p><img align="absmiddle" src="{$urlSparklineNbUniqVisitors}" /> <strong>{$nbUniqVisitors}</strong> unique visitors</p>
+	<p><img align="absmiddle" src="{$urlSparklineNbActions}" /> <strong>{$nbActions}</strong> actions (page views)</p>
+	<p><img align="absmiddle" src="{$urlSparklineSumVisitLength}" /> <strong>{$sumVisitLength|sumtime}</strong> total time spent by the visitors</p>
+	<p><img align="absmiddle" src="{$urlSparklineMaxActions}" /> <strong>{$maxActions}</strong> max actions</p>
+	<p><img align="absmiddle" src="{$urlSparklineBounceCount}" /> <strong>{$bounceCount} </strong>visitors have bounced (left the site directly)</p>
+	
+	
 	<br><br><br><hr width="300px" align="left">
 	<p><small>{$totalTimeGeneration} seconds {if $totalNumberOfQueries != 0}/ {$totalNumberOfQueries}  queries{/if} to generate the page</p>
 </div>

Modified: trunk/plugins/VisitsSummary/API.php
===================================================================
--- trunk/plugins/VisitsSummary/API.php	2008-01-20 04:19:48 UTC (rev 207)
+++ trunk/plugins/VisitsSummary/API.php	2008-01-20 06:57:20 UTC (rev 208)
@@ -60,10 +60,14 @@
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'nb_visits');
 	}
-	public function getUniquesVisitors( $idSite, $period, $date )
+	public function getUniqueVisitors( $idSite, $period, $date )
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'nb_uniq_visitors');
 	}
+	public function getActions( $idSite, $period, $date )
+	{
+		return $this->getNumeric( $idSite, $period, $date, 'nb_actions');
+	}
 	public function getMaxActions( $idSite, $period, $date )
 	{
 		return $this->getNumeric( $idSite, $period, $date, 'max_actions');



More information about the Piwik-svn mailing list