[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/ezc/Graph/src/interfaces/ -> axis_label_renderer.php (source)

   1  <?php
   2  /**
   3   * File containing the abstract ezcGraphAxisLabelRenderer 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   * Abstract class to render labels and grids on axis. Will be extended to
  12   * make it possible using different algorithms for rendering axis labels.
  13   *
  14   * Implements basic methods to render the grid and steps on a axis.
  15   *
  16   * @property bool $majorStepCount
  17   *           Count of major steps.
  18   * @property bool $minorStepCount
  19   *           Count of minor steps.
  20   * @property int $majorStepSize
  21   *           Size of major steps.
  22   * @property int $minorStepSize
  23   *           Size of minor steps.
  24   * @property bool $innerStep
  25   *           Indicates if steps are shown on the inner side of axis.
  26   * @property bool $outerStep
  27   *           Indicates if steps are shown on the outer side of axis.
  28   * @property bool $outerGrid
  29   *           Indicates if the grid is shown on the outer side of axis.
  30   * @property bool $showLables
  31   *           Indicates if the labels should be shown
  32   * @property int $labelPadding
  33   *           Padding of labels.
  34   *
  35   * @version 1.5
  36   * @package Graph
  37   */
  38  abstract class ezcGraphAxisLabelRenderer extends ezcBaseOptions
  39  {
  40      /**
  41       * Driver to render axis labels
  42       * 
  43       * @var ezcGraphDriver
  44       */
  45      protected $driver;
  46  
  47      /**
  48       * Constructor
  49       * 
  50       * @param array $options Default option array
  51       * @return void
  52       * @ignore
  53       */
  54      public function __construct( array $options = array() )
  55      {
  56          $this->properties['majorStepCount'] = false;
  57          $this->properties['minorStepCount'] = false;
  58          $this->properties['majorStepSize'] = 3;
  59          $this->properties['minorStepSize'] = 1;
  60          $this->properties['innerStep'] = true;
  61          $this->properties['outerStep'] = false;
  62          $this->properties['outerGrid'] = false;
  63          $this->properties['showLabels'] = true;
  64          $this->properties['labelPadding'] = 2;
  65  
  66          parent::__construct( $options );
  67      }
  68  
  69      /**
  70       * __set 
  71       * 
  72       * @param mixed $propertyName 
  73       * @param mixed $propertyValue 
  74       * @throws ezcBaseValueException
  75       *          If a submitted parameter was out of range or type.
  76       * @throws ezcBasePropertyNotFoundException
  77       *          If a the value for the property options is not an instance of
  78       * @return void
  79       * @ignore
  80       */
  81      public function __set( $propertyName, $propertyValue )
  82      {
  83          switch ( $propertyName )
  84          {
  85              case 'driver':
  86                  if ( $propertyValue instanceof ezcGraphDriver )
  87                  {
  88                      $this->properties['driver'] = $propertyValue;
  89                  }
  90                  else
  91                  {
  92                      throw new ezcGraphInvalidDriverException( $propertyValue );
  93                  }
  94                  break;
  95              case 'majorStepCount':
  96                  if ( ( $propertyValue !== false ) &&
  97                       !is_numeric( $propertyValue ) ||
  98                       ( $propertyValue < 0 ) )
  99                  {
 100                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 101                  }
 102  
 103                  $this->properties['majorStepCount'] = (int) $propertyValue;
 104                  break;
 105              case 'minorStepCount':
 106                  if ( ( $propertyValue !== false ) &&
 107                       !is_numeric( $propertyValue ) ||
 108                       ( $propertyValue < 0 ) )
 109                  {
 110                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 111                  }
 112  
 113                  $this->properties['minorStepCount'] = (int) $propertyValue;
 114                  break;
 115              case 'majorStepSize':
 116                  if ( !is_numeric( $propertyValue ) ||
 117                       ( $propertyValue < 0 ) )
 118                  {
 119                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 120                  }
 121  
 122                  $this->properties['majorStepSize'] = (int) $propertyValue;
 123                  break;
 124              case 'minorStepSize':
 125                  if ( !is_numeric( $propertyValue ) ||
 126                       ( $propertyValue < 0 ) )
 127                  {
 128                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 129                  }
 130  
 131                  $this->properties['minorStepSize'] = (int) $propertyValue;
 132                  break;
 133              case 'innerStep':
 134                  if ( !is_bool( $propertyValue ) )
 135                  {
 136                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' );
 137                  }
 138  
 139                  $this->properties['innerStep'] = (bool) $propertyValue;
 140                  break;
 141              case 'outerStep':
 142                  if ( !is_bool( $propertyValue ) )
 143                  {
 144                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' );
 145                  }
 146  
 147                  $this->properties['outerStep'] = (bool) $propertyValue;
 148                  break;
 149              case 'outerGrid':
 150                  if ( !is_bool( $propertyValue ) )
 151                  {
 152                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' );
 153                  }
 154  
 155                  $this->properties['outerGrid'] = (bool) $propertyValue;
 156                  break;
 157              case 'showLabels':
 158                  if ( !is_bool( $propertyValue ) )
 159                  {
 160                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' );
 161                  }
 162  
 163                  $this->properties['showLabels'] = (bool) $propertyValue;
 164                  break;
 165              case 'labelPadding':
 166                  if ( !is_numeric( $propertyValue ) ||
 167                       ( $propertyValue < 0 ) )
 168                  {
 169                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'int >= 0' );
 170                  }
 171  
 172                  $this->properties['labelPadding'] = (int) $propertyValue;
 173                  break;
 174              default:
 175                  throw new ezcBasePropertyNotFoundException( $propertyName );
 176          }
 177      }
 178  
 179      /**
 180       * Checks for the cutting point of two lines.
 181       *
 182       * The lines are given by a start position and the direction of the line, 
 183       * both as instances of {@link ezcGraphCoordinate}. If no cutting point
 184       * could be calculated, because the lines are parallel the function will
 185       * return false. Otherwise the factor returned can be used to calculate the
 186       * cutting point using the following equatation:
 187       *  point = $aStart + $factor * $aDir;
 188       *
 189       * We return the factor instead of the resulting point because it can be 
 190       * easily determined from the factor if the cutting point is in "behind"
 191       * the line starting point, or if the distance to the cutting point is
 192       * bigger then the direction vector is long ( $factor > 1 ).
 193       * 
 194       * @param ezcGraphCoordinate $aStart 
 195       * @param ezcGraphCoordinate $aDir 
 196       * @param ezcGraphCoordinate $bStart 
 197       * @param ezcGraphCoordinate $bDir 
 198       * @return mixed
 199       */
 200      public function determineLineCuttingPoint( ezcGraphCoordinate $aStart, ezcGraphCoordinate $aDir, ezcGraphCoordinate $bStart, ezcGraphCoordinate $bDir )
 201      {
 202          // Check if lines are parallel
 203          if ( ( ( abs( $aDir->x ) < .000001 ) && ( abs( $bDir->x ) < .000001 ) ) ||
 204               ( ( abs( $aDir->y ) < .000001 ) && ( abs( $bDir->y ) < .000001 ) ) || 
 205               ( ( abs( $aDir->x * $bDir->x * $aDir->y * $bDir->y ) > .000001 ) && 
 206                 ( abs( ( $aDir->x / $aDir->y ) - ( $bDir->x / $bDir->y ) ) < .000001 )
 207               )
 208             )
 209          {
 210              return false;
 211          }
 212  
 213          // Use ? : to prevent division by zero
 214          $denominator = 
 215              ( abs( $aDir->y ) > .000001 ? $bDir->y / $aDir->y : .0 ) - 
 216              ( abs( $aDir->x ) > .000001 ? $bDir->x / $aDir->x : .0 );
 217  
 218          // Solve equatation
 219          if ( abs( $denominator ) < .000001 )
 220          {
 221              return - ( 
 222                  ( abs( $aDir->y ) > .000001 ? $bStart->y / $aDir->y : .0 ) -
 223                  ( abs( $aDir->y ) > .000001 ? $aStart->y / $aDir->y : .0 ) -
 224                  ( abs( $aDir->x ) > .000001 ? $bStart->x / $aDir->x : .0 ) +
 225                  ( abs( $aDir->x ) > .000001 ? $aStart->x / $aDir->x : .0 )
 226              );
 227          }
 228          else 
 229          {
 230              return - ( 
 231                  ( abs( $aDir->y ) > .000001 ? $bStart->y / $aDir->y : .0 ) -
 232                  ( abs( $aDir->y ) > .000001 ? $aStart->y / $aDir->y : .0 ) -
 233                  ( abs( $aDir->x ) > .000001 ? $bStart->x / $aDir->x : .0 ) +
 234                  ( abs( $aDir->x ) > .000001 ? $aStart->x / $aDir->x : .0 )
 235              ) / $denominator;
 236          }
 237      }
 238  
 239      /**
 240       * Draw single step on a axis
 241       *
 242       * Draws a step on a axis at the current position
 243       * 
 244       * @param ezcGraphRenderer $renderer Renderer to draw the step with
 245       * @param ezcGraphCoordinate $position Position of step
 246       * @param ezcGraphCoordinate $direction Direction of axis
 247       * @param int $axisPosition Position of axis
 248       * @param int $size Step size
 249       * @param ezcGraphColor $color Color of axis
 250       * @return void
 251       */
 252      public function drawStep( ezcGraphRenderer $renderer, ezcGraphCoordinate $position, ezcGraphCoordinate $direction, $axisPosition, $size, ezcGraphColor $color )
 253      {
 254          if ( ! ( $this->innerStep || $this->outerStep ) )
 255          {
 256              return false;
 257          }
 258  
 259          $drawStep = false;
 260          if ( ( ( $axisPosition === ezcGraph::CENTER ) && $this->innerStep ) ||
 261               ( ( $axisPosition === ezcGraph::BOTTOM ) && $this->outerStep ) ||
 262               ( ( $axisPosition === ezcGraph::TOP ) && $this->innerStep ) ||
 263               ( ( $axisPosition === ezcGraph::RIGHT ) && $this->outerStep ) ||
 264               ( ( $axisPosition === ezcGraph::LEFT ) && $this->innerStep ) )
 265          {
 266              // Turn direction vector to left by 90 degrees and multiply 
 267              // with major step size
 268              $stepStart = new ezcGraphCoordinate(
 269                  $position->x + $direction->y * $size,
 270                  $position->y - $direction->x * $size
 271              );
 272              $drawStep = true;
 273          }
 274          else
 275          {
 276              $stepStart = $position;
 277          }
 278  
 279          if ( ( ( $axisPosition === ezcGraph::CENTER ) && $this->innerStep ) ||
 280               ( ( $axisPosition === ezcGraph::BOTTOM ) && $this->innerStep ) ||
 281               ( ( $axisPosition === ezcGraph::TOP ) && $this->outerStep ) ||
 282               ( ( $axisPosition === ezcGraph::RIGHT ) && $this->innerStep ) ||
 283               ( ( $axisPosition === ezcGraph::LEFT ) && $this->outerStep ) )
 284          {
 285              // Turn direction vector to right by 90 degrees and multiply 
 286              // with major step size
 287              $stepEnd = new ezcGraphCoordinate(
 288                  $position->x - $direction->y * $size,
 289                  $position->y + $direction->x * $size
 290              );
 291              $drawStep = true;
 292          }
 293          else
 294          {
 295              $stepEnd = $position;
 296          }
 297  
 298          if ( $drawStep )
 299          {
 300              $renderer->drawStepLine(
 301                  $stepStart,
 302                  $stepEnd,
 303                  $color
 304              );
 305          }
 306      }
 307      
 308      /**
 309       * Draw non-rectangular grid lines grid
 310       *
 311       * Draws a grid line at the current position, for non-rectangular axis.
 312       * 
 313       * @param ezcGraphRenderer $renderer Renderer to draw the grid with
 314       * @param ezcGraphBoundings $boundings Boundings of axis
 315       * @param ezcGraphCoordinate $position Position of step
 316       * @param ezcGraphCoordinate $direction Direction of axis
 317       * @param ezcGraphColor $color Color of axis
 318       * @return void
 319       */
 320      protected function drawNonRectangularGrid( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings, ezcGraphCoordinate $position, ezcGraphCoordinate $direction, ezcGraphColor $color )
 321      {
 322          // Direction of grid line is direction of axis turned right by 90 
 323          // degrees
 324          $gridDirection = new ezcGraphCoordinate(
 325              $direction->y,
 326              - $direction->x
 327          );
 328  
 329          $cuttingPoints = array();
 330          foreach ( array( // Bounding lines
 331                  array(
 332                      'start' => new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ),
 333                      'dir' => new ezcGraphCoordinate( 0, $boundings->y1 - $boundings->y0 )
 334                  ),
 335                  array(
 336                      'start' => new ezcGraphCoordinate( $boundings->x0, $boundings->y0 ),
 337                      'dir' => new ezcGraphCoordinate( $boundings->x1 - $boundings->x0, 0 )
 338                  ),
 339                  array(
 340                      'start' => new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ),
 341                      'dir' => new ezcGraphCoordinate( 0, $boundings->y0 - $boundings->y1 )
 342                  ),
 343                  array(
 344                      'start' => new ezcGraphCoordinate( $boundings->x1, $boundings->y1 ),
 345                      'dir' => new ezcGraphCoordinate( $boundings->x0 - $boundings->x1, 0 )
 346                  ),
 347              ) as $boundingLine )
 348          {
 349              // Test for cutting points with bounding lines, where cutting
 350              // position is between 0 and 1, which means, that the line is hit
 351              // on the bounding box rectangle. Use these points as a start and
 352              // ending point for the grid lines. There should *always* be
 353              // exactly two points returned.
 354              $cuttingPosition = $this->determineLineCuttingPoint(
 355                  $boundingLine['start'],
 356                  $boundingLine['dir'],
 357                  $position,
 358                  $gridDirection
 359              );
 360  
 361              if ( $cuttingPosition === false )
 362              {
 363                  continue;
 364              }
 365  
 366              $cuttingPosition = abs( $cuttingPosition );
 367  
 368              if ( ( $cuttingPosition >= 0 ) && 
 369                   ( $cuttingPosition <= 1 ) )
 370              {
 371                  $cuttingPoints[] = new ezcGraphCoordinate(
 372                      $boundingLine['start']->x + $cuttingPosition * $boundingLine['dir']->x,
 373                      $boundingLine['start']->y + $cuttingPosition * $boundingLine['dir']->y
 374                  );
 375              }
 376          }
 377  
 378          if ( count( $cuttingPoints ) < 2 )
 379          {
 380              // This should not happpen
 381              return false;
 382          }
 383  
 384          // Finally draw grid line
 385          $renderer->drawGridLine(
 386              $cuttingPoints[0],
 387              $cuttingPoints[1],
 388              $color
 389          );
 390      }
 391  
 392      /**
 393       * Draw rectangular grid
 394       *
 395       * Draws a grid line at the current position for rectangular directed axis.
 396       *
 397       * Method special for rectangularly directed axis to minimize the floating
 398       * point calculation inaccuracies. Those are not necessary for rectangles,
 399       * while for non-rectangular directed axis.
 400       * 
 401       * @param ezcGraphRenderer $renderer Renderer to draw the grid with
 402       * @param ezcGraphBoundings $boundings Boundings of axis
 403       * @param ezcGraphCoordinate $position Position of step
 404       * @param ezcGraphCoordinate $direction Direction of axis
 405       * @param ezcGraphColor $color Color of axis
 406       * @return void
 407       */
 408      protected function drawRectangularGrid( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings, ezcGraphCoordinate $position, ezcGraphCoordinate $direction, ezcGraphColor $color )
 409      {
 410          if ( abs( $direction->x ) < .00001 )
 411          {
 412              $renderer->drawGridLine(
 413                  new ezcGraphCoordinate(
 414                      $boundings->x0,
 415                      $position->y
 416                  ),
 417                  new ezcGraphCoordinate(
 418                      $boundings->x1,
 419                      $position->y
 420                  ),
 421                  $color
 422              );
 423          }
 424          else
 425          {
 426              $renderer->drawGridLine(
 427                  new ezcGraphCoordinate(
 428                      $position->x,
 429                      $boundings->y0
 430                  ),
 431                  new ezcGraphCoordinate(
 432                      $position->x,
 433                      $boundings->y1
 434                  ),
 435                  $color
 436              );
 437          }
 438      }
 439  
 440      /**
 441       * Draw grid
 442       *
 443       * Draws a grid line at the current position
 444       * 
 445       * @param ezcGraphRenderer $renderer Renderer to draw the grid with
 446       * @param ezcGraphBoundings $boundings Boundings of axis
 447       * @param ezcGraphCoordinate $position Position of step
 448       * @param ezcGraphCoordinate $direction Direction of axis
 449       * @param ezcGraphColor $color Color of axis
 450       * @return void
 451       */
 452      protected function drawGrid( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings, ezcGraphCoordinate $position, ezcGraphCoordinate $direction, ezcGraphColor $color )
 453      {
 454          // Check if the axis direction is rectangular
 455          if ( ( abs( $direction->x ) < .00001 ) ||
 456               ( abs( $direction->y ) < .00001 ) )
 457          {
 458              return $this->drawRectangularGrid( $renderer, $boundings, $position, $direction, $color );
 459          }
 460          else
 461          {
 462              return $this->drawNonRectangularGrid( $renderer, $boundings, $position, $direction, $color );
 463          }
 464      }
 465  
 466      /**
 467       * Modify chart boundings
 468       *
 469       * Optionally modify boundings of chart data
 470       * 
 471       * @param ezcGraphBoundings $boundings Current boundings of chart
 472       * @param ezcGraphCoordinate $direction Direction of the current axis
 473       * @return ezcGraphBoundings Modified boundings
 474       */
 475      public function modifyChartBoundings( ezcGraphBoundings $boundings, ezcGraphCoordinate $direction )
 476      {
 477          return $boundings;
 478      }
 479      
 480      /**
 481       * Modify chart data position
 482       *
 483       * Optionally additionally modify the coodinate of a data point
 484       * 
 485       * @param ezcGraphCoordinate $coordinate Data point coordinate
 486       * @return ezcGraphCoordinate Modified coordinate
 487       */
 488      public function modifyChartDataPosition( ezcGraphCoordinate $coordinate )
 489      {
 490          return $coordinate;
 491      }
 492  
 493      /**
 494       * Get axis space values
 495       *
 496       * Get axis space values, depending on passed parameters. If
 497       * $innerBoundings is given it will be used to caclulat the axis spaces
 498       * available for label rendering. If not given the legacy method will be
 499       * used, which uses the xAxisSpace and yAxisSpace values calcualted by the
 500       * renderer.
 501       *
 502       * Returns an array( $xSpace, $ySpace ), containing the irespective size in
 503       * pixels. Additionally calculates the grid boundings passed by reference.
 504       * 
 505       * @param ezcGraphRenderer $renderer 
 506       * @param ezcGraphBoundings $boundings 
 507       * @param mixed $innerBoundings 
 508       * @return array
 509       */
 510      protected function getAxisSpace( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings, ezcGraphChartElementAxis $axis, $innerBoundings, &$gridBoundings )
 511      {
 512          if ( $innerBoundings !== null )
 513          {
 514              $gridBoundings = clone $innerBoundings;
 515              $xSpace = abs( $axis->position === ezcGraph::LEFT ? $innerBoundings->x0 - $boundings->x0 : $boundings->x1 - $innerBoundings->x1 );
 516              $ySpace = abs( $axis->position === ezcGraph::TOP  ? $innerBoundings->y0 - $boundings->y0 : $boundings->y1 - $innerBoundings->y1 );
 517          }
 518          else
 519          {
 520              $gridBoundings = new ezcGraphBoundings(
 521                  $boundings->x0 + ( $xSpace = abs( $renderer->xAxisSpace ) ),
 522                  $boundings->y0 + ( $ySpace = abs( $renderer->yAxisSpace ) ),
 523                  $boundings->x1 - $xSpace,
 524                  $boundings->y1 - $ySpace
 525              );
 526          }
 527  
 528          if ( $this->outerGrid )
 529          {
 530              $gridBoundings = $boundings;
 531          }
 532  
 533          return array( $xSpace, $ySpace );
 534      }
 535  
 536      /**
 537       * Render Axis labels
 538       *
 539       * Render labels for an axis.
 540       *
 541       * @param ezcGraphRenderer $renderer Renderer used to draw the chart
 542       * @param ezcGraphBoundings $boundings Boundings of the axis
 543       * @param ezcGraphCoordinate $start Axis starting point
 544       * @param ezcGraphCoordinate $end Axis ending point
 545       * @param ezcGraphChartElementAxis $axis Axis instance
 546       * @return void
 547       */
 548      abstract public function renderLabels(
 549          ezcGraphRenderer $renderer,
 550          ezcGraphBoundings $boundings,
 551          ezcGraphCoordinate $start,
 552          ezcGraphCoordinate $end,
 553          ezcGraphChartElementAxis $axis
 554      );
 555  }
 556  
 557  ?>


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