[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/ezc/Graph/src/element/ -> axis.php (source)

   1  <?php
   2  /**
   3   * File containing the abstract ezcGraphChartElementAxis class
   4   *
   5   * @package Graph
   6   * @version 1.5
   7   * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
   8   * @license http://ez.no/licenses/new_bsd New BSD License
   9   */
  10  /**
  11   * Class to represent an axis as a chart element
  12   *
  13   * Chart elements can be understood as widgets or layout container inside the
  14   * chart. The actual transformation to images happens inside the renderers.
  15   * They represent all elements inside the chart and contain mostly general
  16   * formatting options, while the renderer itself might define additional
  17   * formatting options for some chart elments. You can find more about the
  18   * general formatting options for chart elements in the base class
  19   * ezcGraphChartElement.
  20   *
  21   * The axis elements are special elements, as the border and background
  22   * settings do not apply directly as axis axis are not put inside any boxes.
  23   * The border value is reused for the color of the axis itself.
  24   *
  25   * Generally you should select the axis which matches your data best. By
  26   * default a labeled x axis and a numeric y axis are used. If you are using
  27   * date or time values on either axis, you should for example use a
  28   * ezcGraphChartElementDateAxis. The currently available axis types are:
  29   *
  30   * - ezcGraphChartElementDateAxis
  31   * - ezcGraphChartElementLabeledAxis
  32   * - ezcGraphChartElementLogarithmicalAxis
  33   * - ezcGraphChartElementNumericAxis
  34   *
  35   * Beside this there are several option to define the general layout of the
  36   * axis labels. The $formatString option may be used to add additional text to
  37   * each label on the axis, like a percent sign on the y axis:
  38   *
  39   * <code>
  40   *  $chart->xAxis->formatString = '%s %%';
  41   * </code>
  42   *
  43   * For more complex formatting operations for the label you may assign a custom
  44   * formatter function to the property $labelCallback.
  45   *
  46   * The orientation of labels and their position relatively to the axis ticks is
  47   * calcualted and rendered by the ezcGraphAxisLabelRenderer classes. You can
  48   * choose between different axis label renderer, or create you own, and assign
  49   * an instance of one to the property $axisLabelRenderer. Currently the
  50   * available axis label renderers are:
  51   * 
  52   * - ezcGraphAxisBoxedLabelRenderer
  53   *
  54   *   Renders grid and labels like commonly used in bar charts, with the label
  55   *   between two grid lines.
  56   *  
  57   * - ezcGraphAxisCenteredLabelRenderer
  58   *
  59   *   Centers the label right next to a tick. Commonly used for labeled axis.
  60   *
  61   * - ezcGraphAxisExactLabelRenderer
  62   *
  63   *   Put the label next to each tick. Commonly used for numeric axis.
  64   *
  65   * - ezcGraphAxisNoLabelRenderer
  66   *
  67   *   Renders no labels.
  68   *
  69   * - ezcGraphAxisRadarLabelRenderer
  70   *
  71   *   Special label renderer for radar charts.
  72   *
  73   * - ezcGraphAxisRotatedLabelRenderer
  74   *
  75   *   Accepts a rotation angle for the texts put at some axis, which might be
  76   *   useful for longer textual labels on the axis.
  77   *
  78   * The label renderer used by default is different depending on the axis type.
  79   *
  80   * @property float $nullPosition
  81   *           The position of the null value.
  82   * @property float $axisSpace
  83   *           Percent of the chart space used to display axis labels and 
  84   *           arrowheads instead of data values.
  85   * @property float $outerAxisSpace
  86   *           Percent of the chart space used to display axis arrow at the outer
  87   *           side of the axis. If set to null, the axisSpace will be used here.
  88   * @property ezcGraphColor $majorGrid
  89   *           Color of major majorGrid.
  90   * @property ezcGraphColor $minorGrid
  91   *           Color of minor majorGrid.
  92   * @property mixed $majorStep
  93   *           Labeled major steps displayed on the axis. @TODO: Should be moved
  94   *           to numeric axis.
  95   * @property mixed $minorStep
  96   *           Non labeled minor steps on the axis. @TODO: Should be moved to
  97   *           numeric axis.
  98   * @property string $formatString
  99   *           Formatstring to use for labeling of the axis.
 100   * @property string $label
 101   *           Axis label
 102   * @property int $labelSize
 103   *           Size of axis label
 104   * @property int $labelMargin
 105   *           Distance between label an axis
 106   * @property int $minArrowHeadSize
 107   *           Minimum Size used to draw arrow heads.
 108   * @property int $maxArrowHeadSize
 109   *           Maximum Size used to draw arrow heads.
 110   * @property ezcGraphAxisLabelRenderer $axisLabelRenderer
 111   *           AxisLabelRenderer used to render labels and grid on this axis.
 112   * @property callback $labelCallback
 113   *           Callback function to format chart labels.
 114   *           Function will receive two parameters and should return a 
 115   *           reformatted label.
 116   *              string function( label, step )
 117   * @property float $chartPosition
 118   *           Position of the axis in the chart. Only useful for additional
 119   *           axis. The basic chart axis will be automatically positioned.
 120   * @property-read bool $initialized
 121   *           Property indicating if some values were associated with axis, or a
 122   *           scaling has been set manually.
 123   * @property float $labelRotation
 124   *           Rotation of the axis label in degree
 125   *
 126   * @version 1.5
 127   * @package Graph
 128   */
 129  abstract class ezcGraphChartElementAxis extends ezcGraphChartElement
 130  {
 131      /**
 132       * Axis label renderer class
 133       * 
 134       * @var ezcGraphAxisLabelRenderer
 135       */
 136      protected $axisLabelRenderer;
 137  
 138      /**
 139       * Optionally set inner boundings. May be null depending on the used chart
 140       * implementation.
 141       * 
 142       * @var ezcGraphBoundings
 143       */
 144      protected $innerBoundings;
 145  
 146      /**
 147       * Constructor
 148       * 
 149       * @param array $options Default option array
 150       * @return void
 151       * @ignore
 152       */
 153      public function __construct( array $options = array() )
 154      {
 155          $this->properties['nullPosition'] = false;
 156          $this->properties['axisSpace'] = .1;
 157          $this->properties['outerAxisSpace'] = null;
 158          $this->properties['majorGrid'] = false;
 159          $this->properties['minorGrid'] = false;
 160          $this->properties['majorStep'] = null;
 161          $this->properties['minorStep'] = null;
 162          $this->properties['formatString'] = '%s';
 163          $this->properties['label'] = false;
 164          $this->properties['labelSize'] = 14;
 165          $this->properties['labelMargin'] = 2;
 166          $this->properties['minArrowHeadSize'] = 4;
 167          $this->properties['maxArrowHeadSize'] = 8;
 168          $this->properties['labelCallback'] = null;
 169          $this->properties['chartPosition'] = null;
 170          $this->properties['initialized'] = false;
 171          $this->properties['labelRotation'] = 0.;
 172  
 173          parent::__construct( $options );
 174  
 175          if ( !isset( $this->axisLabelRenderer ) )
 176          {
 177              $this->axisLabelRenderer = new ezcGraphAxisExactLabelRenderer();
 178          }
 179      }
 180  
 181      /**
 182       * Set colors and border fro this element
 183       * 
 184       * @param ezcGraphPalette $palette Palette
 185       * @return void
 186       */
 187      public function setFromPalette( ezcGraphPalette $palette )
 188      {
 189          $this->border = $palette->axisColor;
 190          $this->padding = $palette->padding;
 191          $this->margin = $palette->margin;
 192          $this->majorGrid = $palette->majorGridColor;
 193          $this->minorGrid = $palette->minorGridColor;
 194      }
 195  
 196      /**
 197       * __set 
 198       * 
 199       * @param mixed $propertyName 
 200       * @param mixed $propertyValue 
 201       * @throws ezcBaseValueException
 202       *          If a submitted parameter was out of range or type.
 203       * @throws ezcBasePropertyNotFoundException
 204       *          If a the value for the property options is not an instance of
 205       * @return void
 206       */
 207      public function __set( $propertyName, $propertyValue )
 208      {
 209          switch ( $propertyName )
 210          {
 211              case 'nullPosition':
 212                  $this->properties['nullPosition'] = (float) $propertyValue;
 213                  break;
 214              case 'axisSpace':
 215                  if ( !is_numeric( $propertyValue ) ||
 216                       ( $propertyValue < 0 ) ||
 217                       ( $propertyValue >= 1 ) )
 218                  {
 219                      throw new ezcBaseValueException( $propertyName, $propertyValue, '0 <= float < 1' );
 220                  }
 221  
 222                  $this->properties['axisSpace'] = (float) $propertyValue;
 223                  break;
 224              case 'outerAxisSpace':
 225                  if ( !is_null( $propertyValue ) &&
 226                       ( !is_numeric( $propertyValue ) ||
 227                         ( $propertyValue < 0 ) ||
 228                         ( $propertyValue >= 1 ) ) )
 229                  {
 230                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'null, or 0 <= float < 1' );
 231                  }
 232  
 233                  $this->properties['outerAxisSpace'] = $propertyValue;
 234                  break;
 235              case 'majorGrid':
 236                  $this->properties['majorGrid'] = ezcGraphColor::create( $propertyValue );
 237                  break;
 238              case 'minorGrid':
 239                  $this->properties['minorGrid'] = ezcGraphColor::create( $propertyValue );
 240                  break;
 241              case 'majorStep':
 242                  if ( !is_numeric( $propertyValue ) ||
 243                       ( $propertyValue <= 0 ) )
 244                  {
 245                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'float > 0' );
 246                  }
 247                  
 248                  $this->properties['majorStep'] = (float) $propertyValue;
 249                  break;
 250              case 'minorStep':
 251                  if ( !is_numeric( $propertyValue ) ||
 252                       ( $propertyValue <= 0 ) )
 253                  {
 254                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'float > 0' );
 255                  }
 256                  
 257                  $this->properties['minorStep'] = (float) $propertyValue;
 258                  break;
 259              case 'formatString':
 260                  $this->properties['formatString'] = (string) $propertyValue;
 261                  break;
 262              case 'label':
 263                  $this->properties['label'] = (string) $propertyValue;
 264                  break;
 265              case 'labelSize':
 266                  if ( !is_numeric( $propertyValue ) ||
 267                       ( $propertyValue <= 6 ) )
 268                  {
 269                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 6' );
 270                  }
 271                  
 272                  $this->properties['labelSize'] = (int) $propertyValue;
 273                  break;
 274              case 'labelMargin':
 275                  if ( !is_numeric( $propertyValue ) ||
 276                       ( $propertyValue <= 0 ) )
 277                  {
 278                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 279                  }
 280                  
 281                  $this->properties['labelMargin'] = (int) $propertyValue;
 282                  break;
 283              case 'maxArrowHeadSize':
 284                  if ( !is_numeric( $propertyValue ) ||
 285                       ( $propertyValue <= 0 ) )
 286                  {
 287                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 288                  }
 289                  
 290                  $this->properties['maxArrowHeadSize'] = (int) $propertyValue;
 291                  break;
 292              case 'minArrowHeadSize':
 293                  if ( !is_numeric( $propertyValue ) ||
 294                       ( $propertyValue <= 0 ) )
 295                  {
 296                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 297                  }
 298                  
 299                  $this->properties['minArrowHeadSize'] = (int) $propertyValue;
 300                  break;
 301              case 'axisLabelRenderer':
 302                  if ( $propertyValue instanceof ezcGraphAxisLabelRenderer )
 303                  {
 304                      $this->axisLabelRenderer = $propertyValue;
 305                  }
 306                  else
 307                  {
 308                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphAxisLabelRenderer' );
 309                  }
 310                  break;
 311              case 'labelCallback':
 312                  if ( is_callable( $propertyValue ) )
 313                  {
 314                      $this->properties['labelCallback'] = $propertyValue;
 315                  }
 316                  else
 317                  {
 318                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'callback function' );
 319                  }
 320                  break;
 321              case 'chartPosition':
 322                  if ( !is_numeric( $propertyValue ) ||
 323                       ( $propertyValue < 0 ) ||
 324                       ( $propertyValue > 1 ) )
 325                  {
 326                      throw new ezcBaseValueException( $propertyName, $propertyValue, '0 <= float <= 1' );
 327                  }
 328  
 329                  $this->properties['chartPosition'] = (float) $propertyValue;
 330                  break;
 331              case 'labelRotation':
 332                  if ( !is_numeric( $propertyValue ) )
 333                  {
 334                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'float' );
 335                  }
 336                  
 337                  $this->properties['labelRotation'] = fmod( (float) $propertyValue, 360. );
 338                  break;
 339              default:
 340                  parent::__set( $propertyName, $propertyValue );
 341                  break;
 342          }
 343      }
 344  
 345      /**
 346       * __get 
 347       * 
 348       * @param mixed $propertyName 
 349       * @throws ezcBasePropertyNotFoundException
 350       *          If a the value for the property options is not an instance of
 351       * @return mixed
 352       * @ignore
 353       */
 354      public function __get( $propertyName )
 355      {
 356          switch ( $propertyName )
 357          {
 358              case 'axisLabelRenderer':
 359                  return $this->axisLabelRenderer;
 360              default:
 361                  return parent::__get( $propertyName );
 362          }
 363      }
 364  
 365      /**
 366       * Get coordinate for a dedicated value on the chart
 367       * 
 368       * @param float $value Value to determine position for
 369       * @return float Position on chart
 370       */
 371      abstract public function getCoordinate( $value );
 372  
 373      /**
 374       * Return count of minor steps
 375       * 
 376       * @return integer Count of minor steps
 377       */
 378      abstract public function getMinorStepCount();
 379  
 380      /**
 381       * Return count of major steps
 382       * 
 383       * @return integer Count of major steps
 384       */
 385      abstract public function getMajorStepCount();
 386  
 387      /**
 388       * Get label for a dedicated step on the axis
 389       * 
 390       * @param integer $step Number of step
 391       * @return string label
 392       */
 393      abstract public function getLabel( $step );
 394  
 395      /**
 396       * Return array of steps on this axis
 397       * 
 398       * @return array( ezcGraphAxisStep )
 399       */
 400      public function getSteps()
 401      {
 402          $majorSteps = $this->getMajorStepCount();
 403          $minorStepsPerMajorStepCount = ( $this->getMinorStepCount() / $majorSteps );
 404  
 405          $majorStepSize = 1 / $majorSteps;
 406          $minorStepSize = ( $minorStepsPerMajorStepCount > 0 ? $majorStepSize / $minorStepsPerMajorStepCount : 0 );
 407  
 408          $steps = array();
 409          for ( $major = 0; $major <= $majorSteps; ++$major )
 410          {
 411              $majorStep = new ezcGraphAxisStep(
 412                  $majorStepSize * $major,
 413                  $majorStepSize,
 414                  $this->getLabel( $major ),
 415                  array(),
 416                  $this->isZeroStep( $major ),
 417                  ( $major === $majorSteps )
 418              );
 419  
 420              if ( ( $minorStepsPerMajorStepCount > 0 ) &&
 421                   ( $major < $majorSteps ) )
 422              {
 423                  // Do not add minor steps at major steps positions
 424                  for( $minor = 1; $minor < $minorStepsPerMajorStepCount; ++$minor )
 425                  {
 426                      $majorStep->childs[] = new ezcGraphAxisStep(
 427                          ( $majorStepSize * $major ) + ( $minorStepSize * $minor ),
 428                          $minorStepSize
 429                      );
 430                  }
 431              }
 432  
 433              $steps[] = $majorStep;
 434          }
 435  
 436          return $steps;
 437      }
 438  
 439      /**
 440       * Is zero step
 441       *
 442       * Returns true if the given step is the one on the initial axis position
 443       * 
 444       * @param int $step Number of step
 445       * @return bool Status If given step is initial axis position
 446       */
 447      abstract public function isZeroStep( $step );
 448  
 449      /**
 450       * Add data for this axis
 451       * 
 452       * @param array $values
 453       * @return void
 454       */
 455      abstract public function addData( array $values );
 456  
 457      /**
 458       * Calculate axis bounding values on base of the assigned values 
 459       * 
 460       * @abstract
 461       * @access public
 462       * @return void
 463       */
 464      abstract public function calculateAxisBoundings();
 465  
 466      /**
 467       * Render the axis 
 468       * 
 469       * @param ezcGraphRenderer $renderer Renderer
 470       * @param ezcGraphBoundings $boundings Boundings for the axis
 471       * @return ezcGraphBoundings Remaining boundings
 472       */
 473      public function render( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings, ezcGraphBoundings $innerBoundings = null )
 474      {
 475          $this->innerBoundings = $innerBoundings;
 476          $startSpace = $this->axisSpace;
 477          $endSpace   = $this->outerAxisSpace === null ? $this->axisSpace : $this->outerAxisSpace;
 478  
 479          switch ( $this->position )
 480          {
 481              case ezcGraph::TOP:
 482                  $start = new ezcGraphCoordinate(
 483                      $boundings->width * $startSpace +
 484                          $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
 485                      0
 486                  );
 487                  $end = new ezcGraphCoordinate(
 488                      $boundings->width * $startSpace +
 489                          $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
 490                      $boundings->height
 491                  );
 492                  break;
 493              case ezcGraph::BOTTOM:
 494                  $start = new ezcGraphCoordinate(
 495                      $boundings->width * $startSpace +
 496                          $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
 497                      $boundings->height
 498                  );
 499                  $end = new ezcGraphCoordinate(
 500                      $boundings->width * $startSpace +
 501                          $this->nullPosition * $boundings->width * ( 1 - ( $startSpace + $endSpace ) ),
 502                      0
 503                  );
 504                  break;
 505              case ezcGraph::LEFT:
 506                  $start = new ezcGraphCoordinate(
 507                      0,
 508                      $boundings->height * $endSpace +
 509                          $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
 510                  );
 511                  $end = new ezcGraphCoordinate(
 512                      $boundings->width,
 513                      $boundings->height * $endSpace +
 514                          $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
 515                  );
 516                  break;
 517              case ezcGraph::RIGHT:
 518                  $start = new ezcGraphCoordinate(
 519                      $boundings->width,
 520                      $boundings->height * $endSpace +
 521                          $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
 522                  );
 523                  $end = new ezcGraphCoordinate(
 524                      0,
 525                      $boundings->height * $endSpace +
 526                          $this->nullPosition * $boundings->height * ( 1 - ( $startSpace + $endSpace ) )
 527                  );
 528                  break;
 529          }
 530  
 531          $renderer->drawAxis(
 532              $boundings,
 533              $start,
 534              $end,
 535              $this,
 536              $this->axisLabelRenderer,
 537              $innerBoundings
 538          );
 539  
 540          return $boundings;   
 541      }
 542  }
 543  
 544  ?>


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7