summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKore Nordmann <github@kore-nordmann.de>2007-11-21 11:36:02 +0000
committerKore Nordmann <github@kore-nordmann.de>2007-11-21 11:36:02 +0000
commit02bd18b4ba30a5888633c1210d444c6b4503c4d6 (patch)
treebc98eee3be92ce76823b6114abee77ac12a75475
parent07fb592880d4a394d7e7af2a97f22a84faa18479 (diff)
downloadzetacomponents-graph-02bd18b4ba30a5888633c1210d444c6b4503c4d6.zip
zetacomponents-graph-02bd18b4ba30a5888633c1210d444c6b4503c4d6.tar.gz
- Added support for odometer charts
# Thanks to Lars Jankowski from Oxid esales for the initial patch.
-rw-r--r--design/class_diagram.pngbin222845 -> 247024 bytes
-rw-r--r--src/charts/odometer.php191
-rw-r--r--src/element/axis.php1
-rw-r--r--src/graph.php4
-rw-r--r--src/graph_autoload.php3
-rw-r--r--src/interfaces/odometer_renderer.php51
-rw-r--r--src/options/odometer_chart.php113
-rw-r--r--src/renderer/2d.php155
-rw-r--r--tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometer.svg2
-rw-r--r--tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerToOutput.svg2
-rw-r--r--tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerWithDifferentOptions.svg2
11 files changed, 492 insertions, 32 deletions
diff --git a/design/class_diagram.png b/design/class_diagram.png
index c35f5d5..b337990 100644
--- a/design/class_diagram.png
+++ b/design/class_diagram.png
Binary files differ
diff --git a/src/charts/odometer.php b/src/charts/odometer.php
new file mode 100644
index 0000000..047139d
--- /dev/null
+++ b/src/charts/odometer.php
@@ -0,0 +1,191 @@
+<?php
+/**
+ * File containing the ezcGraphPieChart class
+ *
+ * @package Graph
+ * @version 1.1
+ * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ */
+
+class ezcGraphOdometerChart extends ezcGraphChart
+{
+
+ /**
+ * Constructor
+ *
+ * @param array $options Default option array
+ * @return void
+ * @ignore
+ */
+ public function __construct( array $options = array() )
+ {
+ $this->options = new ezcGraphOdometerChartOptions( $options );
+
+ parent::__construct( $options );
+
+ $this->data = new ezcGraphChartSingleDataContainer( $this );
+
+ $this->addElement( 'axis', new ezcGraphChartElementNumericAxis());
+ $this->elements['axis']->axisLabelRenderer = new ezcGraphAxisCenteredLabelRenderer();
+ $this->elements['axis']->position = ezcGraph::LEFT;
+ $this->elements['axis']->axisSpace = .05;
+ }
+
+ /**
+ * 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 )
+ {
+ // Draw the odometer data
+ $dataset = $this->data->rewind();
+
+ foreach ( $dataset as $key => $value )
+ {
+ $renderer->drawOdometerMarker(
+ $boundings,
+ $this->elements['axis']->axisLabelRenderer->modifyChartDataPosition(
+ new ezcGraphCoordinate(
+ $this->elements['axis']->getCoordinate( $value ),
+ 0
+ )
+ ),
+ $dataset->symbol[$key],
+ $dataset->color[$key],
+ $this->options->markerWidth
+ );
+ }
+ }
+
+ /**
+ * Returns the default display type of the current chart type.
+ *
+ * @return int Display type
+ */
+ public function getDefaultDisplayType()
+ {
+ return ezcGraph::ODOMETER;
+ }
+
+ /**
+ * Renders the basic elements of this chart type
+ *
+ * @param int $width
+ * @param int $height
+ * @return void
+ */
+ protected function renderElements( $width, $height )
+ {
+ if ( !count( $this->data ) )
+ {
+ throw new ezcGraphNoDataException();
+ }
+
+ // Set image properties in driver
+ $this->driver->options->width = $width;
+ $this->driver->options->height = $height;
+
+ // no legend
+ $this->renderElement['legend'] = false;
+
+ // Get boundings from parameters
+ $this->options->width = $width;
+ $this->options->height = $height;
+
+ $boundings = new ezcGraphBoundings();
+ $boundings->x1 = $this->options->width;
+ $boundings->y1 = $this->options->height;
+
+ // Get values out the single used dataset to calculate axis boundings
+ $values = array();
+ foreach( $this->data->rewind() as $value )
+ {
+ $values[] = $value;
+ }
+
+ // Set values for Axis
+ $this->elements['axis']->addData( $values );
+ $this->elements['axis']->nullPosition = 0.5 + $this->options->odometerHeight / 2;
+ $this->elements['axis']->calculateAxisBoundings();
+
+ // Render subelements exept axis, which will be drawn together with the
+ // odometer bar
+ foreach ( $this->elements as $name => $element )
+ {
+ // Skip element, if it should not get rendered
+ if ( $this->renderElement[$name] === false ||
+ $name === 'axis' )
+ {
+ continue;
+ }
+
+ $this->driver->options->font = $element->font;
+ $boundings = $element->render( $this->renderer, $boundings );
+ }
+
+ // Draw basic odometer
+ $this->driver->options->font = $this->elements['axis']->font;
+ $boundings = $this->renderer->drawOdometer(
+ $boundings,
+ $this->elements['axis'],
+ $this->options
+ );
+
+ // Render graph
+ $this->renderData( $this->renderer, $boundings );
+ }
+
+ /**
+ * Render the pie chart
+ *
+ * Renders the chart into a file or stream. The width and height are
+ * needed to specify the dimensions of the resulting image. For direct
+ * output use 'php://stdout' as output file.
+ *
+ * @param int $width Image width
+ * @param int $height Image height
+ * @param string $file Output file
+ * @apichange
+ * @return void
+ */
+ public function render( $width, $height, $file = null )
+ {
+ $this->renderElements( $width, $height );
+
+ if ( !empty( $file ) )
+ {
+ $this->renderer->render( $file );
+ }
+
+ $this->renderedFile = $file;
+ }
+
+ /**
+ * Renders this chart to direct output
+ *
+ * Does the same as ezcGraphChart::render(), but renders directly to
+ * output and not into a file.
+ *
+ * @param int $width
+ * @param int $height
+ * @apichange
+ * @return void
+ */
+ public function renderToOutput( $width, $height )
+ {
+ // @TODO: merge this function with render an deprecate ommit of third
+ // argument in render() when API break is possible
+ $this->renderElements( $width, $height );
+ $this->renderer->render( null );
+ }
+}
+
+?>
diff --git a/src/element/axis.php b/src/element/axis.php
index b4d2a55..db8c57b 100644
--- a/src/element/axis.php
+++ b/src/element/axis.php
@@ -19,6 +19,7 @@
* Color of major majorGrid.
* @property ezcGraphColor $minorGrid
* Color of minor majorGrid.
+ * @TODO: Move next two options to numeric axis
* @property mixed $majorStep
* Labeled major steps displayed on the axis.
* @property mixed $minorStep
diff --git a/src/graph.php b/src/graph.php
index 6653533..3ccbe5a 100644
--- a/src/graph.php
+++ b/src/graph.php
@@ -98,6 +98,10 @@ class ezcGraph
* type ezcGraph::BAR.
*/
const BAR = 3;
+ /**
+ * @TODO:
+ */
+ const ODOMETER = 4;
/**
* Font type definition. Used for True Type fonts.
diff --git a/src/graph_autoload.php b/src/graph_autoload.php
index 1297421..9c54a17 100644
--- a/src/graph_autoload.php
+++ b/src/graph_autoload.php
@@ -52,6 +52,7 @@ return array(
'ezcGraphDriver' => 'Graph/interfaces/driver.php',
'ezcGraphDriverOptions' => 'Graph/options/driver.php',
'ezcGraphLineChart' => 'Graph/charts/line.php',
+ 'ezcGraphOdometerRenderer' => 'Graph/interfaces/odometer_renderer.php',
'ezcGraphPalette' => 'Graph/interfaces/palette.php',
'ezcGraphRadarRenderer' => 'Graph/interfaces/radar_renderer.php',
'ezcGraphRenderer' => 'Graph/interfaces/renderer.php',
@@ -93,6 +94,8 @@ return array(
'ezcGraphLineChartOptions' => 'Graph/options/line_chart.php',
'ezcGraphLinearGradient' => 'Graph/colors/linear_gradient.php',
'ezcGraphNumericDataSet' => 'Graph/datasets/numeric.php',
+ 'ezcGraphOdometerChart' => 'Graph/charts/odometer.php',
+ 'ezcGraphOdometerChartOptions' => 'Graph/options/odometer_chart.php',
'ezcGraphPaletteBlack' => 'Graph/palette/black.php',
'ezcGraphPaletteEz' => 'Graph/palette/ez.php',
'ezcGraphPaletteEzBlue' => 'Graph/palette/ez_blue.php',
diff --git a/src/interfaces/odometer_renderer.php b/src/interfaces/odometer_renderer.php
new file mode 100644
index 0000000..98053ae
--- /dev/null
+++ b/src/interfaces/odometer_renderer.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * File containing the ezcGraphRadarRenderer interface
+ *
+ * @package Graph
+ * @version 1.1
+ * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved.
+ 2006 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ */
+/**
+ * Interface which adds the methods required for rendering radar charts to a
+ * renderer
+ *
+ * @version 1.1
+ * @package Graph
+ */
+interface ezcGraphOdometerRenderer
+{
+ /**
+ * Render odometer chart
+ *
+ * @param ezcGraphBoundings $boundings
+ * @param ezcGraphOdometerChartOptions $options
+ * @return ezcGraphBoundings
+ */
+ public function drawOdometer(
+ ezcGraphBoundings $boundings,
+ ezcGraphChartElementAxis $axis,
+ ezcGraphOdometerChartOptions $options
+ );
+
+ /**
+ * Draw a single odometer marker.
+ *
+ * @param ezcGraphBoundings $boundings
+ * @param ezcGraphCoordinate $position
+ * @param int $symbol
+ * @param ezcGraphColor $color
+ * @param int $width
+ */
+ public function drawOdometerMarker(
+ ezcGraphBoundings $boundings,
+ ezcGraphCoordinate $position,
+ $symbol,
+ ezcGraphColor $color,
+ $width
+ );
+}
+
+?>
diff --git a/src/options/odometer_chart.php b/src/options/odometer_chart.php
new file mode 100644
index 0000000..9b4adda
--- /dev/null
+++ b/src/options/odometer_chart.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * File containing the ezcGraphPieChartOption class
+ *
+ * @package Graph
+ * @version 1.1
+ * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ */
+
+/**
+ * Class containing the options for odometer charts
+ *
+ * <code>
+ * $graph = new ezcGraphOdoMeterChart();
+ *
+ * $graph->data['Test'] = new ezcGraphArrayDataSet( array( 0, 1, 23, 30 ) );
+ *
+ * $graph->options->odometerHeight = .3;
+ * $graph->options->borderColor = '#2e3436';
+ *
+ * $graph->render( 150, 50, 'odometer.svg' );
+ * </code>
+ *
+ * @property ezcGraphColor $borderColor
+ * Color of border around odometer chart
+ * @property int $borderWidth
+ * Width of border around odometer chart
+ * @property ezcGraphColor $startColor
+ * Start color of grdient used as the odometer chart background.
+ * @property ezcGraphColor $endColor
+ * End color of grdient used as the odometer chart background.
+ * @property int $markerWidth
+ * Width of odometer markers
+ * @property float $odometerHeight
+ * Height consumed by odometer chart
+ *
+ * @version //autogentag//
+ * @package Graph
+ */
+class ezcGraphOdometerChartOptions extends ezcGraphChartOptions
+{
+ /**
+ * Constructor
+ *
+ * @param array $options Default option array
+ * @return void
+ * @ignore
+ */
+ public function __construct( array $options = array() )
+ {
+ $this->properties['borderColor'] = ezcGraphColor::create( '#000000' );
+ $this->properties['borderWidth'] = 0;
+
+ $this->properties['startColor'] = ezcGraphColor::create( '#4e9a06A0' );
+ $this->properties['endColor'] = ezcGraphColor::create( '#A40000A0' );
+
+ $this->properties['markerWidth'] = 2;
+
+ $this->properties['odometerHeight'] = 0.5;
+
+ parent::__construct( $options );
+ }
+
+ /**
+ * Set an option value
+ *
+ * @param string $propertyName
+ * @param mixed $propertyValue
+ * @throws ezcBasePropertyNotFoundException
+ * If a property is not defined in this class
+ * @return void
+ * @ignore
+ */
+ public function __set( $propertyName, $propertyValue )
+ {
+ switch ( $propertyName )
+ {
+ case 'borderWidth':
+ case 'markerWidth':
+ if ( !is_numeric( $propertyValue ) ||
+ ( $propertyValue < 1 ) )
+ {
+ throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 1' );
+ }
+
+ $this->properties[$propertyName] = (int) $propertyValue;
+ break;
+
+ case 'borderColor':
+ case 'startColor':
+ case 'endColor':
+ $this->properties[$propertyName] = ezcGraphColor::create( $propertyValue );
+ break;
+
+ case 'odometerHeight':
+ if ( !is_numeric( $propertyValue ) ||
+ ( $propertyValue < 0 ) ||
+ ( $propertyValue > 1 ) )
+ {
+ throw new ezcBaseValueException( $propertyName, $propertyValue, '0 <= float <= 1' );
+ }
+
+ $this->properties[$propertyName] = (float) $propertyValue;
+ break;
+
+ default:
+ return parent::__set( $propertyName, $propertyValue );
+ }
+ }
+}
+
+?>
diff --git a/src/renderer/2d.php b/src/renderer/2d.php
index a1e12d0..c70b8a3 100644
--- a/src/renderer/2d.php
+++ b/src/renderer/2d.php
@@ -60,8 +60,7 @@ class ezcGraphRenderer2d
extends
ezcGraphRenderer
implements
- ezcGraphRadarRenderer,
- ezcGraphStackedBarsRenderer
+ ezcGraphRadarRenderer, ezcGraphStackedBarsRenderer, ezcGraphOdometerRenderer
{
/**
@@ -1430,42 +1429,52 @@ class ezcGraphRenderer2d
if ( $this->xAxisSpace && $this->yAxisSpace )
{
- foreach ( $this->axisLabels as $nr => $axisLabel )
- {
- $start = $axisLabel['start'];
- $end = $axisLabel['end'];
+ $this->drawAxisLabels();
+ }
+ }
- $direction = new ezcGraphVector(
- $end->x - $start->x,
- $end->y - $start->y
- );
- $direction->unify();
+ /**
+ * Draw all left axis labels
+ *
+ * @return void
+ */
+ protected function drawAxisLabels()
+ {
+ foreach ( $this->axisLabels as $nr => $axisLabel )
+ {
+ $start = $axisLabel['start'];
+ $end = $axisLabel['end'];
- // Convert elipse to circle for correct angle calculation
- $direction->y *= ( $this->xAxisSpace / $this->yAxisSpace );
- $angle = $direction->angle( new ezcGraphVector( 0, 1 ) );
+ $direction = new ezcGraphVector(
+ $end->x - $start->x,
+ $end->y - $start->y
+ );
+ $direction->unify();
- $movement = new ezcGraphVector(
- sin( $angle ) * $this->xAxisSpace * ( $direction->x < 0 ? -1 : 1 ),
- cos( $angle ) * $this->yAxisSpace
- );
+ // Convert elipse to circle for correct angle calculation
+ $direction->y *= ( $this->xAxisSpace / $this->yAxisSpace );
+ $angle = $direction->angle( new ezcGraphVector( 0, 1 ) );
- $start->x += $movement->x;
- $start->y += $movement->y;
- $end->x -= $movement->x;
- $end->y -= $movement->y;
+ $movement = new ezcGraphVector(
+ sin( $angle ) * $this->xAxisSpace * ( $direction->x < 0 ? -1 : 1 ),
+ cos( $angle ) * $this->yAxisSpace
+ );
- $axisLabel['object']->renderLabels(
- $this,
- $axisLabel['boundings'],
- $start,
- $end,
- $axisLabel['axis']
- );
+ $start->x += $movement->x;
+ $start->y += $movement->y;
+ $end->x -= $movement->x;
+ $end->y -= $movement->y;
+
+ $axisLabel['object']->renderLabels(
+ $this,
+ $axisLabel['boundings'],
+ $start,
+ $end,
+ $axisLabel['axis']
+ );
- // Prevent from redrawing axis on more then 2 axis.
- unset( $this->axisLabels[$nr] );
- }
+ // Prevent from redrawing axis on more then 2 axis.
+ unset( $this->axisLabels[$nr] );
}
}
@@ -1584,6 +1593,88 @@ class ezcGraphRenderer2d
return true;
}
+
+
+ /**
+ * Render odometer chart
+ *
+ * @param ezcGraphBoundings $boundings
+ * @param ezcGraphOdometerChartOptions $options
+ * @return ezcGraphBoundings
+ */
+ public function drawOdometer(
+ ezcGraphBoundings $boundings,
+ ezcGraphChartElementAxis $axis,
+ ezcGraphOdometerChartOptions $options )
+ {
+ $height = $boundings->height * $options->odometerHeight;
+
+ // Draw axis
+ $oldAxisSpace = $axis->axisSpace;
+ $axis->axisSpace = 0;
+
+ $axis->render( $this, $boundings );
+
+ // Reset axisspaces to correct values
+ $this->xAxisSpace = $boundings->width * $oldAxisSpace;
+ $this->yAxisSpace = ( $boundings->height - $height ) / 2;
+
+ $this->drawAxisLabels();
+
+ // Reduce size of chart boundings respecting requested odometer height
+ $boundings->x0 += $this->xAxisSpace;
+ $boundings->x1 -= $this->xAxisSpace;
+ $boundings->y0 += $this->yAxisSpace;
+ $boundings->y1 -= $this->yAxisSpace;
+
+ $gradient = new ezcGraphLinearGradient(
+ new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ),
+ new ezcGraphCoordinate( $boundings->x1, $boundings->y0 ),
+ $options->startColor,
+ $options->endColor
+ );
+
+ // Simply draw box with gradient and optional border
+ $this->drawBox(
+ $boundings,
+ $gradient,
+ $options->borderColor,
+ $options->borderWidth
+ );
+
+ // Return modified chart boundings
+ return $boundings;
+ }
+
+ /**
+ * Draw a single odometer marker.
+ *
+ * @param ezcGraphBoundings $boundings
+ * @param ezcGraphCoordinate $position
+ * @param int $symbol
+ * @param ezcGraphColor $color
+ * @param int $width
+ */
+ public function drawOdometerMarker(
+ ezcGraphBoundings $boundings,
+ ezcGraphCoordinate $position,
+ $symbol,
+ ezcGraphColor $color,
+ $width )
+ {
+ $this->driver->drawLine(
+ new ezcGraphCoordinate(
+ $xPos = $boundings->x0 + ( $position->x * $boundings->width ),
+ $boundings->y0
+ ),
+ new ezcGraphCoordinate(
+ $xPos,
+ $boundings->y1
+ ),
+ $color,
+ $width
+ );
+ }
}
?>
diff --git a/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometer.svg b/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometer.svg
new file mode 100644
index 0000000..82a5923
--- /dev/null
+++ b/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometer.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="500" height="200" version="1.0" id="ezcGraph"><defs><linearGradient id="Definition_LinearGradient_25_50_475_50_4e9a06a0_a40000a0"><stop offset="0" style="stop-color: #4e9a06; stop-opacity: 0.37;"/><stop offset="1" style="stop-color: #a40000; stop-opacity: 0.37;"/></linearGradient><linearGradient xmlns:xlink="http://www.w3.org/1999/xlink" id="LinearGradient_25_50_475_50_4e9a06a0_a40000a0" x1="25.0000" y1="50.0000" x2="475.0000" y2="50.0000" gradientUnits="userSpaceOnUse" xlink:href="#Definition_LinearGradient_25_50_475_50_4e9a06a0_a40000a0"/></defs><g id="ezcGraphChart" color-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="optimizeLegibility"><path d=" M 0.0000,200.0000 L 0.0000,0.0000 L 500.0000,0.0000 L 500.0000,200.0000 L 0.0000,200.0000 z " style="fill: #eeeeec; fill-opacity: 1.00; stroke: none;" id="ezcGraphPolygon_1"/><path d=" M 0.0000,150.0000 L 500.0000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_2"/><path d=" M 496.0000,148.0000 L 500.0000,150.0000 L 496.0000,152.0000 L 496.0000,148.0000 z " style="fill: #2e3436; fill-opacity: 1.00; stroke: none;" id="ezcGraphPolygon_3"/><path d=" M 80.0000,50.0000 L 80.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_4"/><path d=" M 81.2500,149.0000 L 81.2500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_5"/><path d=" M 140.0000,50.0000 L 135.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_6"/><path d=" M 137.5000,149.0000 L 137.5000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_7"/><path d=" M 195.0000,50.0000 L 195.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_8"/><path d=" M 193.7500,149.0000 L 193.7500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_9"/><path d=" M 250.0000,50.0000 L 250.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_10"/><path d=" M 250.0000,147.0000 L 250.0000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_11"/><path d=" M 305.0000,50.0000 L 305.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_13"/><path d=" M 306.2500,149.0000 L 306.2500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_14"/><path d=" M 365.0000,50.0000 L 360.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_15"/><path d=" M 362.5000,149.0000 L 362.5000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_16"/><path d=" M 420.0000,50.0000 L 420.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_17"/><path d=" M 418.7500,149.0000 L 418.7500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_18"/><path d=" M 475.0000,50.0000 L 475.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_19"/><path d=" M 475.0000,147.0000 L 475.0000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_20"/><path d=" M 25.0000,150.0000 L 25.0000,50.0000 L 475.0000,50.0000 L 475.0000,150.0000 L 25.0000,150.0000 z " style="fill: url(#LinearGradient_25_50_475_50_4e9a06a0_a40000a0); stroke: none;" id="ezcGraphPolygon_22"/><path d=" M 47.5000,50.0000 L 47.5000,150.0000" style="fill: none; stroke: #3465a4; stroke-width: 2; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_23"/><path d=" M 182.5000,50.0000 L 182.5000,150.0000" style="fill: none; stroke: #4e9a06; stroke-width: 2; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_24"/><path d=" M 430.0000,50.0000 L 430.0000,150.0000" style="fill: none; stroke: #cc0000; stroke-width: 2; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_25"/><g id="ezcGraphTextBox_12"><path d=" M 226.5600,190.0000 L 226.5600,151.5000 L 273.9400,151.5000 L 273.9400,190.0000 L 226.5600,190.0000 z " style="fill: #ffffff; fill-opacity: 0.00; stroke: none;" id="ezcGraphPolygon_26"/><text id="ezcGraphTextBox_12_text" x="227.0600" text-length="45.8800px" y="183.4500" style="font-size: 37px; font-family: sans-serif; fill: #2e3436; fill-opacity: 1.00; stroke: none;">10</text></g><g id="ezcGraphTextBox_21"><path d=" M 451.5600,190.0000 L 451.5600,151.5000 L 498.9400,151.5000 L 498.9400,190.0000 L 451.5600,190.0000 z " style="fill: #ffffff; fill-opacity: 0.00; stroke: none;" id="ezcGraphPolygon_27"/><text id="ezcGraphTextBox_21_text" x="452.0600" text-length="45.8800px" y="183.4500" style="font-size: 37px; font-family: sans-serif; fill: #2e3436; fill-opacity: 1.00; stroke: none;">20</text></g></g></svg>
diff --git a/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerToOutput.svg b/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerToOutput.svg
new file mode 100644
index 0000000..82a5923
--- /dev/null
+++ b/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerToOutput.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="500" height="200" version="1.0" id="ezcGraph"><defs><linearGradient id="Definition_LinearGradient_25_50_475_50_4e9a06a0_a40000a0"><stop offset="0" style="stop-color: #4e9a06; stop-opacity: 0.37;"/><stop offset="1" style="stop-color: #a40000; stop-opacity: 0.37;"/></linearGradient><linearGradient xmlns:xlink="http://www.w3.org/1999/xlink" id="LinearGradient_25_50_475_50_4e9a06a0_a40000a0" x1="25.0000" y1="50.0000" x2="475.0000" y2="50.0000" gradientUnits="userSpaceOnUse" xlink:href="#Definition_LinearGradient_25_50_475_50_4e9a06a0_a40000a0"/></defs><g id="ezcGraphChart" color-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="optimizeLegibility"><path d=" M 0.0000,200.0000 L 0.0000,0.0000 L 500.0000,0.0000 L 500.0000,200.0000 L 0.0000,200.0000 z " style="fill: #eeeeec; fill-opacity: 1.00; stroke: none;" id="ezcGraphPolygon_1"/><path d=" M 0.0000,150.0000 L 500.0000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_2"/><path d=" M 496.0000,148.0000 L 500.0000,150.0000 L 496.0000,152.0000 L 496.0000,148.0000 z " style="fill: #2e3436; fill-opacity: 1.00; stroke: none;" id="ezcGraphPolygon_3"/><path d=" M 80.0000,50.0000 L 80.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_4"/><path d=" M 81.2500,149.0000 L 81.2500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_5"/><path d=" M 140.0000,50.0000 L 135.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_6"/><path d=" M 137.5000,149.0000 L 137.5000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_7"/><path d=" M 195.0000,50.0000 L 195.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_8"/><path d=" M 193.7500,149.0000 L 193.7500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_9"/><path d=" M 250.0000,50.0000 L 250.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_10"/><path d=" M 250.0000,147.0000 L 250.0000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_11"/><path d=" M 305.0000,50.0000 L 305.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_13"/><path d=" M 306.2500,149.0000 L 306.2500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_14"/><path d=" M 365.0000,50.0000 L 360.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_15"/><path d=" M 362.5000,149.0000 L 362.5000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_16"/><path d=" M 420.0000,50.0000 L 420.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_17"/><path d=" M 418.7500,149.0000 L 418.7500,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_18"/><path d=" M 475.0000,50.0000 L 475.0000,150.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_19"/><path d=" M 475.0000,147.0000 L 475.0000,150.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_20"/><path d=" M 25.0000,150.0000 L 25.0000,50.0000 L 475.0000,50.0000 L 475.0000,150.0000 L 25.0000,150.0000 z " style="fill: url(#LinearGradient_25_50_475_50_4e9a06a0_a40000a0); stroke: none;" id="ezcGraphPolygon_22"/><path d=" M 47.5000,50.0000 L 47.5000,150.0000" style="fill: none; stroke: #3465a4; stroke-width: 2; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_23"/><path d=" M 182.5000,50.0000 L 182.5000,150.0000" style="fill: none; stroke: #4e9a06; stroke-width: 2; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_24"/><path d=" M 430.0000,50.0000 L 430.0000,150.0000" style="fill: none; stroke: #cc0000; stroke-width: 2; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_25"/><g id="ezcGraphTextBox_12"><path d=" M 226.5600,190.0000 L 226.5600,151.5000 L 273.9400,151.5000 L 273.9400,190.0000 L 226.5600,190.0000 z " style="fill: #ffffff; fill-opacity: 0.00; stroke: none;" id="ezcGraphPolygon_26"/><text id="ezcGraphTextBox_12_text" x="227.0600" text-length="45.8800px" y="183.4500" style="font-size: 37px; font-family: sans-serif; fill: #2e3436; fill-opacity: 1.00; stroke: none;">10</text></g><g id="ezcGraphTextBox_21"><path d=" M 451.5600,190.0000 L 451.5600,151.5000 L 498.9400,151.5000 L 498.9400,190.0000 L 451.5600,190.0000 z " style="fill: #ffffff; fill-opacity: 0.00; stroke: none;" id="ezcGraphPolygon_27"/><text id="ezcGraphTextBox_21_text" x="452.0600" text-length="45.8800px" y="183.4500" style="font-size: 37px; font-family: sans-serif; fill: #2e3436; fill-opacity: 1.00; stroke: none;">20</text></g></g></svg>
diff --git a/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerWithDifferentOptions.svg b/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerWithDifferentOptions.svg
new file mode 100644
index 0000000..6affc64
--- /dev/null
+++ b/tests/data/compare/ezcGraphOdometerChartTest_testRenderCompleteOdometerWithDifferentOptions.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="300" height="100" version="1.0" id="ezcGraph"><defs><linearGradient id="Definition_LinearGradient_15_15_285_15_eeeeec00_a0000000"><stop offset="0" style="stop-color: #eeeeec; stop-opacity: 1.00;"/><stop offset="1" style="stop-color: #a00000; stop-opacity: 1.00;"/></linearGradient><linearGradient xmlns:xlink="http://www.w3.org/1999/xlink" id="LinearGradient_15_15_285_15_eeeeec00_a0000000" x1="15.0000" y1="15.0000" x2="285.0000" y2="15.0000" gradientUnits="userSpaceOnUse" xlink:href="#Definition_LinearGradient_15_15_285_15_eeeeec00_a0000000"/></defs><g id="ezcGraphChart" color-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="optimizeLegibility"><path d=" M 0.0000,100.0000 L 0.0000,0.0000 L 300.0000,0.0000 L 300.0000,100.0000 L 0.0000,100.0000 z " style="fill: #eeeeec; fill-opacity: 1.00; stroke: none;" id="ezcGraphPolygon_1"/><path d=" M 0.0000,85.0000 L 300.0000,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_2"/><path d=" M 296.0000,83.0000 L 300.0000,85.0000 L 296.0000,87.0000 L 296.0000,83.0000 z " style="fill: #2e3436; fill-opacity: 1.00; stroke: none;" id="ezcGraphPolygon_3"/><path d=" M 48.0000,15.0000 L 48.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_4"/><path d=" M 48.7500,84.0000 L 48.7500,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_5"/><path d=" M 84.0000,15.0000 L 81.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_6"/><path d=" M 82.5000,84.0000 L 82.5000,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_7"/><path d=" M 117.0000,15.0000 L 117.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_8"/><path d=" M 116.2500,84.0000 L 116.2500,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_9"/><path d=" M 150.0000,15.0000 L 150.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_10"/><path d=" M 150.0000,82.0000 L 150.0000,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_11"/><path d=" M 183.0000,15.0000 L 183.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_13"/><path d=" M 183.7500,84.0000 L 183.7500,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_14"/><path d=" M 219.0000,15.0000 L 216.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_15"/><path d=" M 217.5000,84.0000 L 217.5000,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_16"/><path d=" M 252.0000,15.0000 L 252.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_17"/><path d=" M 251.2500,84.0000 L 251.2500,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_18"/><path d=" M 285.0000,15.0000 L 285.0000,85.0000" style="fill: none; stroke: #000000; stroke-width: 1; stroke-opacity: 0.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_19"/><path d=" M 285.0000,82.0000 L 285.0000,85.0000" style="fill: none; stroke: #2e3436; stroke-width: 1; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_20"/><path d=" M 15.0000,85.0000 L 15.0000,15.0000 L 285.0000,15.0000 L 285.0000,85.0000 L 15.0000,85.0000 z " style="fill: url(#LinearGradient_15_15_285_15_eeeeec00_a0000000); stroke: none;" id="ezcGraphPolygon_22"/><path d=" M 16.0000,16.0000 L 284.0000,16.0000 L 284.0000,84.0000 L 16.0000,84.0000 L 16.0000,16.0000 z " style="fill: none; stroke: #2e3436; stroke-width: 2; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphPolygon_23"/><path d=" M 30.3000,17.0000 L 30.3000,83.0000" style="fill: none; stroke: #3465a4; stroke-width: 5; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_24"/><path d=" M 110.1000,17.0000 L 110.1000,83.0000" style="fill: none; stroke: #4e9a06; stroke-width: 5; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_25"/><path d=" M 256.4000,17.0000 L 256.4000,83.0000" style="fill: none; stroke: #cc0000; stroke-width: 5; stroke-opacity: 1.00; stroke-linecap: round; stroke-linejoin: round;" id="ezcGraphLine_26"/><g id="ezcGraphTextBox_12"><path d=" M 142.6800,99.0000 L 142.6800,86.5000 L 157.8200,86.5000 L 157.8200,99.0000 L 142.6800,99.0000 z " style="fill: #ffffff; fill-opacity: 0.00; stroke: none;" id="ezcGraphPolygon_27"/><text id="ezcGraphTextBox_12_text" x="143.1800" text-length="13.6400px" y="96.3500" style="font-size: 11px; font-family: sans-serif; fill: #2e3436; fill-opacity: 1.00; stroke: none;">10</text></g><g id="ezcGraphTextBox_21"><path d=" M 277.6800,99.0000 L 277.6800,86.5000 L 292.8200,86.5000 L 292.8200,99.0000 L 277.6800,99.0000 z " style="fill: #ffffff; fill-opacity: 0.00; stroke: none;" id="ezcGraphPolygon_28"/><text id="ezcGraphTextBox_21_text" x="278.1800" text-length="13.6400px" y="96.3500" style="font-size: 11px; font-family: sans-serif; fill: #2e3436; fill-opacity: 1.00; stroke: none;">20</text></g></g></svg>
OpenPOWER on IntegriCloud