[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/ezc/Graph/src/renderer/ -> axis_label_rotated.php (source)

   1  <?php
   2  /**
   3   * File containing the ezcGraphAxisRotatedLabelRenderer 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   * Can render axis labels rotated, so that more axis labels fit on one axis.
  12   * Produces best results if the axis space was increased, so that more spcae is
  13   * available below the axis.
  14   *
  15   * <code>
  16   *   $chart->xAxis->axisLabelRenderer = new ezcGraphAxisRotatedLabelRenderer();
  17   *
  18   *   // Define angle manually in degree
  19   *   $chart->xAxis->axisLabelRenderer->angle = 45;
  20   *
  21   *   // Increase axis space
  22   *   $chart->xAxis->axisSpace = .2;
  23   * </code>
  24   *
  25   * @property float $angle
  26   *           Angle of labels on axis in degrees.
  27   *
  28   * @version 1.5
  29   * @package Graph
  30   * @mainclass
  31   */
  32  class ezcGraphAxisRotatedLabelRenderer extends ezcGraphAxisLabelRenderer
  33  {
  34      /**
  35       * Store step array for later coordinate modifications
  36       * 
  37       * @var array(ezcGraphStep)
  38       */
  39      protected $steps;
  40  
  41      /**
  42       * Store direction for later coordinate modifications
  43       * 
  44       * @var ezcGraphVector
  45       */
  46      protected $direction;
  47  
  48      /**
  49       * Store coordinate width modifier for later coordinate modifications
  50       * 
  51       * @var float
  52       */
  53      protected $widthModifier;
  54      
  55      /**
  56       * Store coordinate offset for later coordinate modifications
  57       * 
  58       * @var float
  59       */
  60      protected $offset;
  61      
  62      /**
  63       * Constructor
  64       * 
  65       * @param array $options Default option array
  66       * @return void
  67       * @ignore
  68       */
  69      public function __construct( array $options = array() )
  70      {
  71          parent::__construct( $options );
  72          $this->properties['angle']  = null;
  73          $this->properties['labelOffset'] = true;
  74      }
  75  
  76      /**
  77       * __set 
  78       * 
  79       * @param mixed $propertyName 
  80       * @param mixed $propertyValue 
  81       * @throws ezcBaseValueException
  82       *          If a submitted parameter was out of range or type.
  83       * @throws ezcBasePropertyNotFoundException
  84       *          If a the value for the property options is not an instance of
  85       * @return void
  86       * @ignore
  87       */
  88      public function __set( $propertyName, $propertyValue )
  89      {
  90          switch ( $propertyName )
  91          {
  92              case 'angle':
  93                  if ( !is_numeric( $propertyValue ) )
  94                  {
  95                      throw new ezcBaseValueException( $propertyName, $propertyValue, '0 <= float < 360' );
  96                  }
  97  
  98                  $reducement = (int) ( $propertyValue - $propertyValue % 360 );
  99                  $this->properties['angle'] = (float) $propertyValue - $reducement;
 100                  break;
 101  
 102              case 'labelOffset':
 103                  if ( !is_bool( $propertyValue ) )
 104                  {
 105                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'bool' );
 106                  }
 107  
 108                  $this->properties[$propertyName] = (bool) $propertyValue;
 109                  break;
 110  
 111              default:
 112                  return parent::__set( $propertyName, $propertyValue );
 113          }
 114      }
 115  
 116      /**
 117       * Determine label angle
 118       *
 119       * Determine the optiomal angle for the axis labels, of no angle has been
 120       * provided by the user.
 121       * 
 122       * @param array $steps 
 123       * @return void
 124       */
 125      protected function determineAngle( array $steps, $xSpace, $ySpace, ezcGraphBoundings $axisBoundings )
 126      {
 127          if ( $this->angle === null )
 128          {
 129              $minimumStepWidth = null;
 130              foreach ( $steps as $nr => $step )
 131              {
 132                  if ( ( $minimumStepWidth === null ) || 
 133                       ( $step->width < $minimumStepWidth ) )
 134                  {
 135                      $minimumStepWidth = $step->width;
 136                  }
 137              }
 138  
 139              $width = abs(
 140                  $axisBoundings->width * $minimumStepWidth * $this->direction->x +
 141                  $axisBoundings->height * $minimumStepWidth * $this->direction->y
 142              );
 143              $height = abs(
 144                  $ySpace * $this->direction->x +
 145                  $xSpace * $this->direction->y
 146              );
 147  
 148              $length = sqrt( pow( $width, 2 ) + pow( $height, 2 ) );
 149              $this->angle = rad2deg( acos( $height / $length ) );
 150          }
 151      }
 152  
 153      /**
 154       * Determine text offset.
 155       *
 156       * Calculate the label offset and angle, from the configured or evaluated
 157       * text angle.
 158       *
 159       * Returns the text angle in degrees.
 160       * 
 161       * @param ezcGraphChartElementAxis $axis
 162       * @param array $steps
 163       * @return float
 164       */
 165      protected function determineTextOffset( ezcGraphChartElementAxis $axis, array $steps ) {
 166          // Determine additional required axis space by boxes
 167          $firstStep = reset( $steps );
 168          $lastStep = end( $steps );
 169  
 170          $axisAngle = -$this->direction->angle( new ezcGraphVector( 1, 0 ) );
 171          $textAngle = $axisAngle + 
 172              deg2rad( $this->angle ) + 
 173              ( $axis->position & ( ezcGraph::TOP | ezcGraph::BOTTOM ) ? deg2rad( 270 ) : deg2rad( 90 ) );
 174  
 175          // Ensure angle between 0 and 360 degrees
 176          $degTextAngle = rad2deg( $textAngle );
 177          while ( $degTextAngle < 0 )
 178          {
 179              $degTextAngle += 360.;
 180          }
 181  
 182          if ( $this->properties['labelOffset'] )
 183          {
 184              $this->offset =
 185                  ( $this->angle < 0 ? -1 : 1 ) *
 186                  ( $axis->position & ( ezcGraph::TOP | ezcGraph::LEFT ) ? 1 : -1 ) *
 187                  ( 1 - cos( deg2rad( $this->angle * 2 ) ) );
 188          }
 189          else
 190          {
 191              $this->offset = 0;
 192          }
 193  
 194          return $degTextAngle;
 195      }
 196  
 197      /**
 198       * Calculate label size
 199       *
 200       * Calculate the size of a single lable in a single step.
 201       * 
 202       * @param array $steps
 203       * @param int $nr 
 204       * @param array $step 
 205       * @param float $xSpace 
 206       * @param float $ySpace 
 207       * @param ezcGraphBoundings $axisBoundings 
 208       * @return float
 209       */
 210      protected function calculateLabelSize( array $steps, $nr, $step, $xSpace, $ySpace, ezcGraphBoundings $axisBoundings )
 211      {
 212          switch ( true )
 213          {
 214              case ( $nr === 0 ):
 215                  $labelSize = min(
 216                      abs( 
 217                          $xSpace * 2 * $this->direction->y +
 218                          $ySpace * 2 * $this->direction->x ),
 219                      abs( 
 220                          $step->width * $axisBoundings->width * $this->direction->x +
 221                          $step->width * $axisBoundings->height * $this->direction->y )
 222                  );
 223                  break;
 224              case ( $step->isLast ):
 225                  $labelSize = min(
 226                      abs( 
 227                          $xSpace * 2 * $this->direction->y +
 228                          $ySpace * 2 * $this->direction->x ),
 229                      abs( 
 230                          $steps[$nr - 1]->width * $axisBoundings->width * $this->direction->x +
 231                          $steps[$nr - 1]->width * $axisBoundings->height * $this->direction->y )
 232                  );
 233                  break;
 234              default:
 235                  $labelSize = abs( 
 236                      $step->width * $axisBoundings->width * $this->direction->x +
 237                      $step->width * $axisBoundings->height * $this->direction->y
 238                  );
 239                  break;
 240          }
 241  
 242          return $labelSize * cos( deg2rad( $this->angle ) );
 243      }
 244  
 245      /**
 246       * Calculate general label length
 247       * 
 248       * @param ezcGraphCoordinate $start 
 249       * @param ezcGraphCoordinate $end 
 250       * @param float $xSpace 
 251       * @param float $ySpace 
 252       * @param ezcGraphBoundings $axisBoundings 
 253       * @return float
 254       */
 255      protected function calculateLabelLength( ezcGraphCoordinate $start, ezcGraphCoordinate $end, $xSpace, $ySpace, ezcGraphBoundings $axisBoundings )
 256      {
 257          $axisSpaceFactor = abs(
 258              ( $this->direction->x == 0 ? 0 :
 259                  $this->direction->x * $ySpace / $axisBoundings->width ) +
 260              ( $this->direction->y == 0 ? 0 :
 261                  $this->direction->y * $xSpace / $axisBoundings->height )
 262          );
 263  
 264          $axisWidth  = $end->x - $start->x;
 265          $axisHeight = $end->y - $start->y;
 266  
 267          $start->x += max( 0., $axisSpaceFactor * $this->offset ) * $axisWidth;
 268          $start->y += max( 0., $axisSpaceFactor * $this->offset ) * $axisHeight;
 269  
 270          $end->x += min( 0., $axisSpaceFactor * $this->offset ) * $axisWidth;
 271          $end->y += min( 0., $axisSpaceFactor * $this->offset ) * $axisHeight;
 272  
 273          $labelLength = sqrt(
 274              pow(
 275                  $xSpace * $this->direction->y +
 276                  ( $this->labelOffset ? 
 277                      $axisSpaceFactor * $this->offset * ( $end->x - $start->x ) :
 278                      $ySpace * 2 * $this->direction->x
 279                  ),
 280                  2 ) +
 281              pow(
 282                  $ySpace * $this->direction->x +
 283                  ( $this->labelOffset ? 
 284                      $axisSpaceFactor * $this->offset * ( $end->y - $start->y ) :
 285                      $xSpace * 2 * $this->direction->y
 286                  ),
 287                  2 )
 288          );
 289  
 290          $this->offset *= $axisSpaceFactor;
 291          return $labelLength;
 292      }
 293  
 294      /**
 295       * Render label text.
 296       *
 297       * Render the text of a single label, depending on the position, length and
 298       * rotation of the label.
 299       * 
 300       * @param ezcGraphRenderer $renderer
 301       * @param ezcGraphChartElementAxis $axis 
 302       * @param ezcGraphCoordinate $position 
 303       * @param string $label 
 304       * @param float $degTextAngle 
 305       * @param float $labelLength 
 306       * @param float $labelSize 
 307       * @param float $lengthReducement 
 308       * @return void
 309       */
 310      protected function renderLabelText( ezcGraphRenderer $renderer, ezcGraphChartElementAxis $axis, ezcGraphCoordinate $position, $label, $degTextAngle, $labelLength, $labelSize, $lengthReducement )
 311      {
 312          switch ( true )
 313          {
 314              case ( ( ( $degTextAngle >= 0 ) && 
 315                       ( $degTextAngle < 90 ) &&
 316                       ( ( $axis->position === ezcGraph::LEFT ) ||
 317                         ( $axis->position === ezcGraph::RIGHT )
 318                       )
 319                     ) ||
 320                     ( ( $degTextAngle >= 270 ) && 
 321                       ( $degTextAngle < 360 ) &&
 322                       ( ( $axis->position === ezcGraph::TOP ) ||
 323                         ( $axis->position === ezcGraph::BOTTOM )
 324                       )
 325                     )
 326                   ):
 327                  $labelBoundings = new ezcGraphBoundings(
 328                      $position->x,
 329                      $position->y,
 330                      $position->x + abs( $labelLength ) - $lengthReducement,
 331                      $position->y + $labelSize
 332                  );
 333                  $labelAlignement = ezcGraph::LEFT | ezcGraph::TOP;
 334                  $labelRotation = $degTextAngle;
 335                  break;
 336              case ( ( ( $degTextAngle >= 90 ) && 
 337                       ( $degTextAngle < 180 ) &&
 338                       ( ( $axis->position === ezcGraph::LEFT ) ||
 339                         ( $axis->position === ezcGraph::RIGHT )
 340                       )
 341                     ) ||
 342                     ( ( $degTextAngle >= 180 ) && 
 343                       ( $degTextAngle < 270 ) &&
 344                       ( ( $axis->position === ezcGraph::TOP ) ||
 345                         ( $axis->position === ezcGraph::BOTTOM )
 346                       )
 347                     )
 348                   ):
 349                  $labelBoundings = new ezcGraphBoundings(
 350                      $position->x - abs( $labelLength ) + $lengthReducement,
 351                      $position->y,
 352                      $position->x,
 353                      $position->y + $labelSize
 354                  );
 355                  $labelAlignement = ezcGraph::RIGHT | ezcGraph::TOP;
 356                  $labelRotation = $degTextAngle - 180;
 357                  break;
 358              case ( ( ( $degTextAngle >= 180 ) && 
 359                       ( $degTextAngle < 270 ) &&
 360                       ( ( $axis->position === ezcGraph::LEFT ) ||
 361                         ( $axis->position === ezcGraph::RIGHT )
 362                       )
 363                     ) ||
 364                     ( ( $degTextAngle >= 90 ) && 
 365                       ( $degTextAngle < 180 ) &&
 366                       ( ( $axis->position === ezcGraph::TOP ) ||
 367                         ( $axis->position === ezcGraph::BOTTOM )
 368                       )
 369                     )
 370                   ):
 371                  $labelBoundings = new ezcGraphBoundings(
 372                      $position->x - abs( $labelLength ) + $lengthReducement,
 373                      $position->y - $labelSize,
 374                      $position->x,
 375                      $position->y
 376                  );
 377                  $labelAlignement = ezcGraph::RIGHT | ezcGraph::BOTTOM;
 378                  $labelRotation = $degTextAngle - 180;
 379                  break;
 380              case ( ( ( $degTextAngle >= 270 ) && 
 381                       ( $degTextAngle < 360 ) &&
 382                       ( ( $axis->position === ezcGraph::LEFT ) ||
 383                         ( $axis->position === ezcGraph::RIGHT )
 384                       )
 385                     ) ||
 386                     ( ( $degTextAngle >= 0 ) && 
 387                       ( $degTextAngle < 90 ) &&
 388                       ( ( $axis->position === ezcGraph::TOP ) ||
 389                         ( $axis->position === ezcGraph::BOTTOM )
 390                       )
 391                     )
 392                   ):
 393                  $labelBoundings = new ezcGraphBoundings(
 394                      $position->x,
 395                      $position->y,
 396                      $position->x - abs( $labelLength ) + $lengthReducement,
 397                      $position->y + $labelSize
 398                  );
 399                  $labelAlignement = ezcGraph::LEFT | ezcGraph::TOP;
 400                  $labelRotation = $degTextAngle;
 401                  break;
 402          }
 403  
 404          $renderer->drawText(
 405              $labelBoundings,
 406              $label,
 407              $labelAlignement,
 408              new ezcGraphRotation(
 409                  $labelRotation,
 410                  $position
 411              )
 412          );
 413      }
 414  
 415      /**
 416       * Render Axis labels
 417       *
 418       * Render labels for an axis.
 419       *
 420       * @param ezcGraphRenderer $renderer Renderer used to draw the chart
 421       * @param ezcGraphBoundings $boundings Boundings of the axis
 422       * @param ezcGraphCoordinate $start Axis starting point
 423       * @param ezcGraphCoordinate $end Axis ending point
 424       * @param ezcGraphChartElementAxis $axis Axis instance
 425       * @return void
 426       */
 427      public function renderLabels(
 428          ezcGraphRenderer $renderer,
 429          ezcGraphBoundings $boundings,
 430          ezcGraphCoordinate $start,
 431          ezcGraphCoordinate $end,
 432          ezcGraphChartElementAxis $axis,
 433          ezcGraphBoundings $innerBoundings = null )
 434      {
 435          // receive rendering parameters from axis
 436          $steps = $axis->getSteps();
 437  
 438          $axisBoundings = new ezcGraphBoundings(
 439              $start->x, $start->y,
 440              $end->x, $end->y
 441          );
 442  
 443          // Determine normalized axis direction
 444          $this->direction = new ezcGraphVector(
 445              $end->x - $start->x,
 446              $end->y - $start->y
 447          );
 448          $this->direction->unify();
 449  
 450          // Get axis space
 451          $gridBoundings = null;
 452          list( $xSpace, $ySpace ) = $this->getAxisSpace( $renderer, $boundings, $axis, $innerBoundings, $gridBoundings );
 453  
 454          // Determine optimal angle if none specified
 455          $this->determineAngle( $steps, $xSpace, $ySpace, $axisBoundings );
 456          $degTextAngle = $this->determineTextOffset( $axis, $steps );
 457          $labelLength  = $this->calculateLabelLength( $start, $end, $xSpace, $ySpace, $axisBoundings );
 458  
 459          // Draw steps and grid
 460          foreach ( $steps as $nr => $step )
 461          {
 462              $position = new ezcGraphCoordinate(
 463                  $start->x + ( $end->x - $start->x ) * $step->position * abs( $this->direction->x ),
 464                  $start->y + ( $end->y - $start->y ) * $step->position * abs( $this->direction->y )
 465              );
 466      
 467              $stepSize = new ezcGraphCoordinate(
 468                  ( $end->x - $start->x ) * $step->width,
 469                  ( $end->y - $start->y ) * $step->width
 470              );
 471  
 472              // Calculate label boundings
 473              $labelSize = $this->calculateLabelSize( $steps, $nr, $step, $xSpace, $ySpace, $axisBoundings );
 474              $lengthReducement = min(
 475                  abs( tan( deg2rad( $this->angle ) ) * ( $labelSize / 2 ) ),
 476                  abs( $labelLength / 2 )
 477              );
 478  
 479              $this->renderLabelText( $renderer, $axis, $position, $step->label, $degTextAngle, $labelLength, $labelSize, $lengthReducement );
 480  
 481              // Major grid
 482              if ( $axis->majorGrid )
 483              {
 484                  $this->drawGrid( $renderer, $gridBoundings, $position, $stepSize, $axis->majorGrid );
 485              }
 486              
 487              // Major step
 488              $this->drawStep( $renderer, $position, $this->direction, $axis->position, $this->majorStepSize, $axis->border );
 489          }
 490      }
 491      
 492      /**
 493       * Modify chart data position
 494       *
 495       * Optionally additionally modify the coodinate of a data point
 496       * 
 497       * @param ezcGraphCoordinate $coordinate Data point coordinate
 498       * @return ezcGraphCoordinate Modified coordinate
 499       */
 500      public function modifyChartDataPosition( ezcGraphCoordinate $coordinate )
 501      {
 502          return new ezcGraphCoordinate(
 503              $coordinate->x * abs( $this->direction->y ) +
 504                  ( $coordinate->x * ( 1 - abs( $this->offset ) ) * abs( $this->direction->x ) ) +
 505                  ( abs( $this->offset ) * abs( $this->direction->x ) ),
 506              $coordinate->y * abs( $this->direction->x ) +
 507                  ( $coordinate->y * ( 1 - abs( $this->offset ) ) * abs( $this->direction->y ) ) +
 508                  ( abs( $this->offset ) * abs( $this->direction->y ) )
 509          );
 510      }
 511  }
 512  ?>


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