diff options
author | Kore Nordmann <github@kore-nordmann.de> | 2006-07-11 08:49:26 +0000 |
---|---|---|
committer | Kore Nordmann <github@kore-nordmann.de> | 2006-07-11 08:49:26 +0000 |
commit | 6f359d97e38932b0da23abb0940f32bf5380c0d8 (patch) | |
tree | bc6221534bf65aa6777245e7f555e943cdd2bbc6 /src | |
parent | 663493a7224dc7869c6c63d770016f9fd8850e2a (diff) | |
download | zetacomponents-graph-6f359d97e38932b0da23abb0940f32bf5380c0d8.zip zetacomponents-graph-6f359d97e38932b0da23abb0940f32bf5380c0d8.tar.gz |
- Refactored ezcGraphRenderer
# Most test run again, but complete result is still errnous
Diffstat (limited to 'src')
-rw-r--r-- | src/axis/labeled.php | 32 | ||||
-rw-r--r-- | src/axis/numeric.php | 35 | ||||
-rw-r--r-- | src/charts/line.php | 134 | ||||
-rw-r--r-- | src/charts/pie.php | 134 | ||||
-rw-r--r-- | src/driver/gd.php | 7 | ||||
-rw-r--r-- | src/driver/verbose.php | 197 | ||||
-rw-r--r-- | src/element/axis.php | 313 | ||||
-rw-r--r-- | src/element/legend.php | 101 | ||||
-rw-r--r-- | src/element/text.php | 35 | ||||
-rw-r--r-- | src/graph.php | 4 | ||||
-rw-r--r-- | src/graph_autoload.php | 5 | ||||
-rw-r--r-- | src/interfaces/axis_label_renderer.php | 284 | ||||
-rw-r--r-- | src/interfaces/chart.php | 61 | ||||
-rw-r--r-- | src/interfaces/driver.php | 2 | ||||
-rw-r--r-- | src/interfaces/element.php | 101 | ||||
-rw-r--r-- | src/interfaces/palette.php | 6 | ||||
-rw-r--r-- | src/interfaces/renderer.php | 216 | ||||
-rw-r--r-- | src/options/chart.php | 10 | ||||
-rw-r--r-- | src/options/renderer_2d.php | 99 | ||||
-rw-r--r-- | src/palette/black.php | 2 | ||||
-rw-r--r-- | src/renderer/2d.php | 860 | ||||
-rw-r--r-- | src/renderer/axis_label_centered.php | 37 | ||||
-rw-r--r-- | src/renderer/axis_label_exact.php | 124 | ||||
-rw-r--r-- | src/structs/boundings.php | 6 |
24 files changed, 1866 insertions, 939 deletions
diff --git a/src/axis/labeled.php b/src/axis/labeled.php index fa18ecd..132200f 100644 --- a/src/axis/labeled.php +++ b/src/axis/labeled.php @@ -130,7 +130,7 @@ class ezcGraphChartElementLabeledAxis extends ezcGraphChartElementAxis * @param string $value Value to determine position for * @return float Position on chart */ - public function getCoordinate( ezcGraphBoundings $boundings, $value ) + public function getCoordinate( $value ) { if ( $value === false || $value === null || @@ -138,40 +138,24 @@ class ezcGraphChartElementLabeledAxis extends ezcGraphChartElementAxis { switch ( $this->position ) { - case ezcGraph::TOP: - return $boundings->y0 + - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ); - case ezcGraph::BOTTOM: - return $boundings->y1 - - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ); case ezcGraph::LEFT: - return $boundings->x0 + - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ); + case ezcGraph::TOP: + return 0.; case ezcGraph::RIGHT: - return $boundings->x1 - - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ); + case ezcGraph::BOTTOM: + return 1.; } } else { switch ( $this->position ) { + case ezcGraph::LEFT: case ezcGraph::TOP: - return $boundings->y0 + - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ) + - ( $boundings->y1 - $boundings->y0 ) * ( 1 - $this->axisSpace ) / ( count ( $this->labels ) - 1 ) * $key; + return (float) $key / ( count ( $this->labels ) - 1 ); case ezcGraph::BOTTOM: - return $boundings->y1 - - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ) - - ( $boundings->y1 - $boundings->y0 ) * ( 1 - $this->axisSpace ) / ( count ( $this->labels ) - 1 ) * $key; - case ezcGraph::LEFT: - return $boundings->x0 + - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ) + - ( $boundings->x1 - $boundings->x0 ) * ( 1 - $this->axisSpace ) / ( count ( $this->labels ) - 1 ) * $key; case ezcGraph::RIGHT: - return $boundings->x1 - - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ) - - ( $boundings->x1 - $boundings->x0 ) * ( 1 - $this->axisSpace ) / ( count ( $this->labels ) - 1 ) * $key; + return (float) 1 - $key / ( count ( $this->labels ) - 1 ); } } } diff --git a/src/axis/numeric.php b/src/axis/numeric.php index 1128134..f0cfc24 100644 --- a/src/axis/numeric.php +++ b/src/axis/numeric.php @@ -264,49 +264,34 @@ class ezcGraphChartElementNumericAxis extends ezcGraphChartElementAxis * @param float $value Value to determine position for * @return float Position on chart */ - public function getCoordinate( ezcGraphBoundings $boundings, $value ) + public function getCoordinate( $value ) { // Force typecast, because ( false < -100 ) results in (bool) true $floatValue = (float) $value; + if ( ( $value === false ) && ( ( $floatValue < $this->min ) || ( $floatValue > $this->max ) ) ) { switch ( $this->position ) { - case ezcGraph::TOP: - return $boundings->y0 + - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ); - case ezcGraph::BOTTOM: - return $boundings->y1 - - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ); case ezcGraph::LEFT: - return $boundings->x0 + - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ); + case ezcGraph::TOP: + return 0.; case ezcGraph::RIGHT: - return $boundings->x1 - - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ); + case ezcGraph::BOTTOM: + return 1.; } } else { switch ( $this->position ) { - case ezcGraph::TOP: - return $boundings->y0 + - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ) + - ( $value - $this->min ) / ( $this->max - $this->min ) * ( $boundings->y1 - $boundings-> y0 ) * ( 1 - $this->axisSpace ); - case ezcGraph::BOTTOM: - return $boundings->y1 - - ( $boundings->y1 - $boundings->y0 ) * ( $this->axisSpace / 2 ) - - ( $value - $this->min ) / ( $this->max - $this->min ) * ( $boundings->y1 - $boundings-> y0 ) * ( 1 - $this->axisSpace ); case ezcGraph::LEFT: - return $boundings->x0 + - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ) + - ( $value - $this->min ) / ( $this->max - $this->min ) * ( $boundings->x1 - $boundings-> x0 ) * ( 1 - $this->axisSpace ); + case ezcGraph::TOP: + return ( $value - $this->min ) / ( $this->max - $this->min ); case ezcGraph::RIGHT: - return $boundings->x1 - - ( $boundings->x1 - $boundings->x0 ) * ( $this->axisSpace / 2 ) - - ( $value - $this->min ) / ( $this->max - $this->min ) * ( $boundings->x1 - $boundings-> x0 ) * ( 1 - $this->axisSpace ); + case ezcGraph::BOTTOM: + return 1 - ( $value - $this->min ) / ( $this->max - $this->min ); } } } diff --git a/src/charts/line.php b/src/charts/line.php index 5f542cc..8983f4a 100644 --- a/src/charts/line.php +++ b/src/charts/line.php @@ -71,126 +71,39 @@ class ezcGraphLineChart extends ezcGraphChart protected function renderData( $renderer, $boundings ) { - $symbolSize = $this->options->symbolSize; - foreach ( $this->data as $data ) { + // Determine fill color for dataset if ( $this->options->fillLines !== false ) { $fillColor = clone $data->color->default; $fillColor->alpha = (int) round( ( 255 - $fillColor->alpha ) * ( $this->options->fillLines / 255 ) ); } + else + { + $fillColor = null; + } + // Draw lines for dataset $lastPoint = false; - $lastKey = false; - $lastValue = false; foreach ( $data as $key => $value ) { $point = new ezcGraphCoordinate( - (int) round( $this->elements['xAxis']->getCoordinate( $boundings, $key ) ), - (int) round( $this->elements['yAxis']->getCoordinate( $boundings, $value ) ) + $this->elements['xAxis']->getCoordinate( $key ), + $this->elements['yAxis']->getCoordinate( $value ) ); - // Fill the line - if ( $lastPoint !== false && $this->options->fillLines !== false ) - { - $axisPosition = (int) round( $this->elements['yAxis']->getCoordinate( $boundings, false ) ); - - $lastAxisPoint = new ezcGraphCoordinate( - (int) round( $this->elements['xAxis']->getCoordinate( $boundings, $lastKey ) ), - $axisPosition - ); - $axisPoint = new ezcGraphCoordinate( - (int) round( $this->elements['xAxis']->getCoordinate( $boundings, $key ) ), - $axisPosition - ); - - if ( ( $value == 0 ) || - ( $lastValue == 0 ) || - ( $value / abs( $value ) == $lastValue / abs( $lastValue ) ) ) - { - // Values have the same sign, so that the line do not cross any axes - $renderer->drawPolygon( - array( - $lastPoint, - $point, - $axisPoint, - $lastAxisPoint, - ), - $fillColor, - true - ); - } - else - { - // Draw two polygones to consider cutting point with axis - $diffOne = abs( $axisPosition - $lastPoint->y ); - $diffTwo = abs( $axisPosition - $point->y ); - - // Switch values, if first is greater then second - $cuttingPosition = $diffOne / ( $diffTwo + $diffOne ); - - // Calculate cutting point - $cuttingPoint = new ezcGraphCoordinate( - (int) round( $lastAxisPoint->x + ( $axisPoint->x - $lastAxisPoint->x ) * $cuttingPosition ), - $axisPosition - ); - - // Finally draw polygons - $renderer->drawPolygon( - array( - $lastPoint, - $cuttingPoint, - $lastAxisPoint, - ), - $fillColor, - true - ); - $renderer->drawPolygon( - array( - $point, - $cuttingPoint, - $axisPoint, - ), - $fillColor, - true - ); - } - } - - // Draw line - if ( $lastPoint !== false ) - { - $renderer->drawLine( - $data->color->default, - $lastPoint, - $point, - $this->options->lineThickness - ); - } - - // Draw Symbol - $symbol = $data->symbol[$key]; - - $symbolPosition = new ezcGraphCoordinate( - $point->x - $symbolSize / 2, - $point->y - $symbolSize / 2 + $renderer->drawDataLine( + $boundings, + $data->color->default, + ( $lastPoint === false ? $point : $lastPoint ), + $point, + $data->symbol[$key], + $data->color[$key], + $fillColor ); - if ( $symbol != ezcGraph::NO_SYMBOL ) - { - $renderer->drawSymbol( - $data->color[$key], - $symbolPosition, - $symbolSize, - $symbolSize, - $symbol - ); - } - $lastPoint = $point; - $lastValue = $value; - $lastKey = $key; } } } @@ -239,9 +152,14 @@ class ezcGraphLineChart extends ezcGraphChart $boundings->y1 = $this->options->height; // Render border and background - $boundings = $this->renderBorder( $boundings ); - $boundings = $this->options->backgroundImage->render( $this->renderer, $boundings ); - $boundings = $this->renderBackground( $boundings ); + $boundings = $this->renderer->drawBox( + $boundings, + $this->options->background, + $this->options->border, + $this->options->borderWidth, + $this->options->margin, + $this->options->padding + ); // Render subelements foreach ( $this->elements as $name => $element ) @@ -257,11 +175,11 @@ class ezcGraphLineChart extends ezcGraphChart { case 'xAxis': // get Position of 0 on the Y-axis for orientation of the x-axis - $element->nullPosition = $this->elements['yAxis']->getCoordinate( $boundings, false ); + $element->nullPosition = $this->elements['yAxis']->getCoordinate( false ); break; case 'yAxis': // get Position of 0 on the X-axis for orientation of the y-axis - $element->nullPosition = $this->elements['xAxis']->getCoordinate( $boundings, false ); + $element->nullPosition = $this->elements['xAxis']->getCoordinate( false ); break; } $this->driver->options->font = $element->font; diff --git a/src/charts/pie.php b/src/charts/pie.php index 3dd397f..d163238 100644 --- a/src/charts/pie.php +++ b/src/charts/pie.php @@ -63,131 +63,18 @@ class ezcGraphPieChart extends ezcGraphChart { $sum += $value; } - - // Calculate position and size of pie - $center = new ezcGraphCoordinate( - (int) round( $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) / 2 ), - (int) round( $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) / 2 ) - ); - // Limit radius to fourth of width and half of height at maximum - $radius = min( - ( $boundings->x1 - $boundings->x0 ) / 4, - ( $boundings->y1 - $boundings->y0 ) / 2 - ); - - // Draw all data - $angle = 0.; - $labels = array(); + $angle = 0; foreach ( $dataset as $label => $value ) { $renderer->drawPieSegment( + $boundings, $dataset->color[$label], - $center, - $radius * ( 1 - $this->options->moveOut ), $angle, - $endAngle = $angle + $value / $sum * 360, - ( $dataset->highlight[$label] ? $radius * $this->options->moveOut : 0 ) + $angle += $value / $sum * 360, + $label, + $dataset->highlight[$label] ); - - // Determine position of label - $middle = $angle + ( $endAngle - $angle ) / 2; - $pieSegmentCenter = new ezcGraphCoordinate( - (int) round( cos( deg2rad( $middle ) ) * $radius + $center->x ), - (int) round( sin( deg2rad( $middle ) ) * $radius + $center->y ) - ); - - // Split labels up into left an right size and index them on their - // y position - $labels[(int) ($pieSegmentCenter->x > $center->x)][$pieSegmentCenter->y] = array( - new ezcGraphCoordinate( - (int) round( cos( deg2rad( $middle ) ) * $radius * 2 / 3 + $center->x ), - (int) round( sin( deg2rad( $middle ) ) * $radius * 2 / 3 + $center->y ) - ), - sprintf( $this->options->label, $label, $value, $value * 100 / $sum ) - ); - $angle = $endAngle; - } - - $labelHeight = (int) round( min( - ( $boundings->y1 - $boundings->y0 ) / count( $labels[0] ), - ( $boundings->y1 - $boundings->y0 ) / count( $labels[1] ), - ( $boundings->y1 - $boundings->y0 ) * $this->options->maxLabelHeight - ) ); - - $symbolSize = $this->options->symbolSize; - - // Finally draw labels - foreach ( $labels as $side => $labelPart ) - { - $minHeight = $boundings->y0; - $toShare = ( $boundings->y1 - $boundings->y0 ) - count( $labelPart ) * $labelHeight; - - // Sort to draw topmost label first - ksort( $labelPart ); - $sign = ( $side ? -1 : 1 ); - - foreach ( $labelPart as $height => $label ) - { - // Determine position of label - $minHeight += round( max( 0, $height - $minHeight ) / ( $boundings->y1 - $boundings->y0 ) * $toShare ); - $labelPosition = new ezcGraphCoordinate( - (int) round( - $center->x - - $sign * ( - cos ( asin ( ( $center->y - $minHeight - $labelHeight / 2 ) / $radius ) ) * $radius + - $symbolSize * (int) $this->options->showSymbol - ) - ), - (int) round( $minHeight + $labelHeight / 2 ) - ); - - if ( $this->options->showSymbol ) - { - // Draw label - $renderer->drawLine( - $this->options->font->color, - $label[0], - $labelPosition, - false - ); - - $renderer->drawSymbol( - $this->options->font->color, - new ezcGraphCoordinate( - $label[0]->x - $symbolSize / 2, - $label[0]->y - $symbolSize / 2 - ), - $symbolSize, - $symbolSize, - ezcGraph::BULLET - ); - $renderer->drawSymbol( - $this->options->font->color, - new ezcGraphCoordinate( - $labelPosition->x - $symbolSize / 2, - $labelPosition->y - $symbolSize / 2 - ), - $symbolSize, - $symbolSize, - ezcGraph::BULLET - ); - } - - $renderer->drawTextBox( - new ezcGraphCoordinate( - ( !$side ? $boundings->x0 : $labelPosition->x + $symbolSize ), - $minHeight - ), - $label[1], - (int) round( !$side ? $labelPosition->x - $boundings->x0 - $symbolSize : $boundings->x1 - $labelPosition->x - $symbolSize ), - $labelHeight, - ( !$side ? ezcGraph::RIGHT : ezcGraph::LEFT ) | ezcGraph::MIDDLE - ); - - // Add used space to minHeight - $minHeight += $labelHeight; - } } } @@ -216,9 +103,14 @@ class ezcGraphPieChart extends ezcGraphChart $boundings->y1 = $this->options->height; // Render border and background - $boundings = $this->renderBorder( $boundings ); - $boundings = $this->options->backgroundImage->render( $this->renderer, $boundings ); - $boundings = $this->renderBackground( $boundings ); + $boundings = $this->renderer->drawBox( + $boundings, + $this->options->background, + $this->options->border, + $this->options->borderWidth, + $this->options->margin, + $this->options->padding + ); // Render subelements foreach ( $this->elements as $name => $element ) diff --git a/src/driver/gd.php b/src/driver/gd.php index 922469d..e64826a 100644 --- a/src/driver/gd.php +++ b/src/driver/gd.php @@ -46,7 +46,12 @@ class ezcGraphGdDriver extends ezcGraphDriver $this->supersample( $this->options->width ), $this->supersample( $this->options->height ) ); - $bgColor = imagecolorallocate( $this->image, 255, 255, 255 ); + $bgColor = imagecolorallocatealpha( $this->image, 255, 255, 255, 127 ); + + // Prepare for alpha channels + imagealphablending( $this->image, true ); + imagesavealpha( $this->image, true ); + // Default to a white background imagefill( $this->image, 1, 1, $bgColor ); diff --git a/src/driver/verbose.php b/src/driver/verbose.php new file mode 100644 index 0000000..80867fd --- /dev/null +++ b/src/driver/verbose.php @@ -0,0 +1,197 @@ +<?php +/** + * File containing the ezcGraphSVGDriver class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Extension of the basic Driver package to utilize the SVGlib. + * + * @package Graph + */ + +class ezcGraphVerboseDriver extends ezcGraphDriver +{ + protected $call = 0; + + public function __construct() + { + echo "\n"; + } + + /** + * Draws a single polygon + * + * @param mixed $points + * @param ezcGraphColor $color + * @param mixed $filled + * @return void + */ + public function drawPolygon( array $points, ezcGraphColor $color, $filled = true, $thickness = 1 ) + { + $pointString = ''; + foreach ( $points as $point ) + { + $pointString .= sprintf( "\t( %.2f, %.2f )\n", $point->x, $point->y ); + } + + printf( "%03d: Draw %spolygon:\n%s", + $this->call++, + ( $filled ? 'filled ' : '' ), + $pointString + ); + } + + /** + * Draws a single line + * + * @param ezcGraphCoordinate $start + * @param ezcGraphCoordinate $end + * @param ezcGraphColor $color + * @return void + */ + public function drawLine( ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphColor $color, $thickness = 1 ) + { + printf( "%03d: Draw line from ( %.2f, %.2f ) to ( %.2f, %.2f ) with thickness %d.\n", + $this->call++, + $start->x, + $start->y, + $end->x, + $end->y, + $thickness + ); + } + + /** + * Wrties text in a box of desired size + * + * @param mixed $string + * @param ezcGraphCoordinate $position + * @param mixed $width + * @param mixed $height + * @param ezcGraphColor $color + * @return void + */ + public function drawTextBox( $string, ezcGraphCoordinate $position, $width, $height, $align ) + { + printf( "%03d: Draw text '%s' at ( %.2f, %.2f ) with dimensions ( %d, %d ) and alignement %d.\n", + $this->call++, + $string, + $position->x, + $position->y, + $width, + $height, + $align + ); + } + /** + * Draws a sector of cirlce + * + * @param ezcGraphCoordinate $center + * @param mixed $width + * @param mixed $height + * @param mixed $startAngle + * @param mixed $endAngle + * @param ezcGraphColor $color + * @return void + */ + public function drawCircleSector( ezcGraphCoordinate $center, $width, $height, $startAngle, $endAngle, ezcGraphColor $color, $filled = true ) + { + printf( "%03d: Draw %scicle sector at ( %.2f, %.2f ) with dimensions ( %d, %d ) from %.2f to %.2f.\n", + $this->call++, + ( $filled ? 'filled ' : '' ), + $center->x, + $center->y, + $width, + $height, + $startAngle, + $endAngle + ); + } + + /** + * Draws a circular arc + * + * @param ezcGraphCoordinate $center Center of ellipse + * @param integer $width Width of ellipse + * @param integer $height Height of ellipse + * @param integer $size Height of border + * @param float $startAngle Starting angle of circle sector + * @param float $endAngle Ending angle of circle sector + * @param ezcGraphColor $color Color of Border + * @return void + */ + public function drawCircularArc( ezcGraphCoordinate $center, $width, $height, $size, $startAngle, $endAngle, ezcGraphColor $color ) + { + printf( "%03d: Draw circular arc at ( %.2f, %.2f ) with dimensions ( %d, %d ) and size %.2f from %.2f to %.2f.\n", + $this->call++, + $center->x, + $center->y, + $width, + $height, + $size, + $startAngle, + $endAngle + ); + } + + /** + * Draws a circle + * + * @param ezcGraphCoordinate $center + * @param mixed $width + * @param mixed $height + * @param ezcGraphColor $color + * @param bool $filled + * + * @return void + */ + public function drawCircle( ezcGraphCoordinate $center, $width, $height, ezcGraphColor $color, $filled = true ) + { + printf( "%03d: Draw %scircle at ( %.2f, %.2f ) with dimensions ( %d, %d ).\n", + $this->call++, + ( $filled ? 'filled ' : '' ), + $center->x, + $center->y, + $width, + $height + ); + } + + /** + * Draws a imagemap of desired size + * + * @param mixed $file + * @param ezcGraphCoordinate $position + * @param mixed $width + * @param mixed $height + * @return void + */ + public function drawImage( $file, ezcGraphCoordinate $position, $width, $height ) + { + printf( "%03d: Draw image '%s' at ( %.2f, %.2f ) with dimensions ( %d, %d ).\n", + $this->call++, + $file, + $position->x, + $position->y, + $width, + $height + ); + } + + /** + * Finally save image + * + * @param mixed $file + * @return void + */ + public function render ( $file ) + { + printf( "Render image.\n" ); + } +} + +?> diff --git a/src/element/axis.php b/src/element/axis.php index 274903a..4b61bd7 100644 --- a/src/element/axis.php +++ b/src/element/axis.php @@ -38,18 +38,18 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement protected $labelPadding = 2; /** - * Color of the griding + * Color of major majorGrid * * @var ezcGraphColor */ - protected $grid = false; + protected $majorGrid; /** - * Raster minor steps on axis + * Color of minor majorGrid * * @var ezcGraphColor */ - protected $minorGrid = false; + protected $minorGrid; /** * Labeled major steps displayed on the axis @@ -67,20 +67,6 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement protected $minorStep = false; /** - * Length of lines for the major steps on the axis - * - * @var integer - */ - protected $majorScalingLineLength = 4; - - /** - * Length of lines for the minor steps on the axis - * - * @var integer - */ - protected $minorScalingLineLength = 2; - - /** * Formatstring to use for labeling og the axis * * @var string @@ -94,8 +80,17 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement */ protected $maxArrowHeadSize = 8; + /** + * Axis label renderer class + * + * @var ezcGraphAxisLabelRenderer + */ + protected $axisLabelRenderer; + public function __construct( array $options = array() ) { + $this->axisLabelRenderer = new ezcGraphAxisExactLabelRenderer(); + parent::__construct( $options ); } @@ -110,7 +105,7 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement $this->border = $palette->axisColor; $this->padding = $palette->padding; $this->margin = $palette->margin; - $this->grid = $palette->gridColor; + $this->majorGrid = $palette->majorGridColor; $this->minorGrid = $palette->minorGridColor; } @@ -138,14 +133,14 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement case 'labelPadding': $this->labelPadding = min( 0, max( 0, (float) $propertyValue ) ); break; - case 'grid': + case 'majorGrid': if ( $propertyValue instanceof ezcGraphColor ) { - $this->grid = $propertyValue; + $this->majorGrid = $propertyValue; } else { - $this->grid = ezcGraphColor::create( $propertyValue ); + $this->majorGrid = ezcGraphColor::create( $propertyValue ); } break; case 'minorGrid': @@ -178,6 +173,16 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement case 'maxArrowHeadSize': $this->maxArrowHeadSize = max( 0, (int) $propertyValue ); break; + case 'axisLabelRenderer': + if ( $propertyValue instanceof ezcGraphAxisLabelRenderer ) + { + $this->axisLabelRenderer = $propertyValue; + } + else + { + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + break; default: parent::__set( $propertyName, $propertyValue ); break; @@ -187,11 +192,10 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement /** * Get coordinate for a dedicated value on the chart * - * @param ezcGraphBounding $boundings * @param float $value Value to determine position for * @return float Position on chart */ - abstract public function getCoordinate( ezcGraphBoundings $boundings, $value ); + abstract public function getCoordinate( $value ); /** * Return count of minor steps @@ -216,186 +220,6 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement abstract protected function getLabel( $step ); /** - * Draw labels for an axis - * - * @param ezcGraphRenderer $renderer - * @param ezcGraphCoordinate $start - * @param ezcGraphCoordinate $end - * @param ezcGraphBoundings $boundings - * @return void - */ - abstract protected function drawLabels( ezcGraphRenderer $renderer, ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphBoundings $boundings ); - - /** - * Draw a axis from a start point to an end point. They do not need to be - * placed in-plane. - * - * @param ezcGraphRenderer $renderer - * @param ezcGraphCoordinate $start - * @param ezcGraphCoordinate $end - * @param float $major - * @param float $minor - * @return void - */ - protected function drawAxis( ezcGraphRenderer $renderer, ezcGraphCoordinate $start, ezcGraphCoordinate $end, ezcGraphBoundings $boundings ) - { - // Determine normalized direction - $direction = new ezcGraphCoordinate( - $start->x - $end->x, - $start->y - $end->y - ); - $length = sqrt( pow( $direction->x, 2) + pow( $direction->y, 2 ) ); - $direction->x /= $length; - $direction->y /= $length; - - // Draw axis - $renderer->drawLine( - $this->border, - $start, - $end, - false - ); - - // Draw small arrowhead - $size = min( - $this->maxArrowHeadSize, - abs( ceil( ( ( $end->x - $start->x ) + ( $end->y - $start->y ) ) * $this->axisSpace / 4 ) ) - ); - - $renderer->drawPolygon( - array( - new ezcGraphCoordinate( - (int) round( $end->x ), - (int) round( $end->y ) - ), - new ezcGraphCoordinate( - (int) round( $end->x - + $direction->y * $size / 2 - + $direction->x * $size ), - (int) round( $end->y - + $direction->x * $size / 2 - + $direction->y * $size ) - ), - new ezcGraphCoordinate( - (int) round( $end->x - - $direction->y * $size / 2 - + $direction->x * $size ), - (int) round( $end->y - - $direction->x * $size / 2 - + $direction->y * $size ) - ), - ), - $this->border, - true - ); - - // Apply axisSpace to start and end - $start->x += ( $end->x - $start->x ) * ( $this->axisSpace / 2 ); - $start->y += ( $end->y - $start->y ) * ( $this->axisSpace / 2 ); - $end->x -= ( $end->x - $start->x ) * ( $this->axisSpace / 2 ); - $end->y -= ( $end->y - $start->y ) * ( $this->axisSpace / 2 ); - - // Draw major steps - $steps = $this->getMajorStepCount(); - - // Calculate stepsize - $xStepsize = ( $end->x - $start->x ) / $steps; - $yStepsize = ( $end->y - $start->y ) / $steps; - - // Calculate grid boundings - $negGrid = ( $boundings->x0 - $start->x ) * $direction->y + ( $boundings->y0 - $end->y ) * $direction->x; - $posGrid = ( $boundings->x1 - $end->x ) * $direction->y + ( $boundings->y1 - $start->y ) * $direction->x; - - // Draw major steps - for ( $i = 0; $i <= $steps; ++$i ) - { - if ( $this->grid && $this->grid->alpha < 255 ) - { - $renderer->drawLine( - $this->grid, - new ezcGraphCoordinate( - (int) round( $start->x + $i * $xStepsize - + $direction->y * $negGrid ), - (int) round( $start->y + $i * $yStepsize - + $direction->x * $negGrid ) - ), - new ezcGraphCoordinate( - (int) round( $start->x + $i * $xStepsize - + $direction->y * $posGrid ), - (int) round( $start->y + $i * $yStepsize - + $direction->x * $posGrid ) - ), - false - ); - } - - $renderer->drawLine( - $this->border, - new ezcGraphCoordinate( - (int) round( $start->x + $i * $xStepsize - + $direction->y * $this->majorScalingLineLength ), - (int) round( $start->y + $i * $yStepsize - + $direction->x * -$this->majorScalingLineLength ) - ), - new ezcGraphCoordinate( - (int) round( $start->x + $i * $xStepsize - + $direction->y * -$this->majorScalingLineLength ), - (int) round( $start->y + $i * $yStepsize - + $direction->x * $this->majorScalingLineLength ) - ), - false - ); - } - - // Draw minor steps if wanted - if ( $this->minorStep ) - { - $steps = $this->getMinorStepCount(); - for ( $i = 0; $i < $steps; ++$i ) - { - if ( $this->minorGrid && $this->minorGrid->alpha < 255 ) - { - $renderer->drawLine( - $this->minorGrid, - new ezcGraphCoordinate( - (int) round($start->x + $i * ( $end->x - $start->x ) / $steps - + $direction->y * $negGrid ), - (int) round($start->y + $i * ( $end->y - $start->y ) / $steps - + -$direction->x * $negGrid ) - ), - new ezcGraphCoordinate( - (int) round($start->x + $i * ( $end->x - $start->x ) / $steps - + $direction->y * $posGrid ), - (int) round($start->y + $i * ( $end->y - $start->y ) / $steps - + -$direction->x * $posGrid ) - ), - false - ); - } - - $renderer->drawLine( - $this->border, - new ezcGraphCoordinate( - (int) round($start->x + $i * ( $end->x - $start->x ) / $steps - + $direction->y * $this->minorScalingLineLength), - (int) round($start->y + $i * ( $end->y - $start->y ) / $steps - + $direction->x * -$this->minorScalingLineLength) - ), - new ezcGraphCoordinate( - (int) round($start->x + $i * ( $end->x - $start->x ) / $steps - + $direction->y * -$this->minorScalingLineLength), - (int) round($start->y + $i * ( $end->y - $start->y ) / $steps - + $direction->x * $this->minorScalingLineLength) - ), - false - ); - } - } - - $this->drawLabels( $renderer, $start, $end, $boundings ); - } - - /** * Add data for this axis * * @param mixed $value Value which will be displayed on this axis @@ -424,62 +248,55 @@ abstract class ezcGraphChartElementAxis extends ezcGraphChartElement switch ( $this->position ) { case ezcGraph::TOP: - $this->drawAxis( - $renderer, - new ezcGraphCoordinate( - (int) $this->nullPosition, - (int) $boundings->y0 - ), - new ezcGraphCoordinate( - (int) $this->nullPosition, - (int) $boundings->y1 - ), - $boundings + $start = new ezcGraphCoordinate( + $this->nullPosition, + $boundings->y0 + ); + $end = new ezcGraphCoordinate( + $this->nullPosition, + $boundings->y1 ); break; case ezcGraph::BOTTOM: - $this->drawAxis( - $renderer, - new ezcGraphCoordinate( - (int) $this->nullPosition, - (int) $boundings->y1 - ), - new ezcGraphCoordinate( - (int) $this->nullPosition, - (int) $boundings->y0 - ), - $boundings + $start = new ezcGraphCoordinate( + (int) $this->nullPosition, + (int) $boundings->y1 + ); + $end = new ezcGraphCoordinate( + (int) $this->nullPosition, + (int) $boundings->y0 ); break; case ezcGraph::LEFT: - $this->drawAxis( - $renderer, - new ezcGraphCoordinate( - (int) $boundings->x0, - (int) $this->nullPosition - ), - new ezcGraphCoordinate( - (int) $boundings->x1, - (int) $this->nullPosition - ), - $boundings + $start = new ezcGraphCoordinate( + (int) $boundings->x0, + (int) $this->nullPosition + ); + $end = new ezcGraphCoordinate( + (int) $boundings->x1, + (int) $this->nullPosition ); break; case ezcGraph::RIGHT: - $this->drawAxis( - $renderer, - new ezcGraphCoordinate( - (int) $boundings->x1, - (int) $this->nullPosition - ), - new ezcGraphCoordinate( - (int) $boundings->x0, - (int) $this->nullPosition - ), - $boundings + $start = new ezcGraphCoordinate( + (int) $boundings->x1, + (int) $this->nullPosition + ); + $end = new ezcGraphCoordinate( + (int) $boundings->x0, + (int) $this->nullPosition ); break; } + + $renderer->drawAxis( + $boundings, + $start, + $end, + $this, + $this->axisLabelRenderer + ); + return $boundings; } } diff --git a/src/element/legend.php b/src/element/legend.php index a8192ae..06a6ab0 100644 --- a/src/element/legend.php +++ b/src/element/legend.php @@ -190,79 +190,6 @@ class ezcGraphChartElementLegend extends ezcGraphChartElement return $boundings; } - protected function renderLegend( ezcGraphRenderer $renderer ) - { - switch ( $this->position ) - { - case ezcGraph::LEFT: - case ezcGraph::RIGHT: - $symbolSize = (int) round( min( - max( - $this->symbolSize, - ( $this->boundings->y1 - $this->boundings->y0 ) * $this->minimumSymbolSize - ), - ( $this->boundings->y1 - $this->boundings->y0 ) / count( $this->labels ) - ) ); - - foreach ( $this->labels as $labelNr => $label ) - { - $renderer->drawSymbol( - $label['color'], - new ezcGraphCoordinate( - $this->boundings->x0 + $this->padding, - $this->boundings->y0 + $labelNr * ( $symbolSize + $this->spacing ) + $this->padding - ), - $symbolSize - 2 * $this->padding, - $symbolSize - 2 * $this->padding, - $label['symbol'] - ); - $renderer->drawTextBox( - new ezcGraphCoordinate( - $this->boundings->x0 + $symbolSize + $this->spacing, - $this->boundings->y0 + $labelNr * ( $symbolSize + $this->spacing ) + $this->padding - ), - $label['label'], - $this->boundings->x1 - $this->boundings->x0 - $symbolSize - $this->padding - $this->spacing, - $symbolSize - 2 * $this->padding, - ezcGraph::LEFT | ezcGraph::MIDDLE - ); - } - break; - case ezcGraph::TOP: - case ezcGraph::BOTTOM: - $symbolSize = (int) round( min( - $this->symbolSize, - ( $this->boundings->y1 - $this->boundings->y0 ) - ) ); - $width = (int) round( ( $this->boundings->x1 - $this->boundings->x0 ) / count( $this->labels ) ); - - foreach ( $this->labels as $labelNr => $label ) - { - $renderer->drawSymbol( - $label['color'], - new ezcGraphCoordinate( - $this->boundings->x0 + $labelNr * $width + $this->padding, - $this->boundings->y0 + $this->padding - ), - $symbolSize - 2 * $this->padding, - $symbolSize - 2 * $this->padding, - $label['symbol'] - ); - $renderer->drawTextBox( - new ezcGraphCoordinate( - $this->boundings->x0 + $labelNr * $width + $this->padding + $symbolSize + $this->spacing, - $this->boundings->y0 + $this->padding - ), - $label['label'], - $width - $this->padding - $symbolSize - $this->spacing, - $symbolSize - 2 * $this->padding, - ezcGraph::LEFT | ezcGraph::MIDDLE - ); - } - break; - } - } - /** * Render a legend * @@ -274,13 +201,33 @@ class ezcGraphChartElementLegend extends ezcGraphChartElement { $boundings = $this->calculateBoundings( $boundings ); + if ( $this->position === ezcGraph::LEFT || $this->position === ezcGraph::RIGHT ) + { + $type = ezcGraph::VERTICAL; + } + else + { + $type = ezcGraph::HORIZONTAL; + } + // Render standard elements - $this->renderBorder( $renderer ); - $this->renderBackground( $renderer ); - $this->renderTitle( $renderer ); + $boundings = $renderer->drawBox( + $boundings, + $this->background, + $this->border, + $this->borderWidth, + $this->margin, + $this->padding, + $this->title, + $this->getTitleSize( $boundings, $type ) + ); // Render legend - $this->renderLegend( $renderer ); + $renderer->drawLegend( + $boundings, + $this, + $type + ); return $boundings; } diff --git a/src/element/text.php b/src/element/text.php index a72ee3e..24fee8e 100644 --- a/src/element/text.php +++ b/src/element/text.php @@ -36,8 +36,14 @@ class ezcGraphChartElementText extends ezcGraphChartElement return $boundings; } - $this->renderBorder( $renderer ); - $this->renderBackground( $renderer ); + $boundings = $renderer->drawBox( + $boundings, + $this->background, + $this->border, + $this->borderWidth, + $this->margin, + $this->padding + ); $height = (int) min( round( $this->maxHeight * ( $boundings->y1 - $boundings->y0 ) ), @@ -47,27 +53,28 @@ class ezcGraphChartElementText extends ezcGraphChartElement switch ( $this->position ) { case ezcGraph::TOP: - $renderer->drawTextBox( - new ezcGraphCoordinate( - $boundings->x0 + $this->padding, - $boundings->y0 + $this->padding + $renderer->drawText( + new ezcGraphBoundings( + $boundings->x0, + $boundings->y0, + $boundings->x1, + $boundings->y0 + $height ), $this->title, - $boundings->x1 - $boundings->x0 - $this->padding * 2, - $height - $this->padding * 2, ezcGraph::CENTER | ezcGraph::MIDDLE ); + $boundings->y0 += $height + $this->margin; break; case ezcGraph::BOTTOM: - $renderer->drawTextBox( - new ezcGraphCoordinate( - $boundings->x0 + $this->padding, - $boundings->y1 - $height + $this->padding + $renderer->drawText( + new ezcGraphBoundings( + $boundings->x0, + $boundings->y1 - $height, + $boundings->x1, + $boundings->y1 ), $this->title, - $boundings->x1 - $boundings->x0 - $this->padding * 2, - $height - $this->padding * 2, ezcGraph::CENTER | ezcGraph::MIDDLE ); $boundings->y1 -= $height + $this->margin; diff --git a/src/graph.php b/src/graph.php index 244dd5f..a9e97ab 100644 --- a/src/graph.php +++ b/src/graph.php @@ -20,6 +20,10 @@ class ezcGraph const BULLET = 2; const CIRCLE = 3; + const NO_REPEAT = 0; + const HORIZONTAL = 1; + const VERTICAL = 2; + const TOP = 1; const BOTTOM = 2; const LEFT = 4; diff --git a/src/graph_autoload.php b/src/graph_autoload.php index 349a02a..653141b 100644 --- a/src/graph_autoload.php +++ b/src/graph_autoload.php @@ -27,9 +27,13 @@ return array( 'ezcGraphRenderer' => 'Graph/interfaces/renderer.php', 'ezcGraphRenderer2D' => 'Graph/renderer/2d.php', + 'ezcGraphRenderer2dOptions' => 'Graph/options/renderer_2d.php', 'ezcGraphRenderer3D' => 'Graph/renderer/3d.php', 'ezcGraphInvalidRendererException' => 'Graph/exceptions/invalid_renderer.php', + 'ezcGraphAxisLabelRenderer' => 'Graph/interfaces/axis_label_renderer.php', + 'ezcGraphAxisExactLabelRenderer' => 'Graph/renderer/axis_label_exact.php', + 'ezcGraphDriver' => 'Graph/interfaces/driver.php', 'ezcGraphDriverOptions' => 'Graph/options/driver.php', 'ezcGraphGdDriver' => 'Graph/driver/gd.php', @@ -39,6 +43,7 @@ return array( 'ezcGraphSvgDriver' => 'Graph/driver/svg.php', 'ezcGraphSvgDriverOptions' => 'Graph/options/svg_driver.php', 'ezcGraphInvalidDriverException' => 'Graph/exceptions/invalid_driver.php', + 'ezcGraphVerboseDriver' => 'Graph/driver/verbose.php', 'ezcGraphPalette' => 'Graph/interfaces/palette.php', 'ezcGraphPaletteTango' => 'Graph/palette/tango.php', diff --git a/src/interfaces/axis_label_renderer.php b/src/interfaces/axis_label_renderer.php new file mode 100644 index 0000000..0a024fb --- /dev/null +++ b/src/interfaces/axis_label_renderer.php @@ -0,0 +1,284 @@ +<?php +/** + * File containing the abstract ezcGraphAxisLabelRenderer class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005, + 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Abstract class to render labels and grids on axis. Will be extended to + * make it possible using different algorithms for rendering axis labels. + * + * @package Graph + */ +abstract class ezcGraphAxisLabelRenderer extends ezcBaseOptions +{ + + protected $driver; + + protected $majorStepCount = false; + + protected $minorStepCount = false; + + protected $majorStepSize = 3; + + protected $minorStepSize = 1; + + protected $innerStep = true; + + protected $outerStep = false; + + protected $innerGrid = true; + + protected $outerGrid = false; + + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case 'driver': + if ( $propertyValue instanceof ezcGraphDriver ) + { + $this->driver = $propertyValue; + } + else + { + throw new ezcGraphInvalidDriverException( $propertyValue ); + } + break; + case 'majorStepCount': + $this->majorStepCount = (int) $propertyValue; + break; + case 'minorStepCount': + $this->minorStepCount = (int) $propertyValue; + break; + case 'majorStepSize': + $this->majorStepSize = (int) $propertyValue; + break; + case 'minorStepSize': + $this->minorStepSize = (int) $propertyValue; + break; + case 'innerStep': + $this->innerStep = (bool) $propertyValue; + break; + case 'outerStep': + $this->outerStep = (bool) $propertyValue; + break; + case 'innerGrid': + $this->innerGrid = (bool) $propertyValue; + break; + case 'outerGrid': + $this->outerGrid = (bool) $propertyValue; + break; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + } + + /** + * Draw single step on a axis + * + * Draws a step on a axis at the current position + * + * @param ezcGraphCoordinate $position Position of step + * @param ezcGraphCoordinate $direction Direction of axis + * @param int $axisPosition Position of axis + * @param int $size Step size + * @param ezcGraphColor $color Color of axis + * @return void + */ + protected function drawStep( ezcGraphCoordinate $position, ezcGraphCoordinate $direction, $axisPosition, $size, ezcGraphColor $color ) + { + $drawStep = false; + + if ( ( ( $axisPosition === ezcGraph::CENTER ) && $this->innerStep ) || + ( ( $axisPosition === ezcGraph::RIGHT ) && $this->innerStep ) || + ( ( $axisPosition === ezcGraph::LEFT ) && $this->outerStep ) ) + { + // Turn direction vector to left by 90 degrees and multiply + // with major step size + $stepStart = new ezcGraphCoordinate( + - $direction->y * $size, + $direction->x * $size + ); + $drawStep = true; + } + else + { + $stepStart = $start; + } + + if ( ( ( $axisPosition === ezcGraph::CENTER ) && $this->innerStep ) || + ( ( $axisPosition === ezcGraph::RIGHT ) && $this->outerStep ) || + ( ( $axisPosition === ezcGraph::LEFT ) && $this->innerStep ) ) + { + // Turn direction vector to right by 90 degrees and multiply + // with major step size + $stepEnd = new ezcGraphCoordinate( + $direction->y * $size, + - $direction->x * $size + ); + $drawStep = true; + } + else + { + $stepEnd = $end; + } + + if ( $drawStep ) + { + $this->driver->drawLine( + $stepStart, + $stepEnd, + $color + ); + } + } + + public function determineLineCuttingPoint( ezcGraphCoordinate $aStart, ezcGraphCoordinate $aDir, ezcGraphCoordinate $bStart, ezcGraphCoordinate $bDir ) + { + // Check if line are parallel + // @TODO: This is not the optimal way because of inexact floating point + // numbers and not needed use of sqrt + $aLength = sqrt( pow( $aDir->x, 2 ) + pow( $aDir->y, 2 ) ); + $bLength = sqrt( pow( $bDir->x, 2 ) + pow( $bDir->y, 2 ) ); + + if ( ( $aDir->x / $aLength == $bDir->x / $bLength ) && + ( $aDir->x / $aLength == $bDir->x / $bLength ) ) + { + return false; + } + + // Solve equatation + return - ( + ( $bStart->y / $aDir->y ) - + ( $aStart->y / $aDir->y ) - + ( $bStart->x / $aDir->x ) + + ( $aStart->x / $aDir->x ) + ) / ( + ( $bDir->y / $aDir->y ) - + ( $bDir->x / $aDir->x ) + ); + } + + /** + * Draw grid + * + * Draws a grid line at the current position + * + * @param ezcGraphBoundings $boundings Boundings of axis + * @param ezcGraphCoordinate $position Position of step + * @param ezcGraphCoordinate $direction Direction of axis + * @param ezcGraphColor $color Color of axis + * @return void + */ + protected function drawGrid( ezcGraphBoundings $boundings, ezcGraphCoordinate $position, ezcGraphCoordinate $direction, ezcGraphColor $color ) + { + // Direction of grid line is direction of axis turned right by 90 + // degrees + $gridDirection = new ezcGraphCoordinate( + $direction->y, + - $direction->x + ); + + $cuttingPoints = array(); + foreach ( array( // Bounding lines + array( + 'start' => new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), + 'dir' => new ezcGraphCoordinate( 0, $boundings->y1 - $boundings->y0 ) + ), + array( + 'start' => new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), + 'dir' => new ezcGraphCoordinate( 0, $boundings->x1 - $boundings->x0 ) + ), + array( + 'start' => new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), + 'dir' => new ezcGraphCoordinate( 0, $boundings->y0 - $boundings->y1 ) + ), + array( + 'start' => new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), + 'dir' => new ezcGraphCoordinate( 0, $boundings->x0 - $boundings->x1 ) + ), + ) as $boundingLine ) + { + // Test for cutting points with bounding lines, where cutting + // position is between 0 and 1, which means, that the line is hit + // on the bounding box rectangle. Use these points as a start and + // ending point for the grid lines. There should *always* be two + // points returned. + $cuttingPosition = $this->determineLineCuttingPoint( + $start, + $gridDirection, + $boundingLine['start'], + $boundingLine['dir'] + ); + + if ( $cuttingPosition > 0 && $cuttingPosition <= 1 ) + { + $cuttingPoints[] = new ezcGraphCoordinate( + $boundingLine['start']->x + $cuttingPosition * $boundingLine['dir']->x, + $boundingLine['start']->y + $cuttingPosition * $boundingLine['dir']->y + ); + } + } + + // Finally draw grid line + $this->driver->drawLine( + $cuttingPoints[0], + $cuttingPoints[1], + $color + ); + } + + /** + * Modify chart boundings + * + * Optionally modify boundings of + * + * @param ezcGraphBoundings $boundings Current boundings of chart + * @param ezcGraphCoordinate $direction Direction of the current axis + * @return ezcGraphBoundings Modified boundings + */ + public function modifyChartBoundings( ezcGraphBoundings $boundings, ezcGraphCoordinate $direction ) + { + return $boundings; + } + + /** + * Modify chart data position + * + * Optionally additionally modify the coodinate of a data point + * + * @param ezcGraphCoordinate $coordinate Data point coordinate + * @param ezcGraphCoordinate $direction Direction of the current axis + * @return ezcGraphCoordinate Modified coordinate + */ + public function modifyChartDataPosition( ezcGraphCoordinate $coordinate, ezcGraphCoordinate $direction ) + { + return $coordinate; + } + + /** + * Render Axis labels + * + * Render labels for an axis. + * + * @param ezcGraphBoundings $boundings Boundings of the axis + * @param ezcGraphCoordinate $start Axis starting point + * @param ezcGraphCoordinate $end Axis ending point + * @param ezcGraphChartElementAxis $axis Axis instance + * @param int $position Position of axis (left, right, or center) + * @return void + */ + abstract public function renderLabels( + ezcGraphBoundings $boundings, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + ezcGraphChartElementAxis $axis, + $axisPosition + ); +} +?> diff --git a/src/interfaces/chart.php b/src/interfaces/chart.php index 18e1849..ac50029 100644 --- a/src/interfaces/chart.php +++ b/src/interfaces/chart.php @@ -57,7 +57,6 @@ abstract class ezcGraphChart implements ArrayAccess */ protected $palette; - /** * Contains the status wheather an element should be rendered * @@ -292,66 +291,6 @@ abstract class ezcGraphChart implements ArrayAccess } /** - * Render chart border - * - * @param ezcGraphBoundings $boundings Boundings - * @return ezcGraphBoundings - */ - protected function renderBorder( ezcGraphBoundings $boundings ) - { - if ( ( $this->options->border instanceof ezcGraphColor ) && - ( $this->options->borderWidth > 0 ) ) - { - // Default bordervalue to 1 - $this->options->borderWidth = max( 1, $this->options->borderWidth ); - - // Draw border - $this->renderer->drawRect( - $this->options->border, - new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), - $boundings->x1 - $boundings->x0, - $boundings->y1 - $boundings->y0, - $this->options->borderWidth - ); - - // Reduce local boundings by borderWidth - $boundings->x0 += $this->options->borderWidth; - $boundings->y0 += $this->options->borderWidth; - $boundings->x1 -= $this->options->borderWidth; - $boundings->y1 -= $this->options->borderWidth; - } - - return $boundings; - } - - /** - * Render chart background - * - * @param ezcGraphBoundings $boundings Boundings - * @return ezcGraphBoundings - */ - protected function renderBackground( ezcGraphBoundings $boundings ) - { - if ( $this->options->background instanceof ezcGraphColor ) - { - $this->renderer->drawBackground( - $this->options->background, - new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), - $boundings->x1 - $boundings->x0, - $boundings->y1 - $boundings->y0 - ); - } - - // Apply padding - $boundings->x0 += $this->options->padding; - $boundings->y0 += $this->options->padding; - $boundings->x1 -= $this->options->padding; - $boundings->y1 -= $this->options->padding; - - return $boundings; - } - - /** * Renders this chart * * Creates basic visual chart elements from the chart to be processed by diff --git a/src/interfaces/driver.php b/src/interfaces/driver.php index 632747b..f66d362 100644 --- a/src/interfaces/driver.php +++ b/src/interfaces/driver.php @@ -111,7 +111,7 @@ abstract class ezcGraphDriver * @param ezcGraphCoordinate $position * @param mixed $width * @param mixed $height - * @param ezcGraphColor $color + * @param int $align Alignement of text * @return void */ abstract public function drawTextBox( $string, ezcGraphCoordinate $position, $width, $height, $align ); diff --git a/src/interfaces/element.php b/src/interfaces/element.php index 8aeb8bf..ebb06a4 100644 --- a/src/interfaces/element.php +++ b/src/interfaces/element.php @@ -235,105 +235,22 @@ abstract class ezcGraphChartElement extends ezcBaseOptions */ abstract public function render( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings ); - protected function renderBorder( ezcGraphRenderer $renderer ) + protected function getTitleSize( ezcGraphBoundings $boundings, $direction = ezcGraph::HORIZONTAL ) { - // Apply margin - $this->boundings->x0 += $this->margin; - $this->boundings->y0 += $this->margin; - $this->boundings->x1 -= $this->margin; - $this->boundings->y1 -= $this->margin; - - if ( ( $this->border instanceof ezcGraphColor ) && - ( $this->borderWidth > 0 ) ) + if ( $direction === ezcGraph::HORIZONTAL ) { - // Default bordervalue to 1 - $this->borderWidth = max( 1, $this->borderWidth ); - - // Draw border - $renderer->drawRect( - $this->border, - new ezcGraphCoordinate( $this->boundings->x0, $this->boundings->y0 ), - $this->boundings->x1 - $this->boundings->x0, - $this->boundings->y1 - $this->boundings->y0, - $this->borderWidth + return min( + $this->maxTitleHeight, + ( $boundings->y1 - $boundings->y0 ) * $this->landscapeTitleSize ); - - // Reduce local boundings by borderWidth - $this->boundings->x0 += $this->borderWidth; - $this->boundings->y0 += $this->borderWidth; - $this->boundings->x1 -= $this->borderWidth; - $this->boundings->y1 -= $this->borderWidth; } - } - - protected function renderBackground( ezcGraphRenderer $renderer ) - { - if ( $this->background instanceof ezcGraphColor ) + else { - $renderer->drawBackground( - $this->background, - new ezcGraphCoordinate( $this->boundings->x0, $this->boundings->y0 ), - $this->boundings->x1 - $this->boundings->x0, - $this->boundings->y1 - $this->boundings->y0 + return min( + $this->maxTitleHeight, + ( $boundings->y1 - $boundings->y0 ) * $this->portraitTitleSize ); } - - // Apply padding - $this->boundings->x0 += $this->padding; - $this->boundings->y0 += $this->padding; - $this->boundings->x1 -= $this->padding; - $this->boundings->y1 -= $this->padding; - } - - protected function renderTitle( ezcGraphRenderer $renderer ) - { - if ( !empty( $this->title ) ) - { - switch ( $this->position ) - { - case ezcGraph::LEFT: - case ezcGraph::RIGHT: - case ezcGraph::CENTER: - $height = min( - $this->maxTitleHeight, - ( $this->boundings->y1 - $this->boundings->y0 ) * $this->portraitTitleSize - ); - $renderer->drawTextBox( - new ezcGraphCoordinate( $this->boundings->x0, $this->boundings->y0 ), - $this->title, - $this->boundings->x1 - $this->boundings->x0, - $height - ); - $this->boundings->y0 += $height; - break; - case ezcGraph::TOP: - $height = min( - $this->maxTitleHeight, - ( $this->boundings->y1 - $this->boundings->y0 ) * $this->landscapeTitleSize - ); - $renderer->drawTextBox( - new ezcGraphCoordinate( $this->boundings->x0, $this->boundings->y0 ), - $this->title, - $this->boundings->x1 - $this->boundings->x0, - $height - ); - $this->boundings->y0 += $height; - break; - case ezcGraph::BOTTOM: - $height = min( - $this->maxTitleHeight, - ( $this->boundings->y1 - $this->boundings->y0 ) * $this->landscapeTitleSize - ); - $renderer->drawTextBox( - new ezcGraphCoordinate( $this->boundings->x0, $this->boundings->y1 - $height ), - $this->title, - $this->boundings->x1 - $this->boundings->x0, - $height - ); - $this->boundings->y1 -= $height; - break; - } - } } } diff --git a/src/interfaces/palette.php b/src/interfaces/palette.php index dcee880..bfb6147 100644 --- a/src/interfaces/palette.php +++ b/src/interfaces/palette.php @@ -40,7 +40,7 @@ abstract class ezcGraphPalette * * @var ezcGraphColor */ - protected $gridColor; + protected $majorGridColor; /** * Color of minor grid lines @@ -168,8 +168,8 @@ abstract class ezcGraphPalette case 'axisColor': return $this->checkColor( $this->axisColor ); - case 'gridColor': - return $this->checkColor( $this->gridColor ); + case 'majorGridColor': + return $this->checkColor( $this->majorGridColor ); case 'minorGridColor': return $this->checkColor( $this->minorGridColor ); diff --git a/src/interfaces/renderer.php b/src/interfaces/renderer.php index c0afda9..03b2ea5 100644 --- a/src/interfaces/renderer.php +++ b/src/interfaces/renderer.php @@ -4,7 +4,8 @@ * * @package Graph * @version //autogentag// - * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @copyright Copyright (C) 2005, + 2006 eZ systems as. All rights reserved. * @license http://ez.no/licenses/new_bsd New BSD License */ /** @@ -24,99 +25,205 @@ abstract class ezcGraphRenderer } /** - * Draw a pie segment + * Draw pie segment + * + * Draws a single pie segment * - * @param ezcGraphCoordinate $position - * @param mixed $radius - * @param float $startAngle - * @param float $endAngle - * @param float $moveOut + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphColor $color Color of pie segment + * @param float $startAngle Start angle + * @param float $endAngle End angle + * @param string $label Label of pie segment + * @param float $moveOut Move out from middle for hilighting * @return void */ - abstract public function drawPieSegment( ezcGraphColor $color, ezcGraphCoordinate $position, $radius, $startAngle = .0, $endAngle = 360., $moveOut = .0 ); + abstract public function drawPieSegment( + ezcGraphBoundings $boundings, + ezcGraphColor $color, + $startAngle = .0, + $endAngle = 360., + $label = false, + $moveOut = false + ); /** - * Draw a line + * Draw data line * - * Semantically means a line as a chart element, not a single line like - * the ones used in axes. + * Draws a line as a data element in a line chart * - * @param ezcGraphCoordinate $position - * @param ezcGraphCoordinate $end - * @param mixed $filled + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphColor $color Color of line + * @param ezcGraphCoordinate $start Starting point + * @param ezcGraphCoordinate $end Ending point + * @param int $symbol Symbol to draw for line + * @param ezcGraphColor $symbolColor Color of the symbol, defaults to linecolor + * @param ezcGraphColor $fillColor Color to fill line with + * @param float $axisPosition Position of axis for drawing filled lines + * @param float $thickness Line thickness * @return void */ - abstract public function drawLine( ezcGraphColor $color, ezcGraphCoordinate $position, ezcGraphCoordinate $end, $thickness = 1 ); + abstract public function drawDataLine( + ezcGraphBoundings $boundings, + ezcGraphColor $color, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + $symbol = ezcGraph::NO_SYMBOL, + ezcGraphColor $symbolColor = null, + ezcGraphColor $fillColor = null, + $axisPosition = 0., + $thickness = 1 + ); /** - * Draws a text box + * Draw legend + * + * Will draw a legend in the bounding box * - * @param ezcGraphCoordinate $position - * @param mixed $text - * @param mixed $width - * @param mixed $height + * @param ezcGraphBoundings $boundings Bounding of legend + * @param ezcGraphChartElementLegend $labels Legend to draw + * @param int $type Type of legend: Protrait or landscape * @return void */ - abstract public function drawTextBox( ezcGraphCoordinate $position, $text, $width = null, $height = null, $align = ezcGraph::LEFT ); + abstract public function drawLegend( + ezcGraphBoundings $boundings, + ezcGraphChartElementLegend $legend, + $type = ezcGraph::VERTICAL + ); /** - * Draws a rectangle + * Draw box * - * @param ezcGraphColor $color - * @param ezcGraphCoordinate $position - * @param mixed $width - * @param mixed $height - * @param float $borderWidth - * @return void + * Box are wrapping each major chart element and draw border, background + * and title to each chart element. + * + * Optionally a padding and margin for each box can be defined. + * + * @param ezcGraphBoundings $boundings Boundings of the box + * @param ezcGraphColor $background Background color + * @param ezcGraphColor $borderColor Border color + * @param int $borderWidth Border width + * @param int $margin Margin + * @param int $padding Padding + * @param string $title Title of the box + * @param int $titleSize Size of title in the box + * @return ezcGraphBoundings Remaining inner boundings */ - abstract public function drawRect( ezcGraphColor $color, ezcGraphCoordinate $position = null, $width = null, $height = null, $borderWidth = 1 ); + abstract public function drawBox( + ezcGraphBoundings $boundings, + ezcGraphColor $background = null, + ezcGraphColor $borderColor = null, + $borderWidth = 0, + $margin = 0, + $padding = 0, + $title = false, + $titleSize = 16 + ); /** - * Draw Background + * Draw text * - * Draws a filled rectangle, used for backgrounds + * Draws the provided text in the boundings * - * @param ezcGraphColor $color - * @param ezcGraphCoordinate $position - * @param mixed $width - * @param mixed $height + * @param ezcGraphBoundings $boundings Boundings of text + * @param string $text Text + * @param int $align Alignement of text + * @param int $align Alignement of text * @return void */ - abstract public function drawBackground( ezcGraphColor $color, ezcGraphCoordinate $position = null, $width = null, $height = null ); + abstract public function drawText( + ezcGraphBoundings $boundings, + $text, + $align = ezcGraph::LEFT + ); /** - * Draws BackgrouniImage + * Draw axis + * + * Draws an axis form the provided start point to the end point. A specific + * angle of the axis is not required. + * + * For the labeleing of the axis a sorted array with major steps and an + * array with minor steps is expected, which are build like this: + * array( + * array( + * 'position' => (float), + * 'label' => (string), + * ) + * ) + * where the label is optional. + * + * The label renderer class defines how the labels are rendered. For more + * documentation on this topic have a look at the basic label renderer + * class. + * + * Additionally it can be specified if a major and minor grid are rendered + * by defining a color for them. Teh axis label is used to add a caption + * for the axis. * - * @param mixed $file - * @param ezcGraphCoordinate $position - * @param mixed $width - * @param mixed $height + * @param ezcGraphBoundings $boundings Boundings of axis + * @param ezcGraphCoordinate $start Start point of axis + * @param ezcGraphCoordinate $end Endpoint of axis + * @param ezcGraphChartElementAxis $axis Axis to render + * @param ezcGraphLabelRenderer $labelClass Used label renderer * @return void */ - abstract public function drawBackgroundImage( $file, ezcGraphCoordinate $position = null, $width = null, $height = null ); + abstract public function drawAxis( + ezcGraphBoundings $boundings, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + ezcGraphChartElementAxis $axis, + ezcGraphAxisLabelRenderer $labelClass = null + ); + + /** + * Draw background image + * + * Draws a background image at the defined position. If repeat is set the + * background image will be repeated like any texture. + * + * @param ezcGraphBoundings $boundings Boundings for the background image + * @param string $file Filename of background image + * @param int $position Position of background image + * @param int $repeat Type of repetition + * @return void + */ + abstract public function drawBackgroundImage( + ezcGraphBoundings $boundings, + $file, + $position = 48, // ezcGraph::CENTER | ezcGraph::MIDDLE + $repeat = ezcGraph::NO_REPEAT + ); /** - * Draws a lines symbol + * Draw Symbol + * + * Draws a single symbol defined by the symbol constants in ezcGraph. for + * NO_SYMBOL a rect will be drawn. * - * @param ezcGraphCoordinate $position - * @param float $width - * @param float $height - * @param int $symbol + * @param ezcGraphBoundings $boundings Boundings of symbol + * @param ezcGraphColor $color Color of symbol + * @param int $symbol Type of symbol * @return void */ - abstract public function drawSymbol( ezcGraphColor $color, ezcGraphCoordinate $position, $width, $height, $symbol = ezcGraph::NO_SYMBOL); + abstract public function drawSymbol( + ezcGraphBoundings $boundings, + ezcGraphColor $color, + $symbol = ezcGraph::NO_SYMBOL + ); /** - * Draws a single polygon + * Finish rendering + * + * Method is called before the final image is renderer, so that finishing + * operations can be performed here. * - * @param mixed $points - * @param ezcGraphColor $color - * @param mixed $filled + * @abstract + * @access public * @return void */ - public function drawPolygon( array $points, ezcGraphColor $color, $filled = true ) + protected function finish() { - $this->driver->drawPolygon( $points, $color, $filled ); + return true; } /** @@ -127,6 +234,7 @@ abstract class ezcGraphRenderer */ public function render( $file ) { + $this->finish(); $this->driver->render( $file ); } } diff --git a/src/options/chart.php b/src/options/chart.php index ccbb6c0..18ea61c 100644 --- a/src/options/chart.php +++ b/src/options/chart.php @@ -65,6 +65,13 @@ class ezcGraphChartOptions extends ezcBaseOptions protected $padding = 0; /** + * Distance between outer boundings and border of an element + * + * @var integer + */ + protected $margin = 0; + + /** * Font used in the graph * * @var int @@ -103,6 +110,9 @@ class ezcGraphChartOptions extends ezcBaseOptions case 'padding': $this->padding = max( 0, (int) $propertyValue ); break; + case 'margin': + $this->margin = max( 0, (int) $propertyValue ); + break; case 'backgroundImage': $this->backgroundImage->source = $propertyValue; break; diff --git a/src/options/renderer_2d.php b/src/options/renderer_2d.php new file mode 100644 index 0000000..caddacd --- /dev/null +++ b/src/options/renderer_2d.php @@ -0,0 +1,99 @@ +<?php +/** + * File containing the ezcGraphRenderer2dOptions class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Class containing the basic options for pie charts + * + * @package Graph + */ +class ezcGraphRenderer2dOptions extends ezcGraphChartOptions +{ + /** + * Percent of chart height used as maximum height for pie chart labels + * + * @var float + * @access protected + */ + protected $maxLabelHeight = .15; + + /** + * Indicates wheather to show the line between pie elements and labels + * + * @var bool + */ + protected $showSymbol = true; + + /** + * Size of symbols used concat a label with a pie + * + * @var float + * @access protected + */ + protected $symbolSize = 6; + + /** + * Percent to move pie chart elements out of the middle on highlight + * + * @var float + * @access protected + */ + protected $moveOut = .1; + + /** + * Position of title in a box + * + * @var int + */ + protected $titlePosition = ezcGraph::TOP; + + /** + * Alignement of box titles + * + * @var int + */ + protected $titleAlignement = 48; // ezcGraph::MIDDLE | ezcGraph::CENTER + + /** + * Set an option value + * + * @param string $propertyName + * @param mixed $propertyValue + * @throws ezcBasePropertyNotFoundException + * If a property is not defined in this class + * @return void + */ + public function __set( $propertyName, $propertyValue ) + { + switch ( $propertyName ) + { + case 'maxLabelHeight': + $this->maxLabelHeight = min( 1, max( 0, (float) $propertyValue ) ); + break; + case 'symbolSize': + $this->symbolSize = (int) $propertyValue; + break; + case 'moveOut': + $this->moveOut = min( 1, max( 0, (float) $propertyValue ) ); + break; + case 'showSymbol': + $this->showSymbol = (bool) $propertyValue; + break; + case 'titlePosition': + $this->titlePosition = (int) $propertyValue; + break; + case 'titleAlignement': + $this->titleAlignement = (int) $propertyValue; + break; + default: + return parent::__set( $propertyName, $propertyValue ); + } + } +} + +?> diff --git a/src/palette/black.php b/src/palette/black.php index 336ee49..48d3029 100644 --- a/src/palette/black.php +++ b/src/palette/black.php @@ -27,7 +27,7 @@ class ezcGraphPaletteBlack extends ezcGraphPalette * * @var ezcGraphColor */ - protected $gridColor = '#888A85'; + protected $majorGridColor = '#888A85'; /** * Color of minor grid lines diff --git a/src/renderer/2d.php b/src/renderer/2d.php index 5d8aca4..0ac0e91 100644 --- a/src/renderer/2d.php +++ b/src/renderer/2d.php @@ -1,47 +1,93 @@ <?php /** - * File containing the ezcGraphRenderer2D class + * File containing teh two dimensional renderer * * @package Graph * @version //autogentag// - * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved. + * @copyright Copyright (C) 2005, + 2006 eZ systems as. All rights reserved. * @license http://ez.no/licenses/new_bsd New BSD License */ /** - * Implements the three dimensional renderer for the graph component + * Class to transform chart primitives into image primitives * * @package Graph */ -class ezcGraphRenderer2D extends ezcGraphRenderer +class ezcGraphRenderer2d extends ezcGraphRenderer { + protected $pieSegmentLabels = array( + 0 => array(), + 1 => array(), + ); + + protected $pieSegmentBoundings = false; + + protected $options; + + public function __construct( array $options = array() ) + { + $this->options = new ezcGraphRenderer2dOptions( $options ); + } + + public function __get( $propertyName ) + { + switch ( $propertyName ) + { + case 'options': + return $this->options; + default: + throw new ezcBasePropertyNotFoundException( $propertyName ); + } + } + /** - * Draw a pie segment + * Draw pie segment + * + * Draws a single pie segment * - * @param ezcGraphCoordinate $position - * @param mixed $radius - * @param float $startAngle - * @param float $endAngle - * @param float $moveOut + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphColor $color Color of pie segment + * @param float $startAngle Start angle + * @param float $endAngle End angle + * @param string $label Label of pie segment + * @param float $moveOut Move out from middle for hilighting * @return void */ - public function drawPieSegment( ezcGraphColor $color, ezcGraphCoordinate $position, $radius, $startAngle = .0, $endAngle = 360., $moveOut = .0 ) + public function drawPieSegment( + ezcGraphBoundings $boundings, + ezcGraphColor $color, + $startAngle = .0, + $endAngle = 360., + $label = false, + $moveOut = false ) { - $direction = $startAngle + ( $endAngle - $startAngle ) / 2; + // Calculate position and size of pie + $center = new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) / 2, + $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) / 2 + ); + + // Limit radius to fourth of width and half of height at maximum + $radius = min( + ( $boundings->x1 - $boundings->x0 ) / 4, + ( $boundings->y1 - $boundings->y0 ) / 2 + ) * ( 1 - $this->options->moveOut ); - if ( $moveOut > 0 ) + // Move pie segment out of the center + if ( $moveOut ) { - $position = new ezcGraphCoordinate( - $position->x + $moveOut * cos( deg2rad( $direction ) ), - $position->y + $moveOut * sin( deg2rad( $direction ) ) - ); + $direction = $startAngle + ( $endAngle - $startAngle ) / 2; + $center = new ezcGraphCoordinate( + $center->x + $this->options->moveOut * $radius * cos( deg2rad( $direction ) ), + $center->y + $this->options->moveOut * $radius * sin( deg2rad( $direction ) ) + ); } - - $darkenedColor = $color->darken( .5 ); + // Draw circle sector $this->driver->drawCircleSector( - $position, + $center, $radius * 2, $radius * 2, $startAngle, @@ -50,8 +96,9 @@ class ezcGraphRenderer2D extends ezcGraphRenderer true ); + $darkenedColor = $color->darken( .5 ); $this->driver->drawCircleSector( - $position, + $center, $radius * 2, $radius * 2, $startAngle, @@ -59,139 +106,711 @@ class ezcGraphRenderer2D extends ezcGraphRenderer $darkenedColor, false ); + + if ( $label ) + { + // Determine position of label + $middle = $startAngle + ( $endAngle - $startAngle ) / 2; + $pieSegmentCenter = new ezcGraphCoordinate( + cos( deg2rad( $middle ) ) * $radius + $center->x, + sin( deg2rad( $middle ) ) * $radius + $center->y + ); + + // Split labels up into left an right size and index them on their + // y position + $this->pieSegmentLabels[(int) ($pieSegmentCenter->x > $center->x)][$pieSegmentCenter->y] = array( + new ezcGraphCoordinate( + cos( deg2rad( $middle ) ) * $radius * 2 / 3 + $center->x, + sin( deg2rad( $middle ) ) * $radius * 2 / 3 + $center->y + ), + $label + ); + } + + if ( !$this->pieSegmentBoundings ) + { + $this->pieSegmentBoundings = $boundings; + } + } + + protected function finishPieSegmentLabels() + { + if ( $this->pieSegmentBoundings === false ) + { + return true; + } + + $boundings = $this->pieSegmentBoundings; + + // Calculate position and size of pie + $center = new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) / 2, + $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) / 2 + ); + + // Limit radius to fourth of width and half of height at maximum + $radius = min( + ( $boundings->x1 - $boundings->x0 ) / 4, + ( $boundings->y1 - $boundings->y0 ) / 2 + ); + + // Calculate maximum height of labels + $labelHeight = (int) round( min( + ( count( $this->pieSegmentLabels[0] ) + ? ( $boundings->y1 - $boundings->y0 ) / count( $this->pieSegmentLabels[0] ) + : ( $boundings->y1 - $boundings->y0 ) + ), + ( count( $this->pieSegmentLabels[1] ) + ? ( $boundings->y1 - $boundings->y0 ) / count( $this->pieSegmentLabels[1] ) + : ( $boundings->y1 - $boundings->y0 ) + ), + ( $boundings->y1 - $boundings->y0 ) * $this->options->maxLabelHeight + ) ); + + $symbolSize = $this->options->symbolSize; + + foreach ( $this->pieSegmentLabels as $side => $labelPart ) + { + $minHeight = $boundings->y0; + $toShare = ( $boundings->y1 - $boundings->y0 ) - count( $labelPart ) * $labelHeight; + + // Sort to draw topmost label first + ksort( $labelPart ); + $sign = ( $side ? -1 : 1 ); + + foreach ( $labelPart as $height => $label ) + { + // Determine position of label + $minHeight += max( 0, $height - $minHeight - $labelHeight ) / ( $boundings->y1 - $boundings->y0 ) * $toShare; + $labelPosition = new ezcGraphCoordinate( + $center->x - + $sign * ( + cos ( asin ( ( $center->y - $minHeight - $labelHeight / 2 ) / $radius ) ) * $radius + + $symbolSize * (int) $this->options->showSymbol + ), + $minHeight + $labelHeight / 2 + ); + + if ( $this->options->showSymbol ) + { + // Draw label + $this->driver->drawLine( + $label[0], + $labelPosition, + $this->options->font->color, + 1 + ); + + $this->driver->drawCircle( + new ezcGraphCoordinate( + $label[0]->x - $symbolSize / 2, + $label[0]->y - $symbolSize / 2 + ), + $symbolSize, + $symbolSize, + $this->options->font->color, + true + ); + $this->driver->drawCircle( + new ezcGraphCoordinate( + $labelPosition->x - $symbolSize / 2, + $labelPosition->y - $symbolSize / 2 + ), + $symbolSize, + $symbolSize, + $this->options->font->color, + true + ); + } + + $this->driver->drawTextBox( + $label[1], + new ezcGraphCoordinate( + ( !$side ? $boundings->x0 : $labelPosition->x + $symbolSize ), + $minHeight + ), + ( !$side ? $labelPosition->x - $boundings->x0 - $symbolSize : $boundings->x1 - $labelPosition->x - $symbolSize ), + $labelHeight, + ( !$side ? ezcGraph::RIGHT : ezcGraph::LEFT ) | ezcGraph::MIDDLE + ); + + // Add used space to minHeight + $minHeight += $labelHeight; + } + } } /** - * Draw a line + * Draw data line * - * Semantically means a line as a chart element, not a single line like - * the ones used in axes. + * Draws a line as a data element in a line chart * - * @param ezcGraphCoordinate $position - * @param ezcGraphCoordinate $end - * @param mixed $filled + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphColor $color Color of line + * @param ezcGraphCoordinate $start Starting point + * @param ezcGraphCoordinate $end Ending point + * @param int $symbol Symbol to draw for line + * @param ezcGraphColor $symbolColor Color of the symbol, defaults to linecolor + * @param ezcGraphColor $fillColor Color to fill line with + * @param float $axisPosition Position of axis for drawing filled lines + * @param float $thickness Line thickness * @return void */ - public function drawLine( ezcGraphColor $color, ezcGraphCoordinate $position, ezcGraphCoordinate $end, $thickness = 1 ) + public function drawDataLine( + ezcGraphBoundings $boundings, + ezcGraphColor $color, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + $symbol = ezcGraph::NO_SYMBOL, + ezcGraphColor $symbolColor = null, + ezcGraphColor $fillColor = null, + $axisPosition = 0., + $thickness = 1 ) { + // Perhaps fill up line + if ( $fillColor !== null && + $start->x != $end->x ) + { + $startValue = $axisPosition - $start->y; + $endValue = $axisPosition - $end->y; + + if ( ( $startValue == 0 ) || + ( $endValue == 0 ) || + ( $startValue / abs( $startValue ) == $endValue / abs( $endValue ) ) ) + { + // Values have the same sign or are on the axis + $this->driver->drawPolygon( + array( + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $start->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $start->y + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $end->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $end->y + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $end->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $axisPosition + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $start->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $axisPosition + ), + ), + $fillColor, + true + ); + } + else + { + // values are on differente sides of the axis - split the filled polygon + $startDiff = abs( $axisPosition - $start->y ); + $endDiff = abs( $axisPosition - $end->y ); + + $cuttingPosition = $startDiff / ( $endDiff / $startDiff ); + $cuttingPoint = new ezcGraphCoordinate( + $start->x + ( $end->x - $start->x ) * $cuttingPosition, + $axisPosition + ); + + $this->driver->drawPolygon( + array( + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $start->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $axisPosition + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $start->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $start->y + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $cuttingPoint->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $cuttingPoint->y + ), + ), + $fillColor, + true + ); + + $this->driver->drawPolygon( + array( + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $end->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $axisPosition + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $end->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $end->y + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $cuttingPoint->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $cuttingPoint->y + ), + ), + $fillColor, + true + ); + } + } + + // Draw line $this->driver->drawLine( - $position, - $end, + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $start->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $start->y + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $end->x, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $end->y + ), $color, - max( 1, $thickness ) + $thickness ); + + // Draw line symbol + if ( $symbol !== ezcGraph::NO_SYMBOL ) + { + if ( $symbolColor === null ) + { + $symbolColor = $color; + } + + $this->drawSymbol( + new ezcGraphBoundings( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $end->x - $this->options->symbolSize / 2, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $end->y - $this->options->symbolSize / 2, + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $end->x + $this->options->symbolSize / 2, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $end->y + $this->options->symbolSize / 2 + ), + $symbolColor, + $symbol + ); + } } /** - * Draws a text box + * Draw legend + * + * Will draw a legend in the bounding box * - * @param ezcGraphCoordinate $position - * @param mixed $text - * @param mixed $width - * @param mixed $height + * @param ezcGraphBoundings $boundings Bounding of legend + * @param ezcGraphChartElementLegend $labels Legend to draw + * @param int $type Type of legend: Protrait or landscape * @return void */ - public function drawTextBox( ezcGraphCoordinate $position, $text, $width = null, $height = null, $align = ezcGraph::LEFT ) + public function drawLegend( + ezcGraphBoundings $boundings, + ezcGraphChartElementLegend $legend, + $type = ezcGraph::VERTICAL ) { - $this->driver->drawTextBox( - $text, - $position, - $width, - $height, - $align - ); + $labels = $legend->labels; + + // Calculate boundings of each label + if ( $type & ezcGraph::VERTICAL ) + { + $labelWidth = $boundings->x1 - $boundings->x0; + $labelHeight = min( + ( $boundings->y1 - $boundings->y0 ) / count( $labels ) - $legend->spacing, + $legend->symbolSize + 2 * $legend->padding + ); + } + else + { + $labelWidth = ( $boundings->x1 - $boundings->x0 ) / count( $labels ) - $legend->spacing; + $labelHeight = min( + $boundings->x1 - $boundings->x0, + $legend->symbolSize + 2 * $legend->padding + ); + } + + $symbolSize = $labelHeight - 2 * $legend->padding; + + // Draw all labels + $labelPosition = new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ); + foreach ( $labels as $label ) + { + $this->drawSymbol( + new ezcGraphBoundings( + $labelPosition->x + $legend->padding, + $labelPosition->y + $legend->padding, + $labelPosition->x + $legend->padding + $symbolSize, + $labelPosition->y + $legend->padding + $symbolSize + ), + $label['color'], + $label['symbol'] + ); + + $this->driver->drawTextBox( + $label['label'], + new ezcGraphCoordinate( + $labelPosition->x + 2 * $legend->padding + $symbolSize, + $labelPosition->y + $legend->padding + ), + $labelWidth - $symbolSize - 3 * $legend->padding, + $labelHeight - 2 * $legend->padding, + ezcGraph::LEFT | ezcGraph::MIDDLE + ); + + $labelPosition->x += ( $type === ezcGraph::VERTICAL ? 0 : $labelWidth + $legend->spacing ); + $labelPosition->y += ( $type === ezcGraph::VERTICAL ? $labelHeight + $legend->spacing : 0 ); + } } /** - * Draws a rectangle + * Draw box + * + * Box are wrapping each major chart element and draw border, background + * and title to each chart element. * - * @param ezcGraphColor $color - * @param ezcGraphCoordinate $position - * @param mixed $width - * @param mixed $height - * @param float $borderWidth + * Optionally a padding and margin for each box can be defined. + * + * @param ezcGraphBoundings $boundings Boundings of the box + * @param ezcGraphColor $background Background color + * @param ezcGraphColor $borderColor Border color + * @param int $borderWidth Border width + * @param int $margin Margin + * @param int $padding Padding + * @param string $title Title of the box + * @param int $titleSize Size of title in the box + * @return ezcGraphBoundings Remaining inner boundings + */ + public function drawBox( + ezcGraphBoundings $boundings, + ezcGraphColor $background = null, + ezcGraphColor $borderColor = null, + $borderWidth = 0, + $margin = 0, + $padding = 0, + $title = false, + $titleSize = 16 ) + { + // Apply margin + $boundings->x0 += $margin; + $boundings->y0 += $margin; + $boundings->x1 -= $margin; + $boundings->y1 -= $margin; + + if ( ( $borderColor instanceof ezcGraphColor ) && + ( $borderWidth > 0 ) ) + { + // Draw border + $this->driver->drawPolygon( + array( + new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), + new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), + new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), + new ezcGraphCoordinate( $boundings->x0, $boundings->y1 ), + ), + $borderColor, + false + ); + + // Reduce local boundings by borderWidth + $boundings->x0 += $borderWidth; + $boundings->y0 += $borderWidth; + $boundings->x1 -= $borderWidth; + $boundings->y1 -= $borderWidth; + } + + if ( $background instanceof ezcGraphColor ) + { + // Draw box background + $this->driver->drawPolygon( + array( + new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), + new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), + new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), + new ezcGraphCoordinate( $boundings->x0, $boundings->y1 ), + ), + $background, + true + ); + } + + // Apply padding + $boundings->x0 += $padding; + $boundings->y0 += $padding; + $boundings->x1 -= $padding; + $boundings->y1 -= $padding; + + // Add box title + if ( $title !== false ) + { + switch ( $this->options->titlePosition ) + { + case ezcGraph::TOP: + $this->driver->drawTextBox( + $title, + new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), + $boundings->x1 - $boundings->x0, + $titleSize, + $this->options->titleAlignement + ); + + $boundings->y0 += $titleSize + $padding; + $boundings->y1 -= $titleSize + $padding; + break; + case ezcGraph::BOTTOM: + $this->driver->drawTextBox( + $title, + new ezcGraphCoordinate( $boundings->x0, $boundings->y1 - $titleSize ), + $boundings->x1 - $boundings->x0, + $titleSize, + $this->options->titleAlignement + ); + + $boundings->y1 -= $titleSize + $padding; + break; + } + } + + return $boundings; + } + + /** + * Draw text + * + * Draws the provided text in the boundings + * + * @param ezcGraphBoundings $boundings Boundings of text + * @param string $text Text + * @param int $align Alignement of text * @return void */ - public function drawRect( ezcGraphColor $color, ezcGraphCoordinate $position = null, $width = null, $height = null, $borderWidth = 1 ) + public function drawText( + ezcGraphBoundings $boundings, + $text, + $align = ezcGraph::LEFT ) { - $this->driver->drawPolygon( - array( - new ezcGraphCoordinate( $position->x, $position->y ), - new ezcGraphCoordinate( $position->x + $width, $position->y ), - new ezcGraphCoordinate( $position->x + $width, $position->y + $height ), - new ezcGraphCoordinate( $position->x, $position->y + $height ), - ), - $color, - false, - $borderWidth - ); + $this->driver->drawTextBox( + $text, + new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), + $boundings->x1 - $boundings->x0, + $boundings->y1 - $boundings->y0, + $align + ); } /** - * Draw Background + * Draw axis + * + * Draws an axis form the provided start point to the end point. A specific + * angle of the axis is not required. + * + * For the labeleing of the axis a sorted array with major steps and an + * array with minor steps is expected, which are build like this: + * array( + * array( + * 'position' => (float), + * 'label' => (string), + * ) + * ) + * where the label is optional. * - * Draws a filled rectangle, used for backgrounds + * The label renderer class defines how the labels are rendered. For more + * documentation on this topic have a look at the basic label renderer + * class. + * + * Additionally it can be specified if a major and minor grid are rendered + * by defining a color for them. Teh axis label is used to add a caption + * for the axis. * - * @param ezcGraphColor $color - * @param ezcGraphCoordinate $position - * @param mixed $width - * @param mixed $height + * @param ezcGraphBoundings $boundings Boundings of axis + * @param ezcGraphCoordinate $start Start point of axis + * @param ezcGraphCoordinate $end Endpoint of axis + * @param ezcGraphChartElementAxis $axis Axis to render + * @param ezcGraphLabelRenderer $labelClass Used label renderer * @return void */ - public function drawBackground( ezcGraphColor $color, ezcGraphCoordinate $position = null, $width = null, $height = null ) + public function drawAxis( + ezcGraphBoundings $boundings, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + ezcGraphChartElementAxis $axis, + ezcGraphAxisLabelRenderer $labelClass = null ) { + // Determine normalized direction + $direction = new ezcGraphCoordinate( + $start->x - $end->x, + $start->y - $end->y + ); + $length = sqrt( pow( $direction->x, 2) + pow( $direction->y, 2 ) ); + $direction->x /= $length; + $direction->y /= $length; + + // Draw axis + $this->driver->drawLine( + $start, + $end, + $axis->border, + 1 + ); + + // Draw small arrowhead + $size = min( + $axis->maxArrowHeadSize, + abs( ceil( ( ( $end->x - $start->x ) + ( $end->y - $start->y ) ) * $axis->axisSpace / 4 ) ) + ); + $this->driver->drawPolygon( array( - $position, - new ezcGraphCoordinate( $position->x + $width, $position->y ), - new ezcGraphCoordinate( $position->x + $width, $position->y + $height ), - new ezcGraphCoordinate( $position->x, $position->y + $height ) + new ezcGraphCoordinate( + $end->x, + $end->y + ), + new ezcGraphCoordinate( + $end->x + + $direction->y * $size / 2 + + $direction->x * $size, + $end->y + + $direction->x * $size / 2 + + $direction->y * $size + ), + new ezcGraphCoordinate( + $end->x + - $direction->y * $size / 2 + + $direction->x * $size, + $end->y + - $direction->x * $size / 2 + + $direction->y * $size + ), ), - $color, + $axis->border, true ); - + + // Apply axisSpace to start and end + $start->x += ( $end->x - $start->x ) * ( $axis->axisSpace / 2 ); + $start->y += ( $end->y - $start->y ) * ( $axis->axisSpace / 2 ); + $end->x -= ( $end->x - $start->x ) * ( $axis->axisSpace / 2 ); + $end->y -= ( $end->y - $start->y ) * ( $axis->axisSpace / 2 ); } - + /** - * Draws BackgrouniImage + * Draw background image + * + * Draws a background image at the defined position. If repeat is set the + * background image will be repeated like any texture. * - * @param mixed $file - * @param ezcGraphCoordinate $position - * @param mixed $width - * @param mixed $height + * @param ezcGraphBoundings $boundings Boundings for the background image + * @param string $file Filename of background image + * @param int $position Position of background image + * @param int $repeat Type of repetition * @return void */ - public function drawBackgroundImage( $file, ezcGraphCoordinate $position = null, $width = null, $height = null ) + public function drawBackgroundImage( + ezcGraphBoundings $boundings, + $file, + $position = 48, // ezcGraph::CENTER | ezcGraph::MIDDLE + $repeat = ezcGraph::NO_REPEAT ) { - $this->driver->drawImage( - $file, - $position, - $width, - $height - ); + $imageData = getimagesize( $file ); + $imageWidth = $imageData[0]; + $imageHeight = $imageData[1]; + + $imagePosition = new ezcGraphCoordinate( 0, 0 ); + + // Determine x position + switch ( true ) { + case ( $repeat & ezcGraph::HORIZONTAL ): + // If is repeated on this axis fall back to position zero + case ( $position & ezcGraph::LEFT ): + $imagePosition->x = $boundings->x0; + break; + case ( $position & ezcGraph::RIGHT ): + $imagePosition->x = max( + $boundings->x1 - $imageWidth, + $boundings->x0 + ); + break; + default: + $imagePosition->x = max( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 - $imageWidth ) / 2, + $boundings->x0 + ); + break; + } + + // Determine y position + switch ( true ) { + case ( $repeat & ezcGraph::VERTICAL ): + // If is repeated on this axis fall back to position zero + case ( $position & ezcGraph::TOP ): + $imagePosition->y = $boundings->y0; + break; + case ( $position & ezcGraph::BOTTOM ): + $imagePosition->y = max( + $boundings->y1 - $imageHeight, + $boundings->y0 + ); + break; + default: + $imagePosition->y = max( + $boundings->y0 + ( $boundings->y1 - $boundings->y0 - $imageHeight ) / 2, + $boundings->y0 + ); + break; + } + + $imageWidth = min( $imageWidth, $boundings->x1 - $boundings->x0 ); + $imageHeight = min( $imageHeight, $boundings->y1 - $boundings->y0 ); + + // Texturize backround based on position and repetition + $position = new ezcGraphCoordinate( + $imagePosition->x, + $imagePosition->y + ); + + do + { + $position->y = $imagePosition->y; + + do + { + $this->driver->drawImage( + $file, + $position, + $imageWidth, + $imageHeight + ); + + $position->y += $imageHeight; + } + while ( ( $position->y < $boundings->y1 ) && + ( $repeat & ezcGraph::VERTICAL ) ); + + $position->x += $imageWidth; + } + while ( ( $position->x < $boundings->x1 ) && + ( $repeat & ezcGraph::HORIZONTAL ) ); } /** - * Draws a lines symbol + * Draw Symbol + * + * Draws a single symbol defined by the symbol constants in ezcGraph. for + * NO_SYMBOL a rect will be drawn. * - * @param ezcGraphCoordinate $position - * @param float $width - * @param float $height - * @param int $symbol + * @param ezcGraphBoundings $boundings Boundings of symbol + * @param ezcGraphColor $color Color of symbol + * @param int $symbol Type of symbol * @return void */ - public function drawSymbol( ezcGraphColor $color, ezcGraphCoordinate $position, $width, $height, $symbol = ezcGraph::NO_SYMBOL) + public function drawSymbol( + ezcGraphBoundings $boundings, + ezcGraphColor $color, + $symbol = ezcGraph::NO_SYMBOL ) { switch ( $symbol ) { case ezcGraph::NO_SYMBOL: $this->driver->drawPolygon( array( - $position, - new ezcGraphCoordinate( $position->x + $width, $position->y ), - new ezcGraphCoordinate( $position->x + $width, $position->y + $height ), - new ezcGraphCoordinate( $position->x, $position->y + $height ) + new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ), + new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ), + new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ), + new ezcGraphCoordinate( $boundings->x0, $boundings->y1 ), ), $color, true @@ -200,10 +819,22 @@ class ezcGraphRenderer2D extends ezcGraphRenderer case ezcGraph::DIAMOND: $this->driver->drawPolygon( array( - new ezcGraphCoordinate( $position->x + $width / 2, $position->y ), - new ezcGraphCoordinate( $position->x + $width, $position->y + $height / 2 ), - new ezcGraphCoordinate( $position->x + $width / 2 , $position->y + $height ), - new ezcGraphCoordinate( $position->x, $position->y + $height / 2 ) + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) / 2, + $boundings->y0 + ), + new ezcGraphCoordinate( + $boundings->x1, + $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) / 2 + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) / 2, + $boundings->y1 + ), + new ezcGraphCoordinate( + $boundings->x0, + $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) / 2 + ), ), $color, true @@ -211,24 +842,37 @@ class ezcGraphRenderer2D extends ezcGraphRenderer break; case ezcGraph::BULLET: $this->driver->drawCircle( - new ezcGraphCoordinate( $position->x + $width / 2, $position->y + $height / 2 ), - $width, - $height, + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) / 2, + $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) / 2 + ), + $boundings->x1 - $boundings->x0, + $boundings->y1 - $boundings->y0, $color, true ); break; case ezcGraph::CIRCLE: $this->driver->drawCircle( - new ezcGraphCoordinate( $position->x + $width / 2, $position->y + $height / 2 ), - $width, - $height, + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) / 2, + $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) / 2 + ), + $boundings->x1 - $boundings->x0, + $boundings->y1 - $boundings->y0, $color, false ); break; } } + + protected function finish() + { + $this->finishPieSegmentLabels(); + + return true; + } } ?> diff --git a/src/renderer/axis_label_centered.php b/src/renderer/axis_label_centered.php new file mode 100644 index 0000000..04edfc4 --- /dev/null +++ b/src/renderer/axis_label_centered.php @@ -0,0 +1,37 @@ +<?php +/** + * File containing the abstract ezcGraphAxisLabelRenderer class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005, + 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Abstract class to render labels and grids on axis. Will be extended to + * make it possible using different algorithms for rendering axis labels. + * + * @package Graph + */ +abstract class ezcGraphAxisLabelRenderer +{ + /** + * Render Axis labels + * + * Render labels for an axis. + * + * @param ezcGraphBoundings $boundings Boundings of the axis + * @param ezcGraphCoordinate $start Axis starting point + * @param ezcGraphCoordinate $end Axis ending point + * @param ezcGraphChartElementAxis $axis Axis instance + * @return void + */ + abstract function renderLabels( + ezcGraphBoundings $boundings, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + ezcGraphChartElementAxis $axis + ); +} +?> diff --git a/src/renderer/axis_label_exact.php b/src/renderer/axis_label_exact.php new file mode 100644 index 0000000..9103956 --- /dev/null +++ b/src/renderer/axis_label_exact.php @@ -0,0 +1,124 @@ +<?php +/** + * File containing the abstract ezcGraphAxisExactLabelRenderer class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005, + 2006 eZ systems as. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Renders axis labels like known from charts drawn in analysis + * + * @package Graph + */ +class ezcGraphAxisExactLabelRenderer extends ezcGraphAxisLabelRenderer +{ + + /** + * Show the last value on the axis, which will be aligned different than + * all other values, to not interfere with the arrow head of the axis. + * + * @var boolean + */ + protected $showLastValue = true; + + /** + * Render Axis labels + * + * Render labels for an axis. + * + * @param ezcGraphBoundings $boundings Boundings of the axis + * @param ezcGraphCoordinate $start Axis starting point + * @param ezcGraphCoordinate $end Axis ending point + * @param ezcGraphChartElementAxis $axis Axis instance + * @param int $position Position of axis (left, right, or center) + * @return void + */ + public function renderLabels( + ezcGraphBoundings $boundings, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + ezcGraphChartElementAxis $axis, + $axisPosition ) + { + // Determine normalized axis direction + $direction = new ezcGraphCoordinate( + $start->x - $end->x, + $start->y - $end->y + ); + $length = sqrt( pow( $direction->x, 2) + pow( $direction->y, 2 ) ); + $direction->x /= $length; + $direction->y /= $length; + + // Calculate stepsizes for mjor and minor steps + $majorStep = new ezcGraphCoordinate( + ( $end->x - $start->x ) / $this->majorStepCount, + ( $end->y - $start->y ) / $this->majorStepCount + ); + + if ( $this->minorStepCount !== false ) + { + $minorStep = new ezcGraphCoordinate( + ( $end->x - $start->x ) / $this->minorStepCount, + ( $end->y - $start->y ) / $this->minorStepCount + ); + } + + if ( $this->outerGrid ) + { + $gridBoundings = $boundings; + } + else + { + $gridBoundings = new ezcGraphBoundings( + $boundings->x0 + ( $boundings->x1 - $boundings->x0 ) * $axis->axisSpace, + $boundings->y0 + ( $boundings->y1 - $boundings->y0 ) * $axis->axisSpace, + $boundings->x1 - ( $boundings->x1 - $boundings->x0 ) * $axis->axisSpace, + $boundings->y1 - ( $boundings->y1 - $boundings->y0 ) * $axis->axisSpace + ); + } + + // Draw steps and grid + while ( $start->x <= $end->x ) + { + // major step + $this->drawStep( $start, $direction, $axisPosition, $this->majorStepSize, $axis->border ); + + // major grid + if ( $this->majorGrid ) + { + $this->drawGrid( $gridBoundings, $start, $majorStep, $axis->majorGrid ); + } + + // second iteration for minor steps, if wanted + if ( $this->minorStepCount !== false ) + { + $minorGridPosition = new ezcGraphCoordinate( + $start->x + $minorStep->x, + $start->y + $minorStep->y + ); + + while ( $minorGridPosition->x < ( $start->x + $majorStep->x ) ) + { + // minor step + $this->drawStep( $minorGridPosition, $direction, $axisPosition, $this->minorStepSize, $axis->border ); + + // minor grid + if ( $this->minorGrid ) + { + $this->drawGrid( $gridBoundings, $minorGridPosition, $majorStep, $axis->minorGrid ); + } + + $minorGridPosition->x += $minorStep->x; + $minorGridPosition->y += $minorStep->y; + } + } + + $start->x += $majorStep->x; + $start->y += $majorStep->y; + } + } +} +?> diff --git a/src/structs/boundings.php b/src/structs/boundings.php index 003c72e..10a2e94 100644 --- a/src/structs/boundings.php +++ b/src/structs/boundings.php @@ -13,8 +13,12 @@ class ezcGraphBoundings /** * Empty constructor */ - public function __construct() + public function __construct( $x0 = 0, $y0 = 0, $x1 = false, $y1 = false ) { + $this->x0 = $x0; + $this->y0 = $y0; + $this->x1 = $x1; + $this->y1 = $y1; } /** |