diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/charts/horizontal_bar.php | 292 | ||||
-rw-r--r-- | src/charts/line.php | 74 | ||||
-rw-r--r-- | src/graph_autoload.php | 17 | ||||
-rw-r--r-- | src/interfaces/horizontal_bar_renderer.php | 48 | ||||
-rw-r--r-- | src/renderer/horizontal_bar.php | 177 |
5 files changed, 569 insertions, 39 deletions
diff --git a/src/charts/horizontal_bar.php b/src/charts/horizontal_bar.php new file mode 100644 index 0000000..7e4e4a0 --- /dev/null +++ b/src/charts/horizontal_bar.php @@ -0,0 +1,292 @@ +<?php +/** + * File containing the ezcGraphBarChart class + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Class for bar charts. Can make use of an unlimited amount of datasets and + * will display them as bars by default. + * X axis: + * - Labeled axis + * - Boxed axis label renderer + * Y axis: + * - Numeric axis + * - Exact axis label renderer + * + * <code> + * // Create a new horizontal bar chart + * $chart = new ezcGraphHorizontalBarChart(); + * + * // Add data to line chart + * $chart->data['sample dataset'] = new ezcGraphArrayDataSet( + * array( + * '100' => 1.2, + * '200' => 43.2, + * '300' => -34.14, + * '350' => 65, + * '400' => 123, + * ) + * ); + * + * // Render chart with the special designated renderer and default SVG driver + * $chart->renderer = new ezcGraphHorizontalRenderer(); + * $chart->render( 500, 200, 'bar_chart.svg' ); + * </code> + * + * Each chart consists of several chart elements which represents logical + * parts of the chart and can be formatted independently. The bar chart + * consists of: + * - title ( {@link ezcGraphChartElementText} ) + * - legend ( {@link ezcGraphChartElementLegend} ) + * - background ( {@link ezcGraphChartElementBackground} ) + * - xAxis ( {@link ezcGraphChartElementLabeledAxis} ) + * - yAxis ( {@link ezcGraphChartElementNumericAxis} ) + * + * The type of the axis may be changed and all elements can be configured by + * accessing them as properties of the chart: + * + * <code> + * $chart->legend->position = ezcGraph::RIGHT; + * </code> + * + * The chart itself also offers several options to configure the appearance. As + * bar charts extend line charts the the extended configure options are + * available in {@link ezcGraphLineChartOptions} extending the + * {@link ezcGraphChartOptions}. + * + * @property ezcGraphLineChartOptions $options + * Chart options class + * + * @version //autogentag// + * @package Graph + * @mainclass + */ +class ezcGraphHorizontalBarChart extends ezcGraphBarChart +{ + /** + * Constructor + * + * @param array $options Default option array + * @return void + * @ignore + */ + public function __construct( array $options = array() ) + { + parent::__construct(); + + $this->addElement( 'xAxis', new ezcGraphChartElementNumericAxis() ); + $this->elements['xAxis']->axisLabelRenderer = new ezcGraphAxisCenteredLabelRenderer(); + $this->elements['xAxis']->position = ezcGraph::LEFT; + + $this->addElement( 'yAxis', new ezcGraphChartElementLabeledAxis() ); + $this->elements['yAxis']->axisLabelRenderer = new ezcGraphAxisBoxedLabelRenderer(); + $this->elements['yAxis']->position = ezcGraph::BOTTOM; + + $this->renderer = new ezcGraphHorizontalRenderer(); + } + + /** + * Render the assigned data + * + * Will renderer all charts data in the remaining boundings after drawing + * all other chart elements. The data will be rendered depending on the + * settings in the dataset. + * + * @param ezcGraphRenderer $renderer Renderer + * @param ezcGraphBoundings $boundings Remaining boundings + * @return void + */ + protected function renderData( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings, ezcGraphBoundings $innerBoundings ) + { + // Use inner boundings for drawning chart data + $boundings = $innerBoundings; + + $yAxisNullPosition = $this->elements['xAxis']->getCoordinate( false ); + + // Initialize counters + $nr = array(); + $count = array(); + + foreach ( $this->data as $data ) + { + if ( !isset( $nr[$data->displayType->default] ) ) + { + $nr[$data->displayType->default] = 0; + $count[$data->displayType->default] = 0; + } + + $nr[$data->displayType->default]++; + $count[$data->displayType->default]++; + } + + $checkedRegularSteps = false; + + // Display data + foreach ( $this->data as $datasetName => $data ) + { + --$nr[$data->displayType->default]; + + // Check which axis should be used + $xAxis = ( $data->xAxis->default ? $data->xAxis->default: $this->elements['xAxis'] ); + $yAxis = ( $data->yAxis->default ? $data->yAxis->default: $this->elements['yAxis'] ); + + // 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; + } + + // Ensure regular steps on axis when used with bar charts and + // precalculate some values use to render bar charts + // + // Called only once and only when bars should be rendered + if ( ( $checkedRegularSteps === false ) && + ( $data->displayType->default === ezcGraph::BAR ) ) + { + $height = $this->calculateStepWidth( $yAxis, $xAxis, $boundings->height )->y; + } + + // Draw lines for dataset + $lastPoint = false; + foreach ( $data as $key => $value ) + { + // Calculate point in chart + $point = $xAxis->axisLabelRenderer->modifyChartDataPosition( + $yAxis->axisLabelRenderer->modifyChartDataPosition( + new ezcGraphCoordinate( + $xAxis->getCoordinate( $value ), + $yAxis->getCoordinate( $key ) + ) + ) + ); + + // Render depending on display type of dataset + switch ( true ) + { + case $data->displayType->default === ezcGraph::BAR: + $renderer->drawHorizontalBar( + $boundings, + new ezcGraphContext( $datasetName, $key, $data->url[$key] ), + $data->color[$key], + $point, + $height, + $nr[$data->displayType->default], + $count[$data->displayType->default], + $data->symbol[$key], + $yAxisNullPosition + ); + + // Render highlight string if requested + if ( $data->highlight[$key] ) + { + $renderer->drawDataHighlightText( + $boundings, + new ezcGraphContext( $datasetName, $key, $data->url[$key] ), + $point, + $yAxisNullPosition, + $nr[$data->displayType->default], + $count[$data->displayType->default], + $this->options->highlightFont, + ( $data->highlightValue[$key] ? $data->highlightValue[$key] : $value ), + $this->options->highlightSize + $this->options->highlightFont->padding * 2, + ( $this->options->highlightLines ? $data->color[$key] : null ), + ( $this->options->highlightXOffset ? $this->options->highlightXOffset : 0 ), + ( $this->options->highlightYOffset ? $this->options->highlightYOffset : 0 ), + $height, + $data->displayType->default + ); + } + break; + default: + throw new ezcGraphInvalidDisplayTypeException( $data->displayType->default ); + break; + } + + // Store last point, used to connect lines in line chart. + $lastPoint = $point; + } + } + } + + /** + * Aggregate and calculate value boundings on axis. + * + * This function is nearly the same as in ezcGraphLineChart, but reverses + * the usage of keys and values for the axis. + * + * @return void + */ + protected function setAxisValues() + { + // Virtual data set build for agrregated values sums for bar charts + $virtualBarSumDataSet = array( array(), array() ); + + // Calculate axis scaling and labeling + foreach ( $this->data as $dataset ) + { + $nr = 0; + $labels = array(); + $values = array(); + foreach ( $dataset as $label => $value ) + { + $labels[] = $label; + $values[] = $value; + + // Build sum of all bars + if ( $this->options->stackBars && + ( $dataset->displayType->default === ezcGraph::BAR ) ) + { + if ( !isset( $virtualBarSumDataSet[(int) $value >= 0][$nr] ) ) + { + $virtualBarSumDataSet[(int) $value >= 0][$nr++] = $value; + } + else + { + $virtualBarSumDataSet[(int) $value >= 0][$nr++] += $value; + } + } + } + + // Check if data has been associated with another custom axis, use + // default axis otherwise. + if ( $dataset->xAxis->default ) + { + $dataset->xAxis->default->addData( $values ); + } + else + { + $this->elements['xAxis']->addData( $values ); + } + + if ( $dataset->yAxis->default ) + { + $dataset->yAxis->default->addData( array_reverse( $labels ) ); + } + else + { + $this->elements['yAxis']->addData( array_reverse( $labels ) ); + } + } + + // There should always be something assigned to the main x and y axis. + if ( !$this->elements['xAxis']->initialized || + !$this->elements['yAxis']->initialized ) + { + throw new ezcGraphNoDataException(); + } + + // Calculate boundings from assigned data + $this->elements['xAxis']->calculateAxisBoundings(); + $this->elements['yAxis']->calculateAxisBoundings(); + } +} +?> diff --git a/src/charts/line.php b/src/charts/line.php index 3348920..4c0ba14 100644 --- a/src/charts/line.php +++ b/src/charts/line.php @@ -174,6 +174,47 @@ class ezcGraphLineChart extends ezcGraphChart } /** + * Calculate bar chart step width + * + * @return void + */ + protected function calculateStepWidth( ezcGraphChartElementAxis $mainAxis, ezcGraphChartElementAxis $secondAxis, $width ) + { + $steps = $mainAxis->getSteps(); + + $stepWidth = null; + foreach ( $steps as $step ) + { + if ( $stepWidth === null ) + { + $stepWidth = $step->width; + } + elseif ( $step->width !== $stepWidth ) + { + throw new ezcGraphUnregularStepsException(); + } + } + + $step = reset( $steps ); + if ( count( $step->childs ) ) + { + // Keep this for BC reasons + $barCount = ( $mainAxis->getMajorStepCount() + 1 ) * ( $mainAxis->getMinorStepCount() - 1 ); + $stepWidth = 1 / $barCount; + } + + $checkedRegularSteps = true; + return $mainAxis->axisLabelRenderer->modifyChartDataPosition( + $secondAxis->axisLabelRenderer->modifyChartDataPosition( + new ezcGraphCoordinate( + $width * $stepWidth, + $width * $stepWidth + ) + ) + ); + } + + /** * Render the assigned data * * Will renderer all charts data in the remaining boundings after drawing @@ -236,38 +277,7 @@ class ezcGraphLineChart extends ezcGraphChart if ( ( $checkedRegularSteps === false ) && ( $data->displayType->default === ezcGraph::BAR ) ) { - $steps = $xAxis->getSteps(); - - $stepWidth = null; - foreach ( $steps as $step ) - { - if ( $stepWidth === null ) - { - $stepWidth = $step->width; - } - elseif ( $step->width !== $stepWidth ) - { - throw new ezcGraphUnregularStepsException(); - } - } - - $step = reset( $steps ); - if ( count( $step->childs ) ) - { - // Keep this for BC reasons - $barCount = ( $xAxis->getMajorStepCount() + 1 ) * ( $xAxis->getMinorStepCount() - 1 ); - $stepWidth = 1 / $barCount; - } - - $checkedRegularSteps = true; - $width = $xAxis->axisLabelRenderer->modifyChartDataPosition( - $yAxis->axisLabelRenderer->modifyChartDataPosition( - new ezcGraphCoordinate( - ( $boundings->x1 - $boundings->x0 ) * $stepWidth, - 0 - ) - ) - )->x; + $width = $this->calculateStepWidth( $xAxis, $yAxis, $boundings->width )->x; } // Draw lines for dataset diff --git a/src/graph_autoload.php b/src/graph_autoload.php index d1e2e61..c66e1a2 100644 --- a/src/graph_autoload.php +++ b/src/graph_autoload.php @@ -40,8 +40,14 @@ return array( 'ezcGraphChart' => 'Graph/interfaces/chart.php', 'ezcGraphChartElement' => 'Graph/interfaces/element.php', 'ezcGraphChartOptions' => 'Graph/options/chart.php', + 'ezcGraphLineChart' => 'Graph/charts/line.php', 'ezcGraphMatrix' => 'Graph/math/matrix.php', + 'ezcGraphOdometerRenderer' => 'Graph/interfaces/odometer_renderer.php', + 'ezcGraphRadarRenderer' => 'Graph/interfaces/radar_renderer.php', + 'ezcGraphRenderer' => 'Graph/interfaces/renderer.php', + 'ezcGraphStackedBarsRenderer' => 'Graph/interfaces/stacked_bar_renderer.php', 'ezcGraphAxisLabelRenderer' => 'Graph/interfaces/axis_label_renderer.php', + 'ezcGraphBarChart' => 'Graph/charts/bar.php', 'ezcGraphChartDataContainer' => 'Graph/data_container/base.php', 'ezcGraphChartElementAxis' => 'Graph/element/axis.php', 'ezcGraphColor' => 'Graph/colors/color.php', @@ -50,13 +56,10 @@ return array( 'ezcGraphDataSetProperty' => 'Graph/interfaces/dataset_property.php', 'ezcGraphDriver' => 'Graph/interfaces/driver.php', 'ezcGraphDriverOptions' => 'Graph/options/driver.php', - 'ezcGraphLineChart' => 'Graph/charts/line.php', - 'ezcGraphOdometerRenderer' => 'Graph/interfaces/odometer_renderer.php', + 'ezcGraphHorizontalBarRenderer' => 'Graph/interfaces/horizontal_bar_renderer.php', 'ezcGraphPalette' => 'Graph/interfaces/palette.php', - 'ezcGraphRadarRenderer' => 'Graph/interfaces/radar_renderer.php', - 'ezcGraphRenderer' => 'Graph/interfaces/renderer.php', + 'ezcGraphRenderer2d' => 'Graph/renderer/2d.php', 'ezcGraphRendererOptions' => 'Graph/options/renderer.php', - 'ezcGraphStackedBarsRenderer' => 'Graph/interfaces/stacked_bar_renderer.php', 'ezcGraphTransformation' => 'Graph/math/transformation.php', 'ezcGraph' => 'Graph/graph.php', 'ezcGraphArrayDataSet' => 'Graph/datasets/array.php', @@ -68,7 +71,6 @@ return array( 'ezcGraphAxisRadarLabelRenderer' => 'Graph/renderer/axis_label_radar.php', 'ezcGraphAxisRotatedLabelRenderer' => 'Graph/renderer/axis_label_rotated.php', 'ezcGraphAxisStep' => 'Graph/structs/step.php', - 'ezcGraphBarChart' => 'Graph/charts/bar.php', 'ezcGraphBoundings' => 'Graph/math/boundings.php', 'ezcGraphCairoDriver' => 'Graph/driver/cairo.php', 'ezcGraphCairoDriverOptions' => 'Graph/options/cairo_driver.php', @@ -92,6 +94,8 @@ return array( 'ezcGraphFontOptions' => 'Graph/options/font.php', 'ezcGraphGdDriver' => 'Graph/driver/gd.php', 'ezcGraphGdDriverOptions' => 'Graph/options/gd_driver.php', + 'ezcGraphHorizontalBarChart' => 'Graph/charts/horizontal_bar.php', + 'ezcGraphHorizontalRenderer' => 'Graph/renderer/horizontal_bar.php', 'ezcGraphLineChartOptions' => 'Graph/options/line_chart.php', 'ezcGraphLinearGradient' => 'Graph/colors/linear_gradient.php', 'ezcGraphNumericDataSet' => 'Graph/datasets/numeric.php', @@ -109,7 +113,6 @@ return array( 'ezcGraphRadarChart' => 'Graph/charts/radar.php', 'ezcGraphRadarChartOptions' => 'Graph/options/radar_chart.php', 'ezcGraphRadialGradient' => 'Graph/colors/radial_gradient.php', - 'ezcGraphRenderer2d' => 'Graph/renderer/2d.php', 'ezcGraphRenderer2dOptions' => 'Graph/options/renderer_2d.php', 'ezcGraphRenderer3d' => 'Graph/renderer/3d.php', 'ezcGraphRenderer3dOptions' => 'Graph/options/renderer_3d.php', diff --git a/src/interfaces/horizontal_bar_renderer.php b/src/interfaces/horizontal_bar_renderer.php new file mode 100644 index 0000000..e6e937f --- /dev/null +++ b/src/interfaces/horizontal_bar_renderer.php @@ -0,0 +1,48 @@ +<?php +/** + * File containing the ezcGraphHorizontalBarRenderer interface + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Interface which adds the methods reqired to render horizontal bar charts to + * the renderer. + * + * @version //autogentag// + * @package Graph + */ +interface ezcGraphHorizontalBarRenderer +{ + /** + * Draw horizontal bar + * + * Draws a horizontal bar as a data element in a line chart + * + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphContext $context Context of call + * @param ezcGraphColor $color Color of line + * @param ezcGraphCoordinate $position Position of data point + * @param float $stepSize Space which can be used for bars + * @param int $dataNumber Number of dataset + * @param int $dataCount Count of datasets in chart + * @param int $symbol Symbol to draw for line + * @param float $axisPosition Position of axis for drawing filled lines + * @return void + */ + public function drawHorizontalBar( + ezcGraphBoundings $boundings, + ezcGraphContext $context, + ezcGraphColor $color, + ezcGraphCoordinate $position, + $stepSize, + $dataNumber = 1, + $dataCount = 1, + $symbol = ezcGraph::NO_SYMBOL, + $axisPosition = 0. + ); +} + +?> diff --git a/src/renderer/horizontal_bar.php b/src/renderer/horizontal_bar.php new file mode 100644 index 0000000..7448741 --- /dev/null +++ b/src/renderer/horizontal_bar.php @@ -0,0 +1,177 @@ +<?php +/** + * File containing the two dimensional renderer + * + * @package Graph + * @version //autogentag// + * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved. + * @license http://ez.no/licenses/new_bsd New BSD License + */ +/** + * Class to transform horizontal bar charts primitives into image primitives. + * Renders charts in a two dimensional view. + * + * The class options are defined in the class {@link ezcGraphRenderer2dOptions} + * extending the basic renderer options in {@link ezcGraphRendererOptions}. + * + * <code> + * @TODO: Add example + * </code> + * + * @version //autogentag// + * @package Graph + * @mainclass + */ +class ezcGraphHorizontalRenderer + extends + ezcGraphRenderer2d + implements + ezcGraphHorizontalBarRenderer +{ + /** + * Draw horizontal bar + * + * Draws a horizontal bar as a data element in a line chart + * + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphContext $context Context of call + * @param ezcGraphColor $color Color of line + * @param ezcGraphCoordinate $position Position of data point + * @param float $stepSize Space which can be used for bars + * @param int $dataNumber Number of dataset + * @param int $dataCount Count of datasets in chart + * @param int $symbol Symbol to draw for line + * @param float $axisPosition Position of axis for drawing filled lines + * @return void + */ + public function drawHorizontalBar( + ezcGraphBoundings $boundings, + ezcGraphContext $context, + ezcGraphColor $color, + ezcGraphCoordinate $position, + $stepSize, + $dataNumber = 1, + $dataCount = 1, + $symbol = ezcGraph::NO_SYMBOL, + $axisPosition = 0. ) + { + // Apply margin + $margin = $stepSize * $this->options->barMargin; + $padding = $stepSize * $this->options->barPadding; + $barHeight = ( $stepSize - $margin ) / $dataCount - $padding; + $offset = - $stepSize / 2 + $margin / 2 + ( $dataCount - $dataNumber - 1 ) * ( $padding + $barHeight ) + $padding / 2; + + $barPointArray = array( + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->width ) * $axisPosition, + $boundings->y0 + ( $boundings->height ) * $position->y + $offset + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->width ) * $position->x, + $boundings->y0 + ( $boundings->height ) * $position->y + $offset + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->width ) * $position->x, + $boundings->y0 + ( $boundings->height ) * $position->y + $offset + $barHeight + ), + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->width ) * $axisPosition, + $boundings->y0 + ( $boundings->height ) * $position->y + $offset + $barHeight + ), + ); + + $this->addElementReference( + $context, + $this->driver->drawPolygon( + $barPointArray, + $color, + true + ) + ); + + if ( $this->options->dataBorder > 0 ) + { + $darkened = $color->darken( $this->options->dataBorder ); + $this->driver->drawPolygon( + $barPointArray, + $darkened, + false, + 1 + ); + } + } + + /** + * Draw bar + * + * Draws a bar as a data element in a line chart + * + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphContext $context Context of call + * @param ezcGraphColor $color Color of line + * @param ezcGraphCoordinate $position Position of data point + * @param float $stepSize Space which can be used for bars + * @param int $dataNumber Number of dataset + * @param int $dataCount Count of datasets in chart + * @param int $symbol Symbol to draw for line + * @param float $axisPosition Position of axis for drawing filled lines + * @return void + */ + public function drawBar( + ezcGraphBoundings $boundings, + ezcGraphContext $context, + ezcGraphColor $color, + ezcGraphCoordinate $position, + $stepSize, + $dataNumber = 1, + $dataCount = 1, + $symbol = ezcGraph::NO_SYMBOL, + $axisPosition = 0. ) + { + throw new ezcBaseFunctionalityNotSupportedException( + "A normal bar chart", + "Only horizontal bar charts can be renderered with the ezcGraphHorizontalRenderer" + ); + } + + /** + * Draw data line + * + * Draws a line as a data element in a line chart + * + * @param ezcGraphBoundings $boundings Chart boundings + * @param ezcGraphContext $context Context of call + * @param ezcGraphColor $color Color of line + * @param ezcGraphCoordinate $start Starting point + * @param ezcGraphCoordinate $end Ending point + * @param int $dataNumber Number of dataset + * @param int $dataCount Count of datasets in chart + * @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 drawDataLine( + ezcGraphBoundings $boundings, + ezcGraphContext $context, + ezcGraphColor $color, + ezcGraphCoordinate $start, + ezcGraphCoordinate $end, + $dataNumber = 1, + $dataCount = 1, + $symbol = ezcGraph::NO_SYMBOL, + ezcGraphColor $symbolColor = null, + ezcGraphColor $fillColor = null, + $axisPosition = 0., + $thickness = 1. ) + { + throw new ezcBaseFunctionalityNotSupportedException( + "A normal line chart", + "Only horizontal bar charts can be renderered with the ezcGraphHorizontalRenderer" + ); + } +} + +?> |