mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-23 09:52:22 +00:00
EZ-Components
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphAxisContainer 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
|
||||
*/
|
||||
/**
|
||||
* The axis container class is internally used to store and validate sets of
|
||||
* axis, and offering access using the SPL ArrayAccess interface to add or
|
||||
* modify its contents.
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
*/
|
||||
class ezcGraphAxisContainer
|
||||
implements
|
||||
Countable,
|
||||
ArrayAccess,
|
||||
Iterator
|
||||
{
|
||||
/**
|
||||
* Chart the container is used with
|
||||
*
|
||||
* @var ezcGraphLineChart
|
||||
*/
|
||||
protected $chart;
|
||||
|
||||
/**
|
||||
* Contains the data of a chart
|
||||
*
|
||||
* @var array(ezcGraphChartElementAxis)
|
||||
*/
|
||||
protected $data = array();
|
||||
|
||||
/**
|
||||
* Construct container with corresponding chart.
|
||||
*
|
||||
* @param ezcGraphLineChart $chart
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( ezcGraphLineChart $chart )
|
||||
{
|
||||
$this->chart = $chart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given offset exists.
|
||||
*
|
||||
* This method is part of the ArrayAccess interface to allow access to the
|
||||
* data of this object as if it was an array.
|
||||
*
|
||||
* @param string $key Identifier of dataset.
|
||||
* @return bool True when the offset exists, otherwise false.
|
||||
*/
|
||||
public function offsetExists( $key )
|
||||
{
|
||||
return isset( $this->data[$key] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element with the given offset.
|
||||
*
|
||||
* This method is part of the ArrayAccess interface to allow access to the
|
||||
* data of this object as if it was an array.
|
||||
*
|
||||
* @param string $key Identifier of dataset.
|
||||
* @return ezcGraphChartElementAxis
|
||||
*
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If no dataset with identifier exists
|
||||
*/
|
||||
public function offsetGet( $key )
|
||||
{
|
||||
if ( !isset( $this->data[$key] ) )
|
||||
{
|
||||
throw new ezcBasePropertyNotFoundException( $key );
|
||||
}
|
||||
|
||||
return $this->data[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the element with the given offset.
|
||||
*
|
||||
* This method is part of the ArrayAccess interface to allow access to the
|
||||
* data of this object as if it was an array.
|
||||
*
|
||||
* @param string $key
|
||||
* @param ezcGraphChartElementAxis $value
|
||||
* @return void
|
||||
*
|
||||
* @throws ezcBaseValueException
|
||||
* If supplied value is not an ezcGraphChartElementAxis
|
||||
*/
|
||||
public function offsetSet( $key, $value )
|
||||
{
|
||||
if ( !$value instanceof ezcGraphChartElementAxis )
|
||||
{
|
||||
throw new ezcBaseValueException( $key, $value, 'ezcGraphChartElementAxis' );
|
||||
}
|
||||
|
||||
if ( $key === null )
|
||||
{
|
||||
$key = count( $this->data );
|
||||
}
|
||||
|
||||
// Add axis and configure it with current font and palette
|
||||
$this->data[$key] = $value;
|
||||
$value->font = $this->chart->options->font;
|
||||
$value->setFromPalette( $this->chart->palette );
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset the element with the given offset.
|
||||
*
|
||||
* This method is part of the ArrayAccess interface to allow access to the
|
||||
* data of this object as if it was an array.
|
||||
*
|
||||
* @param string $key
|
||||
* @return void
|
||||
*/
|
||||
public function offsetUnset( $key )
|
||||
{
|
||||
if ( !isset( $this->data[$key] ) )
|
||||
{
|
||||
throw new ezcBasePropertyNotFoundException( $key );
|
||||
}
|
||||
|
||||
unset( $this->data[$key] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently selected dataset.
|
||||
*
|
||||
* This method is part of the Iterator interface to allow access to the
|
||||
* datasets of this row by iterating over it like an array (e.g. using
|
||||
* foreach).
|
||||
*
|
||||
* @return ezcGraphChartElementAxis The currently selected dataset.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return current( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next dataset and selects it or false on the last dataset.
|
||||
*
|
||||
* This method is part of the Iterator interface to allow access to the
|
||||
* datasets of this row by iterating over it like an array (e.g. using
|
||||
* foreach).
|
||||
*
|
||||
* @return mixed ezcGraphChartElementAxis if the next dataset exists, or false.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
return next( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key of the currently selected dataset.
|
||||
*
|
||||
* This method is part of the Iterator interface to allow access to the
|
||||
* datasets of this row by iterating over it like an array (e.g. using
|
||||
* foreach).
|
||||
*
|
||||
* @return int The key of the currently selected dataset.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return key( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the current dataset is valid.
|
||||
*
|
||||
* This method is part of the Iterator interface to allow access to the
|
||||
* datasets of this row by iterating over it like an array (e.g. using
|
||||
* foreach).
|
||||
*
|
||||
* @return bool If the current dataset is valid
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return ( current( $this->data ) !== false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the very first dataset and returns it.
|
||||
* This method is part of the Iterator interface to allow access to the
|
||||
* datasets of this row by iterating over it like an array (e.g. using
|
||||
* foreach).
|
||||
*
|
||||
* @return ezcGraphChartElementAxis The very first dataset.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
return reset( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of datasets in the row.
|
||||
*
|
||||
* This method is part of the Countable interface to allow the usage of
|
||||
* PHP's count() function to check how many datasets exist.
|
||||
*
|
||||
* @return int Number of datasets.
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count( $this->data );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,585 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphChartElementDateAxis 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 to represent date axis. Date axis will try to find a "nice" interval
|
||||
* based on the values on the x axis. If non numeric values are given,
|
||||
* ezcGraphChartElementDateAxis will convert them to timestamps using PHPs
|
||||
* strtotime function.
|
||||
*
|
||||
* It is always possible to set start date, end date and the interval manually
|
||||
* by yourself.
|
||||
*
|
||||
* @property float $startDate
|
||||
* Starting date used to display on axis.
|
||||
* @property float $endDate
|
||||
* End date used to display on axis.
|
||||
* @property float $interval
|
||||
* Time interval between steps on axis.
|
||||
* @property string $dateFormat
|
||||
* Format of date string
|
||||
* Like http://php.net/date
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphChartElementDateAxis extends ezcGraphChartElementAxis
|
||||
{
|
||||
|
||||
const MONTH = 2629800;
|
||||
|
||||
const YEAR = 31536000;
|
||||
|
||||
const DECADE = 315360000;
|
||||
|
||||
/**
|
||||
* Minimum inserted date
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $minValue = false;
|
||||
|
||||
/**
|
||||
* Maximum inserted date
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $maxValue = false;
|
||||
|
||||
/**
|
||||
* Nice time intervals to used if there is no user defined interval
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $predefinedIntervals = array(
|
||||
// Second
|
||||
1 => 'H:i.s',
|
||||
// Ten seconds
|
||||
10 => 'H:i.s',
|
||||
// Thirty seconds
|
||||
30 => 'H:i.s',
|
||||
// Minute
|
||||
60 => 'H:i',
|
||||
// Ten minutes
|
||||
600 => 'H:i',
|
||||
// Half an hour
|
||||
1800 => 'H:i',
|
||||
// Hour
|
||||
3600 => 'H:i',
|
||||
// Four hours
|
||||
14400 => 'H:i',
|
||||
// Six hours
|
||||
21600 => 'H:i',
|
||||
// Half a day
|
||||
43200 => 'd.m a',
|
||||
// Day
|
||||
86400 => 'd.m',
|
||||
// Week
|
||||
604800 => 'W',
|
||||
// Month
|
||||
self::MONTH => 'M y',
|
||||
// Year
|
||||
self::YEAR => 'Y',
|
||||
// Decade
|
||||
self::DECADE => 'Y',
|
||||
);
|
||||
|
||||
/**
|
||||
* Constant used for calculation of automatic definition of major scaling
|
||||
* steps
|
||||
*/
|
||||
const MAJOR_COUNT = 10;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
$this->properties['startDate'] = false;
|
||||
$this->properties['endDate'] = false;
|
||||
$this->properties['interval'] = false;
|
||||
$this->properties['dateFormat'] = false;
|
||||
|
||||
parent::__construct( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* __set
|
||||
*
|
||||
* @param mixed $propertyName
|
||||
* @param mixed $propertyValue
|
||||
* @throws ezcBaseValueException
|
||||
* If a submitted parameter was out of range or type.
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If a the value for the property options is not an instance of
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __set( $propertyName, $propertyValue )
|
||||
{
|
||||
switch ( $propertyName )
|
||||
{
|
||||
case 'startDate':
|
||||
$this->properties['startDate'] = (int) $propertyValue;
|
||||
break;
|
||||
case 'endDate':
|
||||
$this->properties['endDate'] = (int) $propertyValue;
|
||||
break;
|
||||
case 'interval':
|
||||
$this->properties['interval'] = (int) $propertyValue;
|
||||
$this->properties['initialized'] = true;
|
||||
break;
|
||||
case 'dateFormat':
|
||||
$this->properties['dateFormat'] = (string) $propertyValue;
|
||||
break;
|
||||
default:
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure proper timestamp
|
||||
*
|
||||
* Takes a mixed value from datasets, like timestamps, or strings
|
||||
* describing some time and converts it to a timestamp.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return int
|
||||
*/
|
||||
protected static function ensureTimestamp( $value )
|
||||
{
|
||||
if ( is_numeric( $value ) )
|
||||
{
|
||||
$timestamp = (int) $value;
|
||||
}
|
||||
elseif ( ( $timestamp = strtotime( $value ) ) === false )
|
||||
{
|
||||
throw new ezcGraphErrorParsingDateException( $value );
|
||||
}
|
||||
|
||||
return $timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data for this axis
|
||||
*
|
||||
* @param array $values Value which will be displayed on this axis
|
||||
* @return void
|
||||
*/
|
||||
public function addData( array $values )
|
||||
{
|
||||
foreach ( $values as $nr => $value )
|
||||
{
|
||||
$value = self::ensureTimestamp( $value );
|
||||
|
||||
if ( $this->minValue === false ||
|
||||
$value < $this->minValue )
|
||||
{
|
||||
$this->minValue = $value;
|
||||
}
|
||||
|
||||
if ( $this->maxValue === false ||
|
||||
$value > $this->maxValue )
|
||||
{
|
||||
$this->maxValue = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->properties['initialized'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate nice time interval
|
||||
*
|
||||
* Use the best fitting time interval defined in class property array
|
||||
* predefinedIntervals.
|
||||
*
|
||||
* @param int $min Start time
|
||||
* @param int $max End time
|
||||
* @return void
|
||||
*/
|
||||
protected function calculateInterval( $min, $max )
|
||||
{
|
||||
$diff = $max - $min;
|
||||
|
||||
foreach ( $this->predefinedIntervals as $interval => $format )
|
||||
{
|
||||
if ( ( $diff / $interval ) <= self::MAJOR_COUNT )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( $this->properties['startDate'] !== false ) &&
|
||||
( $this->properties['endDate'] !== false ) )
|
||||
{
|
||||
// Use interval between defined borders
|
||||
if ( ( $diff % $interval ) > 0 )
|
||||
{
|
||||
// Stil use predefined date format from old interval if not set
|
||||
if ( $this->properties['dateFormat'] === false )
|
||||
{
|
||||
$this->properties['dateFormat'] = $this->predefinedIntervals[$interval];
|
||||
}
|
||||
|
||||
$count = ceil( $diff / $interval );
|
||||
$interval = round( $diff / $count, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
$this->properties['interval'] = $interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate lower nice date
|
||||
*
|
||||
* Calculates a date which is earlier or equal to the given date, and is
|
||||
* divisible by the given interval.
|
||||
*
|
||||
* @param int $min Date
|
||||
* @param int $interval Interval
|
||||
* @return int Earlier date
|
||||
*/
|
||||
protected function calculateLowerNiceDate( $min, $interval )
|
||||
{
|
||||
switch ( $interval )
|
||||
{
|
||||
case self::MONTH:
|
||||
// Special handling for months - not covered by the default
|
||||
// algorithm
|
||||
return mktime(
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
(int) date( 'm', $min ),
|
||||
1,
|
||||
(int) date( 'Y', $min )
|
||||
);
|
||||
default:
|
||||
$dateSteps = array( 60, 60, 24, 7, 52 );
|
||||
|
||||
$date = array(
|
||||
(int) date( 's', $min ),
|
||||
(int) date( 'i', $min ),
|
||||
(int) date( 'H', $min ),
|
||||
(int) date( 'd', $min ),
|
||||
(int) date( 'm', $min ),
|
||||
(int) date( 'Y', $min ),
|
||||
);
|
||||
|
||||
$element = 0;
|
||||
while ( ( $step = array_shift( $dateSteps ) ) &&
|
||||
( $interval > $step ) )
|
||||
{
|
||||
$interval /= $step;
|
||||
$date[$element++] = (int) ( $element > 2 );
|
||||
}
|
||||
|
||||
$date[$element] -= $date[$element] % $interval;
|
||||
|
||||
return mktime(
|
||||
$date[2],
|
||||
$date[1],
|
||||
$date[0],
|
||||
$date[4],
|
||||
$date[3],
|
||||
$date[5]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate start date
|
||||
*
|
||||
* Use calculateLowerNiceDate to get a date earlier or equal date then the
|
||||
* minimum date to use it as the start date for the axis depending on the
|
||||
* selected interval.
|
||||
*
|
||||
* @param mixed $min Minimum date
|
||||
* @param mixed $max Maximum date
|
||||
* @return void
|
||||
*/
|
||||
public function calculateMinimum( $min, $max )
|
||||
{
|
||||
if ( $this->properties['endDate'] === false )
|
||||
{
|
||||
$this->properties['startDate'] = $this->calculateLowerNiceDate( $min, $this->interval );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->properties['startDate'] = $this->properties['endDate'];
|
||||
|
||||
while ( $this->properties['startDate'] > $min )
|
||||
{
|
||||
switch ( $this->interval )
|
||||
{
|
||||
case self::MONTH:
|
||||
$this->properties['startDate'] = strtotime( '-1 month', $this->properties['startDate'] );
|
||||
break;
|
||||
case self::YEAR:
|
||||
$this->properties['startDate'] = strtotime( '-1 year', $this->properties['startDate'] );
|
||||
break;
|
||||
case self::DECADE:
|
||||
$this->properties['startDate'] = strtotime( '-10 years', $this->properties['startDate'] );
|
||||
break;
|
||||
default:
|
||||
$this->properties['startDate'] -= $this->interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate end date
|
||||
*
|
||||
* Use calculateLowerNiceDate to get a date later or equal date then the
|
||||
* maximum date to use it as the end date for the axis depending on the
|
||||
* selected interval.
|
||||
*
|
||||
* @param mixed $min Minimum date
|
||||
* @param mixed $max Maximum date
|
||||
* @return void
|
||||
*/
|
||||
public function calculateMaximum( $min, $max )
|
||||
{
|
||||
$this->properties['endDate'] = $this->properties['startDate'];
|
||||
|
||||
while ( $this->properties['endDate'] < $max )
|
||||
{
|
||||
switch ( $this->interval )
|
||||
{
|
||||
case self::MONTH:
|
||||
$this->properties['endDate'] = strtotime( '+1 month', $this->properties['endDate'] );
|
||||
break;
|
||||
case self::YEAR:
|
||||
$this->properties['endDate'] = strtotime( '+1 year', $this->properties['endDate'] );
|
||||
break;
|
||||
case self::DECADE:
|
||||
$this->properties['endDate'] = strtotime( '+10 years', $this->properties['endDate'] );
|
||||
break;
|
||||
default:
|
||||
$this->properties['endDate'] += $this->interval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate axis bounding values on base of the assigned values
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function calculateAxisBoundings()
|
||||
{
|
||||
// Prevent division by zero, when min == max
|
||||
if ( $this->minValue == $this->maxValue )
|
||||
{
|
||||
if ( $this->minValue == 0 )
|
||||
{
|
||||
$this->maxValue = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->minValue -= ( $this->minValue * .1 );
|
||||
$this->maxValue += ( $this->maxValue * .1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Use custom minimum and maximum if available
|
||||
if ( $this->properties['startDate'] !== false )
|
||||
{
|
||||
$this->minValue = $this->properties['startDate'];
|
||||
}
|
||||
|
||||
if ( $this->properties['endDate'] !== false )
|
||||
{
|
||||
$this->maxValue = $this->properties['endDate'];
|
||||
}
|
||||
|
||||
// Calculate "nice" values for scaling parameters
|
||||
if ( $this->properties['interval'] === false )
|
||||
{
|
||||
$this->calculateInterval( $this->minValue, $this->maxValue );
|
||||
}
|
||||
|
||||
if ( $this->properties['dateFormat'] === false && isset( $this->predefinedIntervals[$this->interval] ) )
|
||||
{
|
||||
$this->properties['dateFormat'] = $this->predefinedIntervals[$this->interval];
|
||||
}
|
||||
|
||||
if ( $this->properties['startDate'] === false )
|
||||
{
|
||||
$this->calculateMinimum( $this->minValue, $this->maxValue );
|
||||
}
|
||||
|
||||
if ( $this->properties['endDate'] === false )
|
||||
{
|
||||
$this->calculateMaximum( $this->minValue, $this->maxValue );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coordinate for a dedicated value on the chart
|
||||
*
|
||||
* @param float $value Value to determine position for
|
||||
* @return float Position on chart
|
||||
*/
|
||||
public function getCoordinate( $value )
|
||||
{
|
||||
// Force typecast, because ( false < -100 ) results in (bool) true
|
||||
$intValue = ( $value === false ? false : self::ensureTimestamp( $value ) );
|
||||
|
||||
if ( ( $value === false ) &&
|
||||
( ( $intValue < $this->startDate ) || ( $intValue > $this->endDate ) ) )
|
||||
{
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
return 0.;
|
||||
case ezcGraph::RIGHT:
|
||||
case ezcGraph::BOTTOM:
|
||||
return 1.;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
return ( $intValue - $this->startDate ) / ( $this->endDate - $this->startDate );
|
||||
case ezcGraph::RIGHT:
|
||||
case ezcGraph::BOTTOM:
|
||||
return 1 - ( $intValue - $this->startDate ) / ( $this->endDate - $this->startDate );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of minor steps
|
||||
*
|
||||
* @return integer Count of minor steps
|
||||
*/
|
||||
public function getMinorStepCount()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of major steps
|
||||
*
|
||||
* @return integer Count of major steps
|
||||
*/
|
||||
public function getMajorStepCount()
|
||||
{
|
||||
return (int) ceil( ( $this->properties['endDate'] - $this->startDate ) / $this->interval );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get label for a dedicated step on the axis
|
||||
*
|
||||
* @param integer $step Number of step
|
||||
* @return string label
|
||||
*/
|
||||
public function getLabel( $step )
|
||||
{
|
||||
return $this->getLabelFromTimestamp( $this->startDate + ( $step * $this->interval ), $step );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get label for timestamp
|
||||
*
|
||||
* @param int $time
|
||||
* @param int $step
|
||||
* @return string
|
||||
*/
|
||||
protected function getLabelFromTimestamp( $time, $step )
|
||||
{
|
||||
if ( $this->properties['labelCallback'] !== null )
|
||||
{
|
||||
return call_user_func_array(
|
||||
$this->properties['labelCallback'],
|
||||
array(
|
||||
date( $this->properties['dateFormat'], $time ),
|
||||
$step,
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return date( $this->properties['dateFormat'], $time );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of steps on this axis
|
||||
*
|
||||
* @return array( ezcGraphAxisStep )
|
||||
*/
|
||||
public function getSteps()
|
||||
{
|
||||
$steps = array();
|
||||
|
||||
$start = $this->properties['startDate'];
|
||||
$end = $this->properties['endDate'];
|
||||
$distance = $end - $start;
|
||||
|
||||
$step = 0;
|
||||
for ( $time = $start; $time <= $end; )
|
||||
{
|
||||
$steps[] = new ezcGraphAxisStep(
|
||||
( $time - $start ) / $distance,
|
||||
$this->interval / $distance,
|
||||
$this->getLabelFromTimestamp( $time, $step++ ),
|
||||
array(),
|
||||
$step === 1,
|
||||
$time >= $end
|
||||
);
|
||||
|
||||
switch ( $this->interval )
|
||||
{
|
||||
case self::MONTH:
|
||||
$time = strtotime( '+1 month', $time );
|
||||
break;
|
||||
case self::YEAR:
|
||||
$time = strtotime( '+1 year', $time );
|
||||
break;
|
||||
case self::DECADE:
|
||||
$time = strtotime( '+10 years', $time );
|
||||
break;
|
||||
default:
|
||||
$time += $this->interval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is zero step
|
||||
*
|
||||
* Returns true if the given step is the one on the initial axis position
|
||||
*
|
||||
* @param int $step Number of step
|
||||
* @return bool Status If given step is initial axis position
|
||||
*/
|
||||
public function isZeroStep( $step )
|
||||
{
|
||||
return ( $step == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,448 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphChartElementLabeledAxis 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 to represent a labeled axis. Values on the x axis are considered as
|
||||
* strings and used in the given order.
|
||||
*
|
||||
* @property float $labelCount
|
||||
* Define count of displayed labels on the axis
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphChartElementLabeledAxis extends ezcGraphChartElementAxis
|
||||
{
|
||||
|
||||
/**
|
||||
* Array with labeles for data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $labels = array();
|
||||
|
||||
/**
|
||||
* Reduced amount of labels which will be displayed in the chart
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $displayedLabels = array();
|
||||
|
||||
/**
|
||||
* Maximum count of labels which can be displayed on one axis
|
||||
* @todo Perhaps base this on the chart size
|
||||
*/
|
||||
const MAX_LABEL_COUNT = 10;
|
||||
|
||||
/**
|
||||
* Precalculated steps on the axis
|
||||
*
|
||||
* @var array(ezcGraphAxisStep)
|
||||
*/
|
||||
protected $steps;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
$this->properties['labelCount'] = null;
|
||||
|
||||
$this->axisLabelRenderer = new ezcGraphAxisCenteredLabelRenderer();
|
||||
|
||||
parent::__construct( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* __set
|
||||
*
|
||||
* @param mixed $propertyName
|
||||
* @param mixed $propertyValue
|
||||
* @throws ezcBaseValueException
|
||||
* If a submitted parameter was out of range or type.
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If a the value for the property options is not an instance of
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __set( $propertyName, $propertyValue )
|
||||
{
|
||||
switch ( $propertyName )
|
||||
{
|
||||
case 'labelCount':
|
||||
if ( !is_numeric( $propertyValue ) ||
|
||||
( $propertyValue <= 1 ) )
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'int > 1' );
|
||||
}
|
||||
|
||||
$this->properties['labelCount'] = (int) $propertyValue;
|
||||
break;
|
||||
default:
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increase the keys of all elements in the array up from the start key, to
|
||||
* insert an additional element at the correct position.
|
||||
*
|
||||
* @param array $array Array
|
||||
* @param int $startKey Key to increase keys from
|
||||
* @return array Updated array
|
||||
*/
|
||||
protected function increaseKeys( array $array, $startKey )
|
||||
{
|
||||
foreach ( $array as $key => $value )
|
||||
{
|
||||
if ( $key === $startKey )
|
||||
{
|
||||
// Recursive check, if next key should be increased, too
|
||||
if ( isset ( $array[$key + 1] ) )
|
||||
{
|
||||
$array = $this->increaseKeys( $array, $key + 1 );
|
||||
}
|
||||
|
||||
// Increase key
|
||||
$array[$key + 1] = $array[$key];
|
||||
unset( $array[$key] );
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data for this axis
|
||||
*
|
||||
* @param array $values Value which will be displayed on this axis
|
||||
* @return void
|
||||
*/
|
||||
public function addData( array $values )
|
||||
{
|
||||
$position = 0;
|
||||
foreach ( $values as $label )
|
||||
{
|
||||
$label = (string) $label;
|
||||
|
||||
if ( !in_array( $label, $this->labels, true ) )
|
||||
{
|
||||
if ( isset( $this->labels[$position] ) )
|
||||
{
|
||||
$this->labels = $this->increaseKeys( $this->labels, $position );
|
||||
$this->labels[$position++] = $label;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->labels[$position++] = $label;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$position = array_search( $label, $this->labels, true ) + 1;
|
||||
}
|
||||
}
|
||||
ksort( $this->labels );
|
||||
|
||||
$this->properties['initialized'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate axis bounding values on base of the assigned values
|
||||
*
|
||||
* @abstract
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function calculateAxisBoundings()
|
||||
{
|
||||
$this->steps = array();
|
||||
|
||||
// Apply label format callback function
|
||||
if ( $this->properties['labelCallback'] !== null )
|
||||
{
|
||||
foreach ( $this->labels as $nr => $label )
|
||||
{
|
||||
$this->labels[$nr] = call_user_func_array(
|
||||
$this->properties['labelCallback'],
|
||||
array(
|
||||
$label,
|
||||
$nr
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$labelCount = count( $this->labels ) - 1;
|
||||
|
||||
if ( $labelCount === 0 )
|
||||
{
|
||||
// Create single only step
|
||||
$this->steps = array(
|
||||
new ezcGraphAxisStep(
|
||||
0,
|
||||
1,
|
||||
reset( $this->labels ),
|
||||
array(),
|
||||
true,
|
||||
true
|
||||
),
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $this->properties['labelCount'] === null )
|
||||
{
|
||||
if ( $labelCount <= self::MAX_LABEL_COUNT )
|
||||
{
|
||||
$stepSize = 1 / $labelCount;
|
||||
|
||||
foreach ( $this->labels as $nr => $label )
|
||||
{
|
||||
$this->steps[] = new ezcGraphAxisStep(
|
||||
$stepSize * $nr,
|
||||
$stepSize,
|
||||
$label,
|
||||
array(),
|
||||
$nr === 0,
|
||||
$nr === $labelCount
|
||||
);
|
||||
}
|
||||
|
||||
// @TODO: This line is deprecated and only build for
|
||||
// deprecated getLabel()
|
||||
$this->displayedLabels = $this->labels;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for ( $div = self::MAX_LABEL_COUNT; $div > 1; --$div )
|
||||
{
|
||||
if ( ( $labelCount % $div ) === 0 )
|
||||
{
|
||||
// @TODO: This part is deprecated and only build for
|
||||
// deprecated getLabel()
|
||||
$step = $labelCount / $div;
|
||||
|
||||
foreach ( $this->labels as $nr => $label )
|
||||
{
|
||||
if ( ( $nr % $step ) === 0 )
|
||||
{
|
||||
$this->displayedLabels[] = $label;
|
||||
}
|
||||
}
|
||||
// End of deprecated part
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$div = false;
|
||||
}
|
||||
|
||||
// Build up step array
|
||||
if ( $div > 2 )
|
||||
{
|
||||
$step = $labelCount / $div;
|
||||
$stepSize = 1 / $div;
|
||||
$minorStepSize = $stepSize / $step;
|
||||
|
||||
foreach ( $this->labels as $nr => $label )
|
||||
{
|
||||
if ( ( $nr % $step ) === 0 )
|
||||
{
|
||||
$mainstep = new ezcGraphAxisStep(
|
||||
$stepSize * ( $nr / $step ),
|
||||
$stepSize,
|
||||
$label,
|
||||
array(),
|
||||
$nr === 0,
|
||||
$nr === $labelCount
|
||||
);
|
||||
|
||||
$this->steps[] = $mainstep;
|
||||
}
|
||||
else
|
||||
{
|
||||
$mainstep->childs[] = new ezcGraphAxisStep(
|
||||
$mainstep->position + $minorStepSize * ( $nr % $step ),
|
||||
$minorStepSize
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $this->properties['labelCount'] === null )
|
||||
{
|
||||
$floatStep = $labelCount / ( self::MAX_LABEL_COUNT - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
$floatStep = $labelCount / min( $labelCount, $this->properties['labelCount'] - 1 );
|
||||
}
|
||||
|
||||
$position = 0;
|
||||
$minorStepSize = 1 / $labelCount;
|
||||
|
||||
foreach ( $this->labels as $nr => $label )
|
||||
{
|
||||
if ( $nr >= $position )
|
||||
{
|
||||
$position += $floatStep;
|
||||
|
||||
// Add as major step
|
||||
$mainstep = new ezcGraphAxisStep(
|
||||
$minorStepSize * $nr,
|
||||
ceil( $position - $nr ) * $minorStepSize,
|
||||
$label,
|
||||
array(),
|
||||
$nr === 0,
|
||||
$nr === $labelCount
|
||||
);
|
||||
|
||||
// @TODO: This line is deprecated and only build for
|
||||
// deprecated getLabel()
|
||||
$this->displayedLabels[] = $label;
|
||||
|
||||
$this->steps[] = $mainstep;
|
||||
}
|
||||
else
|
||||
{
|
||||
$mainstep->childs[] = new ezcGraphAxisStep(
|
||||
$minorStepSize * $nr,
|
||||
$minorStepSize
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of steps on this axis
|
||||
*
|
||||
* @return array( ezcGraphAxisStep )
|
||||
*/
|
||||
public function getSteps()
|
||||
{
|
||||
return $this->steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coordinate for a dedicated value on the chart
|
||||
*
|
||||
* @param string $value Value to determine position for
|
||||
* @return float Position on chart
|
||||
*/
|
||||
public function getCoordinate( $value )
|
||||
{
|
||||
if ( $value === false ||
|
||||
$value === null ||
|
||||
( $key = array_search( $value, $this->labels ) ) === false )
|
||||
{
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
return 0.;
|
||||
case ezcGraph::RIGHT:
|
||||
case ezcGraph::BOTTOM:
|
||||
return 1.;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
if ( count( $this->labels ) > 1 )
|
||||
{
|
||||
return (float) $key / ( count ( $this->labels ) - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
case ezcGraph::BOTTOM:
|
||||
case ezcGraph::RIGHT:
|
||||
if ( count( $this->labels ) > 1 )
|
||||
{
|
||||
return (float) 1 - $key / ( count ( $this->labels ) - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of minor steps
|
||||
*
|
||||
* @return integer Count of minor steps
|
||||
*/
|
||||
public function getMinorStepCount()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of major steps
|
||||
*
|
||||
* @return integer Count of major steps
|
||||
*/
|
||||
public function getMajorStepCount()
|
||||
{
|
||||
return max( count( $this->displayedLabels ) - 1, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get label for a dedicated step on the axis
|
||||
*
|
||||
* @param integer $step Number of step
|
||||
* @return string label
|
||||
*/
|
||||
public function getLabel( $step )
|
||||
{
|
||||
if ( isset( $this->displayedLabels[$step] ) )
|
||||
{
|
||||
return $this->displayedLabels[$step];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is zero step
|
||||
*
|
||||
* Returns true if the given step is the one on the initial axis position
|
||||
*
|
||||
* @param int $step Number of step
|
||||
* @return bool Status If given step is initial axis position
|
||||
*/
|
||||
public function isZeroStep( $step )
|
||||
{
|
||||
return !$step;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the ezcGraphChartElementLogarithmicalAxis 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 to represent a numeric axis. The axis tries to calculate "nice" start
|
||||
* and end values for the axis scale. The used interval is considered as nice,
|
||||
* if it is equal to [1,2,5] * 10^x with x in [.., -1, 0, 1, ..].
|
||||
*
|
||||
* The start and end value are the next bigger / smaller multiple of the
|
||||
* intervall compared to the maximum / minimum axis value.
|
||||
*
|
||||
* @property float $min
|
||||
* Minimum value of displayed scale on axis.
|
||||
* @property float $max
|
||||
* Maximum value of displayed scale on axis.
|
||||
* @property float $base
|
||||
* Base for logarithmical scaling.
|
||||
* @property string $logarithmicalFormatString
|
||||
* Sprintf formatstring for the axis labels where
|
||||
* $1 is the base and
|
||||
* $2 is the exponent.
|
||||
* @property-read float $minValue
|
||||
* Minimum Value to display on this axis.
|
||||
* @property-read float $maxValue
|
||||
* Maximum value to display on this axis.
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphChartElementLogarithmicalAxis extends ezcGraphChartElementAxis
|
||||
{
|
||||
|
||||
/**
|
||||
* Constant used for calculation of automatic definition of major scaling
|
||||
* steps
|
||||
*/
|
||||
const MAX_STEPS = 9;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
$this->properties['min'] = null;
|
||||
$this->properties['max'] = null;
|
||||
$this->properties['base'] = 10;
|
||||
$this->properties['logarithmicalFormatString'] = '%1$d^%2$d';
|
||||
$this->properties['minValue'] = null;
|
||||
$this->properties['maxValue'] = null;
|
||||
|
||||
parent::__construct( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* __set
|
||||
*
|
||||
* @param mixed $propertyName
|
||||
* @param mixed $propertyValue
|
||||
* @throws ezcBaseValueException
|
||||
* If a submitted parameter was out of range or type.
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If a the value for the property options is not an instance of
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __set( $propertyName, $propertyValue )
|
||||
{
|
||||
switch ( $propertyName )
|
||||
{
|
||||
case 'min':
|
||||
case 'max':
|
||||
if ( !is_numeric( $propertyValue ) )
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'float' );
|
||||
}
|
||||
|
||||
$this->properties[$propertyName] = (float) $propertyValue;
|
||||
$this->properties['initialized'] = true;
|
||||
break;
|
||||
case 'base':
|
||||
if ( !is_numeric( $propertyValue ) ||
|
||||
( $propertyValue <= 0 ) )
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'float > 0' );
|
||||
}
|
||||
|
||||
$this->properties[$propertyName] = (float) $propertyValue;
|
||||
break;
|
||||
case 'logarithmicalFormatString':
|
||||
$this->properties['logarithmicalFormatString'] = (string) $propertyValue;
|
||||
break;
|
||||
default:
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data for this axis
|
||||
*
|
||||
* @param array $values Value which will be displayed on this axis
|
||||
* @return void
|
||||
*/
|
||||
public function addData( array $values )
|
||||
{
|
||||
foreach ( $values as $value )
|
||||
{
|
||||
if ( $this->properties['minValue'] === null ||
|
||||
$value < $this->properties['minValue'] )
|
||||
{
|
||||
$this->properties['minValue'] = $value;
|
||||
}
|
||||
|
||||
if ( $this->properties['maxValue'] === null ||
|
||||
$value > $this->properties['maxValue'] )
|
||||
{
|
||||
$this->properties['maxValue'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->properties['initialized'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate axis bounding values on base of the assigned values
|
||||
*
|
||||
* @abstract
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function calculateAxisBoundings()
|
||||
{
|
||||
// Prevent division by zero, when min == max
|
||||
if ( $this->properties['minValue'] == $this->properties['maxValue'] )
|
||||
{
|
||||
if ( $this->properties['minValue'] == 0 )
|
||||
{
|
||||
$this->properties['maxValue'] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->properties['minValue'] -= ( $this->properties['minValue'] * .1 );
|
||||
$this->properties['maxValue'] += ( $this->properties['maxValue'] * .1 );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->properties['minValue'] <= 0 )
|
||||
{
|
||||
throw new ezcGraphOutOfLogithmicalBoundingsException( $this->properties['minValue'] );
|
||||
}
|
||||
|
||||
// Use custom minimum and maximum if available
|
||||
if ( $this->properties['min'] !== null )
|
||||
{
|
||||
$this->properties['minValue'] = pow( $this->properties['base'], $this->properties['min'] );
|
||||
}
|
||||
|
||||
if ( $this->properties['max'] !== null )
|
||||
{
|
||||
$this->properties['maxValue'] = pow( $this->properties['base'], $this->properties['max'] );
|
||||
}
|
||||
|
||||
// Calculate "nice" values for scaling parameters
|
||||
if ( $this->properties['min'] === null )
|
||||
{
|
||||
$this->properties['min'] = floor( log( $this->properties['minValue'], $this->properties['base'] ) );
|
||||
}
|
||||
|
||||
if ( $this->properties['max'] === null )
|
||||
{
|
||||
$this->properties['max'] = ceil( log( $this->properties['maxValue'], $this->properties['base'] ) );
|
||||
}
|
||||
|
||||
$this->properties['minorStep'] = 1;
|
||||
if ( ( $modifier = ( ( $this->properties['max'] - $this->properties['min'] ) / self::MAX_STEPS ) ) > 1 )
|
||||
{
|
||||
$this->properties['majorStep'] = $modifier = ceil( $modifier );
|
||||
$this->properties['min'] = floor( $this->properties['min'] / $modifier ) * $modifier;
|
||||
$this->properties['max'] = floor( $this->properties['max'] / $modifier ) * $modifier;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->properties['majorStep'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coordinate for a dedicated value on the chart
|
||||
*
|
||||
* @param float $value Value to determine position for
|
||||
* @return float Position on chart
|
||||
*/
|
||||
public function getCoordinate( $value )
|
||||
{
|
||||
// Force typecast, because ( false < -100 ) results in (bool) true
|
||||
$floatValue = (float) $value;
|
||||
|
||||
if ( $value === false )
|
||||
{
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
return 0.;
|
||||
case ezcGraph::RIGHT:
|
||||
case ezcGraph::BOTTOM:
|
||||
return 1.;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$position = ( log( $value, $this->properties['base'] ) - $this->properties['min'] ) / ( $this->properties['max'] - $this->properties['min'] );
|
||||
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
return $position;
|
||||
case ezcGraph::RIGHT:
|
||||
case ezcGraph::BOTTOM:
|
||||
return 1 - $position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of minor steps
|
||||
*
|
||||
* @return integer Count of minor steps
|
||||
*/
|
||||
public function getMinorStepCount()
|
||||
{
|
||||
return (int) ( ( $this->properties['max'] - $this->properties['min'] ) / $this->properties['minorStep'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of major steps
|
||||
*
|
||||
* @return integer Count of major steps
|
||||
*/
|
||||
public function getMajorStepCount()
|
||||
{
|
||||
return (int) ( ( $this->properties['max'] - $this->properties['min'] ) / $this->properties['majorStep'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get label for a dedicated step on the axis
|
||||
*
|
||||
* @param integer $step Number of step
|
||||
* @return string label
|
||||
*/
|
||||
public function getLabel( $step )
|
||||
{
|
||||
if ( $this->properties['labelCallback'] !== null )
|
||||
{
|
||||
return call_user_func_array(
|
||||
$this->properties['labelCallback'],
|
||||
array(
|
||||
sprintf(
|
||||
$this->properties['logarithmicalFormatString'],
|
||||
$this->properties['base'],
|
||||
$this->properties['min'] + ( $step * $this->properties['majorStep'] )
|
||||
),
|
||||
$step,
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return sprintf(
|
||||
$this->properties['logarithmicalFormatString'],
|
||||
$this->properties['base'],
|
||||
$this->properties['min'] + ( $step * $this->properties['majorStep'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is zero step
|
||||
*
|
||||
* Returns true if the given step is the one on the initial axis position
|
||||
*
|
||||
* @param int $step Number of step
|
||||
* @return bool Status If given step is initial axis position
|
||||
*/
|
||||
public function isZeroStep( $step )
|
||||
{
|
||||
return ( $step == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,422 @@
|
||||
<?php
|
||||
/**
|
||||
* File containing the abstract ezcGraphChartElementNumericAxis 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 to represent a numeric axis. The axis tries to calculate "nice" start
|
||||
* and end values for the axis scale. The used interval is considered as nice,
|
||||
* if it is equal to [1,2,5] * 10^x with x in [.., -1, 0, 1, ..].
|
||||
*
|
||||
* The start and end value are the next bigger / smaller multiple of the
|
||||
* intervall compared to the maximum / minimum axis value.
|
||||
*
|
||||
* @property float $min
|
||||
* Minimum value of displayed scale on axis.
|
||||
* @property float $max
|
||||
* Maximum value of displayed scale on axis.
|
||||
* @property-read float $minValue
|
||||
* Minimum Value to display on this axis.
|
||||
* @property-read float $maxValue
|
||||
* Maximum value to display on this axis.
|
||||
*
|
||||
* @version 1.3
|
||||
* @package Graph
|
||||
* @mainclass
|
||||
*/
|
||||
class ezcGraphChartElementNumericAxis extends ezcGraphChartElementAxis
|
||||
{
|
||||
|
||||
/**
|
||||
* Constant used for calculation of automatic definition of major scaling
|
||||
* steps
|
||||
*/
|
||||
const MIN_MAJOR_COUNT = 5;
|
||||
|
||||
/**
|
||||
* Constant used for automatic calculation of minor steps from given major
|
||||
* steps
|
||||
*/
|
||||
const MIN_MINOR_COUNT = 8;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $options Default option array
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __construct( array $options = array() )
|
||||
{
|
||||
$this->properties['min'] = null;
|
||||
$this->properties['max'] = null;
|
||||
$this->properties['minValue'] = null;
|
||||
$this->properties['maxValue'] = null;
|
||||
|
||||
parent::__construct( $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* __set
|
||||
*
|
||||
* @param mixed $propertyName
|
||||
* @param mixed $propertyValue
|
||||
* @throws ezcBaseValueException
|
||||
* If a submitted parameter was out of range or type.
|
||||
* @throws ezcBasePropertyNotFoundException
|
||||
* If a the value for the property options is not an instance of
|
||||
* @return void
|
||||
* @ignore
|
||||
*/
|
||||
public function __set( $propertyName, $propertyValue )
|
||||
{
|
||||
switch ( $propertyName )
|
||||
{
|
||||
case 'min':
|
||||
if ( !is_numeric( $propertyValue ) )
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'float' );
|
||||
}
|
||||
|
||||
$this->properties['min'] = (float) $propertyValue;
|
||||
$this->properties['initialized'] = true;
|
||||
break;
|
||||
case 'max':
|
||||
if ( !is_numeric( $propertyValue ) )
|
||||
{
|
||||
throw new ezcBaseValueException( $propertyName, $propertyValue, 'float' );
|
||||
}
|
||||
|
||||
$this->properties['max'] = (float) $propertyValue;
|
||||
$this->properties['initialized'] = true;
|
||||
break;
|
||||
default:
|
||||
parent::__set( $propertyName, $propertyValue );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "nice" number for a given floating point number.
|
||||
*
|
||||
* Nice numbers are steps on a scale which are easily recognized by humans
|
||||
* like 0.5, 25, 1000 etc.
|
||||
*
|
||||
* @param float $float Number to be altered
|
||||
* @return float Nice number
|
||||
*/
|
||||
protected function getNiceNumber( $float )
|
||||
{
|
||||
// Get absolute value and save sign
|
||||
$abs = abs( $float );
|
||||
$sign = $float / $abs;
|
||||
|
||||
// Normalize number to a range between 1 and 10
|
||||
$log = (int) round( log10( $abs ), 0 );
|
||||
$abs /= pow( 10, $log );
|
||||
|
||||
|
||||
// find next nice number
|
||||
if ( $abs > 5 )
|
||||
{
|
||||
$abs = 10.;
|
||||
}
|
||||
elseif ( $abs > 2.5 )
|
||||
{
|
||||
$abs = 5.;
|
||||
}
|
||||
elseif ( $abs > 1 )
|
||||
{
|
||||
$abs = 2.5;
|
||||
}
|
||||
else
|
||||
{
|
||||
$abs = 1;
|
||||
}
|
||||
|
||||
// unnormalize number to original values
|
||||
return $abs * pow( 10, $log ) * $sign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate minimum value for displayed axe basing on real minimum and
|
||||
* major step size
|
||||
*
|
||||
* @param float $min Real data minimum
|
||||
* @param float $max Real data maximum
|
||||
* @return void
|
||||
*/
|
||||
protected function calculateMinimum( $min, $max )
|
||||
{
|
||||
if ( $this->properties['max'] === null )
|
||||
{
|
||||
$this->properties['min'] = floor( $min / $this->properties['majorStep'] ) * $this->properties['majorStep'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$calculatedMin = $this->properties['max'];
|
||||
|
||||
do {
|
||||
$calculatedMin -= $this->properties['majorStep'];
|
||||
} while ( $calculatedMin > $min );
|
||||
|
||||
$this->properties['min'] = $calculatedMin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate maximum value for displayed axe basing on real maximum and
|
||||
* major step size
|
||||
*
|
||||
* @param float $min Real data minimum
|
||||
* @param float $max Real data maximum
|
||||
* @return void
|
||||
*/
|
||||
protected function calculateMaximum( $min, $max )
|
||||
{
|
||||
$calculatedMax = $this->properties['min'];
|
||||
|
||||
do {
|
||||
$calculatedMax += $this->properties['majorStep'];
|
||||
} while ( $calculatedMax < $max );
|
||||
|
||||
$this->properties['max'] = $calculatedMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate size of minor steps based on the size of the major step size
|
||||
*
|
||||
* @param float $min Real data minimum
|
||||
* @param float $max Real data maximum
|
||||
* @return void
|
||||
*/
|
||||
protected function calculateMinorStep( $min, $max )
|
||||
{
|
||||
$stepSize = $this->properties['majorStep'] / self::MIN_MINOR_COUNT;
|
||||
$this->properties['minorStep'] = $this->getNiceNumber( $stepSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate size of major step based on the span to be displayed and the
|
||||
* defined MIN_MAJOR_COUNT constant.
|
||||
*
|
||||
* @param float $min Real data minimum
|
||||
* @param float $max Real data maximum
|
||||
* @return void
|
||||
*/
|
||||
protected function calculateMajorStep( $min, $max )
|
||||
{
|
||||
$span = $max - $min;
|
||||
$stepSize = $span / self::MIN_MAJOR_COUNT;
|
||||
$this->properties['majorStep'] = $this->getNiceNumber( $stepSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data for this axis
|
||||
*
|
||||
* @param array $values Value which will be displayed on this axis
|
||||
* @return void
|
||||
*/
|
||||
public function addData( array $values )
|
||||
{
|
||||
foreach ( $values as $value )
|
||||
{
|
||||
if ( $this->properties['minValue'] === null ||
|
||||
$value < $this->properties['minValue'] )
|
||||
{
|
||||
$this->properties['minValue'] = $value;
|
||||
}
|
||||
|
||||
if ( $this->properties['maxValue'] === null ||
|
||||
$value > $this->properties['maxValue'] )
|
||||
{
|
||||
$this->properties['maxValue'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->properties['initialized'] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate axis bounding values on base of the assigned values
|
||||
*
|
||||
* @abstract
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function calculateAxisBoundings()
|
||||
{
|
||||
// Prevent division by zero, when min == max
|
||||
if ( $this->properties['minValue'] == $this->properties['maxValue'] )
|
||||
{
|
||||
if ( $this->properties['minValue'] == 0 )
|
||||
{
|
||||
$this->properties['maxValue'] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $this->properties['majorStep'] !== null )
|
||||
{
|
||||
$this->properties['minValue'] -= $this->properties['majorStep'];
|
||||
$this->properties['maxValue'] += $this->properties['majorStep'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->properties['minValue'] -= ( $this->properties['minValue'] * .1 );
|
||||
$this->properties['maxValue'] += ( $this->properties['maxValue'] * .1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use custom minimum and maximum if available
|
||||
if ( $this->properties['min'] !== null )
|
||||
{
|
||||
$this->properties['minValue'] = $this->properties['min'];
|
||||
}
|
||||
|
||||
if ( $this->properties['max'] !== null )
|
||||
{
|
||||
$this->properties['maxValue'] = $this->properties['max'];
|
||||
}
|
||||
|
||||
// If min and max values are forced, we may not be able to find a
|
||||
// "nice" number for the steps. Try to find such a nice step size, or
|
||||
// fall back to a step size, which is just the span divided by 5.
|
||||
if ( ( $this->properties['min'] !== null ) &&
|
||||
( $this->properties['max'] !== null ) )
|
||||
{
|
||||
$diff = $this->properties['max'] - $this->properties['min'];
|
||||
$this->calculateMajorStep( $this->properties['minValue'], $this->properties['maxValue'] );
|
||||
$stepInvariance = $diff / $this->properties['majorStep'];
|
||||
if ( ( $stepInvariance - floor( $stepInvariance ) ) > .0000001 )
|
||||
{
|
||||
// For too big step invariances calculate the step size just
|
||||
// from the given difference between min and max value.
|
||||
$this->properties['majorStep'] = ( $this->properties['max'] - $this->properties['min'] ) / self::MIN_MAJOR_COUNT;
|
||||
$this->properties['minorStep'] = $this->properties['majorStep'] / self::MIN_MAJOR_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate "nice" values for scaling parameters
|
||||
if ( $this->properties['majorStep'] === null )
|
||||
{
|
||||
$this->calculateMajorStep( $this->properties['minValue'], $this->properties['maxValue'] );
|
||||
}
|
||||
|
||||
if ( $this->properties['minorStep'] === null )
|
||||
{
|
||||
$this->calculateMinorStep( $this->properties['minValue'], $this->properties['maxValue'] );
|
||||
}
|
||||
|
||||
if ( $this->properties['min'] === null )
|
||||
{
|
||||
$this->calculateMinimum( $this->properties['minValue'], $this->properties['maxValue'] );
|
||||
}
|
||||
|
||||
if ( $this->properties['max'] === null )
|
||||
{
|
||||
$this->calculateMaximum( $this->properties['minValue'], $this->properties['maxValue'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coordinate for a dedicated value on the chart
|
||||
*
|
||||
* @param float $value Value to determine position for
|
||||
* @return float Position on chart
|
||||
*/
|
||||
public function getCoordinate( $value )
|
||||
{
|
||||
// Force typecast, because ( false < -100 ) results in (bool) true
|
||||
$floatValue = (float) $value;
|
||||
|
||||
if ( ( $value === false ) &&
|
||||
( ( $floatValue < $this->properties['min'] ) || ( $floatValue > $this->properties['max'] ) ) )
|
||||
{
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
return 0.;
|
||||
case ezcGraph::RIGHT:
|
||||
case ezcGraph::BOTTOM:
|
||||
return 1.;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( $this->position )
|
||||
{
|
||||
case ezcGraph::LEFT:
|
||||
case ezcGraph::TOP:
|
||||
return ( $value - $this->properties['min'] ) / ( $this->properties['max'] - $this->properties['min'] );
|
||||
case ezcGraph::RIGHT:
|
||||
case ezcGraph::BOTTOM:
|
||||
return 1 - ( $value - $this->properties['min'] ) / ( $this->properties['max'] - $this->properties['min'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of minor steps
|
||||
*
|
||||
* @return integer Count of minor steps
|
||||
*/
|
||||
public function getMinorStepCount()
|
||||
{
|
||||
return (int) ( ( $this->properties['max'] - $this->properties['min'] ) / $this->properties['minorStep'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return count of major steps
|
||||
*
|
||||
* @return integer Count of major steps
|
||||
*/
|
||||
public function getMajorStepCount()
|
||||
{
|
||||
return (int) ( ( $this->properties['max'] - $this->properties['min'] ) / $this->properties['majorStep'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get label for a dedicated step on the axis
|
||||
*
|
||||
* @param integer $step Number of step
|
||||
* @return string label
|
||||
*/
|
||||
public function getLabel( $step )
|
||||
{
|
||||
if ( $this->properties['labelCallback'] !== null )
|
||||
{
|
||||
return call_user_func_array(
|
||||
$this->properties['labelCallback'],
|
||||
array(
|
||||
$this->properties['min'] + ( $step * $this->properties['majorStep'] ),
|
||||
$step,
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->properties['min'] + ( $step * $this->properties['majorStep'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is zero step
|
||||
*
|
||||
* Returns true if the given step is the one on the initial axis position
|
||||
*
|
||||
* @param int $step Number of step
|
||||
* @return bool Status If given step is initial axis position
|
||||
*/
|
||||
public function isZeroStep( $step )
|
||||
{
|
||||
return ( $this->getLabel( $step ) == 0 );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user