mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-25 16:44:28 +00:00
EZ-Components
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphBarChart class
|
||||
*
|
||||
* @package Graph
|
||||
* @version 1.3
|
||||
* @copyright Copyright (C) 2005-2008 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 line chart
|
||||
* $chart = new ezcGraphBarChart();
|
||||
*
|
||||
* // 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 default 2d renderer and default SVG driver
|
||||
* $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 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphBarChart extends ezcGraphLineChart
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->elements['xAxis']->axisLabelRenderer = new ezcGraphAxisBoxedLabelRenderer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default display type of the current chart type.
|
||||
*
|
||||
* @return int Display type
|
||||
*/
|
||||
public function getDefaultDisplayType()
|
||||
{
|
||||
return ezcGraph::BAR;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,652 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphLineChart class
|
||||
*
|
||||
* @package Graph
|
||||
* @version 1.3
|
||||
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
|
||||
* @license http://ez.no/licenses/new_bsd New BSD License
|
||||
*/
|
||||
/**
|
||||
* Class for line charts. Can make use of an unlimited amount of datasets and
|
||||
* will display them as lines by default.
|
||||
* X axis:
|
||||
* - Labeled axis
|
||||
* - Centered axis label renderer
|
||||
* Y axis:
|
||||
* - Numeric axis
|
||||
* - Exact axis label renderer
|
||||
*
|
||||
* <code>
|
||||
* // Create a new line chart
|
||||
* $chart = new ezcGraphLineChart();
|
||||
*
|
||||
* // 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 default 2d renderer and default SVG driver
|
||||
* $chart->render( 500, 200, 'line_chart.svg' );
|
||||
* </code>
|
||||
*
|
||||
* Each chart consists of several chart elements which represents logical
|
||||
* parts of the chart and can be formatted independently. The line 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.
|
||||
* The extended configure options are available in
|
||||
* {@link ezcGraphLineChartOptions} extending the {@link ezcGraphChartOptions}.
|
||||
*
|
||||
* @property ezcGraphLineChartOptions $options
|
||||
* Chart options class
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphLineChart extends ezcGraphChart
|
||||
{
|
||||
/**
|
||||
* Array with additional axis for the chart
|
||||
*
|
||||
* @var ezcGraphAxisContainer
|
||||
*/
|
||||
protected $additionalAxis;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
$this->additionalAxis = new ezcGraphAxisContainer( $this );
|
||||
|
||||
$this->options = new ezcGraphLineChartOptions( $options );
|
||||
$this->options->highlightFont = $this->options->font;
|
||||
|
||||
parent::__construct();
|
||||
|
||||
$this->addElement( 'xAxis', new ezcGraphChartElementLabeledAxis() );
|
||||
$this->elements['xAxis']->position = ezcGraph::LEFT;
|
||||
|
||||
$this->addElement( 'yAxis', new ezcGraphChartElementNumericAxis() );
|
||||
$this->elements['yAxis']->position = ezcGraph::BOTTOM;
|
||||
}
|
||||
|
||||
/**
|
||||
* __get
|
||||
*
|
||||
* @param mixed $propertyName
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If a the value for the property options is not an instance of
|
||||
* @return mixed
|
||||
* @ignore
|
||||
*/
|
||||
public function __get( $propertyName )
|
||||
{
|
||||
switch ( $propertyName )
|
||||
{
|
||||
case 'additionalAxis':
|
||||
return $this->additionalAxis;
|
||||
}
|
||||
|
||||
return parent::__get( $propertyName );
|
||||
}
|
||||
|
||||
/**
|
||||
* Options write access
|
||||
*
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If Option could not be found
|
||||
* @throws ezcBaseValueException
|
||||
* If value is out of range
|
||||
* @param mixed $propertyName Option name
|
||||
* @param mixed $propertyValue Option value;
|
||||
* @return mixed
|
||||
* @ignore
|
||||
*/
|
||||
public function __set( $propertyName, $propertyValue )
|
||||
{
|
||||
switch ( $propertyName ) {
|
||||
case 'xAxis':
|
||||
if ( $propertyValue instanceof ezcGraphChartElementAxis )
|
||||
{
|
||||
$this->addElement( 'xAxis', $propertyValue );
|
||||
$this->elements['xAxis']->position = ezcGraph::LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
|
||||
}
|
||||
break;
|
||||
case 'yAxis':
|
||||
if ( $propertyValue instanceof ezcGraphChartElementAxis )
|
||||
{
|
||||
$this->addElement( 'yAxis', $propertyValue );
|
||||
$this->elements['yAxis']->position = ezcGraph::BOTTOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set colors and border for this element
|
||||
*
|
||||
* @param ezcGraphPalette $palette Palette
|
||||
* @return void
|
||||
*/
|
||||
public function setFromPalette( ezcGraphPalette $palette )
|
||||
{
|
||||
foreach ( $this->additionalAxis as $element )
|
||||
{
|
||||
$element->setFromPalette( $palette );
|
||||
}
|
||||
|
||||
parent::setFromPalette( $palette );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
// Apply axis space
|
||||
$xAxisSpace = ( $boundings->x1 - $boundings->x0 ) * $this->yAxis->axisSpace;
|
||||
$yAxisSpace = ( $boundings->y1 - $boundings->y0 ) * $this->xAxis->axisSpace;
|
||||
|
||||
$boundings->x0 += $xAxisSpace;
|
||||
$boundings->x1 -= $xAxisSpace;
|
||||
|
||||
$boundings->y0 += $yAxisSpace;
|
||||
$boundings->y1 -= $yAxisSpace;
|
||||
|
||||
$yAxisNullPosition = $this->elements['yAxis']->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 ) )
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
// 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( $key ),
|
||||
$yAxis->getCoordinate( $value )
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// Render depending on display type of dataset
|
||||
switch ( true )
|
||||
{
|
||||
case $data->displayType->default === ezcGraph::LINE:
|
||||
$renderer->drawDataLine(
|
||||
$boundings,
|
||||
new ezcGraphContext( $datasetName, $key, $data->url[$key] ),
|
||||
$data->color->default,
|
||||
( $lastPoint === false ? $point : $lastPoint ),
|
||||
$point,
|
||||
$nr[$data->displayType->default],
|
||||
$count[$data->displayType->default],
|
||||
$data->symbol[$key],
|
||||
$data->color[$key],
|
||||
$fillColor,
|
||||
$yAxisNullPosition,
|
||||
( $data->lineThickness->default ? $data->lineThickness->default : $this->options->lineThickness )
|
||||
);
|
||||
break;
|
||||
case ( $data->displayType->default === ezcGraph::BAR ) &&
|
||||
$this->options->stackBars :
|
||||
// Check if a bar has already been stacked
|
||||
if ( !isset( $stackedValue[(int) ( $point->x * 10000 )][(int) $value > 0] ) )
|
||||
{
|
||||
$start = new ezcGraphCoordinate(
|
||||
$point->x,
|
||||
$yAxisNullPosition
|
||||
);
|
||||
|
||||
$stackedValue[(int) ( $point->x * 10000 )][(int) $value > 0] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$start = $xAxis->axisLabelRenderer->modifyChartDataPosition(
|
||||
$yAxis->axisLabelRenderer->modifyChartDataPosition(
|
||||
new ezcGraphCoordinate(
|
||||
$xAxis->getCoordinate( $key ),
|
||||
$yAxis->getCoordinate( $stackedValue[(int) ( $point->x * 10000 )][(int) $value > 0] )
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$point = $xAxis->axisLabelRenderer->modifyChartDataPosition(
|
||||
$yAxis->axisLabelRenderer->modifyChartDataPosition(
|
||||
new ezcGraphCoordinate(
|
||||
$xAxis->getCoordinate( $key ),
|
||||
$yAxis->getCoordinate( $stackedValue[(int) ( $point->x * 10000 )][(int) $value > 0] += $value )
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Force one symbol for each stacked bar
|
||||
if ( !isset( $stackedSymbol[(int) ( $point->x * 10000 )] ) )
|
||||
{
|
||||
$stackedSymbol[(int) ( $point->x * 10000 )] = $data->symbol[$key];
|
||||
}
|
||||
|
||||
// Store stacked value for next iteration
|
||||
$stacked[(int) ( $point->x * 10000 )][$point->y / abs( $point->y )] = $point;
|
||||
|
||||
$renderer->drawStackedBar(
|
||||
$boundings,
|
||||
new ezcGraphContext( $datasetName, $key, $data->url[$key] ),
|
||||
$data->color->default,
|
||||
$start,
|
||||
$point,
|
||||
$width,
|
||||
$stackedSymbol[(int) ( $point->x * 10000 )],
|
||||
$yAxisNullPosition
|
||||
);
|
||||
break;
|
||||
case $data->displayType->default === ezcGraph::BAR:
|
||||
$renderer->drawBar(
|
||||
$boundings,
|
||||
new ezcGraphContext( $datasetName, $key, $data->url[$key] ),
|
||||
$data->color[$key],
|
||||
$point,
|
||||
$width,
|
||||
$nr[$data->displayType->default],
|
||||
$count[$data->displayType->default],
|
||||
$data->symbol[$key],
|
||||
$yAxisNullPosition
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new ezcGraphInvalidDisplayTypeException( $data->displayType->default );
|
||||
break;
|
||||
}
|
||||
|
||||
// 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 )
|
||||
);
|
||||
}
|
||||
|
||||
// Store last point, used to connect lines in line chart.
|
||||
$lastPoint = $point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default display type of the current chart type.
|
||||
*
|
||||
* @return int Display type
|
||||
*/
|
||||
public function getDefaultDisplayType()
|
||||
{
|
||||
return ezcGraph::LINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if renderer supports features requested by some special chart
|
||||
* options.
|
||||
*
|
||||
* @throws ezcBaseValueException
|
||||
* If some feature is not supported
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function checkRenderer()
|
||||
{
|
||||
// When stacked bars are enabled, check if renderer supports them
|
||||
if ( $this->options->stackBars )
|
||||
{
|
||||
if ( !$this->renderer instanceof ezcGraphStackedBarsRenderer )
|
||||
{
|
||||
throw new ezcBaseValueException( 'renderer', $this->renderer, 'ezcGraphStackedBarsRenderer' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregate and calculate value boundings on 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( $labels );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->elements['xAxis']->addData( $labels );
|
||||
}
|
||||
|
||||
if ( $dataset->yAxis->default )
|
||||
{
|
||||
$dataset->yAxis->default->addData( $values );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->elements['yAxis']->addData( $values );
|
||||
}
|
||||
}
|
||||
|
||||
// Also use stacked bar values as base for y axis value span
|
||||
// calculation
|
||||
if ( $this->options->stackBars )
|
||||
{
|
||||
$this->elements['yAxis']->addData( $virtualBarSumDataSet[0] );
|
||||
$this->elements['yAxis']->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 )
|
||||
{
|
||||
throw new ezcGraphNoDataException();
|
||||
}
|
||||
|
||||
// Calculate boundings from assigned data
|
||||
$this->elements['xAxis']->calculateAxisBoundings();
|
||||
$this->elements['yAxis']->calculateAxisBoundings();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
// Check if renderer supports requested features
|
||||
$this->checkRenderer();
|
||||
|
||||
// Set values form datasets on axis to calculate correct spans
|
||||
$this->setAxisValues();
|
||||
|
||||
// Generate legend
|
||||
$this->elements['legend']->generateFromDataSets( $this->data );
|
||||
|
||||
// Get boundings from parameters
|
||||
$this->options->width = $width;
|
||||
$this->options->height = $height;
|
||||
|
||||
// Set image properties in driver
|
||||
$this->driver->options->width = $width;
|
||||
$this->driver->options->height = $height;
|
||||
|
||||
// Render subelements
|
||||
$boundings = new ezcGraphBoundings();
|
||||
$boundings->x1 = $this->options->width;
|
||||
$boundings->y1 = $this->options->height;
|
||||
|
||||
$boundings = $this->elements['xAxis']->axisLabelRenderer->modifyChartBoundings(
|
||||
$this->elements['yAxis']->axisLabelRenderer->modifyChartBoundings(
|
||||
$boundings, new ezcGraphCoordinate( 1, 0 )
|
||||
), new ezcGraphCoordinate( -1, 0 )
|
||||
);
|
||||
|
||||
// Render subelements
|
||||
foreach ( $this->elements as $name => $element )
|
||||
{
|
||||
// Skip element, if it should not get rendered
|
||||
if ( $this->renderElement[$name] === false )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Special settings for special elements
|
||||
switch ( $name )
|
||||
{
|
||||
case 'xAxis':
|
||||
// get Position of 0 on the Y-axis for orientation of the x-axis
|
||||
$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( false );
|
||||
break;
|
||||
}
|
||||
|
||||
$this->driver->options->font = $element->font;
|
||||
$boundings = $element->render( $this->renderer, $boundings );
|
||||
}
|
||||
|
||||
// Render additional axis
|
||||
foreach ( $this->additionalAxis as $element )
|
||||
{
|
||||
if ( $element->initialized )
|
||||
{
|
||||
// Calculate all required step sizes if values has been
|
||||
// assigned to axis.
|
||||
$element->calculateAxisBoundings();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not render any axis labels, if no values were assigned
|
||||
// and no step sizes were defined.
|
||||
$element->axisLabelRenderer = new ezcGraphAxisNoLabelRenderer();
|
||||
}
|
||||
|
||||
$this->driver->options->font = $element->font;
|
||||
$element->nullPosition = $element->chartPosition;
|
||||
$boundings = $element->render( $this->renderer, $boundings );
|
||||
}
|
||||
|
||||
// Render graph
|
||||
$this->renderData( $this->renderer, $boundings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the line 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 );
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphOdometerChart class
|
||||
*
|
||||
* @package Graph
|
||||
* @version 1.3
|
||||
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
|
||||
* @license http://ez.no/licenses/new_bsd New BSD License
|
||||
*/
|
||||
/**
|
||||
* Class for odometer charts. Can only use one dataset which will be dispalyed
|
||||
* as a odometer chart.
|
||||
*
|
||||
* <code>
|
||||
* $graph = new ezcGraphOdometerChart();
|
||||
* $graph->title = 'Custom odometer';
|
||||
*
|
||||
* $graph->data['data'] = new ezcGraphArrayDataSet(
|
||||
* array( 87 )
|
||||
* );
|
||||
*
|
||||
* // Set the marker color
|
||||
* $graph->data['data']->color[0] = '#A0000055';
|
||||
*
|
||||
* // Set colors for the background gradient
|
||||
* $graph->options->startColor = '#2E3436';
|
||||
* $graph->options->endColor = '#EEEEEC';
|
||||
*
|
||||
* // Define a border for the odometer
|
||||
* $graph->options->borderWidth = 2;
|
||||
* $graph->options->borderColor = '#BABDB6';
|
||||
*
|
||||
* // Set marker width
|
||||
* $graph->options->markerWidth = 5;
|
||||
*
|
||||
* // Set space, which the odometer may consume
|
||||
* $graph->options->odometerHeight = .7;
|
||||
*
|
||||
* // Set axis span and label
|
||||
* $graph->axis->min = 0;
|
||||
* $graph->axis->max = 100;
|
||||
* $graph->axis->label = 'Coverage ';
|
||||
*
|
||||
* $graph->render( 400, 150, 'custom_odometer_chart.svg' );
|
||||
* </code>
|
||||
*
|
||||
* Each chart consists of several chart elements which represents logical parts
|
||||
* of the chart and can be formatted independently. The odometer chart consists
|
||||
* of:
|
||||
* - title ( {@link ezcGraphChartElementText} )
|
||||
* - background ( {@link ezcGraphChartElementBackground} )
|
||||
*
|
||||
* All elements can be configured by accessing them as properties of the chart:
|
||||
*
|
||||
* <code>
|
||||
* $chart->title->position = ezcGraph::BOTTOM;
|
||||
* </code>
|
||||
*
|
||||
* The chart itself also offers several options to configure the appearance.
|
||||
* The extended configure options are available in
|
||||
* {@link ezcGraphOdometerChartOptions} extending the {@link
|
||||
* ezcGraphChartOptions}.
|
||||
*
|
||||
* @property ezcGraphOdometerChartOptions $options
|
||||
* Chart options class
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
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']->axisLabelRenderer->showZeroValue = true;
|
||||
$this->elements['axis']->position = ezcGraph::LEFT;
|
||||
$this->elements['axis']->axisSpace = .05;
|
||||
}
|
||||
|
||||
/**
|
||||
* Property write access
|
||||
*
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If Option could not be found
|
||||
* @throws ezcBaseValueException
|
||||
* If value is out of range
|
||||
* @param string $propertyName Option name
|
||||
* @param mixed $propertyValue Option value;
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __set( $propertyName, $propertyValue )
|
||||
{
|
||||
switch ( $propertyName ) {
|
||||
case 'axis':
|
||||
if ( $propertyValue instanceof ezcGraphChartElementAxis )
|
||||
{
|
||||
$this->addElement( 'axis', $propertyValue );
|
||||
$this->elements['axis']->axisLabelRenderer = new ezcGraphAxisCenteredLabelRenderer();
|
||||
$this->elements['axis']->axisLabelRenderer->showZeroValue = true;
|
||||
$this->elements['axis']->position = ezcGraph::LEFT;
|
||||
$this->elements['axis']->axisSpace = .05;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
|
||||
}
|
||||
break;
|
||||
case 'renderer':
|
||||
if ( $propertyValue instanceof ezcGraphOdometerRenderer )
|
||||
{
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphOdometerRenderer' );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphPieChart class
|
||||
*
|
||||
* @package Graph
|
||||
* @version 1.3
|
||||
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
|
||||
* @license http://ez.no/licenses/new_bsd New BSD License
|
||||
*/
|
||||
/**
|
||||
* Class for pie charts. Can only use one dataset which will be dispalyed as a
|
||||
* pie chart.
|
||||
*
|
||||
* <code>
|
||||
* // Create a new pie chart
|
||||
* $chart = new ezcGraphPieChart();
|
||||
*
|
||||
* // Add data to line chart
|
||||
* $chart->data['sample dataset'] = new ezcGraphArrayDataSet(
|
||||
* array(
|
||||
* 'one' => 1.2,
|
||||
* 'two' => 43.2,
|
||||
* 'three' => -34.14,
|
||||
* 'four' => 65,
|
||||
* 'five' => 123,
|
||||
* )
|
||||
* );
|
||||
*
|
||||
* // Render chart with default 2d renderer and default SVG driver
|
||||
* $chart->render( 500, 200, 'pie_chart.svg' );
|
||||
* </code>
|
||||
*
|
||||
* Each chart consists of several chart elements which represents logical
|
||||
* parts of the chart and can be formatted independently. The pie chart
|
||||
* consists of:
|
||||
* - title ( {@link ezcGraphChartElementText} )
|
||||
* - legend ( {@link ezcGraphChartElementLegend} )
|
||||
* - background ( {@link ezcGraphChartElementBackground} )
|
||||
*
|
||||
* 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.
|
||||
* The extended configure options are available in
|
||||
* {@link ezcGraphPieChartOptions} extending the {@link ezcGraphChartOptions}.
|
||||
*
|
||||
* @property ezcGraphPieChartOptions $options
|
||||
* Chart options class
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphPieChart extends ezcGraphChart
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
$this->options = new ezcGraphPieChartOptions( $options );
|
||||
|
||||
parent::__construct( $options );
|
||||
|
||||
$this->data = new ezcGraphChartSingleDataContainer( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
// Only draw the first (and only) dataset
|
||||
$dataset = $this->data->rewind();
|
||||
$datasetName = $this->data->key();
|
||||
|
||||
$this->driver->options->font = $this->options->font;
|
||||
|
||||
// Calculate sum of all values to be able to calculate percentage
|
||||
$sum = 0;
|
||||
foreach ( $dataset as $name => $value )
|
||||
{
|
||||
if ( $value < 0 )
|
||||
{
|
||||
throw new ezcGraphInvalidDataException( "Values >= 0 required, '$name' => '$value'." );
|
||||
}
|
||||
|
||||
$sum += $value;
|
||||
}
|
||||
if ( $this->options->sum !== false )
|
||||
{
|
||||
$sum = max( $sum, $this->options->sum );
|
||||
}
|
||||
|
||||
if ( $sum <= 0 )
|
||||
{
|
||||
throw new ezcGraphInvalidDataException( "Pie charts require a value sum > 0, your value: '$sum'." );
|
||||
}
|
||||
|
||||
$angle = 0;
|
||||
foreach ( $dataset as $label => $value )
|
||||
{
|
||||
// Skip rendering values which equals 0
|
||||
if ( $value <= 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
switch ( $dataset->displayType->default )
|
||||
{
|
||||
case ezcGraph::PIE:
|
||||
$displayLabel = ( $this->options->labelCallback !== null
|
||||
? call_user_func( $this->options->labelCallback, $label, $value, $value / $sum )
|
||||
: sprintf( $this->options->label, $label, $value, $value / $sum * 100 ) );
|
||||
|
||||
$renderer->drawPieSegment(
|
||||
$boundings,
|
||||
new ezcGraphContext( $datasetName, $label, $dataset->url[$label] ),
|
||||
$dataset->color[$label],
|
||||
$angle,
|
||||
$angle += $value / $sum * 360,
|
||||
$displayLabel,
|
||||
$dataset->highlight[$label]
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new ezcGraphInvalidDisplayTypeException( $dataset->displayType->default );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default display type of the current chart type.
|
||||
*
|
||||
* @return int Display type
|
||||
*/
|
||||
public function getDefaultDisplayType()
|
||||
{
|
||||
return ezcGraph::PIE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply tresh hold
|
||||
*
|
||||
* Iterates over the dataset and applies the configured tresh hold to
|
||||
* the datasets data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function applyThreshold()
|
||||
{
|
||||
if ( $this->options->percentThreshold || $this->options->absoluteThreshold )
|
||||
{
|
||||
$dataset = $this->data->rewind();
|
||||
|
||||
$sum = 0;
|
||||
foreach ( $dataset as $value )
|
||||
{
|
||||
$sum += $value;
|
||||
}
|
||||
if ( $this->options->sum !== false )
|
||||
{
|
||||
$sum = max( $sum, $this->options->sum );
|
||||
}
|
||||
|
||||
$unset = array();
|
||||
foreach ( $dataset as $label => $value )
|
||||
{
|
||||
if ( $label === $this->options->summarizeCaption )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( $value <= $this->options->absoluteThreshold ) ||
|
||||
( ( $value / $sum ) <= $this->options->percentThreshold ) )
|
||||
{
|
||||
if ( !isset( $dataset[$this->options->summarizeCaption] ) )
|
||||
{
|
||||
$dataset[$this->options->summarizeCaption] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dataset[$this->options->summarizeCaption] += $value;
|
||||
}
|
||||
|
||||
$unset[] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $unset as $label )
|
||||
{
|
||||
unset( $dataset[$label] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// Apply tresh hold
|
||||
$this->applyThreshold();
|
||||
|
||||
// Generate legend
|
||||
$this->elements['legend']->generateFromDataSet( $this->data->rewind() );
|
||||
|
||||
// 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;
|
||||
|
||||
// Render subelements
|
||||
foreach ( $this->elements as $name => $element )
|
||||
{
|
||||
// Skip element, if it should not get rendered
|
||||
if ( $this->renderElement[$name] === false )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->driver->options->font = $element->font;
|
||||
$boundings = $element->render( $this->renderer, $boundings );
|
||||
}
|
||||
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,457 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphRadarChart class
|
||||
*
|
||||
* @package Graph
|
||||
* @version 1.3
|
||||
* @copyright Copyright (C) 2005-2008 eZ systems as. All rights reserved.
|
||||
* @license http://ez.no/licenses/new_bsd New BSD License
|
||||
*/
|
||||
/**
|
||||
* Class for radar charts.
|
||||
* Can make use of an unlimited amount of datasets and will display them as
|
||||
* lines by default.
|
||||
* Rotation axis:
|
||||
* - Labeled axis
|
||||
* - Centered axis label renderer
|
||||
* Axis:
|
||||
* - Numeric axis
|
||||
* - radar axis label renderer
|
||||
*
|
||||
* <code>
|
||||
* // Create a new radar chart
|
||||
* $chart = new ezcGraphRadarChart();
|
||||
*
|
||||
* // 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 default 2d renderer and default SVG driver
|
||||
* $chart->render( 500, 200, 'radar_chart.svg' );
|
||||
* </code>
|
||||
*
|
||||
* Each chart consists of several chart elements which represents logical
|
||||
* parts of the chart and can be formatted independently. The line chart
|
||||
* consists of:
|
||||
* - title ( {@link ezcGraphChartElementText} )
|
||||
* - legend ( {@link ezcGraphChartElementLegend} )
|
||||
* - background ( {@link ezcGraphChartElementBackground} )
|
||||
* - axis ( {@link ezcGraphChartElementNumericAxis} )
|
||||
* - ratation axis ( {@link ezcGraphChartElementLabeledAxis} )
|
||||
*
|
||||
* The type of the axis may be changed and all elements can be configured by
|
||||
* accessing them as properties of the chart:
|
||||
*
|
||||
* The chart itself also offers several options to configure the appearance.
|
||||
* The extended configure options are available in
|
||||
* {@link ezcGraphRadarChartOptions} extending the
|
||||
* {@link ezcGraphChartOptions}.
|
||||
*
|
||||
* <code>
|
||||
* $chart->legend->position = ezcGraph::RIGHT;
|
||||
* </code>
|
||||
*
|
||||
* @property ezcGraphRadarChartOptions $options
|
||||
* Chart options class
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphRadarChart extends ezcGraphChart
|
||||
{
|
||||
/**
|
||||
* Store major grid color for child axis.
|
||||
*
|
||||
* @var ezcGraphColor
|
||||
*/
|
||||
protected $childAxisColor;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
$this->options = new ezcGraphRadarChartOptions( $options );
|
||||
$this->options->highlightFont = $this->options->font;
|
||||
|
||||
parent::__construct();
|
||||
|
||||
$this->elements['rotationAxis'] = new ezcGraphChartElementLabeledAxis();
|
||||
|
||||
$this->addElement( 'axis', new ezcGraphChartElementNumericAxis() );
|
||||
$this->elements['axis']->position = ezcGraph::BOTTOM;
|
||||
$this->elements['axis']->axisLabelRenderer = new ezcGraphAxisRadarLabelRenderer();
|
||||
$this->elements['axis']->axisLabelRenderer->outerStep = true;
|
||||
|
||||
$this->addElement( 'rotationAxis', new ezcGraphChartElementLabeledAxis() );
|
||||
|
||||
// Do not render axis with default method, because we need an axis for
|
||||
// each label in dataset
|
||||
$this->renderElement['axis'] = false;
|
||||
$this->renderElement['rotationAxis'] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set colors and border fro this element
|
||||
*
|
||||
* @param ezcGraphPalette $palette Palette
|
||||
* @return void
|
||||
*/
|
||||
public function setFromPalette( ezcGraphPalette $palette )
|
||||
{
|
||||
$this->childAxisColor = $palette->majorGridColor;
|
||||
|
||||
parent::setFromPalette( $palette );
|
||||
}
|
||||
|
||||
/**
|
||||
* Property write access
|
||||
*
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If Option could not be found
|
||||
* @throws ezcBaseValueException
|
||||
* If value is out of range
|
||||
* @param string $propertyName Option name
|
||||
* @param mixed $propertyValue Option value;
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __set( $propertyName, $propertyValue )
|
||||
{
|
||||
switch ( $propertyName ) {
|
||||
case 'axis':
|
||||
if ( $propertyValue instanceof ezcGraphChartElementAxis )
|
||||
{
|
||||
$this->addElement( 'axis', $propertyValue );
|
||||
$this->elements['axis']->position = ezcGraph::BOTTOM;
|
||||
$this->elements['axis']->axisLabelRenderer = new ezcGraphAxisRadarLabelRenderer();
|
||||
$this->renderElement['axis'] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
|
||||
}
|
||||
break;
|
||||
case 'rotationAxis':
|
||||
if ( $propertyValue instanceof ezcGraphChartElementAxis )
|
||||
{
|
||||
$this->addElement( 'rotationAxis', $propertyValue );
|
||||
$this->renderElement['rotationAxis'] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
|
||||
}
|
||||
break;
|
||||
case 'renderer':
|
||||
if ( $propertyValue instanceof ezcGraphRadarRenderer )
|
||||
{
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphRadarRenderer' );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a single rotated axis
|
||||
*
|
||||
* Sets the axis label position depending on the axis rotation.
|
||||
*
|
||||
* @param ezcGraphChartElementAxis $axis
|
||||
* @param ezcGraphBoundings $boundings
|
||||
* @param ezcGraphCoordinate $center
|
||||
* @param float $position
|
||||
* @param float $lastPosition
|
||||
* @return void
|
||||
*/
|
||||
protected function drawRotatedAxis( ezcGraphChartElementAxis $axis, ezcGraphBoundings $boundings, ezcGraphCoordinate $center, $position, $lastPosition = null )
|
||||
{
|
||||
// Set axis position depending on angle for better axis label
|
||||
// positioning
|
||||
$angle = $position * 2 * M_PI;
|
||||
switch ( (int) ( ( $position + .125 ) * 4 ) )
|
||||
{
|
||||
case 0:
|
||||
case 4:
|
||||
$axis->position = ezcGraph::BOTTOM;
|
||||
break;
|
||||
case 1:
|
||||
$axis->position = ezcGraph::LEFT;
|
||||
break;
|
||||
case 2:
|
||||
$axis->position = ezcGraph::TOP;
|
||||
break;
|
||||
case 3:
|
||||
$axis->position = ezcGraph::RIGHT;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set last step to correctly draw grid
|
||||
if ( $axis->axisLabelRenderer instanceof ezcGraphAxisRadarLabelRenderer )
|
||||
{
|
||||
$axis->axisLabelRenderer->lastStep = $lastPosition;
|
||||
}
|
||||
|
||||
// Do not draw axis label for last step
|
||||
if ( abs( $position - 1 ) <= .001 )
|
||||
{
|
||||
$axis->label = null;
|
||||
}
|
||||
|
||||
$this->renderer->drawAxis(
|
||||
$boundings,
|
||||
clone $center,
|
||||
$dest = new ezcGraphCoordinate(
|
||||
$center->x + sin( $angle ) * ( $boundings->width / 2 ),
|
||||
$center->y - cos( $angle ) * ( $boundings->height / 2 )
|
||||
),
|
||||
clone $axis,
|
||||
clone $axis->axisLabelRenderer
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 )
|
||||
{
|
||||
// Apply axis space
|
||||
$xAxisSpace = ( $boundings->x1 - $boundings->x0 ) * $this->axis->axisSpace;
|
||||
$yAxisSpace = ( $boundings->y1 - $boundings->y0 ) * $this->axis->axisSpace;
|
||||
|
||||
$center = new ezcGraphCoordinate(
|
||||
( $boundings->width / 2 ),
|
||||
( $boundings->height / 2 )
|
||||
);
|
||||
|
||||
// We do not differentiate between display types in radar charts.
|
||||
$nr = $count = count( $this->data );
|
||||
|
||||
// Draw axis at major steps of virtual axis
|
||||
$steps = $this->elements['rotationAxis']->getSteps();
|
||||
$lastStepPosition = null;
|
||||
$axisColor = $this->elements['axis']->border;
|
||||
foreach ( $steps as $step )
|
||||
{
|
||||
$this->elements['axis']->label = $step->label;
|
||||
$this->drawRotatedAxis( $this->elements['axis'], $boundings, $center, $step->position, $lastStepPosition );
|
||||
$lastStepPosition = $step->position;
|
||||
|
||||
if ( count( $step->childs ) )
|
||||
{
|
||||
foreach ( $step->childs as $childStep )
|
||||
{
|
||||
$this->elements['axis']->label = null;
|
||||
$this->elements['axis']->border = $this->childAxisColor;
|
||||
|
||||
$this->drawRotatedAxis( $this->elements['axis'], $boundings, $center, $childStep->position, $lastStepPosition );
|
||||
$lastStepPosition = $childStep->position;
|
||||
}
|
||||
}
|
||||
|
||||
$this->elements['axis']->border = $axisColor;
|
||||
}
|
||||
|
||||
// Display data
|
||||
$this->elements['axis']->position = ezcGraph::TOP;
|
||||
foreach ( $this->data as $datasetName => $data )
|
||||
{
|
||||
--$nr;
|
||||
// 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;
|
||||
foreach ( $data as $key => $value )
|
||||
{
|
||||
$point = new ezcGraphCoordinate(
|
||||
$this->elements['rotationAxis']->getCoordinate( $key ),
|
||||
$this->elements['axis']->getCoordinate( $value )
|
||||
);
|
||||
|
||||
/* Transformation required for 3d like renderers ...
|
||||
* which axis should transform here?
|
||||
$point = $this->elements['xAxis']->axisLabelRenderer->modifyChartDataPosition(
|
||||
$this->elements['yAxis']->axisLabelRenderer->modifyChartDataPosition(
|
||||
new ezcGraphCoordinate(
|
||||
$this->elements['xAxis']->getCoordinate( $key ),
|
||||
$this->elements['yAxis']->getCoordinate( $value )
|
||||
)
|
||||
)
|
||||
);
|
||||
// */
|
||||
|
||||
$renderer->drawRadarDataLine(
|
||||
$boundings,
|
||||
new ezcGraphContext( $datasetName, $key, $data->url[$key] ),
|
||||
$data->color->default,
|
||||
clone $center,
|
||||
( $lastPoint === false ? $point : $lastPoint ),
|
||||
$point,
|
||||
$nr,
|
||||
$count,
|
||||
$data->symbol[$key],
|
||||
$data->color[$key],
|
||||
$fillColor,
|
||||
$this->options->lineThickness
|
||||
);
|
||||
|
||||
$lastPoint = $point;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default display type of the current chart type.
|
||||
*
|
||||
* @return int Display type
|
||||
*/
|
||||
public function getDefaultDisplayType()
|
||||
{
|
||||
return ezcGraph::LINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// Calculate axis scaling and labeling
|
||||
foreach ( $this->data as $dataset )
|
||||
{
|
||||
$labels = array();
|
||||
$values = array();
|
||||
foreach ( $dataset as $label => $value )
|
||||
{
|
||||
$labels[] = $label;
|
||||
$values[] = $value;
|
||||
}
|
||||
|
||||
$this->elements['axis']->addData( $values );
|
||||
$this->elements['rotationAxis']->addData( $labels );
|
||||
}
|
||||
|
||||
$this->elements['axis']->calculateAxisBoundings();
|
||||
$this->elements['rotationAxis']->calculateAxisBoundings();
|
||||
|
||||
// Generate legend
|
||||
$this->elements['legend']->generateFromDataSets( $this->data );
|
||||
|
||||
// Get boundings from parameters
|
||||
$this->options->width = $width;
|
||||
$this->options->height = $height;
|
||||
|
||||
// Render subelements
|
||||
$boundings = new ezcGraphBoundings();
|
||||
$boundings->x1 = $this->options->width;
|
||||
$boundings->y1 = $this->options->height;
|
||||
|
||||
// Render subelements
|
||||
foreach ( $this->elements as $name => $element )
|
||||
{
|
||||
// Skip element, if it should not get rendered
|
||||
if ( $this->renderElement[$name] === false )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->driver->options->font = $element->font;
|
||||
$boundings = $element->render( $this->renderer, $boundings );
|
||||
}
|
||||
|
||||
// Render graph
|
||||
$this->renderData( $this->renderer, $boundings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the line 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 );
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user