From e9c87466ccdb248527d5fa7f325c05fe0745c69d Mon Sep 17 00:00:00 2001 From: YuCheng Hu Date: Sat, 12 Jun 2010 07:30:38 +0000 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=88=B0=20trunk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit +YUCHENG HU+ git-svn-id: https://svn.code.sf.net/p/hawebs/svn@152 a2543c7e-f6e9-4f8a-8bff-1ffc34733512 --- oss/vtiger/trunk/Image/Graph/Constants.php | 225 ++++ .../trunk/Image/Graph/DataPreprocessor.php | 74 ++ oss/vtiger/trunk/Image/Graph/DataSelector.php | 67 + oss/vtiger/trunk/Image/Graph/Dataset.php | 483 +++++++ oss/vtiger/trunk/Image/Graph/Element.php | 763 +++++++++++ oss/vtiger/trunk/Image/Graph/Fill.php | 63 + oss/vtiger/trunk/Image/Graph/Font.php | 158 +++ oss/vtiger/trunk/Image/Graph/Grid.php | 175 +++ oss/vtiger/trunk/Image/Graph/Layout.php | 219 ++++ oss/vtiger/trunk/Image/Graph/Legend.php | 385 ++++++ oss/vtiger/trunk/Image/Graph/Logo.php | 153 +++ oss/vtiger/trunk/Image/Graph/Marker.php | 123 ++ oss/vtiger/trunk/Image/Graph/Plot.php | 824 ++++++++++++ oss/vtiger/trunk/Image/Graph/Plotarea.php | 1145 +++++++++++++++++ oss/vtiger/trunk/Image/Graph/Simple.php | 121 ++ oss/vtiger/trunk/Image/Graph/Title.php | 194 +++ oss/vtiger/trunk/Image/Graph/Tool.php | 291 +++++ 17 files changed, 5463 insertions(+) create mode 100644 oss/vtiger/trunk/Image/Graph/Constants.php create mode 100644 oss/vtiger/trunk/Image/Graph/DataPreprocessor.php create mode 100644 oss/vtiger/trunk/Image/Graph/DataSelector.php create mode 100644 oss/vtiger/trunk/Image/Graph/Dataset.php create mode 100644 oss/vtiger/trunk/Image/Graph/Element.php create mode 100644 oss/vtiger/trunk/Image/Graph/Fill.php create mode 100644 oss/vtiger/trunk/Image/Graph/Font.php create mode 100644 oss/vtiger/trunk/Image/Graph/Grid.php create mode 100644 oss/vtiger/trunk/Image/Graph/Layout.php create mode 100644 oss/vtiger/trunk/Image/Graph/Legend.php create mode 100644 oss/vtiger/trunk/Image/Graph/Logo.php create mode 100644 oss/vtiger/trunk/Image/Graph/Marker.php create mode 100644 oss/vtiger/trunk/Image/Graph/Plot.php create mode 100644 oss/vtiger/trunk/Image/Graph/Plotarea.php create mode 100644 oss/vtiger/trunk/Image/Graph/Simple.php create mode 100644 oss/vtiger/trunk/Image/Graph/Title.php create mode 100644 oss/vtiger/trunk/Image/Graph/Tool.php diff --git a/oss/vtiger/trunk/Image/Graph/Constants.php b/oss/vtiger/trunk/Image/Graph/Constants.php new file mode 100644 index 00000000..030f36d6 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Constants.php @@ -0,0 +1,225 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Constants.php,v 1.7 2005/08/03 21:21:52 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Font.php + */ +require_once 'Image/Graph/Font.php'; + +// Constant declarations + +/** + * Defines an X (horizontal) axis + */ +define('IMAGE_GRAPH_AXIS_X', 1); + +/** + * Defines an Y (vertical) axis + */ +define('IMAGE_GRAPH_AXIS_Y', 2); + +/** + * Defines an Y (vertical) axis + */ +define('IMAGE_GRAPH_AXIS_Y_SECONDARY', 3); + +/** + * Defines an horizontal (X) axis + */ +define('IMAGE_GRAPH_AXIS_HORIZONTAL', 1); + +/** + * Defines an vertical (Y) axis + */ +define('IMAGE_GRAPH_AXIS_VERTICAL', 2); + +/** + * Define if label should be shown for axis minimum value + */ +define('IMAGE_GRAPH_LABEL_MINIMUM', 1); + +/** + * Define if label should be shown for axis 0 (zero) value + */ +define('IMAGE_GRAPH_LABEL_ZERO', 2); + +/** + * Define if label should be shown for axis maximum value + */ +define('IMAGE_GRAPH_LABEL_MAXIMUM', 4); + +/** + * Defines a horizontal gradient fill + */ +define('IMAGE_GRAPH_GRAD_HORIZONTAL', 1); + +/** + * Defines a vertical gradient fill + */ +define('IMAGE_GRAPH_GRAD_VERTICAL', 2); + +/** + * Defines a horizontally mirrored gradient fill + */ +define('IMAGE_GRAPH_GRAD_HORIZONTAL_MIRRORED', 3); + +/** + * Defines a vertically mirrored gradient fill + */ +define('IMAGE_GRAPH_GRAD_VERTICAL_MIRRORED', 4); + +/** + * Defines a diagonal gradient fill from top-left to bottom-right + */ +define('IMAGE_GRAPH_GRAD_DIAGONALLY_TL_BR', 5); + +/** + * Defines a diagonal gradient fill from bottom-left to top-right + */ +define('IMAGE_GRAPH_GRAD_DIAGONALLY_BL_TR', 6); + +/** + * Defines a radial gradient fill + */ +define('IMAGE_GRAPH_GRAD_RADIAL', 7); + +/** + * Defines the default builtin font + */ +define('IMAGE_GRAPH_FONT', 1); + +/** + * Defines a X value should be used + */ +define('IMAGE_GRAPH_VALUE_X', 0); + +/** + * Defines a Y value should be used + */ +define('IMAGE_GRAPH_VALUE_Y', 1); + +/** + * Defines a min X% value should be used + */ +define('IMAGE_GRAPH_PCT_X_MIN', 2); + +/** + * Defines a max X% value should be used + */ +define('IMAGE_GRAPH_PCT_X_MAX', 3); + +/** + * Defines a min Y% value should be used + */ +define('IMAGE_GRAPH_PCT_Y_MIN', 4); + +/** + * Defines a max Y% value should be used + */ +define('IMAGE_GRAPH_PCT_Y_MAX', 5); + +/** + * Defines a total Y% value should be used + */ +define('IMAGE_GRAPH_PCT_Y_TOTAL', 6); + +/** + * Defines a ID value should be used + */ +define('IMAGE_GRAPH_POINT_ID', 7); + +/** + * Align text left + */ +define('IMAGE_GRAPH_ALIGN_LEFT', 0x1); + +/** + * Align text right + */ +define('IMAGE_GRAPH_ALIGN_RIGHT', 0x2); + +/** + * Align text center x (horizontal) + */ +define('IMAGE_GRAPH_ALIGN_CENTER_X', 0x4); + +/** + * Align text top + */ +define('IMAGE_GRAPH_ALIGN_TOP', 0x8); + +/** + * Align text bottom + */ +define('IMAGE_GRAPH_ALIGN_BOTTOM', 0x10); + +/** + * Align text center y (vertical) + */ +define('IMAGE_GRAPH_ALIGN_CENTER_Y', 0x20); + +/** + * Align text center (both x and y) + */ +define('IMAGE_GRAPH_ALIGN_CENTER', IMAGE_GRAPH_ALIGN_CENTER_X + IMAGE_GRAPH_ALIGN_CENTER_Y); + +/** + * Align text top left + */ +define('IMAGE_GRAPH_ALIGN_TOP_LEFT', IMAGE_GRAPH_ALIGN_TOP + IMAGE_GRAPH_ALIGN_LEFT); + +/** + * Align text top right + */ +define('IMAGE_GRAPH_ALIGN_TOP_RIGHT', IMAGE_GRAPH_ALIGN_TOP + IMAGE_GRAPH_ALIGN_RIGHT); + +/** + * Align text bottom left + */ +define('IMAGE_GRAPH_ALIGN_BOTTOM_LEFT', IMAGE_GRAPH_ALIGN_BOTTOM + IMAGE_GRAPH_ALIGN_LEFT); + +/** + * Align text bottom right + */ +define('IMAGE_GRAPH_ALIGN_BOTTOM_RIGHT', IMAGE_GRAPH_ALIGN_BOTTOM + IMAGE_GRAPH_ALIGN_RIGHT); + +/** + * Align vertical + */ +define('IMAGE_GRAPH_ALIGN_VERTICAL', IMAGE_GRAPH_ALIGN_TOP); + +/** + * Align horizontal + */ +define('IMAGE_GRAPH_ALIGN_HORIZONTAL', IMAGE_GRAPH_ALIGN_LEFT); + +// Error codes +define('IMAGE_GRAPH_ERROR_GENERIC', 0); + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/DataPreprocessor.php b/oss/vtiger/trunk/Image/Graph/DataPreprocessor.php new file mode 100644 index 00000000..f4074b4f --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/DataPreprocessor.php @@ -0,0 +1,74 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: DataPreprocessor.php,v 1.7 2005/08/24 20:35:55 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Data preprocessor used for preformatting a data. + * + * A data preprocessor is used in cases where a value from a dataset or label must be + * displayed in another format or way than entered. This could for example be the need + * to display X-values as a date instead of 1, 2, 3, .. or even worse unix-timestamps. + * It could also be when a {@link Image_Graph_Marker_Value} needs to display values as percentages + * with 1 decimal digit instead of the default formatting (fx. 12.01271 -> 12.0%). + * + * @category Images + * @package Image_Graph + * @subpackage DataPreprocessor + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_DataPreprocessor +{ + + /** + * Image_Graph_DataPreprocessor [Constructor]. + */ + function Image_Graph_DataPreprocessor() + { + } + + /** + * Process the value + * + * @param var $value The value to process/format + * @return string The processed value + * @access private + */ + function _process($value) + { + return $value; + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/DataSelector.php b/oss/vtiger/trunk/Image/Graph/DataSelector.php new file mode 100644 index 00000000..77b1d215 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/DataSelector.php @@ -0,0 +1,67 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: DataSelector.php,v 1.7 2005/08/24 20:35:56 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Filter used for selecting which data to show as markers + * + * @category Images + * @package Image_Graph + * @subpackage DataSelector + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + */ +class Image_Graph_DataSelector +{ + + /** + * Image_Graph_DataSelector [Constructor] + */ + function Image_Graph_DataSelector() + { + } + + /** + * Check if a specified value should be 'selected', ie shown as a marker + * + * @param array $values The values to check + * @return bool True if the Values should cause a marker to be shown, false if not + * @access private + */ + function _select($values) + { + return true; + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Dataset.php b/oss/vtiger/trunk/Image/Graph/Dataset.php new file mode 100644 index 00000000..7e2eac36 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Dataset.php @@ -0,0 +1,483 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Dataset.php,v 1.10 2005/08/24 20:35:55 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + + +/** + * Data set used to represent a data collection to plot in a chart + * + * @category Images + * @package Image_Graph + * @subpackage Dataset + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Dataset +{ + + /** + * The pointer of the data set + * @var int + * @access private + */ + var $_posX = 0; + + /** + * The minimum X value of the dataset + * @var int + * @access private + */ + var $_minimumX = 0; + + /** + * The maximum X value of the dataset + * @var int + * @access private + */ + var $_maximumX = 0; + + /** + * The minimum Y value of the dataset + * @var int + * @access private + */ + var $_minimumY = 0; + + /** + * The maximum Y value of the dataset + * @var int + * @access private + */ + var $_maximumY = 0; + + /** + * The number of points in the dataset + * @var int + * @access private + */ + var $_count = 0; + + /** + * The name of the dataset, used for legending + * @var string + * @access private + */ + var $_name = ''; + + /** + * Image_Graph_Dataset [Constructor] + */ + function Image_Graph_Dataset() + { + } + + /** + * Sets the name of the data set, used for legending + * + * @param string $name The name of the dataset + */ + function setName($name) + { + $this->_name = $name; + } + + /** + * Add a point to the dataset + * + * $ID can contain either the ID of the point, i.e. 'DK', 123, 'George', etc. or it can contain + * values used for creation of the HTML image map. This is achieved using is an an associated array + * with the following values: + * + * 'url' The URL to create the link to + * + * 'alt' [optional] The alt text on the link + * + * 'target' [optional] The target of the link + * + * 'htmltags' [optional] An associated array with html tags (tag as key), fx. 'onMouseOver' => 'history.go(-1);', 'id' => 'thelink' + * + * @param int $x The X value to add + * @param int $y The Y value to add, can be omited + * @param var $ID The ID of the point + */ + function addPoint($x, $y = false, $ID = false) + { + if ($y !== null) { + if (is_array($y)) { + $maxY = max($y); + $minY = min($y); + } else { + $maxY = $y; + $minY = $y; + } + } + + if ($this->_count) { + $this->_minimumX = min($x, $this->_minimumX); + $this->_maximumX = max($x, $this->_maximumX); + if ($y !== null) { + $this->_minimumY = min($minY, $this->_minimumY); + $this->_maximumY = max($maxY, $this->_maximumY); + } + } else { + $this->_minimumX = $x; + $this->_maximumX = $x; + if ($y !== null) { + $this->_minimumY = $minY; + $this->_maximumY = $maxY; + } + } + + $this->_count++; + } + + /** + * The number of values in the dataset + * + * @return int The number of values in the dataset + */ + function count() + { + return $this->_count; + } + + /** + * Gets a X point from the dataset + * + * @param var $x The variable to return an X value from, fx in a vector + * function data set + * @return var The X value of the variable + * @access private + */ + function _getPointX($x) + { + return $x; + } + + /** + * Gets a Y point from the dataset + * + * @param var $x The variable to return an Y value from, fx in a vector + * function data set + * @return var The Y value of the variable + * @access private + */ + function _getPointY($x) + { + return $x; + } + + /** + * Gets a ID from the dataset + * + * @param var $x The variable to return an Y value from, fx in a vector + * function data set + * @return var The ID value of the variable + * @access private + */ + function _getPointID($x) + { + return false; + } + + /** + * Gets point data from the dataset + * + * @param var $x The variable to return an Y value from, fx in a vector + * function data set + * @return array The data for the point + * @access private + */ + function _getPointData($x) + { + return false; + } + + /** + * The minimum X value + * + * @return var The minimum X value + */ + function minimumX() + { + return $this->_minimumX; + } + + /** + * The maximum X value + * + * @return var The maximum X value + */ + function maximumX() + { + return $this->_maximumX; + } + + /** + * The minimum Y value + * + * @return var The minimum Y value + */ + function minimumY() + { + return $this->_minimumY; + } + + /** + * The maximum Y value + * + * @return var The maximum Y value + */ + function maximumY() + { + return $this->_maximumY; + } + + /** + * The first point + * + * @return array The last point + */ + function first() + { + return array('X' => $this->minimumX(), 'Y' => $this->minimumY()); + } + + /** + * The last point + * + * @return array The first point + */ + function last() + { + return array('X' => $this->maximumX(), 'Y' => $this->maximumY()); + } + + /** + * The minimum X value + * + * @param var $value The minimum X value + * @access private + */ + function _setMinimumX($value) + { + $this->_minimumX = $value; + } + + /** + * The maximum X value + * + * @param var $value The maximum X value + * @access private + */ + function _setMaximumX($value) + { + $this->_maximumX = $value; + } + + /** + * The minimum Y value + * + * @param var $value The minimum X value + * @access private + */ + function _setMinimumY($value) + { + $this->_minimumY = $value; + } + + /** + * The maximum Y value + * + * @param var $value The maximum X value + * @access private + */ + function _setMaximumY($value) + { + $this->_maximumY = $value; + } + + /** + * The interval between 2 adjacent X values + * + * @return var The interval + * @access private + */ + function _stepX() + { + return 1; + } + + /** + * The interval between 2 adjacent Y values + * + * @return var The interval + * @access private + */ + function _stepY() + { + return 1; + } + + /** + * Reset the intertal dataset pointer + * + * @return var The first X value + * @access private + */ + function _reset() + { + $this->_posX = $this->_minimumX; + return $this->_posX; + } + + /** + * Get a point close to the internal pointer + * + * @param int Step Number of points next to the internal pointer, negative + * Step is towards lower X values, positive towards higher X values + * @return array The point + * @access private + */ + function _nearby($step = 0) + { + $x = $this->_getPointX($this->_posX + $this->_stepX() * $step); + $y = $this->_getPointY($this->_posX + $this->_stepX() * $step); + $ID = $this->_getPointID($this->_posX + $this->_stepX() * $step); + $data = $this->_getPointData($this->_posX + $this->_stepX() * $step); + if (($x === false) || ($y === false)) { + return false; + } else { + return array ('X' => $x, 'Y' => $y, 'ID' => $ID, 'data' => $data); + } + } + + /** + * Get the next point the internal pointer refers to and advance the pointer + * + * @return array The next point + * @access private + */ + function _next() + { + if ($this->_posX > $this->_maximumX) { + return false; + } + + $x = $this->_getPointX($this->_posX); + $y = $this->_getPointY($this->_posX); + $ID = $this->_getPointID($this->_posX); + $data = $this->_getPointData($this->_posX); + $this->_posX += $this->_stepX(); + + return array ('X' => $x, 'Y' => $y, 'ID' => $ID, 'data' => $data); + } + + /** + * Get the average of the dataset's Y points + * + * @return var The Y-average across the dataset + * @access private + */ + function _averageY() + { + $posX = $this->_minimumX; + $count = 0; + $total = 0; + while ($posX < $this->_maximumX) { + $count ++; + $total += $this->_getPointY($posX); + $posX += $this->_stepX(); + } + + if ($count != 0) { + return $total / $count; + } else { + return false; + } + } + + /** + * Get the median of the array passed Y points + * + * @param array $data The data-array to get the median from + * @param int $quartile The quartile to return the median from + * @return var The Y-median across the dataset from the specified quartile + * @access private + */ + function _median($data, $quartile = 'second') + { + sort($data); + $point = (count($data) - 1) / 2; + + if ($quartile == 'first') { + $lowPoint = 0; + $highPoint = floor($point); + } elseif ($quartile == 'third') { + $lowPoint = round($point); + $highPoint = count($data) - 1; + } else { + $lowPoint = 0; + $highPoint = count($data) - 1; + } + + $point = ($lowPoint + $highPoint) / 2; + + if (floor($point) != $point) { + $point = floor($point); + return ($data[$point] + $data[($point + 1)]) / 2; + } else { + return $data[$point]; + } + } + + /** + * Get the median of the datasets Y points + * + * @param int $quartile The quartile to return the median from + * @return var The Y-median across the dataset from the specified quartile + * @access private + */ + function _medianY($quartile = 'second') + { + $pointsY = array(); + $posX = $this->_minimumX; + while ($posX <= $this->_maximumX) { + $pointsY[] = $this->_getPointY($posX); + $posX += $this->_stepX(); + } + return $this->_median($pointsY, $quartile); + } + +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Element.php b/oss/vtiger/trunk/Image/Graph/Element.php new file mode 100644 index 00000000..312a2783 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Element.php @@ -0,0 +1,763 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Element.php,v 1.18 2006/02/28 22:48:07 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Common.php + */ +require_once 'Image/Graph/Common.php'; + +/** + * Representation of a element. + * + * The Image_Graph_Element can be drawn on the canvas, ie it has coordinates, + * {@link Image_Graph_Line}, {@link Image_Graph_Fill}, border and background - + * although not all of these may apply to all children. + * + * @category Images + * @package Image_Graph + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Element extends Image_Graph_Common +{ + + /** + * The leftmost pixel of the element on the canvas + * @var int + * @access private + */ + var $_left = 0; + + /** + * The topmost pixel of the element on the canvas + * @var int + * @access private + */ + var $_top = 0; + + /** + * The rightmost pixel of the element on the canvas + * @var int + * @access private + */ + var $_right = 0; + + /** + * The bottommost pixel of the element on the canvas + * @var int + * @access private + */ + var $_bottom = 0; + + /** + * Background of the element. Default: None + * @var FillStyle + * @access private + */ + var $_background = null; + + /** + * Borderstyle of the element. Default: None + * @var LineStyle + * @access private + */ + var $_borderStyle = null; + + /** + * Line style of the element. Default: None + * @var LineStyle + * @access private + */ + var $_lineStyle = 'black'; + + /** + * Fill style of the element. Default: None + * @var FillStyle + * @access private + */ + var $_fillStyle = 'white'; + + /** + * Font of the element. Default: Standard font - FONT + * @var Font + * @access private + * @see $IMAGE_GRAPH_FONT + */ + var $_font = null; + + /** + * Font options + * @var array + * @access private + */ + var $_fontOptions = array(); + + /** + * Default font options + * + * This option is included for performance reasons. The value is calculated + * before output and reused in default cases to avoid unnecessary recursive + * calls. + * + * @var array + * @access private + */ + var $_defaultFontOptions = false; + + /** + * Shadows options of the element + * @var mixed + * @access private + */ + var $_shadow = false; + + /** + * The padding displayed on the element + * @var int + * @access private + */ + var $_padding = array('left' => 0, 'top' => 0, 'right' => 0, 'bottom' => 0); + + /** + * Sets the background fill style of the element + * + * @param Image_Graph_Fill $background The background + * @see Image_Graph_Fill + */ + function setBackground(& $background) + { + if (!is_a($background, 'Image_Graph_Fill')) { + $this->_error( + 'Could not set background for ' . get_class($this) . ': ' . + get_class($background), array('background' => &$background) + ); + } else { + $this->_background =& $background; + $this->add($background); + } + } + + /** + * Shows shadow on the element + */ + function showShadow($color = 'black@0.2', $size = 5) + { + $this->_shadow = array( + 'color' => $color, + 'size' => $size + ); + } + + /** + * Sets the background color of the element. + * + * See colors.txt in the docs/ folder for a list of available named colors. + * + * @param mixed $color The color + */ + function setBackgroundColor($color) + { + $this->_background = $color; + } + + /** + * Gets the background fill style of the element + * + * @return int A GD fillstyle representing the background style + * @see Image_Graph_Fill + * @access private + */ + function _getBackground() + { + if (is_object($this->_background)) { + $this->_canvas->setFill($this->_background->_getFillStyle()); + } elseif ($this->_background != null) { + $this->_canvas->setFill($this->_background); + } else { + return false; + } + return true; + } + + /** + * Sets the border line style of the element + * + * @param Image_Graph_Line $borderStyle The line style of the border + * @see Image_Graph_Line + */ + function setBorderStyle(& $borderStyle) + { + if (!is_a($borderStyle, 'Image_Graph_Line')) { + $this->_error( + 'Could not set border style for ' . get_class($this) . ': ' . + get_class($borderStyle), array('borderstyle' => &$borderStyle) + ); + } else { + $this->_borderStyle =& $borderStyle; + $this->add($borderStyle); + } + } + + /** + * Sets the border color of the element. + * + * See colors.txt in the docs/ folder for a list of available named colors. + * @param mixed $color The color + */ + function setBorderColor($color) + { + $this->_borderStyle = $color; + } + + /** + * Gets the border line style of the element + * + * @return int A GD linestyle representing the borders line style + * @see Image_Graph_Line + * @access private + */ + function _getBorderStyle() + { + if (is_object($this->_borderStyle)) { + $result = $this->_borderStyle->_getLineStyle(); + $this->_canvas->setLineThickness($result['thickness']); + $this->_canvas->setLineColor($result['color']); + } elseif ($this->_borderStyle != null) { + $this->_canvas->setLineThickness(1); + $this->_canvas->setLineColor($this->_borderStyle); + } else { + return false; + } + return true; + } + + /** + * Sets the line style of the element + * + * @param Image_Graph_Line $lineStyle The line style of the element + * @see Image_Graph_Line + */ + function setLineStyle(& $lineStyle) + { + if (!is_object($lineStyle)) { + $this->_error( + 'Could not set line style for ' . get_class($this) . ': ' . + get_class($lineStyle), array('linestyle' => &$lineStyle) + ); + } else { + $this->_lineStyle =& $lineStyle; + $this->add($lineStyle); + } + } + + /** + * Sets the line color of the element. + * + * See colors.txt in the docs/ folder for a list of available named colors. + * + * @param mixed $color The color + */ + function setLineColor($color) + { + $this->_lineStyle = $color; + } + + /** + * Gets the line style of the element + * + * @return int A GD linestyle representing the line style + * @see Image_Graph_Line + * @access private + */ + function _getLineStyle($ID = false) + { + if (is_object($this->_lineStyle)) { + $result = $this->_lineStyle->_getLineStyle($ID); + if (is_array($result)) { + $this->_canvas->setLineThickness($result['thickness']); + $this->_canvas->setLineColor($result['color']); + } else { + $this->_canvas->setLineThickness(1); + $this->_canvas->setLineColor($result); + } + } elseif ($this->_lineStyle != null) { + $this->_canvas->setLineThickness(1); + $this->_canvas->setLineColor($this->_lineStyle); + } else { + return false; + } + return true; + } + + /** + * Sets the fill style of the element + * + * @param Image_Graph_Fill $fillStyle The fill style of the element + * @see Image_Graph_Fill + */ + function setFillStyle(& $fillStyle) + { + if (!is_a($fillStyle, 'Image_Graph_Fill')) { + $this->_error( + 'Could not set fill style for ' . get_class($this) . ': ' . + get_class($fillStyle), array('fillstyle' => &$fillStyle) + ); + } else { + $this->_fillStyle =& $fillStyle; + $this->add($fillStyle); + } + } + + /** + * Sets the fill color of the element. + * + * See colors.txt in the docs/ folder for a list of available named colors. + * + * @param mixed $color The color + */ + function setFillColor($color) + { + $this->_fillStyle = $color; + } + + + /** + * Gets the fill style of the element + * + * @return int A GD filestyle representing the fill style + * @see Image_Graph_Fill + * @access private + */ + function _getFillStyle($ID = false) + { + if (is_object($this->_fillStyle)) { + $this->_canvas->setFill($this->_fillStyle->_getFillStyle($ID)); + } elseif ($this->_fillStyle != null) { + $this->_canvas->setFill($this->_fillStyle); + } else { + return false; + } + return true; + } + + /** + * Gets the font of the element. + * + * If not font has been set, the parent font is propagated through it's + * children. + * + * @return array An associated array used for canvas + * @access private + */ + function _getFont($options = false) + { + if (($options === false) && ($this->_defaultFontOptions !== false)) { + return $this->_defaultFontOptions; + } + + if ($options === false) { + $saveDefault = true; + } else { + $saveDefault = false; + } + + if ($options === false) { + $options = $this->_fontOptions; + } else { + $options = array_merge($this->_fontOptions, $options); + } + + if ($this->_font == null) { + $result = $this->_parent->_getFont($options); + } else { + $result = $this->_font->_getFont($options); + } + + if ((isset($result['size'])) && (isset($result['size_rel']))) { + $result['size'] += $result['size_rel']; + unset($result['size_rel']); + } + + if ($saveDefault) { + $this->_defaultFontOptions = $result; + } + + return $result; + } + + /** + * Sets the font of the element + * + * @param Image_Graph_Font $font The font of the element + * @see Image_Graph_Font + */ + function setFont(& $font) + { + if (!is_a($font, 'Image_Graph_Font')) { + $this->_error('Invalid font set on ' . get_class($this)); + } else { + $this->_font =& $font; + $this->add($font); + } + } + + /** + * Sets the font size + * + * @param int $size The size of the font + */ + function setFontSize($size) + { + $this->_fontOptions['size'] = $size; + } + + /** + * Sets the font angle + * + * @param int $angle The angle of the font + */ + function setFontAngle($angle) + { + if ($angle == 'vertical') { + $this->_fontOptions['vertical'] = true; + $this->_fontOptions['angle'] = 90; + } else { + $this->_fontOptions['angle'] = $angle; + } + } + + /** + * Sets the font color + * + * @param mixed $color The color of the font + */ + function setFontColor($color) + { + $this->_fontOptions['color'] = $color; + } + + /** + * Clip the canvas to the coordinates of the element + * + * @param $enable bool Whether clipping should be enabled or disabled + * @access protected + */ + function _clip($enable) + { + $this->_canvas->setClipping( + ($enable ? + array( + 'x0' => min($this->_left, $this->_right), + 'y0' => min($this->_top, $this->_bottom), + 'x1' => max($this->_left, $this->_right), + 'y1' => max($this->_top, $this->_bottom) + ) + : false + ) + ); + } + + /** + * Sets the coordinates of the element + * + * @param int $left The leftmost pixel of the element on the canvas + * @param int $top The topmost pixel of the element on the canvas + * @param int $right The rightmost pixel of the element on the canvas + * @param int $bottom The bottommost pixel of the element on the canvas + * @access private + */ + function _setCoords($left, $top, $right, $bottom) + { + if ($left === false) { + $left = $this->_left; + } + + if ($top === false) { + $top = $this->_top; + } + + if ($right === false) { + $right = $this->_right; + } + + if ($bottom === false) { + $bottom = $this->_bottom; + } + + $this->_left = min($left, $right); + $this->_top = min($top, $bottom); + $this->_right = max($left, $right); + $this->_bottom = max($top, $bottom); + } + + /** + * Moves the element + * + * @param int $deltaX Number of pixels to move the element to the right + * (negative values move to the left) + * @param int $deltaY Number of pixels to move the element downwards + * (negative values move upwards) + * @access private + */ + function _move($deltaX, $deltaY) + { + $this->_left += $deltaX; + $this->_right += $deltaX; + $this->_top += $deltaY; + $this->_bottom += $deltaY; + } + + /** + * Sets the width of the element relative to the left side + * + * @param int $width Number of pixels the element should be in width + * @access private + */ + function _setWidth($width) + { + $this->_right = $this->_left + $width; + } + + /** + * Sets the height of the element relative to the top + * + * @param int $width Number of pixels the element should be in height + * @access private + */ + function _setHeight($height) + { + $this->_bottom = $this->_top + $height; + } + + /** + * Sets padding of the element + * + * @param mixed $padding Number of pixels the element should be padded with + * or an array of paddings (left, top, right and bottom as index) + */ + function setPadding($padding) + { + if (is_array($padding)) { + $this->_padding = array(); + $this->_padding['left'] = (isset($padding['left']) ? $padding['left'] : 0); + $this->_padding['top'] = (isset($padding['top']) ? $padding['top'] : 0); + $this->_padding['right'] = (isset($padding['right']) ? $padding['right'] : 0); + $this->_padding['bottom'] = (isset($padding['bottom']) ? $padding['bottom'] : 0); + } + else { + $this->_padding = array( + 'left' => $padding, + 'top' => $padding, + 'right' => $padding, + 'bottom' => $padding + ); + } + } + + /** + * The width of the element on the canvas + * + * @return int Number of pixels representing the width of the element + */ + function width() + { + return abs($this->_right - $this->_left) + 1; + } + + /** + * The height of the element on the canvas + * + * @return int Number of pixels representing the height of the element + */ + function height() + { + return abs($this->_bottom - $this->_top) + 1; + } + + /** + * Left boundary of the background fill area + * + * @return int Leftmost position on the canvas + * @access private + */ + function _fillLeft() + { + return $this->_left + $this->_padding['left']; + } + + /** + * Top boundary of the background fill area + * + * @return int Topmost position on the canvas + * @access private + */ + function _fillTop() + { + return $this->_top + $this->_padding['top']; + } + + /** + * Right boundary of the background fill area + * + * @return int Rightmost position on the canvas + * @access private + */ + function _fillRight() + { + return $this->_right - $this->_padding['right']; + } + + /** + * Bottom boundary of the background fill area + * + * @return int Bottommost position on the canvas + * @access private + */ + function _fillBottom() + { + return $this->_bottom - $this->_padding['bottom']; + } + + /** + * Returns the filling width of the element on the canvas + * + * @return int Filling width + * @access private + */ + function _fillWidth() + { + return $this->_fillRight() - $this->_fillLeft() + 1; + } + + /** + * Returns the filling height of the element on the canvas + * + * @return int Filling height + * @access private + */ + function _fillHeight() + { + return $this->_fillBottom() - $this->_fillTop() + 1; + } + + /** + * Draws a shadow 'around' the element + * + * Not implemented yet. + * + * @access private + */ + function _displayShadow() + { + if (is_array($this->_shadow)) { + $this->_canvas->startGroup(get_class($this) . '_shadow'); + $this->_canvas->setFillColor($this->_shadow['color']); + $this->_canvas->addVertex(array('x' => $this->_right + 1, 'y' => $this->_top + $this->_shadow['size'])); + $this->_canvas->addVertex(array('x' => $this->_right + $this->_shadow['size'], 'y' => $this->_top + $this->_shadow['size'])); + $this->_canvas->addVertex(array('x' => $this->_right + $this->_shadow['size'], 'y' => $this->_bottom + $this->_shadow['size'])); + $this->_canvas->addVertex(array('x' => $this->_left + $this->_shadow['size'], 'y' => $this->_bottom + $this->_shadow['size'])); + $this->_canvas->addVertex(array('x' => $this->_left + $this->_shadow['size'], 'y' => $this->_bottom + 1)); + $this->_canvas->addVertex(array('x' => $this->_right + 1, 'y' => $this->_bottom + 1)); + $this->_canvas->polygon(array('connect' => true)); + $this->_canvas->endGroup(); + } + } + + /** + * Writes text to the canvas. + * + * @param int $x The x position relative to alignment + * @param int $y The y position relative to alignment + * @param string $text The text + * @param int $alignmen The text alignment (both vertically and horizontally) + */ + function write($x, $y, $text, $alignment = false, $font = false) + { + if (($font === false) && ($this->_defaultFontOptions !== false)) { + $font = $this->_defaultFontOptions; + } else { + $font = $this->_getFont($font); + } + + if ($alignment === false) { + $alignment = IMAGE_GRAPH_ALIGN_LEFT + IMAGE_GRAPH_ALIGN_TOP; + } + + $align = array(); + + if (($alignment & IMAGE_GRAPH_ALIGN_TOP) != 0) { + $align['vertical'] = 'top'; + } else if (($alignment & IMAGE_GRAPH_ALIGN_BOTTOM) != 0) { + $align['vertical'] = 'bottom'; + } else { + $align['vertical'] = 'center'; + } + + if (($alignment & IMAGE_GRAPH_ALIGN_LEFT) != 0) { + $align['horizontal'] = 'left'; + } else if (($alignment & IMAGE_GRAPH_ALIGN_RIGHT) != 0) { + $align['horizontal'] = 'right'; + } else { + $align['horizontal'] = 'center'; + } + + $this->_canvas->setFont($font); + $this->_canvas->addText(array('x' => $x, 'y' => $y, 'text' => $text, 'alignment' => $align)); + } + + /** + * Output the element to the canvas + * + * @return bool Was the output 'good' (true) or 'bad' (false). + * @see Image_Graph_Common + * @access private + */ + function _done() + { + $background = $this->_getBackground(); + $border = $this->_getBorderStyle(); + if (($background) || ($border)) { + $this->_canvas->rectangle(array('x0' => $this->_left, 'y0' => $this->_top, 'x1' => $this->_right, 'y1' => $this->_bottom)); + } + + $result = parent::_done(); + + if ($this->_shadow !== false) { + $this->_displayShadow(); + } + + return $result; + } + +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Fill.php b/oss/vtiger/trunk/Image/Graph/Fill.php new file mode 100644 index 00000000..8b966a42 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Fill.php @@ -0,0 +1,63 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Fill.php,v 1.6 2005/02/21 20:49:46 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Element.php + */ +require_once 'Image/Graph/Element.php'; + +/** + * Style used for filling elements. + * + * @category Images + * @package Image_Graph + * @subpackage Fill + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Fill extends Image_Graph_Common +{ + + /** + * Resets the fillstyle + * + * @access private + */ + function _reset() + { + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Font.php b/oss/vtiger/trunk/Image/Graph/Font.php new file mode 100644 index 00000000..0496d961 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Font.php @@ -0,0 +1,158 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Font.php,v 1.8 2005/08/24 20:35:55 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Common.php + */ +require_once 'Image/Graph/Common.php'; + +/** + * A font. + * + * @category Images + * @package Image_Graph + * @subpackage Text + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Font extends Image_Graph_Common +{ + + /** + * The name of the font + * @var string + * @access private + */ + var $_name = false; + + /** + * The angle of the output + * @var int + * @access private + */ + var $_angle = false; + + /** + * The size of the font + * @var int + * @access private + */ + var $_size = 11; + + /** + * The color of the font + * @var Color + * @access private + */ + var $_color = 'black'; + + /** + * Image_Graph_Font [Constructor] + */ + function Image_Graph_Font($name = false, $size = false) + { + parent::Image_Graph_Common(); + if ($name !== false) { + $this->_name = $name; + } + if ($size !== false) { + $this->_size = $size; + } + } + + /** + * Set the color of the font + * + * @param mixed $color The color object of the Font + */ + function setColor($color) + { + $this->_color = $color; + } + + /** + * Set the angle slope of the output font. + * + * 0 = normal, 90 = bottom and up, 180 = upside down, 270 = top and down + * + * @param int $angle The angle in degrees to slope the text + */ + function setAngle($angle) + { + $this->_angle = $angle; + } + + /** + * Set the size of the font + * + * @param int $size The size in pixels of the font + */ + function setSize($size) + { + $this->_size = $size; + } + + /** + * Get the font 'array' + * + * @return array The font 'summary' to pass to the canvas + * @access private + */ + function _getFont($options = false) + { + if ($options === false) { + $options = array(); + } + + if ($this->_name !== false) { + $options['name'] = $this->_name; + } + + if (!isset($options['color'])) { + $options['color'] = $this->_color; + } + + if (!isset($options['size'])) { + $options['size'] = $this->_size; + } + + if ((!isset($options['angle'])) && ($this->_angle !== false)) { + $options['angle'] = $this->_angle; + } + return $options; + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Grid.php b/oss/vtiger/trunk/Image/Graph/Grid.php new file mode 100644 index 00000000..e88aa8d2 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Grid.php @@ -0,0 +1,175 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Grid.php,v 1.8 2005/02/21 20:49:47 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Element.php + */ +require_once 'Image/Graph/Element.php'; + +/** + * A grid displayed on the plotarea. + * + * A grid is associated with a primary and a secondary axis. The grid is + * displayed in context of the primary axis' label interval - meaning that a + * grid for an Y-axis displays a grid for every label on the y-axis (fx. a {@link + * Image_Graph_Grid_Lines}, which displays horizontal lines for every label on + * the y-axis from the x-axis minimum to the x-axis maximum). You should always + * add the grid as one of the first elements to the plotarea. This is due to the + * fact that elements are 'outputted' in the order they are added, i.e. if an + * grid is added *after* a chart, the grid will be displayed on top of the chart + * which is (probably) not desired. + * + * @category Images + * @package Image_Graph + * @subpackage Grid + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Grid extends Image_Graph_Plotarea_Element +{ + + /** + * The primary axis: the grid 'refers' to + * @var Axis + * @access private + */ + var $_primaryAxis = null; + + /** + * The secondary axis + * @var Axis + * @access private + */ + var $_secondaryAxis = null; + + /** + * Set the primary axis: the grid should 'refer' to + * + * @param Image_Graph_Axis $axis The axis + * @access private + */ + function _setPrimaryAxis(& $axis) + { + $this->_primaryAxis =& $axis; + } + + /** + * Set the secondary axis + * + * @param Image_Graph_Axis $axis The axis + * @access private + */ + function _setSecondaryAxis(& $axis) + { + $this->_secondaryAxis =& $axis; + } + + /** + * Get the points on the secondary axis that the grid should 'connect' + * + * @return array The secondary data values that should mark the grid 'end points' + * @access private + */ + function _getSecondaryAxisPoints() + { + if (is_a($this->_secondaryAxis, 'Image_Graph_Axis_Radar')) { + $secondaryValue = false; + $firstValue = $secondaryValue; + while (($secondaryValue = $this->_secondaryAxis->_getNextLabel($secondaryValue)) !== false) { + $secondaryAxisPoints[] = $secondaryValue; + } + $secondaryAxisPoints[] = $firstValue; + } else { + $secondaryAxisPoints = array ('#min#', '#max#'); + } + return $secondaryAxisPoints; + } + + /** + * Get the X pixel position represented by a value + * + * @param double $point the value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _pointX($point) + { + if (($this->_primaryAxis->_type == IMAGE_GRAPH_AXIS_Y) || + ($this->_primaryAxis->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY)) + { + $point['AXIS_Y'] = $this->_primaryAxis->_type; + } else { + $point['AXIS_Y'] = $this->_secondaryAxis->_type; + } + return parent::_pointX($point); + } + + /** + * Get the Y pixel position represented by a value + * + * @param double $point the value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _pointY($point) + { + if (($this->_primaryAxis->_type == IMAGE_GRAPH_AXIS_Y) || + ($this->_primaryAxis->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY)) + { + $point['AXIS_Y'] = $this->_primaryAxis->_type; + } else { + $point['AXIS_Y'] = $this->_secondaryAxis->_type; + } + return parent::_pointY($point); + } + + /** + * Causes the object to update all sub elements coordinates. + * + * @access private + */ + function _updateCoords() + { + $this->_setCoords( + $this->_parent->_plotLeft, + $this->_parent->_plotTop, + $this->_parent->_plotRight, + $this->_parent->_plotBottom + ); + parent::_updateCoords(); + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Layout.php b/oss/vtiger/trunk/Image/Graph/Layout.php new file mode 100644 index 00000000..32c18caa --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Layout.php @@ -0,0 +1,219 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Layout.php,v 1.12 2006/02/28 22:48:07 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Plotarea/Element.php + */ +require_once 'Image/Graph/Plotarea/Element.php'; + +/** + * Defines an area of the graph that can be layout'ed. + * + * Any class that extends this abstract class can be used within a layout on the canvas. + * + * @category Images + * @package Image_Graph + * @subpackage Layout + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Layout extends Image_Graph_Plotarea_Element +{ + + /** + * Has the coordinates already been updated? + * @var bool + * @access private + */ + var $_updated = false; + + /** + * Alignment of the area for each vertice (left, top, right, bottom) + * @var array + * @access private + */ + var $_alignSize = array ('left' => 0, 'top' => 0, 'right' => 0, 'bottom' => 0); + + /** + * Image_Graph_Layout [Constructor] + */ + function Image_Graph_Layout() + { + parent::Image_Graph_Element(); + $this->_padding = array('left' => 2, 'top' => 2, 'right' => 2, 'bottom' => 2); + } + + /** + * Resets the elements + * + * @access private + */ + function _reset() + { + parent::_reset(); + $this->_updated = false; + } + + /** + * Calculate the edge offset for a specific edge + * @param array $alignSize The alignment of the edge + * @param int $offset The offset/posision of the at 0% edge + * @param int $total The total size (width or height) of the element + * @param int $multiplier +/- 1 if the edge should pushed either toward more + * negative or positive values + * @since 0.3.0dev2 + * @access private + */ + function _calcEdgeOffset($alignSize, $offset, $total, $multiplier) + { + if ($alignSize['unit'] == 'percentage') { + return $offset + $multiplier * ($total * $alignSize['value'] / 100); + } elseif ($alignSize['unit'] == 'pixels') { + if (($alignSize['value'] == 'auto_part1') || ($alignSize['value'] == 'auto_part2')) { + $alignSize['value'] = $multiplier * $this->_parent->_getAbsolute($alignSize['value']); + } + if ($alignSize['value'] < 0) { + return $offset + $multiplier * ($total + $alignSize['value']); + } else { + return $offset + $multiplier * $alignSize['value']; + } + } + return $offset; + } + + /** + * Calculate the edges + * + * @access private + */ + function _calcEdges() + { + if ((is_array($this->_alignSize)) && (!$this->_updated)) { + $left = $this->_calcEdgeOffset( + $this->_alignSize['left'], + $this->_parent->_fillLeft(), + $this->_parent->_fillWidth(), + +1 + ); + $top = $this->_calcEdgeOffset( + $this->_alignSize['top'], + $this->_parent->_fillTop(), + $this->_parent->_fillHeight(), + +1 + ); + $right = $this->_calcEdgeOffset( + $this->_alignSize['right'], + $this->_parent->_fillRight(), + $this->_parent->_fillWidth(), + -1 + ); + $bottom = $this->_calcEdgeOffset( + $this->_alignSize['bottom'], + $this->_parent->_fillBottom(), + $this->_parent->_fillHeight(), + -1 + ); + + $this->_setCoords( + $left + $this->_padding['left'], + $top + $this->_padding['top'], + $right - $this->_padding['right'], + $bottom - $this->_padding['bottom'] + ); + } + } + + /** + * Update coordinates + * + * @access private + */ + function _updateCoords() + { + $this->_calcEdges(); + parent::_updateCoords(); + } + + /** + * Pushes an edge of area a specific distance 'into' the canvas + * + * @param int $edge The edge of the canvas to align relative to + * @param int $size The number of pixels or the percentage of the canvas total size to occupy relative to the selected alignment edge + * @access private + */ + function _push($edge, $size = '100%') + { + $result = array(); + if (ereg("([0-9]*)\%", $size, $result)) { + $this->_alignSize[$edge] = array( + 'value' => min(100, max(0, $result[1])), + 'unit' => 'percentage' + ); + } else { + $this->_alignSize[$edge] = array( + 'value' => $size, + 'unit' => 'pixels' + ); + } + } + + /** + * Sets the coordinates of the element + * + * @param int $left The leftmost pixel of the element on the canvas + * @param int $top The topmost pixel of the element on the canvas + * @param int $right The rightmost pixel of the element on the canvas + * @param int $bottom The bottommost pixel of the element on the canvas + * @access private + */ + function _setCoords($left, $top, $right, $bottom) + { + parent::_setCoords($left, $top, $right, $bottom); + $this->_updated = true; + } + + /** + * Returns the calculated "auto" size + * + * @return int The calculated auto size + * @access private + */ + function _getAutoSize() + { + return false; + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Legend.php b/oss/vtiger/trunk/Image/Graph/Legend.php new file mode 100644 index 00000000..99c83adb --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Legend.php @@ -0,0 +1,385 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Legend.php,v 1.16 2006/02/28 22:48:07 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Layout.php + */ +require_once 'Image/Graph/Layout.php'; + +/** + * Displays a legend for a plotarea. + * + * A legend can be displayed in two ways: + * + * 1 As an overlayed box within the plotarea + * + * 2 Layout'ed on the canvas smewhere next to the plotarea. + * + * @category Images + * @package Image_Graph + * @subpackage Legend + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + */ +class Image_Graph_Legend extends Image_Graph_Layout +{ + + /** + * Alignment of the text + * @var int + * @access private + */ + var $_alignment = false; + + /** + * The plotarea(s) to show the legend for + * @var array + * @access private + */ + var $_plotareas = array(); + + /** + * Should markers be shown or not on this legend + * @var bool + * @access private + */ + var $_showMarker = false; + + /** + * Image_Graph_Legend [Constructor] + */ + function Image_Graph_Legend() + { + parent::Image_Graph_Layout(); + $this->_padding = array('left' => 5, 'top' => 5, 'right' => 5, 'bottom' => 5); + } + + /** + * The number of actual plots in the plot area + * + * @return int The number of plotes + * @access private + */ + function _plotCount() + { + $count = 0; + $keys = array_keys($this->_plotareas); + foreach($keys as $key) { + $plotarea =& $this->_plotareas[$key]; + if (is_a($plotarea, 'Image_Graph_Plotarea')) { + $keys2 = array_keys($plotarea->_elements); + foreach ($keys2 as $key) { + $element =& $plotarea->_elements[$key]; + if (is_a($element, 'Image_Graph_Plot')) { + $count ++; + } + } + unset($keys2); + } + } + unset($keys); + return $count; + } + + /** + * Get a default parameter array for legendSamples + * @param bool $simulate Whether the array should be used for simulation or + * not + * @return array Default parameter array + * @access private + */ + function _parameterArray($simulate = false) + { + $param['left'] = $this->_left + $this->_padding['left']; + $param['top'] = $this->_top + $this->_padding['top']; + $param['right'] = $this->_right - $this->_padding['right']; + $param['bottom'] = $this->_bottom - $this->_padding['bottom']; + $param['align'] = $this->_alignment; + $param['x'] = $this->_left + $this->_padding['left']; + $param['y'] = $this->_top + $this->_padding['top']; + $param['width'] = 16; + $param['height'] = 16; + $param['show_marker'] = $this->_showMarker; + $param['maxwidth'] = 0; + $param['font'] = $this->_getFont(); + if ($simulate) { + $param['simulate'] = true; + } + + return $param; + } + + /** + * The height of the element on the canvas + * + * @return int Number of pixels representing the height of the element + * @access private + */ + function _height() + { + $parent = (is_object($this->_parent) ? get_class($this->_parent) : $this->_parent); + + if (strtolower($parent) == 'image_graph_plotarea') { + $param = $this->_parameterArray(true); + $param['align'] = IMAGE_GRAPH_ALIGN_VERTICAL; + $param0 = $param; + $keys = array_keys($this->_plotareas); + foreach($keys as $key) { + $plotarea =& $this->_plotareas[$key]; + $keys2 = array_keys($plotarea->_elements); + foreach($keys2 as $key) { + $element =& $plotarea->_elements[$key]; + if (is_a($element, 'Image_Graph_Plot')) { + $element->_legendSample($param); + } + } + unset($keys2); + } + unset($keys); + return abs($param['y'] - $param0['y']) + $this->_padding['top'] + $this->_padding['bottom']; + } else { + return parent::height(); + } + } + + /** + * The width of the element on the canvas + * + * @return int Number of pixels representing the width of the element + * @access private + */ + function _width() + { + $parent = (is_object($this->_parent) ? get_class($this->_parent) : $this->_parent); + + if (strtolower($parent) == 'image_graph_plotarea') { + $param = $this->_parameterArray(true); + $param['align'] = IMAGE_GRAPH_ALIGN_VERTICAL; + $keys = array_keys($this->_plotareas); + foreach($keys as $key) { + $plotarea =& $this->_plotareas[$key]; + $keys2 = array_keys($plotarea->_elements); + foreach($keys2 as $key) { + $element =& $plotarea->_elements[$key]; + if (is_a($element, 'Image_Graph_Plot')) { + $element->_legendSample($param); + } + } + unset($keys2); + } + unset($keys); + return $param['maxwidth']; + } else { + return parent::width(); + } + } + + /** + * Set the alignment of the legend + * + * @param int $alignment The alignment + */ + function setAlignment($alignment) + { + $this->_alignment = $alignment; + } + + /** + * Update coordinates + * + * @access private + */ + function _updateCoords() + { + parent::_updateCoords(); + + $parent = (is_object($this->_parent) ? get_class($this->_parent) : $this->_parent); + + if (strtolower($parent) == 'image_graph_plotarea') { + $w = $this->_width(); + $h = $this->_height(); + + if ($this->_alignment === false) { + $this->_alignment = IMAGE_GRAPH_ALIGN_TOP + IMAGE_GRAPH_ALIGN_RIGHT; + } + + if (($this->_alignment & IMAGE_GRAPH_ALIGN_BOTTOM) != 0) { + $y = $this->_parent->_fillBottom() - $h - $this->_padding['bottom']; + } else { + $y = $this->_parent->_fillTop() + $this->_padding['top']; + } + + if (($this->_alignment & IMAGE_GRAPH_ALIGN_LEFT) != 0) { + $x = $this->_parent->_fillLeft() + $this->_padding['left']; + } else { + $x = $this->_parent->_fillRight() - $w - $this->_padding['right']; + } + + $this->_setCoords($x, $y, $x + $w, $y + $h); + } + } + + /** + * Sets Plotarea + * + * @param Image_Graph_Plotarea $plotarea The plotarea + */ + function setPlotarea(& $plotarea) + { + if (is_a($plotarea, 'Image_Graph_Plotarea')) { + $this->_plotareas[] =& $plotarea; + } + } + + /** + * Sets the parent. The parent chain should ultimately be a GraPHP object + * + * @see Image_Graph + * @param Image_Graph_Common $parent The parent + * @access private + */ + function _setParent(& $parent) + { + parent::_setParent($parent); + if (count($this->_plotareas) == 0) { + $this->setPlotarea($parent); + } + } + + /** + * Set if this legends should show markers + * + * @param bool $showMarker True if markers are to be shown, false is not + */ + function setShowMarker($showMarker) + { + $this->_showMarker = $showMarker; + } + + + /** + * Output the plot + * + * @return bool Was the output 'good' (true) or 'bad' (false). + * @access private + */ + function _done() + { + + if (Image_Graph_Element::_done() === false) { + return false; + } + + $this->_canvas->startGroup(get_class($this)); + + $param = $this->_parameterArray(); + + $parent = (is_object($this->_parent) ? + get_class($this->_parent) : + $this->_parent + ); + + if (strtolower($parent) == 'image_graph_plotarea') { + $this->_getFillStyle(); + $this->_getLineStyle(); + $this->_canvas->rectangle( + array( + 'x0' => $this->_left, + 'y0' => $this->_top, + 'x1' => $this->_right, + 'y1' => $this->_bottom + ) + ); + + $param = $this->_parameterArray(); + + $keys = array_keys($this->_plotareas); + foreach($keys as $key) { + $plotarea =& $this->_plotareas[$key]; + $keys2 = array_keys($plotarea->_elements); + foreach($keys2 as $key) { + $element =& $plotarea->_elements[$key]; + if (is_a($element, 'Image_Graph_Plot')) { + $element->_legendSample($param); + } + } + unset($keys2); + } + unset($keys); + } else { + $param0 = $param; + $param0['simulate'] = true; + $keys = array_keys($this->_plotareas); + foreach($keys as $key) { + $plotarea =& $this->_plotareas[$key]; + $keys2 = array_keys($plotarea->_elements); + foreach($keys2 as $key) { + $element =& $plotarea->_elements[$key]; + if (is_a($element, 'Image_Graph_Plot')) { + $element->_legendSample($param0); + } + } + unset($keys2); + } + unset($keys); + if (($this->_alignment & IMAGE_GRAPH_ALIGN_VERTICAL) != 0) { + if ($param0['x'] == $param['x']) { + $param['y'] = $param['y'] + ($this->_height() - ($param0['y'] - $param['y']))/2; + } + } else { + if ($param0['y'] == $param['y']) { + $param['x'] = $param['x'] + ($this->_width() - ($param0['x'] - $param['x']))/2; + } + } + + $keys = array_keys($this->_plotareas); + foreach($keys as $key) { + $plotarea =& $this->_plotareas[$key]; + $keys2 = array_keys($plotarea->_elements); + foreach($keys2 as $key) { + $element =& $plotarea->_elements[$key]; + if (is_a($element, 'Image_Graph_Plot')) { + $element->_legendSample($param); + } + } + unset($keys2); + } + unset($keys); + } + + $this->_canvas->endGroup(); + + return true; + } +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Logo.php b/oss/vtiger/trunk/Image/Graph/Logo.php new file mode 100644 index 00000000..e1ba1452 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Logo.php @@ -0,0 +1,153 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Logo.php,v 1.9 2005/08/24 20:35:56 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Element.php + */ +require_once 'Image/Graph/Element.php'; + +/** + * Displays a logo on the canvas. + * + * By default the logo is displayed in the top-right corner of the canvas. + * + * @category Images + * @package Image_Graph + * @subpackage Logo + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + */ +class Image_Graph_Logo extends Image_Graph_Element +{ + + /** + * The file name + * @var stirng + * @access private + */ + var $_filename; + + /** + * The GD Image resource + * @var resource + * @access private + */ + var $_image; + + /** + * Alignment of the logo + * @var int + * @access private + */ + var $_alignment; + + /** + * Logo [Constructor] + * + * @param string $filename The filename and path of the image to use for logo + */ + function Image_Graph_Logo($filename, $alignment = IMAGE_GRAPH_ALIGN_TOP_RIGHT) + { + parent::Image_Graph_Element(); + $this->_filename = $filename; + $this->_alignment = $alignment; + } + + /** + * Sets the parent. The parent chain should ultimately be a GraPHP object + * + * @see Image_Graph + * @param Image_Graph_Common $parent The parent + * @access private + */ + function _setParent(& $parent) + { + parent::_setParent($parent); + $this->_setCoords( + $this->_parent->_left, + $this->_parent->_top, + $this->_parent->_right, + $this->_parent->_bottom + ); + } + + /** + * Output the logo + * + * @return bool Was the output 'good' (true) or 'bad' (false). + * @access private + */ + function _done() + { + if (parent::_done() === false) { + return false; + } + + $align = array(); + + if ($this->_alignment & IMAGE_GRAPH_ALIGN_LEFT) { + $x = $this->_parent->_left + 2; + $align['horizontal'] = 'left'; + } elseif ($this->_alignment & IMAGE_GRAPH_ALIGN_RIGHT) { + $x = $this->_parent->_right - 2; + $align['horizontal'] = 'right'; + } else { + $x = ($this->_parent->_left + $this->_parent->_right) / 2; + $align['horizontal'] = 'center'; + } + + if ($this->_alignment & IMAGE_GRAPH_ALIGN_TOP) { + $y = $this->_parent->_top + 2; + $align['vertical'] = 'top'; + } elseif ($this->_alignment & IMAGE_GRAPH_ALIGN_BOTTOM) { + $y = $this->_parent->_bottom - 2; + $align['vertical'] = 'bottom'; + } else { + $y = ($this->_parent->_top + $this->_parent->_bottom) / 2; + $align['vertical'] = 'center'; + } + + $this->_canvas->image( + array( + 'x' => $x, + 'y' => $y, + 'filename' => $this->_filename, + 'alignment' => $align + ) + ); + return true; + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Marker.php b/oss/vtiger/trunk/Image/Graph/Marker.php new file mode 100644 index 00000000..63f5812a --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Marker.php @@ -0,0 +1,123 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Marker.php,v 1.8 2005/02/21 20:49:47 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Plotarea/Element.php + */ +require_once 'Image/Graph/Plotarea/Element.php'; + +/** + * Data point marker. + * + * The data point marker is used for marking the datapoints on a graph with some + * visual label, fx. a cross, a text box with the value or an icon. + * + * @category Images + * @package Image_Graph + * @subpackage Marker + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Marker extends Image_Graph_Plotarea_Element +{ + + /** + * Secondary marker + * @var Marker + * @access private + */ + var $_secondaryMarker = false; + + /** + * The 'size' of the marker, the meaning depends on the specific Marker + * implementation + * @var int + * @access private + */ + var $_size = 6; + + /** + * Set the 'size' of the marker + * + * @param int $size The 'size' of the marker, the meaning depends on the + * specific Marker implementation + */ + function setSize($size) + { + $this->_size = $size; + } + + /** + * Set the secondary marker + * + * @param Marker $secondaryMarker The secondary marker + */ + function setSecondaryMarker(& $secondaryMarker) + { + $this->_secondaryMarker =& $secondaryMarker; + $this->_secondaryMarker->_setParent($this); + } + + /** + * Draw the marker on the canvas + * + * @param int $x The X (horizontal) position (in pixels) of the marker on + * the canvas + * @param int $y The Y (vertical) position (in pixels) of the marker on the + * canvas + * @param array $values The values representing the data the marker 'points' + * to + * @access private + */ + function _drawMarker($x, $y, $values = false) + { + if (is_a($this->_secondaryMarker, 'Image_Graph_Marker')) { + $this->_secondaryMarker->_drawMarker($x, $y, $values); + } + } + + /** + * Output to the canvas + * + * @return bool Was the output 'good' (true) or 'bad' (false). + * @access private + */ + function _done() + { + return true; + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Plot.php b/oss/vtiger/trunk/Image/Graph/Plot.php new file mode 100644 index 00000000..666a282f --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Plot.php @@ -0,0 +1,824 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Plot.php,v 1.20 2006/02/28 22:33:00 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Plotarea/Element.php + */ +require_once 'Image/Graph/Plotarea/Element.php'; + +/** + * Framework for a chart + * + * @category Images + * @package Image_Graph + * @subpackage Plot + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + * @abstract + */ +class Image_Graph_Plot extends Image_Graph_Plotarea_Element +{ + + /** + * The dataset to plot + * @var Dataset + * @access private + */ + var $_dataset; + + /** + * The marker to plot the data set as + * @var Marker + * @access private + */ + var $_marker = null; + + /** + * The dataselector to use for data marking + * @var DataSelector + * @access private + */ + var $_dataSelector = null; + + /** + * The Y axis to associate the plot with + * @var int + * @access private + */ + var $_axisY = IMAGE_GRAPH_AXIS_Y; + + /** + * The type of the plot if multiple datasets are used + * @var string + * @access private + */ + var $_multiType = 'normal'; + + /** + * The title of the plot, used for legending in case of simple plots + * @var string + * @access private + */ + var $_title = 'plot'; + + /** + * PlotType [Constructor] + * + * Valid values for multiType are: + * + * 'normal' Plot is normal, multiple datasets are displayes next to one + * another + * + * 'stacked' Datasets are stacked on top of each other + * + * 'stacked100pct' Datasets are stacked and displayed as percentages of the + * total sum + * + * I no title is specified a default is used, which is basically the plot + * type (fx. for a 'Image_Graph_Plot_Smoothed_Area' default title is + * 'Smoothed Area') + * + * @param Image_Graph_Dataset $dataset The data set (value containter) to + * plot or an array of datasets + * @param string $multiType The type of the plot + * @param string $title The title of the plot (used for legends, + * {@link Image_Graph_Legend}) + */ + function Image_Graph_Plot(& $dataset, $multiType = 'normal', $title = '') + { + if (!is_a($dataset, 'Image_Graph_Dataset')) { + if (is_array($dataset)) { + $keys = array_keys($dataset); + foreach ($keys as $key) { + if (!is_a($dataset[$key], 'Image_Graph_Dataset')) { + $this->_error('Invalid dataset passed to ' . get_class($this)); + } + } + unset($keys); + } else { + $this->_error('Invalid dataset passed to ' . get_class($this)); + } + } + + parent::Image_Graph_Common(); + if ($dataset) { + if (is_array($dataset)) { + $this->_dataset =& $dataset; + } else { + $this->_dataset = array(&$dataset); + } + } + if ($title) { + $this->_title = $title; + } else { + $this->_title = str_replace('_', ' ', substr(get_class($this), 17)); + } + + $multiType = strtolower($multiType); + if (($multiType == 'normal') || + ($multiType == 'stacked') || + ($multiType == 'stacked100pct')) + { + $this->_multiType = $multiType; + } else { + $this->_error( + 'Invalid multitype: ' . $multiType . + ' expected (normal|stacked|stacked100pct)' + ); + $this->_multiType = 'normal'; + } + } + + /** + * Sets the title of the plot, used for legend + * + * @param string $title The title of the plot + */ + function setTitle($title) + { + $this->_title = $title; + } + + /** + * Parses the URL mapping data in the point and adds it to the parameter array used by + * Image_Canvas + * + * @param array $point The data point (from the dataset) + * @param array $canvasData The The for the canvas method + * @return array The union of the canvas data points and the appropriate points for the dataset + * @access private + */ + function _mergeData($point, $canvasData) + { + if (isset($point['data'])) { + if (isset($point['data']['url'])) { + $canvasData['url'] = $point['data']['url']; + } + if (isset($point['data']['target'])) { + $canvasData['target'] = $point['data']['target']; + } + if (isset($point['data']['alt'])) { + $canvasData['alt'] = $point['data']['alt']; + } + if (isset($point['data']['htmltags'])) { + $canvasData['htmltags'] = $point['data']['htmltags']; + } + } + + return $canvasData; + } + + /** + * Sets the Y axis to plot the data + * + * @param int $axisY The Y axis (either IMAGE_GRAPH_AXIS_Y / 'y' or + * IMAGE_GRAPH_AXIS_Y_SECONDARY / 'ysec' (defaults to IMAGE_GRAPH_AXIS_Y)) + * @access private + */ + function _setAxisY($axisY) + { + if ($axisY == 'y') { + $this->_axisY = IMAGE_GRAPH_AXIS_Y; + } elseif ($axisY == 'ysec') { + $this->_axisY = IMAGE_GRAPH_AXIS_Y_SECONDARY; + } else { + $this->_axisY = $axisY; + } + } + + /** + * Sets the marker to 'display' data points on the graph + * + * @param Marker $marker The marker + */ + function &setMarker(& $marker) + { + $this->add($marker); + $this->_marker =& $marker; + return $marker; + } + + /** + * Sets the dataselector to specify which data should be displayed on the + * plot as markers and which are not + * + * @param DataSelector $dataSelector The dataselector + */ + function setDataSelector(& $dataSelector) + { + $this->_dataSelector =& $dataSelector; + } + + /** + * Calculate marker point data + * + * @param array Point The point to calculate data for + * @param array NextPoint The next point + * @param array PrevPoint The previous point + * @param array Totals The pre-calculated totals, if needed + * @return array An array containing marker point data + * @access private + */ + function _getMarkerData($point, $nextPoint, $prevPoint, & $totals) + { + if (is_array($this->_dataset)) { + if ($this->_multiType == 'stacked') { + if (!isset($totals['SUM_Y'])) { + $totals['SUM_Y'] = array(); + } + $x = $point['X']; + if (!isset($totals['SUM_Y'][$x])) { + $totals['SUM_Y'][$x] = 0; + } + } elseif ($this->_multiType == 'stacked100pct') { + $x = $point['X']; + if ($totals['TOTAL_Y'][$x] != 0) { + if (!isset($totals['SUM_Y'])) { + $totals['SUM_Y'] = array(); + } + if (!isset($totals['SUM_Y'][$x])) { + $totals['SUM_Y'][$x] = 0; + } + } + } + + if (isset($totals['ALL_SUM_Y'])) { + $point['SUM_Y'] = $totals['ALL_SUM_Y']; + } + + if (!$prevPoint) { + $point['AX'] = -5; + $point['AY'] = 5; + $point['PPX'] = 0; + $point['PPY'] = 0; + $point['NPX'] = $nextPoint['X']; + $point['NPY'] = $nextPoint['Y']; + } elseif (!$nextPoint) { + $point['AX'] = 5; + $point['AY'] = 5; + $point['PPX'] = $prevPoint['X']; + $point['PPY'] = $prevPoint['Y']; + $point['NPX'] = 0; + $point['NPY'] = 0; + } else { + $point['AX'] = $this->_pointY($prevPoint) - $this->_pointY($nextPoint); + $point['AY'] = $this->_pointX($nextPoint) - $this->_pointX($prevPoint); + $point['PPX'] = $prevPoint['X']; + $point['PPY'] = $prevPoint['Y']; + $point['NPX'] = $nextPoint['X']; + $point['NPY'] = $nextPoint['Y']; + } + + $point['APX'] = $point['X']; + $point['APY'] = $point['Y']; + + if ((isset($totals['MINIMUM_X'])) && ($totals['MINIMUM_X'] != 0)) { + $point['PCT_MIN_X'] = 100 * $point['X'] / $totals['MINIMUM_X']; + } + if ((isset($totals['MAXIMUM_X'])) && ($totals['MAXIMUM_X'] != 0)) { + $point['PCT_MAX_X'] = 100 * $point['X'] / $totals['MAXIMUM_X']; + } + + if ((isset($totals['MINIMUM_Y'])) && ($totals['MINIMUM_Y'] != 0)) { + $point['PCT_MIN_Y'] = 100 * $point['Y'] / $totals['MINIMUM_Y']; + } + if ((isset($totals['MAXIMUM_Y'])) && ($totals['MAXIMUM_Y'] != 0)) { + $point['PCT_MAX_Y'] = 100 * $point['Y'] / $totals['MAXIMUM_Y']; + } + + $point['LENGTH'] = sqrt($point['AX'] * $point['AX'] + + $point['AY'] * $point['AY']); + + if ((isset($point['LENGTH'])) && ($point['LENGTH'] != 0)) { + $point['ANGLE'] = asin($point['AY'] / $point['LENGTH']); + } + + if ((isset($point['AX'])) && ($point['AX'] > 0)) { + $point['ANGLE'] = pi() - $point['ANGLE']; + } + + if ($this->_parent->_horizontal) { + $point['MARKER_Y1'] = $this->_pointY($point) - + (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0); + + $point['MARKER_Y2'] = $this->_pointY($point) + + (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0); + + $point['COLUMN_WIDTH'] = abs($point['MARKER_Y2'] - + $point['MARKER_Y1']) / count($this->_dataset); + + $point['MARKER_Y'] = $point['MARKER_Y1'] + + ((isset($totals['NUMBER']) ? $totals['NUMBER'] : 0) + 0.5) * + $point['COLUMN_WIDTH']; + + $point['MARKER_X'] = $this->_pointX($point); + + if ($this->_multiType == 'stacked') { + $point['MARKER_Y'] = + ($point['MARKER_Y1'] + $point['MARKER_Y2']) / 2; + + $P1 = array('Y' => $totals['SUM_Y'][$x]); + $P2 = array('Y' => $totals['SUM_Y'][$x] + $point['Y']); + + $point['MARKER_X'] = + ($this->_pointX($P1) + $this->_pointX($P2)) / 2; + } elseif ($this->_multiType == 'stacked100pct') { + $x = $point['X']; + if ($totals['TOTAL_Y'][$x] != 0) { + $point['MARKER_Y'] = + ($point['MARKER_Y1'] + $point['MARKER_Y2']) / 2; + + $P1 = array( + 'Y' => 100 * $totals['SUM_Y'][$x] / $totals['TOTAL_Y'][$x] + ); + + $P2 = array( + 'Y' => 100 * ($totals['SUM_Y'][$x] + $point['Y']) / $totals['TOTAL_Y'][$x] + ); + + $point['MARKER_X'] = + ($this->_pointX($P1) + $this->_pointX($P2)) / 2; + } else { + $point = false; + } + } + } + else { + $point['MARKER_X1'] = $this->_pointX($point) - + (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0); + + $point['MARKER_X2'] = $this->_pointX($point) + + (isset($totals['WIDTH']) ? $totals['WIDTH'] : 0); + + $point['COLUMN_WIDTH'] = abs($point['MARKER_X2'] - + $point['MARKER_X1']) / count($this->_dataset); + + $point['MARKER_X'] = $point['MARKER_X1'] + + ((isset($totals['NUMBER']) ? $totals['NUMBER'] : 0) + 0.5) * + $point['COLUMN_WIDTH']; + + $point['MARKER_Y'] = $this->_pointY($point); + + if ($this->_multiType == 'stacked') { + $point['MARKER_X'] = + ($point['MARKER_X1'] + $point['MARKER_X2']) / 2; + + $P1 = array('Y' => $totals['SUM_Y'][$x]); + $P2 = array('Y' => $totals['SUM_Y'][$x] + $point['Y']); + + $point['MARKER_Y'] = + ($this->_pointY($P1) + $this->_pointY($P2)) / 2; + } elseif ($this->_multiType == 'stacked100pct') { + $x = $point['X']; + if ($totals['TOTAL_Y'][$x] != 0) { + $point['MARKER_X'] = + ($point['MARKER_X1'] + $point['MARKER_X2']) / 2; + + $P1 = array( + 'Y' => 100 * $totals['SUM_Y'][$x] / $totals['TOTAL_Y'][$x] + ); + + $P2 = array( + 'Y' => 100 * ($totals['SUM_Y'][$x] + $point['Y']) / $totals['TOTAL_Y'][$x] + ); + + $point['MARKER_Y'] = + ($this->_pointY($P1) + $this->_pointY($P2)) / 2; + } else { + $point = false; + } + } + } + return $point; + } + } + + /** + * Draws markers on the canvas + * + * @access private + */ + function _drawMarker() + { + if (($this->_marker) && (is_array($this->_dataset))) { + $this->_canvas->startGroup(get_class($this) . '_marker'); + + $totals = $this->_getTotals(); + $totals['WIDTH'] = $this->width() / ($this->_maximumX() + 2) / 2; + + $number = 0; + $keys = array_keys($this->_dataset); + foreach ($keys as $key) { + $dataset =& $this->_dataset[$key]; + $totals['MINIMUM_X'] = $dataset->minimumX(); + $totals['MAXIMUM_X'] = $dataset->maximumX(); + $totals['MINIMUM_Y'] = $dataset->minimumY(); + $totals['MAXIMUM_Y'] = $dataset->maximumY(); + $totals['NUMBER'] = $number ++; + $dataset->_reset(); + while ($point = $dataset->_next()) { + $prevPoint = $dataset->_nearby(-2); + $nextPoint = $dataset->_nearby(); + + $x = $point['X']; + $y = $point['Y']; + if (((!is_object($this->_dataSelector)) || + ($this->_dataSelector->_select($point))) && ($point['Y'] !== null)) + { + + $point = $this->_getMarkerData( + $point, + $nextPoint, + $prevPoint, + $totals + ); + + if (is_array($point)) { + $this->_marker->_drawMarker( + $point['MARKER_X'], + $point['MARKER_Y'], + $point + ); + } + } + if (!isset($totals['SUM_Y'])) { + $totals['SUM_Y'] = array(); + } + if (isset($totals['SUM_Y'][$x])) { + $totals['SUM_Y'][$x] += $y; + } else { + $totals['SUM_Y'][$x] = $y; + } + } + } + unset($keys); + $this->_canvas->endGroup(); + } + } + + /** + * Get the minimum X value from the dataset + * + * @return double The minimum X value + * @access private + */ + function _minimumX() + { + if (!is_array($this->_dataset)) { + return 0; + } + + $min = false; + if (is_array($this->_dataset)) { + $keys = array_keys($this->_dataset); + foreach ($keys as $key) { + if ($min === false) { + $min = $this->_dataset[$key]->minimumX(); + } else { + $min = min($min, $this->_dataset[$key]->minimumX()); + } + } + unset($keys); + } + return $min; + } + + /** + * Get the maximum X value from the dataset + * + * @return double The maximum X value + * @access private + */ + function _maximumX() + { + if (!is_array($this->_dataset)) { + return 0; + } + + $max = 0; + if (is_array($this->_dataset)) { + $keys = array_keys($this->_dataset); + foreach ($keys as $key) { + $max = max($max, $this->_dataset[$key]->maximumX()); + } + unset($keys); + } + return $max; + } + + /** + * Get the minimum Y value from the dataset + * + * @return double The minimum Y value + * @access private + */ + function _minimumY() + { + if (!is_array($this->_dataset)) { + return 0; + } + + $min = false; + if (is_array($this->_dataset)) { + $keys = array_keys($this->_dataset); + foreach ($keys as $key) { + if ($this->_multiType == 'normal') { + if ($min === false) { + $min = $this->_dataset[$key]->minimumY(); + } else { + $min = min($min, $this->_dataset[$key]->minimumY()); + } + } else { + if ($min === false) { + $min = 0; + } + $dataset =& $this->_dataset[$key]; + $dataset->_reset(); + while ($point = $dataset->_next()) { + if ($point['Y'] < 0) { + $x = $point['X']; + if ((!isset($total)) || (!isset($total[$x]))) { + $total[$x] = $point['Y']; + } else { + $total[$x] += $point['Y']; + } + if (isset($min)) { + $min = min($min, $total[$x]); + } else { + $min = $total[$x]; + } + } + } + } + } + unset($keys); + } + return $min; + } + + /** + * Get the maximum Y value from the dataset + * + * @return double The maximum Y value + * @access private + */ + function _maximumY() + { + if ($this->_multiType == 'stacked100pct') { + return 100; + } + + $maxY = 0; + if (is_array($this->_dataset)) { + $keys = array_keys($this->_dataset); + foreach ($keys as $key) { + $dataset =& $this->_dataset[$key]; + + if ($this->_multiType == 'normal') { + if (isset($maxY)) { + $maxY = max($maxY, $dataset->maximumY()); + } else { + $maxY = $dataset->maximumY(); + } + } else { + $dataset->_reset(); + while ($point = $dataset->_next()) { + if ($point['Y'] > 0) { + $x = $point['X']; + if ((!isset($total)) || (!isset($total[$x]))) { + $total[$x] = $point['Y']; + } else { + $total[$x] += $point['Y']; + } + if (isset($maxY)) { + $maxY = max($maxY, $total[$x]); + } else { + $maxY = $total[$x]; + } + } + } + } + } + unset($keys); + } + return $maxY; + } + + /** + * Get the X pixel position represented by a value + * + * @param double $point The value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _pointX($point) + { + $point['AXIS_Y'] = $this->_axisY; + return parent::_pointX($point); + } + + /** + * Get the Y pixel position represented by a value + * + * @param double $point the value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _pointY($point) + { + $point['AXIS_Y'] = $this->_axisY; + return parent::_pointY($point); + } + + /** + * Update coordinates + * + * @access private + */ + function _updateCoords() + { + $this->_setCoords($this->_parent->_plotLeft, $this->_parent->_plotTop, $this->_parent->_plotRight, $this->_parent->_plotBottom); + parent::_updateCoords(); + } + + /** + * Get the dataset + * + * @return Image_Graph_Dataset The dataset(s) + */ + function &dataset() + { + return $this->_dataset; + } + + /** + * Calulate totals + * + * @return array An associated array with the totals + * @access private + */ + function _getTotals() + { + $total = array( + 'MINIMUM_X' => $this->_minimumX(), + 'MAXIMUM_X' => $this->_maximumX(), + 'MINIMUM_Y' => $this->_minimumY(), + 'MAXIMUM_Y' => $this->_maximumY() + ); + $total['ALL_SUM_Y'] = 0; + + $keys = array_keys($this->_dataset); + foreach ($keys as $key) { + $dataset =& $this->_dataset[$key]; + + $dataset->_reset(); + while ($point = $dataset->_next()) { + $x = $point['X']; + + if (is_numeric($point['Y'])) { + $total['ALL_SUM_Y'] += $point['Y']; + if (isset($total['TOTAL_Y'][$x])) { + $total['TOTAL_Y'][$x] += $point['Y']; + } else { + $total['TOTAL_Y'][$x] = $point['Y']; + } + } + + if (is_numeric($point['X'])) { + if (isset($total['TOTAL_X'][$x])) { + $total['TOTAL_X'][$x] += $point['X']; + } else { + $total['TOTAL_X'][$x] = $point['X']; + } + } + } + } + unset($keys); + return $total; + } + + /** + * Perform the actual drawing on the legend. + * + * @param int $x0 The top-left x-coordinate + * @param int $y0 The top-left y-coordinate + * @param int $x1 The bottom-right x-coordinate + * @param int $y1 The bottom-right y-coordinate + * @access private + */ + function _drawLegendSample($x0, $y0, $x1, $y1) + { + $this->_canvas->rectangle(array('x0' => $x0, 'y0' => $y0, 'x1' => $x1, 'y1' => $y1)); + } + + /** + * Draw a sample for use with legend + * + * @param array $param The parameters for the legend + * @access private + */ + function _legendSample(&$param) + { + if (!is_array($this->_dataset)) { + return false; + } + + if (is_a($this->_fillStyle, 'Image_Graph_Fill')) { + $this->_fillStyle->_reset(); + } + + $count = 0; + $keys = array_keys($this->_dataset); + foreach ($keys as $key) { + $dataset =& $this->_dataset[$key]; + $count++; + + $caption = ($dataset->_name ? $dataset->_name : $this->_title); + + $this->_canvas->setFont($param['font']); + $width = 20 + $param['width'] + $this->_canvas->textWidth($caption); + $param['maxwidth'] = max($param['maxwidth'], $width); + $x2 = $param['x'] + $width; + $y2 = $param['y'] + $param['height'] + 5; + + if ((($param['align'] & IMAGE_GRAPH_ALIGN_VERTICAL) != 0) && ($y2 > $param['bottom'])) { + $param['y'] = $param['top']; + $param['x'] = $x2; + $y2 = $param['y'] + $param['height']; + } elseif ((($param['align'] & IMAGE_GRAPH_ALIGN_VERTICAL) == 0) && ($x2 > $param['right'])) { + $param['x'] = $param['left']; + $param['y'] = $y2; + $x2 = $param['x'] + 20 + $param['width'] + $this->_canvas->textWidth($caption); + } + + $x = $x0 = $param['x']; + $y = $param['y']; + $y0 = $param['y']; + $x1 = $param['x'] + $param['width']; + $y1 = $param['y'] + $param['height']; + + if (!isset($param['simulate'])) { + $this->_getFillStyle($key); + $this->_getLineStyle(); + $this->_drawLegendSample($x0, $y0, $x1, $y1); + + if (($this->_marker) && ($dataset) && ($param['show_marker'])) { + $dataset->_reset(); + $point = $dataset->_next(); + $prevPoint = $dataset->_nearby(-2); + $nextPoint = $dataset->_nearby(); + + $tmp = array(); + $point = $this->_getMarkerData($point, $nextPoint, $prevPoint, $tmp); + if (is_array($point)) { + $point['MARKER_X'] = $x+$param['width']/2; + $point['MARKER_Y'] = $y; + unset ($point['AVERAGE_Y']); + $this->_marker->_drawMarker($point['MARKER_X'], $point['MARKER_Y'], $point); + } + } + $this->write($x + $param['width'] + 10, $y + $param['height'] / 2, $caption, IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_LEFT, $param['font']); + } + + if (($param['align'] & IMAGE_GRAPH_ALIGN_VERTICAL) != 0) { + $param['y'] = $y2; + } else { + $param['x'] = $x2; + } + } + unset($keys); + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Plotarea.php b/oss/vtiger/trunk/Image/Graph/Plotarea.php new file mode 100644 index 00000000..3665d82c --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Plotarea.php @@ -0,0 +1,1145 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Plotarea.php,v 1.23 2006/02/28 22:48:07 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Layout.php + */ +require_once 'Image/Graph/Layout.php'; + +/** + * Plot area used for drawing plots. + * + * The plotarea consists of an x-axis and an y-axis, the plotarea can plot multiple + * charts within one plotares, by simply adding them (the axis' will scale to the + * plots automatically). A graph can consist of more plotareas + * + * @category Images + * @package Image_Graph + * @subpackage Plotarea + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + */ +class Image_Graph_Plotarea extends Image_Graph_Layout +{ + + /** + * The left most pixel of the 'real' plot area on the canvas + * @var int + * @access private + */ + var $_plotLeft = 0; + + /** + * The top most pixel of the 'real' plot area on the canvas + * @var int + * @access private + */ + var $_plotTop = 0; + + /** + * The right most pixel of the 'real' plot area on the canvas + * @var int + * @access private + */ + var $_plotRight = 0; + + /** + * The bottom most pixel of the 'real' plot area on the canvas + * @var int + * @access private + */ + var $_plotBottom = 0; + + /** + * The X axis + * @var Axis + * @access private + */ + var $_axisX = null; + + /** + * The Y axis + * @var Axis + * @access private + */ + var $_axisY = null; + + /** + * The secondary Y axis + * @var Axis + * @access private + */ + var $_axisYSecondary = null; + + /** + * The border style of the 'real' plot area + * @var LineStyle + * @access private + */ + var $_plotBorderStyle = null; + + /** + * Does any plot have any data? + * @var bool + * @access private + */ + var $_hasData = false; + + /** + * Is the plotarea horizontal? + * @var bool + * @access private + */ + var $_horizontal = false; + + /** + * Image_Graph_Plotarea [Constructor] + * + * @param string $axisX The class of the X axis (if omitted a std. axis is created) + * @param string $axisY The class of the Y axis (if omitted a std. axis is created) + * @param string $direction The direction of the plotarea - 'horizontal' or 'vertical' (default) + */ + function Image_Graph_Plotarea($axisX = 'Image_Graph_Axis_Category', $axisY = 'Image_Graph_Axis', $direction = 'vertical') + { + parent::Image_Graph_Layout(); + + $this->_padding = array('left' => 5, 'top' => 5, 'right' => 5, 'bottom' => 5);; + + include_once 'Image/Graph.php'; + + $this->_axisX =& Image_Graph::factory($axisX, IMAGE_GRAPH_AXIS_X); + $this->_axisX->_setParent($this); + + $this->_axisY =& Image_Graph::factory($axisY, IMAGE_GRAPH_AXIS_Y); + $this->_axisY->_setParent($this); + $this->_axisY->_setMinimum(0); + + $this->_fillStyle = false; + + if ($direction == 'horizontal') { + $this->_horizontal = true; + $this->_axisX->_transpose = true; + $this->_axisY->_transpose = true; + } + } + + /** + * Sets the parent. The parent chain should ultimately be a GraPHP object + * + * @see Image_Graph_Common + * @param Image_Graph_Common $parent The parent + * @access private + */ + function _setParent(& $parent) + { + parent::_setParent($parent); + if ($this->_axisX !== null) { + $this->_axisX->_setParent($this); + } + if ($this->_axisY !== null) { + $this->_axisY->_setParent($this); + } + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setParent($this); + } + } + + /** + * Sets the plot border line style of the element. + * + * @param Image_Graph_Line $lineStyle The line style of the border + * @deprecated 0.3.0dev2 - 2004-12-16 + */ + function setPlotBorderStyle(& $plotBorderStyle) + { + } + + /** + * Adds an element to the plotarea + * + * @param Image_Graph_Element $element The element to add + * @param int $axis The axis to associate the element with, either + * IMAGE_GRAPH_AXIS_X, IMAGE_GRAPH_AXIS_Y, IMAGE_GRAPH_AXIS_Y_SECONDARY + * or the shorter string notations 'x', 'y' or 'ysec' (defaults to + * IMAGE_GRAPH_AXIS_Y) + * @return Image_Graph_Element The added element + * @see Image_Graph_Common::add() + */ + function &add(& $element, $axis = IMAGE_GRAPH_AXIS_Y) + { + if ($axis == 'x') { + $axis = IMAGE_GRAPH_AXIS_X; + } + if ($axis == 'y') { + $axis = IMAGE_GRAPH_AXIS_Y; + } + if ($axis == 'ysec') { + $axis = IMAGE_GRAPH_AXIS_Y_SECONDARY; + } + if (($axis == IMAGE_GRAPH_AXIS_Y_SECONDARY) && + ($this->_axisYSecondary == null)) + { + $this->_axisYSecondary =& Image_Graph::factory('axis', IMAGE_GRAPH_AXIS_Y_SECONDARY); + $this->_axisYSecondary->_setMinimum(0); + if ($this->_horizontal) { + $this->_axisYSecondary->_transpose = true; + } + } + + parent::add($element); + + if (is_a($element, 'Image_Graph_Plot')) { + $element->_setAxisY($axis); + // postpone extrema calculation until we calculate coordinates + //$this->_setExtrema($element); + } elseif (is_a($element, 'Image_Graph_Grid')) { + switch ($axis) { + case IMAGE_GRAPH_AXIS_X: + if ($this->_axisX != null) { + $element->_setPrimaryAxis($this->_axisX); + if ($this->_axisY != null) { + $element->_setSecondaryAxis($this->_axisY); + } + } + break; + case IMAGE_GRAPH_AXIS_Y: + if ($this->_axisY != null) { + $element->_setPrimaryAxis($this->_axisY); + if ($this->_axisX != null) { + $element->_setSecondaryAxis($this->_axisX); + } + } + break; + case IMAGE_GRAPH_AXIS_Y_SECONDARY: + if ($this->_axisYSecondary != null) { + $element->_setPrimaryAxis($this->_axisYSecondary); + if ($this->_axisX != null) { + $element->_setSecondaryAxis($this->_axisX); + } + } + break; + } + } elseif (is_a($element, 'Image_Graph_Axis')) { + switch ($element->_type) { + case IMAGE_GRAPH_AXIS_X: + $this->_axisX =& $element; + break; + + case IMAGE_GRAPH_AXIS_Y: + $this->_axisY =& $element; + break; + + case IMAGE_GRAPH_AXIS_Y_SECONDARY: + $this->_axisYSecondary =& $element; + break; + + } + if ($element->_getMinimum() == $element->_getMaximum()) { + $element->_setMinimum(0); + $element->_setMaximum(1); + } + } + return $element; + } + + /** + * Get the width of the 'real' plotarea + * + * @return int The width of the 'real' plotarea, ie not including space occupied by padding and axis + * @access private + */ + function _plotWidth() + { + return abs($this->_plotRight - $this->_plotLeft); + } + + /** + * Get the height of the 'real' plotarea + * + * @return int The height of the 'real' plotarea, ie not including space + * occupied by padding and axis + * @access private + */ + function _plotHeight() + { + return abs($this->_plotBottom - $this->_plotTop); + } + + /** + * Set the extrema of the axis + * + * @param Image_Graph_Plot $plot The plot that 'hold' the values + * @access private + */ + function _setExtrema(& $plot) + { + if (($this->_axisX != null) && ($this->_axisX->_isNumeric())) { + $this->_axisX->_setMinimum($plot->_minimumX()); + $this->_axisX->_setMaximum($plot->_maximumX()); + } + + if (($plot->_axisY == IMAGE_GRAPH_AXIS_Y_SECONDARY) && + ($this->_axisYSecondary !== null) && + ($this->_axisYSecondary->_isNumeric())) + { + $this->_axisYSecondary->_setMinimum($plot->_minimumY()); + $this->_axisYSecondary->_setMaximum($plot->_maximumY()); + } elseif (($this->_axisY != null) && ($this->_axisY->_isNumeric())) { + $this->_axisY->_setMinimum($plot->_minimumY()); + $this->_axisY->_setMaximum($plot->_maximumY()); + } + + $datasets =& $plot->dataset(); + if (!is_array($datasets)) { + $datasets = array($datasets); + } + + $keys = array_keys($datasets); + foreach ($keys as $key) { + $dataset =& $datasets[$key]; + if ($dataset->count() > 0) { + $this->_hasData = true; + } + + if (is_a($dataset, 'Image_Graph_Dataset')) { + if (($this->_axisX != null) && (!$this->_axisX->_isNumeric())) { + $this->_axisX->_applyDataset($dataset); + } + + if (($plot->_axisY == IMAGE_GRAPH_AXIS_Y_SECONDARY) && + ($this->_axisYSecondary !== null) && + (!$this->_axisYSecondary->_isNumeric())) + { + $this->_axisYSecondary->_applyDataset($dataset); + } elseif (($this->_axisY != null) && (!$this->_axisY->_isNumeric())) { + $this->_axisY->_applyDataset($dataset); + } + } + } + unset($keys); + } + + /** + * Left boundary of the background fill area + * + * @return int Leftmost position on the canvas + * @access private + */ + function _fillLeft() + { + return $this->_plotLeft; + } + + /** + * Top boundary of the background fill area + * + * @return int Topmost position on the canvas + * @access private + */ + function _fillTop() + { + return $this->_plotTop; + } + + /** + * Right boundary of the background fill area + * + * @return int Rightmost position on the canvas + * @access private + */ + function _fillRight() + { + return $this->_plotRight; + } + + /** + * Bottom boundary of the background fill area + * + * @return int Bottommost position on the canvas + * @access private + */ + function _fillBottom() + { + return $this->_plotBottom; + } + + /** + * Get the point from the x-axis + * @param array $value The value array + * @param int $min The minimum pixel position possible + * @param int $max The maximum pixel position possible + * @return int The pixel position from the axis + * @access private + */ + function _axisPointX($value, $min, $max) + { + if (($this->_axisX == null) || (!isset($value['X']))) { + return false; + } + + if ($value['X'] === '#min#') { + return $min; + } + if ($value['X'] === '#max#') { + return $max; + } + + return $this->_axisX->_point($value['X']); + } + + /** + * Get the point from the x-axis + * @param array $value The value array + * @param int $min The minimum pixel position possible + * @param int $max The maximum pixel position possible + * @return int The pixel position from the axis + * @access private + */ + function _axisPointY($value, $min, $max) + { + if (!isset($value['Y'])) { + return false; + } + + if (($value['Y'] === '#min_pos#') || ($value['Y'] === '#max_nex#')) { + // return the minimum (bottom) position or if negative then zero + // or the maxmum (top) position or if positive then zero + if ((isset($value['AXIS_Y'])) && + ($value['AXIS_Y'] == IMAGE_GRAPH_AXIS_Y_SECONDARY) && + ($this->_axisYSecondary !== null) + ) { + $axisY =& $this->_axisYSecondary; + } else { + $axisY =& $this->_axisY; + } + if ($value['Y'] === '#min_pos#') { + return $axisY->_point(max(0, $axisY->_getMinimum())); + } else { + return $axisY->_point(min(0, $axisY->_getMaximum())); + } + } + + if ($value['Y'] === '#min#') { + return $min; + } + if ($value['Y'] === '#max#') { + return $max; + } + + if ((isset($value['AXIS_Y'])) && + ($value['AXIS_Y'] == IMAGE_GRAPH_AXIS_Y_SECONDARY) + ) { + if ($this->_axisYSecondary !== null) { + return $this->_axisYSecondary->_point($value['Y']); + } + } else { + if ($this->_axisY !== null) { + return $this->_axisY->_point($value['Y']); + } + } + return false; + } + + /** + * Get the X pixel position represented by a value + * + * @param double Value the value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _pointX($value) + { + if ($this->_horizontal) { + return $this->_axisPointY($value, $this->_plotLeft, $this->_plotRight); + } + else { + return $this->_axisPointX($value, $this->_plotLeft, $this->_plotRight); + } + } + + /** + * Get the Y pixel position represented by a value + * + * @param double Value the value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _pointY($value) + { + if ($this->_horizontal) { + return $this->_axisPointX($value, $this->_plotBottom, $this->_plotTop); + } + else { + return $this->_axisPointY($value, $this->_plotBottom, $this->_plotTop); + } + } + + /** + * Return the minimum value of the specified axis + * + * @param int $axis The axis to return the minimum value of (see {$link + * Image_Graph_Plotarea::getAxis()}) + * @return double The minimum value of the axis + * @access private + */ + function _getMinimum($axis = IMAGE_GRAPH_AXIS_Y) + { + $axis =& $this->getAxis($axis); + if ($axis !== null) { + return $axis->_getMinimum(); + } else { + return 0; + } + } + + /** + * Return the maximum value of the specified axis + * + * @param int $axis The axis to return the maximum value of(see {$link + * Image_Graph_Plotarea::getAxis()}) + * @return double The maximum value of the axis + * @access private + */ + function _getMaximum($axis = IMAGE_GRAPH_AXIS_Y) + { + $axis =& $this->getAxis($axis); + if ($axis !== null) { + return $axis->_getMaximum(); + } else { + return 0; + } + } + + /** + * Return the label distance for the specified axis. + * + * @param int $axis The axis to return the label distance for + * @return int The distance between 2 adjacent labels + * @access private + */ + function _labelDistance($axis) + { + $axis =& $this->getAxis($axis); + if ($axis !== null) { + return $axis->_labelDistance(); + } + + return false; + } + + /** + * Hides the axis + */ + function hideAxis($axis = false) + { + if (((!$axis) || ($axis === $this->_axisX) || ($axis === 'x')) && ($this->_axisX != null)) { + $this->_axisX->hide(); + } + if (((!$axis) || ($axis === $this->_axisY) || ($axis === 'y')) && ($this->_axisY != null)) { + $this->_axisY->hide(); + } + if (((!$axis) || ($axis === $this->_axisYSecondary) || ($axis === 'y_sec')) && ($this->_axisYSecondary != null)) { + $this->_axisYSecondary->hide(); + } + } + + /** + * Clears/removes the axis + */ + function clearAxis() + { + $this->_axisX = $this->_axisY = $this->_axisYSecondary = null; + } + + /** + * Get axis. + * + * Possible values are IMAGE_GRAPH_AXIS_X, IMAGE_GRAPH_AXIS_Y, + * IMAGE_GRAPH_AXIS_Y_SECONDARY or a short hand notation using + * string identifiers: 'x', 'y', 'ysec' + * + * @param int $axis The axis to return + * @return Image_Graph_Axis The axis + */ + function &getAxis($axis = IMAGE_GRAPH_AXIS_X) + { + switch ($axis) { + case IMAGE_GRAPH_AXIS_X: + case 'x': + return $this->_axisX; + + case IMAGE_GRAPH_AXIS_Y: + case 'y': + return $this->_axisY; + + case IMAGE_GRAPH_AXIS_Y_SECONDARY: + case 'ysec': + return $this->_axisYSecondary; + + } + return null; + } + + /** + * Update coordinates + * + * @access private + */ + function _updateCoords() + { + if (is_array($this->_elements)) { + $keys = array_keys($this->_elements); + foreach ($keys as $key) { + $element =& $this->_elements[$key]; + if (is_a($element, 'Image_Graph_Plot')) { + if (((is_a($element, 'Image_Graph_Plot_Bar')) || + (is_a($element, 'Image_Graph_Plot_Step')) || + (is_a($element, 'Image_Graph_Plot_Dot')) || + (is_a($element, 'Image_Graph_Plot_CandleStick')) || + (is_a($element, 'Image_Graph_Plot_BoxWhisker')) || + (is_a($element, 'Image_Graph_Plot_Impulse'))) && + ($this->_axisX != null) && + (strtolower(get_class($this->_axisX)) != 'image_graph_axis') // do not push plot if x-axis is linear + ) + { + $this->_axisX->_pushValues(); + } + $this->_setExtrema($element); + } + } + unset($keys); + } + + $this->_calcEdges(); + + $pctWidth = (int) ($this->width() * 0.05); + $pctHeight = (int) ($this->height() * 0.05); + + $left = $this->_left + $this->_padding['left']; + $top = $this->_top + $this->_padding['top']; + $right = $this->_right - $this->_padding['right']; + $bottom = $this->_bottom - $this->_padding['bottom']; + + // temporary place holder for axis point calculations + $axisPoints['x'] = array($left, $top, $right, $bottom); + $axisPoints['y'] = $axisPoints['x']; + $axisPoints['y2'] = $axisPoints['x']; + + if ($this->_axisX !== null) { + $intersectX = $this->_axisX->_getAxisIntersection(); + $sizeX = $this->_axisX->_size(); + $this->_axisX->_setCoords($left, $top, $right, $bottom); + $this->_axisX->_updateCoords(); + } + + if ($this->_axisY !== null) { + $intersectY = $this->_axisY->_getAxisIntersection(); + $sizeY = $this->_axisY->_size(); + $this->_axisY->_setCoords($left, $top, $right, $bottom); + $this->_axisY->_updateCoords(); + } + + if ($this->_axisYSecondary !== null) { + $intersectYsec = $this->_axisYSecondary->_getAxisIntersection(); + $sizeYsec = $this->_axisYSecondary->_size(); + $this->_axisYSecondary->_setCoords($left, $top, $right, $bottom); + $this->_axisYSecondary->_updateCoords(); + } + + $axisCoordAdd = array('left' => 0, 'right' => 0, 'top' => 0, 'bottom' => 0); + + if ($this->_axisY != null) { + if ($this->_axisX != null) { + $pos = $this->_axisX->_intersectPoint($intersectY['value']); + } else { + $pos = ($this->_horizontal ? $bottom : $left); + } + + if ($this->_horizontal) { + if (($pos + $sizeY) > $bottom) { + $axisCoordAdd['bottom'] = ($pos + $sizeY) - $bottom; + // the y-axis position needs to be recalculated! + } else { + // top & bottom may need to be adjusted when the x-axis has been + // calculated! + $this->_axisY->_setCoords( + $left, + $pos, + $right, + $pos + $sizeY + ); + $this->_axisY->_updateCoords(); + } + } + else { + if (($pos - $sizeY) < $left) { + $axisCoordAdd['left'] = $left - ($pos - $sizeY); + // the y-axis position needs to be recalculated! + } else { + // top & bottom may need to be adjusted when the x-axis has been + // calculated! + $this->_axisY->_setCoords( + $pos - $sizeY, + $top, + $pos, + $bottom + ); + $this->_axisY->_updateCoords(); + } + } + } + + if ($this->_axisYSecondary != null) { + if ($this->_axisX != null) { + $pos = $this->_axisX->_intersectPoint($intersectYsec['value']); + } else { + $pos = ($this->_horizontal ? $top : $right); + } + + if ($this->_horizontal) { + if (($pos - $sizeYsec) < $top) { + $axisCoordAdd['top'] = $top - ($pos - $sizeYsec); + // the secondary y-axis position need to be recalculated + } else { + // top & bottom may need to be adjusted when the x-axis has been + // calculated! + $this->_axisYSecondary->_setCoords( + $left, + $pos - $sizeY, + $right, + $pos + ); + $this->_axisYSecondary->_updateCoords(); + } + } + else { + if (($pos + $sizeYsec) > $right) { + $axisCoordAdd['right'] = ($pos + $sizeYsec) - $right; + // the secondary y-axis position need to be recalculated + } else { + // top & bottom may need to be adjusted when the x-axis has been + // calculated! + $this->_axisYSecondary->_setCoords( + $pos, + $top, + $pos + $sizeY, + $bottom + ); + $this->_axisYSecondary->_updateCoords(); + } + } + } + + if ($this->_axisX != null) { + if (($intersectX['axis'] == IMAGE_GRAPH_AXIS_Y_SECONDARY) && + ($this->_axisYSecondary !== null) + ) { + $axis =& $this->_axisYSecondary; + } elseif ($this->_axisY !== null) { + $axis =& $this->_axisY; + } else { + $axis = false; + } + + if ($axis !== false) { + $pos = $axis->_intersectPoint($intersectX['value']); + } else { + $pos = ($this->_horizontal ? $left : $bottom); + } + + if ($this->_horizontal) { + if (($pos - $sizeX) < $left) { + $axisCoordAdd['left'] = $left - ($pos - $sizeX); + $pos = $left + $sizeX; + } + + $this->_axisX->_setCoords( + $pos - $sizeX, + $top + $axisCoordAdd['top'], + $pos, + $bottom - $axisCoordAdd['bottom'] + ); + $this->_axisX->_updateCoords(); + } + else { + if (($pos + $sizeX) > $bottom) { + $axisCoordAdd['bottom'] = ($pos + $sizeX) - $bottom; + $pos = $bottom - $sizeX; + } + + $this->_axisX->_setCoords( + $left + $axisCoordAdd['left'], + $pos, + $right - $axisCoordAdd['right'], + $pos + $sizeX + ); + $this->_axisX->_updateCoords(); + } + } + + if ($this->_horizontal) { + if (($this->_axisX !== null) && + (($axisCoordAdd['top'] != 0) || + ($axisCoordAdd['bottom'] != 0)) + ) { + // readjust y-axis for better estimate of position + if ($this->_axisY !== null) { + $pos = $this->_axisX->_intersectPoint($intersectY['value']); + $this->_axisY->_setCoords( + false, + $pos, + false, + $pos + $sizeY + ); + $this->_axisY->_updateCoords(); + } + + if ($this->_axisYSecondary !== null) { + $pos = $this->_axisX->_intersectPoint($intersectYsec['value']); + $this->_axisYSecondary->_setCoords( + false, + $pos - $sizeYsec, + false, + $pos + ); + $this->_axisYSecondary->_updateCoords(); + } + } + + // adjust top and bottom of y-axis + if ($this->_axisY !== null) { + $this->_axisY->_setCoords( + $left + $axisCoordAdd['left'], + false, + $right - $axisCoordAdd['right'], + false + ); + $this->_axisY->_updateCoords(); + } + + // adjust top and bottom of y-axis + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setCoords( + $left + $axisCoordAdd['left'], + false, + $right - $axisCoordAdd['right'], + false + ); + $this->_axisYSecondary->_updateCoords(); + } + + if ($this->_axisX !== null) { + $this->_plotTop = $this->_axisX->_top; + $this->_plotBottom = $this->_axisX->_bottom; + } else { + $this->_plotTop = $top; + $this->_plotBottom = $bottom; + } + + if ($this->_axisY !== null) { + $this->_plotLeft = $this->_axisY->_left; + $this->_plotRight = $this->_axisY->_right; + } elseif ($this->_axisYSecondary !== null) { + $this->_plotLeft = $this->_axisYSecondary->_left; + $this->_plotRight = $this->_axisYSecondary->_right; + } else { + $this->_plotLeft = $this->_left; + $this->_plotRight = $this->_right; + } + } + else { + if (($this->_axisX !== null) && + (($axisCoordAdd['left'] != 0) || + ($axisCoordAdd['right'] != 0)) + ) { + // readjust y-axis for better estimate of position + if ($this->_axisY !== null) { + $pos = $this->_axisX->_intersectPoint($intersectY['value']); + $this->_axisY->_setCoords( + $pos - $sizeY, + false, + $pos, + false + ); + $this->_axisY->_updateCoords(); + } + + if ($this->_axisYSecondary !== null) { + $pos = $this->_axisX->_intersectPoint($intersectYsec['value']); + $this->_axisYSecondary->_setCoords( + $pos, + false, + $pos + $sizeYsec, + false + ); + $this->_axisYSecondary->_updateCoords(); + } + } + + // adjust top and bottom of y-axis + if ($this->_axisY !== null) { + $this->_axisY->_setCoords( + false, + $top + $axisCoordAdd['top'], + false, + $bottom - $axisCoordAdd['bottom'] + ); + $this->_axisY->_updateCoords(); + } + + // adjust top and bottom of y-axis + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setCoords( + false, + $top + $axisCoordAdd['top'], + false, + $bottom - $axisCoordAdd['bottom'] + ); + $this->_axisYSecondary->_updateCoords(); + } + + if ($this->_axisX !== null) { + $this->_plotLeft = $this->_axisX->_left; + $this->_plotRight = $this->_axisX->_right; + } else { + $this->_plotLeft = $left; + $this->_plotRight = $right; + } + + if ($this->_axisY !== null) { + $this->_plotTop = $this->_axisY->_top; + $this->_plotBottom = $this->_axisY->_bottom; + } elseif ($this->_axisYSecondary !== null) { + $this->_plotTop = $this->_axisYSecondary->_top; + $this->_plotBottom = $this->_axisYSecondary->_bottom; + } else { + $this->_plotTop = $this->_top; + $this->_plotBottom = $this->_bottom; + } + } + + Image_Graph_Element::_updateCoords(); +/* + if ($this->_axisX != null) { + $this->_axisX->_updateCoords(); + } + if ($this->_axisY != null) { + $this->_axisY->_updateCoords(); + } + if ($this->_axisYSecondary != null) { + $this->_axisYSecondary->_updateCoords(); + }*/ + } + + /** + * Set the axis padding for a specified position. + * + * The axis padding is padding "inside" the plotarea (i.e. to put some space + * between the axis line and the actual plot). + * + * This can be specified in a number of ways: + * + * 1) Specify an associated array with 'left', 'top', 'right' and 'bottom' + * indices with values for the paddings. Leave out 2nd parameter. + * + * 2) Specify an overall padding as the first parameter + * + * 3) Specify the padding and position with position values as mentioned + * above + * + * Normally you'd only consider applying axis padding to a category x-axis. + * + * @param mixed $value The value/padding + * @param mixed $position The "position" of the padding + */ + function setAxisPadding($value, $position = false) + { + if ($position === false) { + if (is_array($value)) { + if ($this->_horizontal) { + if ((isset($value['top'])) && ($this->_axisX !== null)) { + $this->_axisX->_setAxisPadding('low', $value['top']); + } + if ((isset($value['bottom'])) && ($this->_axisX !== null)) { + $this->_axisX->_setAxisPadding('high', $value['bottom']); + } + if ((isset($value['left'])) && ($this->_axisY !== null)) { + $this->_axisY->_setAxisPadding('low', $value['left']); + } + if ((isset($value['right'])) && ($this->_axisY !== null)) { + $this->_axisY->_setAxisPadding('high', $value['right']); + } + if ((isset($value['left'])) && ($this->_axisYSecondary !== null)) { + $this->_axisYSecondary->_setAxisPadding('low', $value['left']); + } + if ((isset($value['right'])) && ($this->_axisYSecondary !== null)) { + $this->_axisYSecondary->_setAxisPadding('high', $value['right']); + } + } + else { + if ((isset($value['left'])) && ($this->_axisX !== null)) { + $this->_axisX->_setAxisPadding('low', $value['left']); + } + if ((isset($value['right'])) && ($this->_axisX !== null)) { + $this->_axisX->_setAxisPadding('high', $value['right']); + } + if ((isset($value['bottom'])) && ($this->_axisY !== null)) { + $this->_axisY->_setAxisPadding('low', $value['bottom']); + } + if ((isset($value['top'])) && ($this->_axisY !== null)) { + $this->_axisY->_setAxisPadding('high', $value['top']); + } + if ((isset($value['bottom'])) && ($this->_axisYSecondary !== null)) { + $this->_axisYSecondary->_setAxisPadding('low', $value['bottom']); + } + if ((isset($value['top'])) && ($this->_axisYSecondary !== null)) { + $this->_axisYSecondary->_setAxisPadding('high', $value['top']); + } + } + } else { + if ($this->_axisX !== null) { + $this->_axisX->_setAxisPadding('low', $value); + $this->_axisX->_setAxisPadding('high', $value); + } + if ($this->_axisY !== null) { + $this->_axisY->_setAxisPadding('low', $value); + $this->_axisY->_setAxisPadding('high', $value); + } + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setAxisPadding('low', $value); + $this->_axisYSecondary->_setAxisPadding('high', $value); + } + } + } else { + switch ($position) { + case 'left': + if ($this->_horizontal) { + if ($this->_axisY !== null) { + $this->_axisY->_setAxisPadding('low', $value); + } + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setAxisPadding('low', $value); + } + } + else if ($this->_axisX !== null) { + $this->_axisX->_setAxisPadding('low', $value); + } + break; + + case 'right': + if ($this->_horizontal) { + if ($this->_axisY !== null) { + $this->_axisY->_setAxisPadding('high', $value); + } + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setAxisPadding('high', $value); + } + } + else if ($this->_axisX !== null) { + $this->_axisX->_setAxisPadding('high', $value); + } + break; + + case 'top': + if (!$this->_horizontal) { + if ($this->_axisY !== null) { + $this->_axisY->_setAxisPadding('high', $value); + } + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setAxisPadding('high', $value); + } + } + else if ($this->_axisX !== null) { + $this->_axisX->_setAxisPadding('high', $value); + } + break; + + case 'bottom': + if (!$this->_horizontal) { + if ($this->_axisY !== null) { + $this->_axisY->_setAxisPadding('low', $value); + } + if ($this->_axisYSecondary !== null) { + $this->_axisYSecondary->_setAxisPadding('low', $value); + } + } + else if ($this->_axisX !== null) { + $this->_axisX->_setAxisPadding('low', $value); + } + break; + } + } + } + + /** + * Output the plotarea to the canvas + * + * @return bool Was the output 'good' (true) or 'bad' (false). + * @access private + */ + function _done() + { + if ($this->_hasData) { + $this->_canvas->startGroup(get_class($this)); + + if ($this->_axisX != null) { + $this->add($this->_axisX); + } + if ($this->_axisY != null) { + $this->add($this->_axisY); + } + if ($this->_axisYSecondary != null) { + $this->add($this->_axisYSecondary); + } + + $this->_getFillStyle(); + $this->_canvas->rectangle( + array( + 'x0' => $this->_plotLeft, + 'y0' => $this->_plotTop, + 'x1' => $this->_plotRight, + 'y1' => $this->_plotBottom + ) + ); + $result = parent::_done(); + $this->_canvas->endGroup(); + return $result; + } else { + // no data -> do nothing at all! + return true; + } + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Simple.php b/oss/vtiger/trunk/Image/Graph/Simple.php new file mode 100644 index 00000000..b7fe356b --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Simple.php @@ -0,0 +1,121 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Simple.php,v 1.8 2005/08/24 20:35:54 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph.php + */ +require_once 'Image/Graph.php'; + +/** + * Class for simple creation of graphs + * + * @category Images + * @package Image_Graph + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + */ +class Image_Graph_Simple extends Image_Graph +{ + + /** + * Image_Graph_Simple [Constructor] + * + * @param int $width The width of the graph in pixels + * @param int $height The height of the graph in pixels + */ + function Image_Graph_Simple($width, $height, $plotType, $data, $title, $lineColor = 'black', $fillColor = 'white', $font = false) + { + parent::Image_Graph($width, $height); + + $plotarea =& Image_Graph::factory('plotarea'); + + $dataset =& Image_Graph::factory('dataset', array($data)); + + if ($font === false) { + $font =& Image_Graph::factory('Image_Graph_Font'); + } elseif (is_string($font)) { + $font =& Image_Graph::factory('ttf_font', $font); + $font->setSize(8); + } + + $this->setFont($font); + + $this->add( + Image_Graph::vertical( + Image_Graph::factory('title', + array( + $title, + array('size_rel' => 2) + ) + ), + $plotarea, + 10 + ) + ); + + $plotarea->addNew('line_grid', array(), IMAGE_GRAPH_AXIS_Y); + + $plot =& $plotarea->addNew($plotType, array(&$dataset)); + $plot->setLineColor($lineColor); + $plot->setFillColor($fillColor); + + $axisX =& $plotarea->getAxis(IMAGE_GRAPH_AXIS_X); + $axisX->showLabel( + IMAGE_GRAPH_LABEL_MINIMUM + + IMAGE_GRAPH_LABEL_ZERO + + IMAGE_GRAPH_LABEL_MAXIMUM + ); + + } + + /** + * Factory method to create the Image_Simple_Graph object. + */ + function &factory($width, $height, $plotType, $data, $title, $lineColor = 'black', $fillColor = 'white', $font = false) + { + $obj =& Image_Graph::factory('Image_Graph_Simple', + array( + $width, + $height, + $plotType, + $data, + $title, + $lineColor, + $fillColor, + $font + ) + ); + return $obj; + } + +} +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Title.php b/oss/vtiger/trunk/Image/Graph/Title.php new file mode 100644 index 00000000..75471456 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Title.php @@ -0,0 +1,194 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Title.php,v 1.12 2005/08/24 20:35:56 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Layout.php + */ +require_once 'Image/Graph/Layout.php'; + +/** + * Title + * + * @category Images + * @package Image_Graph + * @subpackage Text + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + */ +class Image_Graph_Title extends Image_Graph_Layout +{ + + /** + * The text to print + * @var string + * @access private + */ + var $_text; + + /** + * The font to use + * @var Font + * @access private + */ + var $_font; + + /** + * The alignment of the title + * @var int + * @access private + */ + var $_alignment = IMAGE_GRAPH_ALIGN_CENTER_X; + + /** + * Create the title. + * + * Pass a Image_Graph_Font object - preferably by-ref (&) as second + * parameter, the font size in pixels or an associated array with some or + * all of the followin keys: + * + * 'size' The size of the title + * + * 'angle' The angle at which to write the title (in degrees or 'vertical') + * + * 'color' The font-face color + * + * @param sting $text The text to represent the title + * @param mixed $fontOptions The font to use in the title + */ + function Image_Graph_Title($text, $fontOptions = false) + { + parent::Image_Graph_Layout(); + if (is_object($fontOptions)) { + $this->_font =& $fontOptions; + } else { + if (is_array($fontOptions)) { + $this->_fontOptions = $fontOptions; + } else { + $this->_fontOptions['size'] = $fontOptions; + } + } + $this->setText($text); + } + + /** + * Set the text + * + * @param string $text The text to display + */ + function setText($text) + { + $this->_text = $text; + } + + /** + * Returns the calculated "auto" size + * + * @return int The calculated auto size + * @access private + */ + function _getAutoSize() + { + if ($this->_defaultFontOptions !== false) { + $this->_canvas->setFont($this->_defaultFontOptions); + } else { + $this->_canvas->setFont($this->_getFont()); + } + + return $this->_canvas->textHeight($this->_text); + } + + /** + * Set the alignment of the legend + * + * @param int $alignment The alignment + */ + function setAlignment($alignment) + { + $this->_alignment = $alignment & 0x7; + } + + /** + * Output the text + * + * @return bool Was the output 'good' (true) or 'bad' (false). + * @access private + */ + function _done() + { + if ($this->_defaultFontOptions !== false) { + $this->_canvas->setFont($this->_defaultFontOptions); + } else { + $this->_canvas->setFont($this->_getFont()); + } + + if (is_a($this->_parent, 'Image_Graph_Plotarea')) { + $this->_setCoords( + $this->_parent->_left, + $this->_parent->_top, + $this->_parent->_right, + $this->_parent->_top + $this->_canvas->textHeight($this->_text) + ); + } elseif (!is_a($this->_parent, 'Image_Graph_Layout')) { + $this->_setCoords( + $this->_parent->_fillLeft(), + $this->_parent->_fillTop(), + $this->_parent->_fillRight(), + $this->_parent->_fillTop() + $this->_canvas->textHeight($this->_text) + ); + } + + if (parent::_done() === false) { + return false; + } + + if ($this->_alignment == IMAGE_GRAPH_ALIGN_CENTER_X) { + $x = ($this->_left + $this->_right) / 2; + } elseif ($this->_alignment == IMAGE_GRAPH_ALIGN_LEFT) { + $x = $this->_left; + } else { + $x = $this->_right; + } + $y = ($this->_top + $this->_bottom) / 2; + + $this->write( + $x, + $y, + $this->_text, + $this->_alignment + IMAGE_GRAPH_ALIGN_CENTER_Y + ); + return true; + } + +} + +?> \ No newline at end of file diff --git a/oss/vtiger/trunk/Image/Graph/Tool.php b/oss/vtiger/trunk/Image/Graph/Tool.php new file mode 100644 index 00000000..8c844a13 --- /dev/null +++ b/oss/vtiger/trunk/Image/Graph/Tool.php @@ -0,0 +1,291 @@ + + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id: Tool.php,v 1.4 2005/09/14 20:27:24 nosey Exp $ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * This class contains a set of tool-functions. + * + * These functions are all to be called statically + * + * @category Images + * @package Image_Graph + * @author Jesper Veggerby + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: 0.7.2 + * @link http://pear.php.net/package/Image_Graph + */ +class Image_Graph_Tool +{ + + /** + * Return the average of 2 points + * + * @param double P1 1st point + * @param double P2 2nd point + * @return double The average of P1 and P2 + * @static + */ + function mid($p1, $p2) + { + return ($p1 + $p2) / 2; + } + + /** + * Mirrors P1 in P2 by a amount of Factor + * + * @param double $p1 1st point, point to mirror + * @param double $o2 2nd point, mirror point + * @param double $factor Mirror factor, 0 returns $p2, 1 returns a pure + * mirror, ie $p1 on the exact other side of $p2 + * @return double $p1 mirrored in $p2 by Factor + * @static + */ + function mirror($p1, $p2, $factor = 1) + { + return $p2 + $factor * ($p2 - $p1); + } + + /** + * Calculates a Bezier control point, this function must be called for BOTH + * X and Y coordinates (will it work for 3D coordinates!?) + * + * @param double $p1 1st point + * @param double $p2 Point to + * @param double $factor Mirror factor, 0 returns P2, 1 returns a pure + * mirror, i.e. P1 on the exact other side of P2 + * @return double P1 mirrored in P2 by Factor + * @static + */ + function controlPoint($p1, $p2, $factor, $smoothFactor = 0.75) + { + $sa = Image_Graph_Tool::mirror($p1, $p2, $smoothFactor); + $sb = Image_Graph_Tool::mid($p2, $sa); + + $m = Image_Graph_Tool::mid($p2, $factor); + + $pC = Image_Graph_Tool::mid($sb, $m); + + return $pC; + } + + /** + * Calculates a Bezier point, this function must be called for BOTH X and Y + * coordinates (will it work for 3D coordinates!?) + * + * @param double $t A position between $p2 and $p3, value between 0 and 1 + * @param double $p1 Point to use for calculating control points + * @param double $p2 Point 1 to calculate bezier curve between + * @param double $p3 Point 2 to calculate bezier curve between + * @param double $p4 Point to use for calculating control points + * @return double The bezier value of the point t between $p2 and $p3 using + * $p1 and $p4 to calculate control points + * @static + */ + function bezier($t, $p1, $p2, $p3, $p4) + { + // (1-t)^3*p1 + 3*(1-t)^2*t*p2 + 3*(1-t)*t^2*p3 + t^3*p4 + return pow(1 - $t, 3) * $p1 + + 3 * pow(1 - $t, 2) * $t * $p2 + + 3 * (1 - $t) * pow($t, 2) * $p3 + + pow($t, 3) * $p4; + } + + /** + * For a given point (x,y) return a point rotated by a given angle aroung the center (xy,yc) + * + * @param int $x x coordinate of the point to rotate + * @param int $y y coordinate of the point to rotate + * @param int $xc x coordinate of the center of the rotation + * @param int $yc y coordinate of the center of the rotation + * @param int $angle angle of the rotation + * @return array the coordinate of the new point + * @static + */ + function rotate($x, $y, $xc, $yc, $angle) + { + $cos = cos(deg2rad($angle)); + $sin = sin(deg2rad($angle)); + $xr= $x - $xc; + $yr= $y - $yc; + $x1= $xc + $cos * $xr - $sin * $yr; + $y1= $yc + $sin * $xr + $cos * $yr; + return array((int) $x1,(int) $y1); + } + + /** + * If a number is close 0 zero (i.e. 0 within $decimal decimals) it is rounded down to zero + * + * @param double $value The value to round + * @param int $decimal The number of decimals + * @return double The value or zero if "close enough" to zero + * @static + */ + function close2zero($value, $decimal) + { + if (abs($value) < pow(10, -$decimal)) { + return 0; + } + else { + return $value; + } + } + + /** + * Calculate the dimensions and center point (of gravity) for an arc + * + * @param int $v1 The angle at which the arc starts + * @param int $v2 The angle at which the arc ends + * @return array An array with the dimensions in a fraction of a circle width radius 1 'rx', 'ry' and the + * center point of gravity ('cx', 'cy') + * @static + */ + function calculateArcDimensionAndCenter($v1, $v2) + { + // $v2 always larger than $v1 + $r1x = Image_Graph_Tool::close2zero(cos(deg2rad($v1)), 3); + $r2x = Image_Graph_Tool::close2zero(cos(deg2rad($v2)), 3); + + $r1y = Image_Graph_Tool::close2zero(sin(deg2rad($v1)), 3); + $r2y = Image_Graph_Tool::close2zero(sin(deg2rad($v2)), 3); + + // $rx = how many percent of the x-diameter of the entire ellipse does the arc x-diameter occupy: 1 entire width, 0 no width + // $cx = at what percentage of the diameter does the center lie + + // if the arc passes through 0/360 degrees the "highest" of r1x and r2x is replaced by 1! + if ((($v1 <= 0) && ($v2 >= 0)) || (($v1 <= 360) && ($v2 >= 360))) { + $r1x = min($r1x, $r2x); + $r2x = 1; + } + + // if the arc passes through 180 degrees the "lowest" of r1x and r2x is replaced by -1! + if ((($v1 <= 180) && ($v2 >= 180)) || (($v1 <= 540) && ($v2 >= 540))) { + $r1x = max($r1x, $r2x); + $r2x = -1; + } + + if ($r1x >= 0) { // start between [270; 360] or [0; 90] + if ($r2x >= 0) { + $rx = max($r1x, $r2x) / 2; + $cx = 0; // center lies 0 percent along this "vector" + } + else { + $rx = abs($r1x - $r2x) / 2; + $cx = abs($r2x / 2) / $rx; + } + } + else { // start between ]90; 270[ + if ($r2x < 0) { + $rx = max(abs($r1x), abs($r2x)) / 2; + $cx = $rx; + } + else { + $rx = abs($r1x - $r2x) / 2; + $cx = abs($r1x / 2) / $rx; + } + } + + // $ry = how many percent of the y-diameter of the entire ellipse does the arc y-diameter occupy: 1 entire, 0 none + // $cy = at what percentage of the y-diameter does the center lie + + // if the arc passes through 90 degrees the "lowest" of r1x and r2x is replaced by -1! + if ((($v1 <= 90) && ($v2 >= 90)) || (($v1 <= 450) && ($v2 >= 450))) { + $r1y = min($r1y, $r2y); + $r2y = 1; + } + + // if the arc passes through 270 degrees the "highest" of r1y and r2y is replaced by -1! + if ((($v1 <= 270) && ($v2 >= 270)) || (($v1 <= 630) && ($v2 >= 630))) { + $r1y = max($r1y, $r2y); + $r2y = -1; + } + + if ($r1y >= 0) { // start between [0; 180] + if ($r2y >= 0) { + $ry = max($r1y, $r2y) / 2; + $cy = 0; // center lies 0 percent along this "vector" + } + else { + $ry = abs($r1y - $r2y) / 2; + $cy = abs($r2y / 2) / $ry; + } + } + else { // start between ]180; 360[ + if ($r2y < 0) { + $ry = max(abs($r1y), abs($r2y)) / 2; + $cy = $ry; + } + else { + $ry = abs($r1y - $r2y) / 2; + $cy = abs($r1y / 2) / $ry; + } + } + + return array( + 'rx' => $rx, + 'cx' => $cx, + 'ry' => $ry, + 'cy' => $cy + ); + } + + /** + * Calculate linear regression on a dataset + * @param array $data The data to calculate regression upon + * @return array The slope and intersection of the "best-fit" line + * @static + */ + function calculateLinearRegression(&$data) + { + $sumX = 0; + $sumY = 0; + foreach ($data as $point) { + $sumX += $point['X']; + $sumY += $point['Y']; + } + $meanX = $sumX / count($data); + $meanY = $sumY / count($data); + + $sumXX = 0; + $sumYY = 0; + $sumXY = 0; + foreach ($data as $point) { + $sumXX += ($point['X'] - $meanX) * ($point['X'] - $meanX); + $sumYY += ($point['Y'] - $meanY) * ($point['Y'] - $meanY); + $sumXY += ($point['X'] - $meanX) * ($point['Y'] - $meanY); + } + + $result = array(); + $result['slope'] = ($sumXY / $sumXX); + $result['intersection'] = $meanY - ($result['slope'] * $meanX); + return $result; + } + +} + +?> \ No newline at end of file