From 4427f59c63f88971deeaaa9809374df18d1eb288 Mon Sep 17 00:00:00 2001 From: Daniel Stefan Haischt Date: Thu, 27 Jul 2006 01:32:35 +0000 Subject: - added missing PEAR Image dependency --- packages/dspam/pear/Image/Graph/Plot.php | 824 +++++++++++++++++++++++++++++++ 1 file changed, 824 insertions(+) create mode 100644 packages/dspam/pear/Image/Graph/Plot.php (limited to 'packages/dspam/pear/Image/Graph/Plot.php') diff --git a/packages/dspam/pear/Image/Graph/Plot.php b/packages/dspam/pear/Image/Graph/Plot.php new file mode 100644 index 00000000..4a6c16d3 --- /dev/null +++ b/packages/dspam/pear/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$ + * @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: @package_version@ + * @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 -- cgit v1.2.3