From 825295b8ae3979aff902f485edf00e8e513fb067 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Fri, 11 Dec 2015 16:17:39 -0600 Subject: Enable stacked rendering for horizontal bar charts --- src/charts/horizontal_bar.php | 89 +++++++++++++++++++++- src/renderer/horizontal_bar.php | 70 +++++++++++++++++ tests/renderer_horizontal_bar_test.php | 135 +++++++++++++++++++++++++++++++++ 3 files changed, 291 insertions(+), 3 deletions(-) create mode 100644 tests/renderer_horizontal_bar_test.php diff --git a/src/charts/horizontal_bar.php b/src/charts/horizontal_bar.php index feb9122..9fe700e 100644 --- a/src/charts/horizontal_bar.php +++ b/src/charts/horizontal_bar.php @@ -121,7 +121,7 @@ class ezcGraphHorizontalBarChart extends ezcGraphBarChart // Use inner boundings for drawning chart data $boundings = $innerBoundings; - $yAxisNullPosition = $this->elements['xAxis']->getCoordinate( false ); + $xAxisNullPosition = $this->elements['xAxis']->getCoordinate( false ); // Initialize counters $nr = array(); @@ -188,6 +188,81 @@ class ezcGraphHorizontalBarChart extends ezcGraphBarChart // Render depending on display type of dataset switch ( true ) { + case ( $data->displayType->default === ezcGraph::BAR ) && + $this->options->stackBars : + // Check if a bar has already been stacked + if ( !isset( $stackedValue[(int) ( $point->y * 10000 )][(int) $value > 0] ) ) + { + $start = new ezcGraphCoordinate( + $xAxisNullPosition, + $point->y + ); + + $stackedValue[(int) ( $point->y * 10000 )][(int) $value > 0] = $value; + } + else + { + $start = $yAxis->axisLabelRenderer->modifyChartDataPosition( + $xAxis->axisLabelRenderer->modifyChartDataPosition( + new ezcGraphCoordinate( + $xAxis->getCoordinate( $stackedValue[(int) ( $point->y * 10000 )][(int) $value > 0] ), + $yAxis->getCoordinate( $key ) + ) + ) + ); + + $point = $yAxis->axisLabelRenderer->modifyChartDataPosition( + $xAxis->axisLabelRenderer->modifyChartDataPosition( + new ezcGraphCoordinate( + $xAxis->getCoordinate( $stackedValue[(int) ( $point->y * 10000 )][(int) $value > 0] += $value ), + $yAxis->getCoordinate( $key ) + ) + ) + ); + } + + // Force one symbol for each stacked bar + if ( !isset( $stackedSymbol[(int) ( $point->y * 10000 )] ) ) + { + $stackedSymbol[(int) ( $point->y * 10000 )] = $data->symbol[$key]; + } + + // Store stacked value for next iteration + $side = ( $point->x == 0 ? 1 : $point->x / abs( $point->x ) ); + $stacked[(int) ( $point->y * 10000 )][$side] = $point; + + $renderer->drawHorizontalStackedBar( + $boundings, + new ezcGraphContext( $datasetName, $key, $data->url[$key] ), + $data->color->default, + $start, + $point, + $height, + $stackedSymbol[(int) ( $point->y * 10000 )], + $xAxisNullPosition + ); + + // Render highlight string if requested + if ( $data->highlight[$key] ) + { + $renderer->drawDataHighlightText( + $boundings, + new ezcGraphContext( $datasetName, $key, $data->url[$key] ), + $point, + $xAxisNullPosition, + $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; case $data->displayType->default === ezcGraph::BAR: $renderer->drawHorizontalBar( $boundings, @@ -198,7 +273,7 @@ class ezcGraphHorizontalBarChart extends ezcGraphBarChart $nr[$data->displayType->default], $count[$data->displayType->default], $data->symbol[$key], - $yAxisNullPosition + $xAxisNullPosition ); // Render highlight string if requested @@ -208,7 +283,7 @@ class ezcGraphHorizontalBarChart extends ezcGraphBarChart $boundings, new ezcGraphContext( $datasetName, $key, $data->url[$key] ), $point, - $yAxisNullPosition, + $xAxisNullPosition, $nr[$data->displayType->default], $count[$data->displayType->default], $this->options->highlightFont, @@ -293,6 +368,14 @@ class ezcGraphHorizontalBarChart extends ezcGraphBarChart } } + // Also use stacked bar values as base for x axis value span + // calculation + if ( $this->options->stackBars ) + { + $this->elements['xAxis']->addData( $virtualBarSumDataSet[0] ); + $this->elements['xAxis']->addData( $virtualBarSumDataSet[1] ); + } + // There should always be something assigned to the main x and y axis. if ( !$this->elements['xAxis']->initialized || !$this->elements['yAxis']->initialized ) diff --git a/src/renderer/horizontal_bar.php b/src/renderer/horizontal_bar.php index d8c143e..c851188 100644 --- a/src/renderer/horizontal_bar.php +++ b/src/renderer/horizontal_bar.php @@ -118,6 +118,76 @@ class ezcGraphHorizontalRenderer } /** + * Draw horizontal stacked bar + * + * Draws a horizontal stacked bar part 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 + * @param ezcGraphCoordinate $position + * @param float $stepSize Space which can be used for bars + * @param int $symbol Symbol to draw for line + * @param float $axisPosition Position of axis for drawing filled lines + * @return void + */ + public function drawHorizontalStackedBar( + ezcGraphBoundings $boundings, + ezcGraphContext $context, + ezcGraphColor $color, + ezcGraphCoordinate $start, + ezcGraphCoordinate $position, + $stepSize, + $symbol = ezcGraph::NO_SYMBOL, + $axisPosition = 0. ) + { + // Apply margin + $margin = $stepSize * $this->options->barMargin; + $barHeight = $stepSize - $margin; + $offset = - $stepSize / 2 + $margin / 2; + + $barPointArray = array( + new ezcGraphCoordinate( + $boundings->x0 + ( $boundings->width ) * $start->x, + $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 ) * $start->x, + $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 diff --git a/tests/renderer_horizontal_bar_test.php b/tests/renderer_horizontal_bar_test.php new file mode 100644 index 0000000..32b5715 --- /dev/null +++ b/tests/renderer_horizontal_bar_test.php @@ -0,0 +1,135 @@ +markTestSkipped( "This test requires PHP 5.1.3 or later." ); + } + + $this->tempDir = $this->createTempDir( __CLASS__ . sprintf( '_%03d_', ++$i ) ) . '/'; + $this->basePath = dirname( __FILE__ ) . '/data/'; + + $this->renderer = new ezcGraphHorizontalRenderer(); + + $this->driver = $this->getMockBuilder( 'ezcGraphSvgDriver' ) + ->enableArgumentCloning() + ->setMethods( array( + 'drawPolygon', + 'drawLine', + 'drawTextBox', + 'drawCircleSector', + 'drawCircularArc', + 'drawCircle', + 'drawImage', + ) )->getMock(); + $this->renderer->setDriver( $this->driver ); + + $this->driver->options->width= 400; + $this->driver->options->height= 200; + } + + public function tearDown() + { + $this->driver = null; + $this->renderer = null; + + if ( !$this->hasFailed() ) + { + $this->removeTempDir(); + } + } +// /* + + public function testRenderHorizontalStackedBar() + { + $this->driver + ->expects( $this->at( 0 ) ) + ->method( 'drawPolygon' ) + ->with( + $this->equalTo( array( + new ezcGraphCoordinate( 200, 75. ), + new ezcGraphCoordinate( 200, 75. ), + new ezcGraphCoordinate( 200, 165. ), + new ezcGraphCoordinate( 200, 165. ), + ), 1. ), + $this->equalTo( ezcGraphColor::fromHex( '#FF0000' ) ), + $this->equalTo( true ) + ); + $this->driver + ->expects( $this->at( 1 ) ) + ->method( 'drawPolygon' ) + ->with( + $this->equalTo( array( + new ezcGraphCoordinate( 200, 75. ), + new ezcGraphCoordinate( 200, 75. ), + new ezcGraphCoordinate( 200, 165. ), + new ezcGraphCoordinate( 200, 165. ), + ), 1. ), + $this->equalTo( ezcGraphColor::fromHex( '#800000' ) ), + $this->equalTo( false ) + ); + + $this->renderer->drawHorizontalStackedBar( + new ezcGraphBoundings( 0, 0, 400, 200 ), + new ezcGraphContext(), + ezcGraphColor::fromHex( '#FF0000' ), + new ezcGraphCoordinate( .5, .2 ), + new ezcGraphCoordinate( .5, .6 ), + 100, + 0 + ); + } +} +?> -- cgit v1.1