diff options
Diffstat (limited to 'config/dspam/pear/Image/Graph/Axis.php')
-rw-r--r-- | config/dspam/pear/Image/Graph/Axis.php | 1690 |
1 files changed, 1690 insertions, 0 deletions
diff --git a/config/dspam/pear/Image/Graph/Axis.php b/config/dspam/pear/Image/Graph/Axis.php new file mode 100644 index 00000000..99da305f --- /dev/null +++ b/config/dspam/pear/Image/Graph/Axis.php @@ -0,0 +1,1690 @@ +<?php + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +/** + * Class for axis handling. + * + * PHP versions 4 and 5 + * + * LICENSE: This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. This library is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. You should have received a copy of + * the GNU Lesser General Public License along with this library; if not, write + * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA + * + * @category Images + * @package Image_Graph + * @subpackage Axis + * @author Jesper Veggerby <pear.nosey@veggerby.dk> + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version CVS: $Id$ + * @link http://pear.php.net/package/Image_Graph + */ + +/** + * Include file Image/Graph/Plotarea/Element.php + */ +require_once 'Image/Graph/Plotarea/Element.php'; + +/** + * Diplays a normal linear axis (either X- or Y-axis). + * + * @category Images + * @package Image_Graph + * @subpackage Axis + * @author Jesper Veggerby <pear.nosey@veggerby.dk> + * @copyright Copyright (C) 2003, 2004 Jesper Veggerby Hansen + * @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1 + * @version Release: @package_version@ + * @link http://pear.php.net/package/Image_Graph + */ + class Image_Graph_Axis extends Image_Graph_Plotarea_Element +{ + + /** + * The type of the axis, possible values are: + * <ul> + * <li>IMAGE_GRAPH_AXIS_X / IMAGE_GRAPH_AXIS_HORIZONTAL + * <li>IMAGE_GRAPH_AXIS_Y / IMAGE_GRAPH_AXIS_VERTICAL / + * IMAGE_GRAPH_AXIS_Y_SECONDARY + * </ul> + * @var int + * @access private + */ + var $_type; + + /** + * The minimum value the axis displays + * @var int + * @access private + */ + var $_minimum = false; + + /** + * The minimum value the axis has been explicitly set by the user + * @var bool + * @access private + */ + var $_minimumSet = false; + + /** + * The maximum value the axis displays + * @var int + * @access private + */ + var $_maximum = false; + + /** + * The maximum value the axis has been explicitly set by the user + * @var bool + * @access private + */ + var $_maximumSet = false; + + /** + * The value span of the axis. + * This is primarily included for performance reasons + * @var double + * @access private + */ + var $_axisSpan = false; + + /** + * The value span of the axis. + * This is primarily included for performance reasons + * @var double + * @access private + */ + var $_axisValueSpan = false; + + /** + * The axis padding. + * The index 'low' specifies the padding for the low axis values (when not + * inverted), i.e. to the left on an x-axis and on the bottom of an y-axis, + * vice versa for 'high'. + * + * Axis padding does not make sense on a normal linear y-axis with a 'y-min' + * of 0 since this corresponds to displaying a small part of the y-axis + * below 0! + * + * @var array + * @access private + */ + var $_axisPadding = array('low' => 0, 'high' => 0); + + /** + * The number of "pixels" representing 1 unit on the axis + * + * This is primarily included for performance reasons + * @var double + * @access private + */ + var $_delta = false; + + /** + * Specify if the axis should label the minimum value + * @var bool + * @access private + */ + var $_showLabelMinimum = true; + + /** + * Specify if the axis should label 0 (zero) + * @var bool + * @access private + */ + var $_showLabelZero = false; + + /** + * Specify if the axis should label the maximum value + * @var bool + * @access private + */ + var $_showLabelMaximum = true; + + /** + * Show arrow heads at the 'end' of the axis, default: false + * @var bool + * @access private + */ + var $_showArrow = false; + + /** + * Intersection data of axis + * @var array + * @access private + */ + var $_intersect = array('value' => 'default', 'axis' => 'default'); + + /** + * The fixed size of the axis (i.e. width for y-axis, height for x-axis) + * @var mixed + * @access private + */ + var $_fixedSize = false; + + /** + * The label options + * + * Should text be shows, preferences for ticks. The indexes start at level + * 1, which is chosen for readability + * @var array + * @access private + */ + var $_labelOptions = array( + 1 => array( + 'interval' => 1, + 'type' => 'auto', + 'tick' => array( + 'start' => -2, + 'end' => 2, + 'color' => false // default color + ), + 'showtext' => true, + 'showoffset' => false, + 'font' => array(), + 'offset' => 0, + 'position' => 'outside', + ) + ); + + /** + * The labels that are shown. + * + * This is used to make values show only once... + * @access private + */ + var $_labelText = array(); + + /** + * A data preprocessor for formatting labels, fx showing dates as a standard + * date instead of Unix time stamp + * @var Image_Graph_DatePreProcessor + * @access private + * @see Image_Graph_DataPreProcessor + */ + var $_dataPreProcessor = null; + + /** + * Point marked in the axis + * @var array + * @access private + */ + var $_marks = array(); + + /** + * Specifies whether the values should be 'pushed' by 0.5 + * @var bool + * @access private + */ + var $_pushValues = false; + + /** + * The title of this axis + * @var string + * @access private + */ + var $_title = ''; + + /** + * The font used for the title of this axis + * @var Image_Graph_Font + * @access private + */ + var $_titleFont = false; + + /** + * Invert the axis (i.e. if an y-axis normally displays minimum values at + * the bottom, they are not displayed at the top + * @var bool + * @access private + * @since 0.3.0dev3 + */ + var $_invert = false; + + /** + * Transpose the axis (i.e. is a normal y-axis transposed, so thats it's not show + * vertically as normally expected, but instead horizontally) + * @var bool + * @access private + */ + var $_transpose = false; + + /** + * Image_Graph_Axis [Constructor]. + * Normally a manual creation should not be necessary, axis are created + * automatically by the {@link Image_Graph_Plotarea} constructor unless + * explicitly defined otherwise + * + * @param int $type The type (direction) of the Axis, use IMAGE_GRAPH_AXIS_X + * for an X-axis (default, may be omitted) and IMAGE_GRAPH_AXIS_Y for Y- + * axis) + */ + function Image_Graph_Axis($type = IMAGE_GRAPH_AXIS_X) + { + parent::Image_Graph_Element(); + $this->_type = $type; + $this->_fillStyle = 'black'; + } + + /** + * Push the values by 0.5 (for bar and step chart) + * + * @access private + */ + function _pushValues() + { + $this->_pushValues = true; + } + + /** + * Sets the axis padding for a given position ('low' or 'high') + * @param string $where The position + * @param int $value The number of pixels to "pad" + * @access private + */ + function _setAxisPadding($where, $value) + { + $this->_axisPadding[$where] = $value; + } + + /** + * Gets the font of the title. + * + * 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 _getTitleFont() + { + if ($this->_titleFont === false) { + if ($this->_defaultFontOptions !== false) { + return $this->_defaultFontOptions; + } else { + return $this->_getFont(); + } + } else { + if (is_object($this->_titleFont)) { + return $this->_titleFont->_getFont(); + } elseif (is_array($this->_titleFont)) { + return $this->_getFont($this->_titleFont); + } elseif (is_int($this->_titleFont)) { + return $this->_getFont(array('size' => $this->_titleFont)); + } + } + return array(); + } + + /** + * Shows a label for the the specified values. + * + * Allowed values are combinations of: + * <ul> + * <li>IMAGE_GRAPH_LABEL_MINIMUM + * <li>IMAGE_GRAPH_LABEL_ZERO + * <li>IMAGE_GRAPH_LABEL_MAXIMUM + * </ul> + * By default none of these are shows on the axis + * + * @param int $value The values to show labels for + */ + function showLabel($value) + { + $this->_showLabelMinimum = ($value & IMAGE_GRAPH_LABEL_MINIMUM); + $this->_showLabelZero = ($value & IMAGE_GRAPH_LABEL_ZERO); + $this->_showLabelMaximum = ($value & IMAGE_GRAPH_LABEL_MAXIMUM); + } + + /** + * Sets a data preprocessor for formatting the axis labels + * + * @param Image_Graph_DataPreprocessor $dataPreProcessor The data preprocessor + * @see Image_Graph_DataPreprocessor + */ + function setDataPreProcessor(& $dataPreProcessor) + { + $this->_dataPreProcessor =& $dataPreProcessor; + } + + /** + * Gets the minimum value the axis will show + * + * @return double The minumum value + * @access private + */ + function _getMinimum() + { + return $this->_minimum; + } + + /** + * Gets the maximum value the axis will show + * + * @return double The maximum value + * @access private + */ + function _getMaximum() + { + return $this->_maximum; + } + + /** + * Sets the minimum value the axis will show + * + * @param double $minimum The minumum value to use on the axis + * @access private + */ + function _setMinimum($minimum) + { + if ($this->_minimum === false) { + $this->forceMinimum($minimum, false); + } else { + $this->forceMinimum(min($this->_minimum, $minimum), false); + } + } + + /** + * Sets the maximum value the axis will show + * + * @param double $maximum The maximum value to use on the axis + * @access private + */ + function _setMaximum($maximum) + { + if ($this->_maximum === false) { + $this->forceMaximum($maximum, false); + } else { + $this->forceMaximum(max($this->_maximum, $maximum), false); + } + } + + /** + * Forces the minimum value of the axis + * + * @param double $minimum The minumum value to use on the axis + * @param bool $userEnforce This value should not be set, used internally + */ + function forceMinimum($minimum, $userEnforce = true) + { + if (($userEnforce) || (!$this->_minimumSet)) { + $this->_minimum = $minimum; + $this->_minimumSet = $userEnforce; + } + $this->_calcLabelInterval(); + } + + /** + * Forces the maximum value of the axis + * + * @param double $maximum The maximum value to use on the axis + * @param bool $userEnforce This value should not be set, used internally + */ + function forceMaximum($maximum, $userEnforce = true) + { + if (($userEnforce) || (!$this->_maximumSet)) { + $this->_maximum = $maximum; + $this->_maximumSet = $userEnforce; + } + $this->_calcLabelInterval(); + } + + /** + * Show an arrow head on the 'end' of the axis + */ + function showArrow() + { + $this->_showArrow = true; + } + + /** + * Do not show an arrow head on the 'end' of the axis (default) + */ + function hideArrow() + { + $this->_showArrow = false; + } + + /** + * Return the label distance. + * + * @param int $level The label level to return the distance of + * @return int The distance between 2 adjacent labels + * @access private + */ + function _labelDistance($level = 1) + { + $l1 = $this->_getNextLabel(false, $level); + $l2 = $this->_getNextLabel($l1, $level);; + return abs($this->_point($l2) - $this->_point($l1)); + } + + /** + * Sets an interval for when labels are shown on the axis. + * + * By default 'auto' is used, forcing the axis to calculate a approximate + * best label interval to be used. Specify an array to use user-defined + * values for labels. + * + * @param mixed $labelInterval The interval with which labels are shown + * @param int $level The label level to set the interval on + */ + function setLabelInterval($labelInterval = 'auto', $level = 1) + { + if (!isset($this->_labelOptions[$level])) { + $this->_labelOptions[$level] = array(); + } + + if ($labelInterval === 'auto') { + $this->_labelOptions[$level]['type'] = 'auto'; + $this->_calcLabelInterval(); + } else { + $this->_labelOptions[$level]['type'] = 'manual'; + $this->_labelOptions[$level]['interval'] = $labelInterval; + } + } + + /** + * Sets options for the label at a specific level. + * + * Possible options are: + * + * 'showtext' true or false whether label text should be shown or not + * + * 'showoffset' should the label be shown at an offset, i.e. should the + * label be shown at a position so that it does not overlap with prior + * levels. Only applies to multilevel labels with text + * + * 'font' The font options as an associated array + * + * 'position' The position at which the labels are written ('inside' or + * 'outside' the axis). NB! This relative position only applies to the + * default location of the axis, i.e. if an x-axis is inverted then + * 'outside' still refers to the "left" side of a normal y-axis (since this + * is normally 'outside') but the actual output will be labels on the + * "inside"! + * + * 'format' To format the label text according to a sprintf statement + * + * 'dateformat' To format the label as a date, fx. j. M Y = 29. Jun 2005 + * + * @param string $option The label option name (see detailed description + * for possible values) + * @param mixed $value The value for the option + * @param int $level The label level to set the interval on + */ + function setLabelOption($option, $value, $level = 1) + { + if (!isset($this->_labelOptions[$level])) { + $this->_labelOptions[$level] = array('type' => 'auto'); + } + + $this->_labelOptions[$level][$option] = $value; + } + + /** + * Sets options for the label at a specific level. + * + * The possible options are specified in {@link Image_Graph_Axis:: + * setLabelOption()}. + * + * @param array $options An assciated array with label options + * @param int $level The label level to set the interval on + */ + function setLabelOptions($options, $level = 1) + { + if (is_array($options)) { + if (isset($this->_labelOptions[$level])) { + $this->_labelOptions[$level] = array_merge($this->_labelOptions[$level], $options); + } else { + $this->_labelOptions[$level] = $options; + } + + } + } + + /** + * Sets the title of this axis. + * + * This is used as an alternative (maybe better) method, than using layout's + * for axis-title generation. + * + * To use the current propagated font, but just set it vertically, simply + * pass 'vertical' as second parameter for vertical alignment down-to-up or + * 'vertical2' for up-to-down alignment. + * + * @param string $title The title of this axis + * @param Image_Graph_Font $font The font used for the title + * @since 0.3.0dev2 + */ + function setTitle($title, $font = false) + { + $this->_title = $title; + if ($font === 'vertical') { + $this->_titleFont = array('vertical' => true, 'angle' => 90); + } elseif ($font === 'vertical2') { + $this->_titleFont = array('vertical' => true, 'angle' => 270); + } else { + $this->_titleFont =& $font; + } + } + + /** + * Sets a fixed "size" for the axis. + * + * If the axis is any type of y-axis the size relates to the width of the + * axis, if an x-axis is concerned the size is the height. + * + * @param int $size The fixed size of the axis + * @since 0.3.0dev5 + */ + function setFixedSize($size) + { + $this->_fixedSize = $size; + } + + /** + * Preprocessor for values, ie for using logarithmic axis + * + * @param double $value The value to preprocess + * @return double The preprocessed value + * @access private + */ + function _value($value) + { + return $value - $this->_getMinimum() + ($this->_pushValues ? 0.5 : 0); + } + + /** + * Apply the dataset to the axis + * + * @param Image_Graph_Dataset $dataset The dataset + * @access private + */ + function _applyDataset(&$dataset) + { + if ($this->_type == IMAGE_GRAPH_AXIS_X) { + $this->_setMinimum($dataset->minimumX()); + $this->_setMaximum($dataset->maximumX()); + } else { + $this->_setMinimum($dataset->minimumY()); + $this->_setMaximum($dataset->maximumY()); + } + } + + /** + * Get the pixel position represented by a value on the canvas + * + * @param double $value the value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _point($value) + { + if ((($this->_type == IMAGE_GRAPH_AXIS_X) && (!$this->_transpose)) || + (($this->_type != IMAGE_GRAPH_AXIS_X) && ($this->_transpose))) + { + if ($this->_invert) { + return max($this->_left, $this->_right - $this->_axisPadding['high'] - $this->_delta * $this->_value($value)); + } else { + return min($this->_right, $this->_left + $this->_axisPadding['low'] + $this->_delta * $this->_value($value)); + } + } else { + if ($this->_invert) { + return min($this->_bottom, $this->_top + $this->_axisPadding['high'] + $this->_delta * $this->_value($value)); + } else { + return max($this->_top, $this->_bottom - $this->_axisPadding['low'] - $this->_delta * $this->_value($value)); + } + } + } + + + /** + * Get the axis intersection pixel position + * + * This is only to be called prior to output! I.e. between the user + * invokation of Image_Graph::done() and any actual output is performed. + * This is because it can change the axis range. + * + * @param double $value the intersection value to get the pixel-point for + * @return double The pixel position along the axis + * @access private + */ + function _intersectPoint($value) + { + + if (($value === 'min') || ($value < $this->_getMinimum())) { + if ($this->_type == IMAGE_GRAPH_AXIS_X) { + if ($this->_invert) { + return ($this->_transpose ? $this->_top : $this->_right); + } else { + return ($this->_transpose ? $this->_bottom : $this->_left); + } + } else { + if ($this->_invert) { + return ($this->_transpose ? $this->_right : $this->_top); + } else { + return ($this->_transpose ? $this->_left : $this->_bottom); + } + } + } elseif (($value === 'max') || ($value > $this->_getMaximum())) { + if ($this->_type == IMAGE_GRAPH_AXIS_X) { + if ($this->_invert) { + return ($this->_transpose ? $this->_bottom : $this->_left); + } else { + return ($this->_transpose ? $this->_top : $this->_right); + } + } else { + if ($this->_invert) { + return ($this->_transpose ? $this->_left : $this->_bottom); + } else { + return ($this->_transpose ? $this->_right : $this->_top); + } + } + } + + return $this->_point($value); + } + + /** + * Calculate the delta value (the number of pixels representing one unit + * on the axis) + * + * @return double The label interval + * @access private + */ + function _calcDelta() + { + if ($this->_axisValueSpan == 0) { + $this->_delta = false; + } elseif ($this->_type == IMAGE_GRAPH_AXIS_X) { + $this->_delta = (($this->_transpose ? $this->height() : $this->width()) - ($this->_axisPadding['low'] + $this->_axisPadding['high'])) / ($this->_axisValueSpan + ($this->_pushValues ? 1 : 0)); + } else { + $this->_delta = (($this->_transpose ? $this->width() : $this->height()) - ($this->_axisPadding['low'] + $this->_axisPadding['high'])) / ($this->_axisValueSpan + ($this->_pushValues ? 1 : 0)); + } + } + + /** + * Calculate the label interval + * + * If explicitly defined this will be calucated to an approximate best. + * + * @return double The label interval + * @access private + */ + function _calcLabelInterval() + { + $min = $this->_getMinimum(); + $max = $this->_getMaximum(); + + $this->_axisValueSpan = $this->_axisSpan = abs($max - $min); + + if ((!empty($min)) && (!empty($max)) && ($min > $max)) { + $this->_labelOptions[1]['interval'] = 1; + return true; + } + + $span = 0; + foreach($this->_labelOptions as $level => $labelOptions) { + if ((!isset($labelOptions['type'])) || ($labelOptions['type'] !== 'auto')) { + $span = false; + } elseif ($level == 1) { + $span = $this->_axisValueSpan; + } else { + $l1 = $this->_getNextLabel(false, $level - 1); + $l2 = $this->_getNextLabel($l1, $level - 1); + if ((!is_numeric($l1)) || (!is_numeric($l2))) { + $span == false; + } else { + $span = $l2 - $l1; + } + } + + if ($span !== false) { + $interval = pow(10, floor(log10($span))); + + if ($interval == 0) { + $interval = 1; + } + + if ((($span) / $interval) < 3) { + $interval = $interval / 4; + } elseif ((($span) / $interval) < 5) { + $interval = $interval / 2; + } elseif ((($span) / $interval) > 10) { + $interval = $interval * 2; + } + + if (($interval -floor($interval) == 0.5) && ($interval != 0.5)) { + $interval = floor($interval); + } + + // just to be 100% sure that an interval of 0 is not returned some + // additional checks are performed + if ($interval == 0) { + $interval = ($span) / 5; + } + + if ($interval == 0) { + $interval = 1; + } + + $this->_labelOptions[$level]['interval'] = $interval; + } + } + } + + /** + * Get next label point + * + * @param doubt $currentLabel The current label, if omitted or false, the + * first is returned + * @param int $level The label level to get the next label from + * @return double The next label point + * @access private + */ + function _getNextLabel($currentLabel = false, $level = 1) + { + if (!isset($this->_labelOptions[$level])) { + return false; + } + + if (is_array($this->_labelOptions[$level]['interval'])) { + if ($currentLabel === false) { + reset($this->_labelOptions[$level]['interval']); + } + + if (list(, $label) = each($this->_labelOptions[$level]['interval'])) { + return $label; + } else { + return false; + } + } else { + $li = $this->_labelInterval($level); + if (($this->_axisSpan == 0) || ($this->_axisValueSpan == 0) || + ($li == 0) + ) { + return false; + } + + $labelInterval = $this->_axisSpan / ($this->_axisValueSpan / $li); + + if ($labelInterval == 0) { + return false; + } + + if ($currentLabel === false) { + $label = ((int) ($this->_getMinimum() / $labelInterval)) * + $labelInterval - $labelInterval; + while ($label < $this->_getMinimum()) { + $label += $labelInterval; + } + return $label; + } else { + if ($currentLabel + $labelInterval > $this->_getMaximum()) { + return false; + } else { + return $currentLabel + $labelInterval; + } + } + } + } + + /** + * Get the interval with which labels are shown on the axis. + * + * If explicitly defined this will be calucated to an approximate best. + * + * @param int $level The label level to get the label interval for + * @return double The label interval + * @access private + */ + function _labelInterval($level = 1) + { + if ((!isset($this->_labelOptions[$level])) || + (!isset($this->_labelOptions[$level]['interval'])) + ) { + return 1; + } + + return (is_array($this->_labelOptions[$level]['interval']) + ? 1 + : $this->_labelOptions[$level]['interval'] + ); + } + + /** + * Get the size in pixels of the axis. + * + * For an x-axis this is the width of the axis including labels, and for an + * y-axis it is the corrresponding height + * + * @return int The size of the axis + * @access private + */ + function _size() + { + if (!$this->_visible) { + return 0; + } + + if ($this->_fixedSize !== false) { + return $this->_fixedSize; + } + + krsort($this->_labelOptions); + + $totalMaxSize = 0; + + foreach ($this->_labelOptions as $level => $labelOptions) { + if ((isset($labelOptions['showoffset'])) && ($labelOptions['showoffset'] === true)) { + $this->_labelOptions[$level]['offset'] += $totalMaxSize; + } elseif (!isset($this->_labelOptions[$level]['offset'])) { + $this->_labelOptions[$level]['offset'] = 0; + } + if ( + (isset($labelOptions['showtext'])) && + ($labelOptions['showtext'] === true) && + ( + (!isset($labelOptions['position'])) || + ($labelOptions['position'] == 'outside') + ) + ) { + if (isset($labelOptions['font'])) { + $font = $this->_getFont($labelOptions['font']); + } else { + if ($this->_defaultFontOptions !== false) { + $font = $this->_defaultFontOptions; + } else { + $font = $this->_getFont(); + } + } + $this->_canvas->setFont($font); + + $value = false; + $maxSize = 0; + while (($value = $this->_getNextLabel($value, $level)) !== false) { + if ((abs($value) > 0.0001) && ($value > $this->_getMinimum()) && + ($value < $this->_getMaximum())) + { + if (is_object($this->_dataPreProcessor)) { + $labelText = $this->_dataPreProcessor->_process($value); + } elseif (isset($labelOptions['format'])) { + $labelText = sprintf($labelOptions['format'], $value); + } elseif (isset($labelOptions['dateformat'])) { + $labelText = date($labelOptions['dateformat'], $value); + } else { + $labelText = $value; + } + + if ((($this->_type == IMAGE_GRAPH_AXIS_X) && (!$this->_transpose)) || + (($this->_type != IMAGE_GRAPH_AXIS_X) && ($this->_transpose))) + { + $maxSize = max($maxSize, $this->_canvas->textHeight($labelText)); + } else { + $maxSize = max($maxSize, $this->_canvas->textWidth($labelText)); + } + } + } + if ((isset($labelOptions['showoffset'])) && ($labelOptions['showoffset'] === true)) { + $totalMaxSize += $maxSize; + } else { + $totalMaxSize = max($totalMaxSize, $maxSize); + } + } + } + + if ($this->_title) { + $this->_canvas->setFont($this->_getTitleFont()); + + if ((($this->_type == IMAGE_GRAPH_AXIS_X) && (!$this->_transpose)) || + (($this->_type != IMAGE_GRAPH_AXIS_X) && ($this->_transpose))) + { + $totalMaxSize += $this->_canvas->textHeight($this->_title); + } else { + $totalMaxSize += $this->_canvas->textWidth($this->_title); + } + $totalMaxSize += 10; + } + + return $totalMaxSize + 3; + } + + /** + * Adds a mark to the axis at the specified value + * + * @param double $value The value + * @param double $value2 The second value (for a ranged mark) + */ + function addMark($value, $value2 = false, $text = false) + { + if ($value2 === false) { + $this->_marks[] = $value; + } else { + $this->_marks[] = array($value, $value2); + } + } + + /** + * Is the axis numeric or not? + * + * @return bool True if numeric, false if not + * @access private + */ + function _isNumeric() + { + return true; + } + + /** + * Set the major tick appearance. + * + * The positions are specified in pixels relative to the axis, meaning that + * a value of -1 for start will draw the major tick 'line' starting at 1 + * pixel outside (negative) value the axis (i.e. below an x-axis and to the + * left of a normal y-axis). + * + * @param int $start The start position relative to the axis + * @param int $end The end position relative to the axis + * @param int $level The label level to set the tick options for + * @since 0.3.0dev2 + */ + function setTickOptions($start, $end, $level = 1) + { + if (!isset($this->_labelOptions[$level])) { + $this->_labelOptions[$level] = array(); + } + + $this->_labelOptions[$level]['tick'] = array( + 'start' => $start, + 'end' => $end + ); + } + + /** + * Invert the axis direction + * + * If the minimum values are normally displayed fx. at the bottom setting + * axis inversion to true, will cause the minimum values to be displayed at + * the top and maximum at the bottom. + * + * @param bool $invert True if the axis is to be inverted, false if not + * @since 0.3.0dev3 + */ + function setInverted($invert) + { + $this->_invert = $invert; + } + + /** + * Set axis intersection. + * + * Sets the value at which the axis intersects other axis, fx. at which Y- + * value the x-axis intersects the y-axis (normally at 0). + * + * Possible values are 'default', 'min', 'max' or a number between axis min + * and max (the value will automatically be limited to this range). + * + * For a coordinate system with 2 y-axis, the x-axis can either intersect + * the primary or the secondary y-axis. To make the x-axis intersect the + * secondary y-axis at a given value pass IMAGE_GRAPH_AXIS_Y_SECONDARY as + * second parameter. + * + * @param mixed $intersection The value at which the axis intersect the + * 'other' axis + * @param mixed $axis The axis to intersect. Only applies to x-axis with + * both a primary and secondary y-axis available. + * @since 0.3.0dev2 + */ + function setAxisIntersection($intersection, $axis = 'default') + { + if ($axis == 'x') { + $axis = IMAGE_GRAPH_AXIS_X; + } elseif ($axis == 'y') { + $axis = IMAGE_GRAPH_AXIS_Y; + } elseif ($axis == 'ysec') { + $axis = IMAGE_GRAPH_AXIS_Y_SECONDARY; + } + $this->_intersect = array( + 'value' => $intersection, + 'axis' => $axis + ); + } + + /** + * Get axis intersection data. + * + * @return array An array with the axis intersection data. + * @since 0.3.0dev2 + * @access private + */ + function _getAxisIntersection() + { + $value = $this->_intersect['value']; + $axis = $this->_intersect['axis']; + if (($this->_type == IMAGE_GRAPH_AXIS_Y) + || ($this->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY) + ) { + $axis = IMAGE_GRAPH_AXIS_X; + } elseif ($axis == 'default') { + $axis = IMAGE_GRAPH_AXIS_Y; + } + + if ($value === 'default') { + switch ($this->_type) { + case IMAGE_GRAPH_AXIS_Y: + $value = 'min'; + break; + case IMAGE_GRAPH_AXIS_Y_SECONDARY: + $value = 'max'; + break; + case IMAGE_GRAPH_AXIS_X: + $value = 0; + break; + } + } + + return array('value' => $value, 'axis' => $axis); + } + + /** + * Resets the elements + * + * @access private + */ + function _reset() + { + parent::_reset(); + $this->_labelText = array(); + } + + /** + * Output an axis tick mark. + * + * @param int $value The value to output + * @param int $level The label level to draw the tick for + * @access private + */ + function _drawTick($value, $level = 1) + { + if (isset($this->_labelOptions[$level])) { + $labelOptions = $this->_labelOptions[$level]; + $labelPosition = $this->_point($value); + + if (isset($labelOptions['offset'])) { + $offset = $labelOptions['offset']; + } else { + $offset = 0; + } + + if ((isset($labelOptions['showtext'])) && ($labelOptions['showtext'] === true)) { + if (is_object($this->_dataPreProcessor)) { + $labelText = $this->_dataPreProcessor->_process($value); + } elseif (isset($labelOptions['format'])) { + $labelText = sprintf($labelOptions['format'], $value); + } elseif (isset($labelOptions['dateformat'])) { + $labelText = date($labelOptions['dateformat'], $value); + } else { + $labelText = $value; + } + + if (!in_array($labelText, $this->_labelText)) { + $this->_labelText[] = $labelText; + + if (isset($labelOptions['font'])) { + $font = $this->_getFont($labelOptions['font']); + } else { + if ($this->_defaultFontOptions !== false) { + $font = $this->_defaultFontOptions; + } else { + $font = $this->_getFont(); + } + } + $this->_canvas->setFont($font); + + if ( + (isset($labelOptions['position'])) && + ($labelOptions['position'] == 'inside') + ) { + $labelInside = true; + } else { + $labelInside = false; + } + + if ($this->_type == IMAGE_GRAPH_AXIS_Y) { + if ($this->_transpose) { + if ($labelInside) { + $this->write( + $labelPosition, + $this->_top - 3 - $offset, + $labelText, + IMAGE_GRAPH_ALIGN_BOTTOM | IMAGE_GRAPH_ALIGN_CENTER_X, + $font + ); + } else { + $this->write( + $labelPosition, + $this->_top + 6 + $offset + $font['size'] * (substr_count($labelText, "\n") + 1), + $labelText, + IMAGE_GRAPH_ALIGN_BOTTOM | IMAGE_GRAPH_ALIGN_CENTER_X, + $font + ); + } + } + else { + if ($labelInside) { + $this->write( + $this->_right + 3 + $offset, + $labelPosition, + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_LEFT, + $font + ); + } else { + $this->write( + $this->_right - 3 - $offset, + $labelPosition, + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_RIGHT, + $font + ); + } + } + } elseif ($this->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY) { + if ($this->_transpose) { + if ($labelInside) { + $this->write( + $labelPosition, + $this->_bottom + 6 + $offset + $font['size'] * (substr_count($labelText, "\n") + 1), + $labelText, + IMAGE_GRAPH_ALIGN_BOTTOM | IMAGE_GRAPH_ALIGN_CENTER_X, + $font + ); + } else { + $this->write( + $labelPosition, + $this->_bottom - 3 - $offset, + $labelText, + IMAGE_GRAPH_ALIGN_BOTTOM | IMAGE_GRAPH_ALIGN_CENTER_X, + $font + ); + } + } + else { + if ($labelInside) { + $this->write( + $this->_left - 3 - $offset, + $labelPosition, + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_RIGHT, + $font + ); + } else { + $this->write( + $this->_left + 3 + $offset, + $labelPosition, + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_LEFT, + $font + ); + } + } + } else { + if ($this->_transpose) { + if ($labelInside) { + $this->write( + $this->_right + 3 + $offset, + $labelPosition, + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_LEFT, + $font + ); + } else { + $this->write( + $this->_right - 3 - $offset, + $labelPosition, + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_Y | IMAGE_GRAPH_ALIGN_RIGHT, + $font + ); + } + } + else { + if ($labelInside === true) { + $this->write( + $labelPosition, + $this->_top - 3 - $offset, + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_X | IMAGE_GRAPH_ALIGN_BOTTOM, + $font + ); + } else { + $this->write( + $labelPosition, + $this->_top + 6 + $offset + $font['size'] * (substr_count($labelText, "\n") + 1), + $labelText, + IMAGE_GRAPH_ALIGN_CENTER_X | IMAGE_GRAPH_ALIGN_BOTTOM, + $font + ); + } + } + } + } + } + + $tickColor = false; + if (isset($this->_labelOptions[$level]['tick'])) { + if (isset($this->_labelOptions[$level]['tick']['start'])) { + $tickStart = $this->_labelOptions[$level]['tick']['start']; + } else { + $tickStart = false; + } + + if (isset($this->_labelOptions[$level]['tick']['end'])) { + $tickEnd = $this->_labelOptions[$level]['tick']['end']; + } else { + $tickEnd = false; + } + + if ((isset($this->_labelOptions[$level]['tick']['color'])) && ($this->_labelOptions[$level]['tick']['color'] !== false)) { + $tickColor = $this->_labelOptions[$level]['tick']['color']; + } + } + + if ($tickStart === false) { + $tickStart = -2; + } + + if ($tickEnd === false) { + $tickEnd = 2; + } + + if ($tickColor !== false) { + $this->_canvas->setLineColor($tickColor); + } + else { + $this->_getLineStyle(); + } + + if ($this->_type == IMAGE_GRAPH_AXIS_Y) { + if ($tickStart === 'auto') { + $tickStart = -$offset; + } + if ($this->_transpose) { + $this->_canvas->line( + array( + 'x0' => $labelPosition, + 'y0' => $this->_top + $tickStart, + 'x1' => $labelPosition, + 'y1' => $this->_top + $tickEnd + ) + ); + } + else { + $this->_canvas->line( + array( + 'x0' => $this->_right + $tickStart, + 'y0' => $labelPosition, + 'x1' => $this->_right + $tickEnd, + 'y1' => $labelPosition + ) + ); + } + } elseif ($this->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY) { + if ($tickStart === 'auto') { + $tickStart = $offset; + } + if ($this->_transpose) { + $this->_canvas->line( + array( + 'x0' => $labelPosition, + 'y0' => $this->_bottom - $tickStart, + 'x1' => $labelPosition, + 'y1' => $this->_bottom - $tickEnd + ) + ); + } + else { + $this->_canvas->line( + array( + 'x0' => $this->_left - $tickStart, + 'y0' => $labelPosition, + 'x1' => $this->_left - $tickEnd, + 'y1' => $labelPosition + ) + ); + } + } else { + if ($tickStart === 'auto') { + $tickStart = $offset; + } + if ($this->_transpose) { + $this->_canvas->line( + array( + 'x0' => $this->_right + $tickStart, + 'y0' => $labelPosition, + 'x1' => $this->_right + $tickEnd, + 'y1' => $labelPosition + ) + ); + } + else { + $this->_canvas->line( + array( + 'x0' => $labelPosition, + 'y0' => $this->_top - $tickStart, + 'x1' => $labelPosition, + 'y1' => $this->_top - $tickEnd + ) + ); + } + } + } + } + + /** + * Draws axis lines. + * + * @access private + */ + function _drawAxisLines() + { + if ($this->_type == IMAGE_GRAPH_AXIS_X) { + $this->_getLineStyle(); + $this->_getFillStyle(); + + if ($this->_transpose) { + $data = array( + 'x0' => $this->_right, + 'y0' => $this->_top, + 'x1' => $this->_right, + 'y1' => $this->_bottom + ); + } else { + $data = array( + 'x0' => $this->_left, + 'y0' => $this->_top, + 'x1' => $this->_right, + 'y1' => $this->_top + ); + } + + if ($this->_showArrow) { + if ($this->_getMaximum() <= 0) { + $data['end0'] = 'arrow2'; + $data['size0'] = 7; + } + else { + $data['end1'] = 'arrow2'; + $data['size1'] = 7; + } + } + + $this->_canvas->line($data); + + if ($this->_title) { + if (!$this->_transpose) { + $y = $this->_bottom; + $x = $this->_left + $this->width() / 2; + $this->write($x, $y, $this->_title, IMAGE_GRAPH_ALIGN_CENTER_X + IMAGE_GRAPH_ALIGN_BOTTOM, $this->_getTitleFont()); + } + else { + $y = $this->_top + $this->height() / 2; + $x = $this->_left; + $this->write($x, $y, $this->_title, IMAGE_GRAPH_ALIGN_LEFT + IMAGE_GRAPH_ALIGN_CENTER_Y, $this->_getTitleFont()); + } + } + } elseif ($this->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY) { + $this->_getLineStyle(); + $this->_getFillStyle(); + + if ($this->_transpose) { + $data = array( + 'x0' => $this->_left, + 'y0' => $this->_bottom, + 'x1' => $this->_right, + 'y1' => $this->_bottom + ); + } else { + $data = array( + 'x0' => $this->_left, + 'y0' => $this->_bottom, + 'x1' => $this->_left, + 'y1' => $this->_top + ); + } + if ($this->_showArrow) { + if ($this->_getMaximum() <= 0) { + $data['end0'] = 'arrow2'; + $data['size0'] = 7; + } + else { + $data['end1'] = 'arrow2'; + $data['size1'] = 7; + } + } + $this->_canvas->line($data); + + if ($this->_title) { + if ($this->_transpose) { + $y = $this->_top; + $x = $this->_left + $this->width() / 2; + $this->write($x, $y, $this->_title, IMAGE_GRAPH_ALIGN_CENTER_X + IMAGE_GRAPH_ALIGN_TOP, $this->_getTitleFont()); + } + else { + $y = $this->_top + $this->height() / 2; + $x = $this->_right; + $this->write($x, $y, $this->_title, IMAGE_GRAPH_ALIGN_RIGHT + IMAGE_GRAPH_ALIGN_CENTER_Y, $this->_getTitleFont()); + } + } + } else { + $this->_getLineStyle(); + $this->_getFillStyle(); + + if ($this->_transpose) { + $data = array( + 'x0' => $this->_left, + 'y0' => $this->_top, + 'x1' => $this->_right, + 'y1' => $this->_top + ); + } else { + $data = array( + 'x0' => $this->_right, + 'y0' => $this->_bottom, + 'x1' => $this->_right, + 'y1' => $this->_top + ); + } + if ($this->_showArrow) { + if ($this->_getMaximum() <= 0) { + $data['end0'] = 'arrow2'; + $data['size0'] = 7; + } + else { + $data['end1'] = 'arrow2'; + $data['size1'] = 7; + } + } + $this->_canvas->line($data); + + if ($this->_title) { + if ($this->_transpose) { + $y = $this->_bottom; + $x = $this->_left + $this->width() / 2; + $this->write($x, $y, $this->_title, IMAGE_GRAPH_ALIGN_CENTER_X + IMAGE_GRAPH_ALIGN_BOTTOM, $this->_getTitleFont()); + } + else { + $y = $this->_top + $this->height() / 2; + $x = $this->_left; + $this->write($x, $y, $this->_title, IMAGE_GRAPH_ALIGN_LEFT + IMAGE_GRAPH_ALIGN_CENTER_Y, $this->_getTitleFont()); + } + } + } + } + + /** + * Causes the object to update all sub elements coordinates + * + * (Image_Graph_Common, does not itself have coordinates, this is basically + * an abstract method) + * + * @access private + */ + function _updateCoords() + { + parent::_updateCoords(); + $this->_calcDelta(); + } + + /** + * Output the axis + * + * @return bool Was the output 'good' (true) or 'bad' (false). + * @access private + */ + function _done() + { + $this->_canvas->startGroup(get_class($this)); + + if (parent::_done() === false) { + return false; + } + + $this->_drawAxisLines(); + + $this->_canvas->startGroup(get_class($this) . '_ticks'); + ksort($this->_labelOptions); + foreach ($this->_labelOptions as $level => $labelOption) { + $value = false; + while (($value = $this->_getNextLabel($value, $level)) !== false) { + if ((((abs($value) > 0.0001) || ($this->_showLabelZero)) && + (($value > $this->_getMinimum()) || ($this->_showLabelMinimum)) && + (($value < $this->_getMaximum()) || ($this->_showLabelMaximum))) && + ($value >= $this->_getMinimum()) && ($value <= $this->_getMaximum()) + ) { + $this->_drawTick($value, $level); + } + } + } + $this->_canvas->endGroup(); + + $tickStart = -3; + $tickEnd = 2; + + foreach ($this->_marks as $mark) { + if (is_array($mark)) { + if ($this->_type == IMAGE_GRAPH_AXIS_X) { + if ($this->_transpose) { + $x0 = $this->_right + $tickStart; + $y0 = $this->_point($mark[1]); + $x1 = $this->_right + $tickEnd; + $y1 = $this->_point($mark[0]); + } + else { + $x0 = $this->_point($mark[0]); + $y0 = $this->_top + $tickStart; + $x1 = $this->_point($mark[1]); + $y1 = $this->_top + $tickEnd; + } + } elseif ($this->_type == IMAGE_GRAPH_AXIS_Y) { + if ($this->_transpose) { + $x0 = $this->_point($mark[0]); + $y0 = $this->_top + $tickStart; + $x1 = $this->_point($mark[1]); + $y1 = $this->_top + $tickEnd; + } + else { + $x0 = $this->_right + $tickStart; + $y0 = $this->_point($mark[1]); + $x1 = $this->_right + $tickEnd; + $y1 = $this->_point($mark[0]); + } + } elseif ($this->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY) { + if ($this->_transpose) { + $x0 = $this->_point($mark[0]); + $y0 = $this->_bottom + $tickStart; + $x1 = $this->_point($mark[1]); + $y1 = $this->_bottom + $tickEnd; + } + else { + $x0 = $this->_left + $tickStart; + $y0 = $this->_point($mark[1]); + $x1 = $this->_left + $tickEnd; + $y1 = $this->_point($mark[0]); + } + } + $this->_getFillStyle(); + $this->_getLineStyle(); + $this->_canvas->rectangle(array('x0' => $x0, 'y0' => $y0, 'x1' => $x1, 'y1' => $y1)); + } else { + if ($this->_type == IMAGE_GRAPH_AXIS_X) { + if ($this->_transpose) { + $x0 = $this->_right + 5; + $y0 = $this->_point($mark); + $x1 = $this->_right + 15; + $y1 = $y0; + } + else { + $x0 = $this->_point($mark); + $y0 = $this->_top - 5; + $x1 = $x0; + $y1 = $this->_top - 15; + } + } elseif ($this->_type == IMAGE_GRAPH_AXIS_Y) { + if ($this->_transpose) { + $x0 = $this->_point($mark); + $y0 = $this->_top - 5; + $x1 = $x0; + $y1 = $this->_top - 15; + } + else { + $x0 = $this->_right + 5; + $y0 = $this->_point($mark); + $x1 = $this->_right + 15; + $y1 = $y0; + } + } elseif ($this->_type == IMAGE_GRAPH_AXIS_Y_SECONDARY) { + if ($this->_transpose) { + $x0 = $this->_point($mark); + $y0 = $this->_bottom + 5; + $x1 = $x0; + $y1 = $this->_bottom + 15; + } + else { + $x0 = $this->_left - 5; + $y0 = $this->_point($mark); + $x1 = $this->_left - 15; + $y1 = $y0; + } + } + $this->_getFillStyle(); + $this->_getLineStyle(); + $this->_canvas->line( + array( + 'x0' => $x0, + 'y0' => $y0, + 'x1' => $x1, + 'y1' => $y1, + 'end0' => 'arrow2', + 'size0' => 5 + ) + ); + } + } + $this->_canvas->endGroup(); + + return true; + } + +} + +?>
\ No newline at end of file |