[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/library/ezc/Graph/src/charts/ -> radar.php (source)

   1  <?php
   2  /**
   3   * File containing the ezcGraphRadarChart 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 for radar charts.
  12   * Can make use of an unlimited amount of datasets and will display them as
  13   * lines by default.
  14   * Rotation axis:
  15   *  - Labeled axis
  16   *  - Centered axis label renderer
  17   * Axis:
  18   *  - Numeric axis
  19   *  - radar axis label renderer
  20   *
  21   * <code>
  22   *  // Create a new radar chart
  23   *  $chart = new ezcGraphRadarChart();
  24   *
  25   *  // Add data to line chart
  26   *  $chart->data['sample dataset'] = new ezcGraphArrayDataSet(
  27   *      array(
  28   *          '100' => 1.2,
  29   *          '200' => 43.2,
  30   *          '300' => -34.14,
  31   *          '350' => 65,
  32   *          '400' => 123,
  33   *      )   
  34   *  );
  35   *
  36   *  // Render chart with default 2d renderer and default SVG driver
  37   *  $chart->render( 500, 200, 'radar_chart.svg' );
  38   * </code>
  39   *
  40   * Each chart consists of several chart elements which represents logical 
  41   * parts of the chart and can be formatted independently. The line chart
  42   * consists of:
  43   *  - title ( {@link ezcGraphChartElementText} )
  44   *  - legend ( {@link ezcGraphChartElementLegend} )
  45   *  - background ( {@link ezcGraphChartElementBackground} )
  46   *  - axis ( {@link ezcGraphChartElementNumericAxis} )
  47   *  - ratation axis ( {@link ezcGraphChartElementLabeledAxis} )
  48   *
  49   * The type of the axis may be changed and all elements can be configured by
  50   * accessing them as properties of the chart:
  51   *
  52   * The chart itself also offers several options to configure the appearance.
  53   * The extended configure options are available in 
  54   * {@link ezcGraphRadarChartOptions} extending the 
  55   * {@link ezcGraphChartOptions}.
  56   *
  57   * <code>
  58   *  $chart->legend->position = ezcGraph::RIGHT;
  59   * </code>
  60   *
  61   * @property ezcGraphRadarChartOptions $options
  62   *           Chart options class
  63   *
  64   * @version 1.5
  65   * @package Graph
  66   * @mainclass
  67   */
  68  class ezcGraphRadarChart extends ezcGraphChart
  69  {
  70      /**
  71       * Store major grid color for child axis.
  72       * 
  73       * @var ezcGraphColor
  74       */
  75      protected $childAxisColor;
  76  
  77      /**
  78       * Constructor
  79       * 
  80       * @param array $options Default option array
  81       * @return void
  82       * @ignore
  83       */
  84      public function __construct( array $options = array() )
  85      {
  86          $this->options = new ezcGraphRadarChartOptions( $options );
  87          $this->options->highlightFont = $this->options->font;
  88  
  89          parent::__construct();
  90  
  91          $this->elements['rotationAxis'] = new ezcGraphChartElementLabeledAxis();
  92  
  93          $this->addElement( 'axis', new ezcGraphChartElementNumericAxis() );
  94          $this->elements['axis']->position = ezcGraph::BOTTOM;
  95          $this->elements['axis']->axisLabelRenderer = new ezcGraphAxisRadarLabelRenderer();
  96          $this->elements['axis']->axisLabelRenderer->outerStep = true;
  97  
  98          $this->addElement( 'rotationAxis', new ezcGraphChartElementLabeledAxis() );
  99  
 100          // Do not render axis with default method, because we need an axis for
 101          // each label in dataset
 102          $this->renderElement['axis'] = false;
 103          $this->renderElement['rotationAxis'] = false;
 104      }
 105  
 106      /**
 107       * Set colors and border fro this element
 108       * 
 109       * @param ezcGraphPalette $palette Palette
 110       * @return void
 111       */
 112      public function setFromPalette( ezcGraphPalette $palette )
 113      {
 114          $this->childAxisColor = $palette->majorGridColor;
 115  
 116          parent::setFromPalette( $palette );
 117      }
 118  
 119      /**
 120       * Property write access
 121       * 
 122       * @throws ezcBasePropertyNotFoundException
 123       *          If Option could not be found
 124       * @throws ezcBaseValueException
 125       *          If value is out of range
 126       * @param string $propertyName Option name
 127       * @param mixed $propertyValue Option value;
 128       * @return void
 129       * @ignore
 130       */
 131      public function __set( $propertyName, $propertyValue ) 
 132      {
 133          switch ( $propertyName ) {
 134              case 'axis':
 135                  if ( $propertyValue instanceof ezcGraphChartElementAxis )
 136                  {
 137                      $this->addElement( 'axis', $propertyValue );
 138                      $this->elements['axis']->position = ezcGraph::BOTTOM;
 139                      $this->elements['axis']->axisLabelRenderer = new ezcGraphAxisRadarLabelRenderer();
 140                      $this->renderElement['axis'] = false;
 141                  }
 142                  else
 143                  {
 144                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
 145                  }
 146                  break;
 147              case 'rotationAxis':
 148                  if ( $propertyValue instanceof ezcGraphChartElementAxis )
 149                  {
 150                      $this->addElement( 'rotationAxis', $propertyValue );
 151                      $this->renderElement['rotationAxis'] = false;
 152                  }
 153                  else
 154                  {
 155                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphChartElementAxis' );
 156                  }
 157                  break;
 158              case 'renderer':
 159                  if ( $propertyValue instanceof ezcGraphRadarRenderer )
 160                  {
 161                      parent::__set( $propertyName, $propertyValue );
 162                  }
 163                  else 
 164                  {
 165                      throw new ezcBaseValueException( $propertyName, $propertyValue, 'ezcGraphRadarRenderer' );
 166                  }
 167                  break;
 168              default:
 169                  parent::__set( $propertyName, $propertyValue );
 170          }
 171      }
 172  
 173      /**
 174       * Draws a single rotated axis
 175       *
 176       * Sets the axis label position depending on the axis rotation.
 177       * 
 178       * @param ezcGraphChartElementAxis $axis 
 179       * @param ezcGraphBoundings $boundings 
 180       * @param ezcGraphCoordinate $center 
 181       * @param float $position 
 182       * @param float $lastPosition 
 183       * @return void
 184       */
 185      protected function drawRotatedAxis( ezcGraphChartElementAxis $axis, ezcGraphBoundings $boundings, ezcGraphCoordinate $center, $position, $lastPosition = null )
 186      {
 187          // Set axis position depending on angle for better axis label 
 188          // positioning
 189          $angle = $position * 2 * M_PI;
 190          switch ( (int) ( ( $position + .125 ) * 4 ) )
 191          {
 192              case 0:
 193              case 4:
 194                  $axis->position = ezcGraph::BOTTOM;
 195                  break;
 196              case 1:
 197                  $axis->position = ezcGraph::LEFT;
 198                  break;
 199              case 2:
 200                  $axis->position = ezcGraph::TOP;
 201                  break;
 202              case 3:
 203                  $axis->position = ezcGraph::RIGHT;
 204                  break;
 205          }
 206  
 207          // Set last step to correctly draw grid
 208          if ( $axis->axisLabelRenderer instanceof ezcGraphAxisRadarLabelRenderer )
 209          {
 210              $axis->axisLabelRenderer->lastStep = $lastPosition;
 211          }
 212  
 213          // Do not draw axis label for last step
 214          if ( abs( $position - 1 ) <= .001 ) 
 215          {
 216              $axis->label = null;
 217          }
 218  
 219          $this->renderer->drawAxis(
 220              $boundings,
 221              clone $center,
 222              $dest = new ezcGraphCoordinate(
 223                  $center->x + sin( $angle ) * ( $boundings->width / 2 ),
 224                  $center->y - cos( $angle ) * ( $boundings->height / 2 )
 225              ),
 226              clone $axis,
 227              clone $axis->axisLabelRenderer
 228          );
 229      }
 230  
 231      /**
 232       * Render the assigned data
 233       *
 234       * Will renderer all charts data in the remaining boundings after drawing 
 235       * all other chart elements. The data will be rendered depending on the 
 236       * settings in the dataset.
 237       * 
 238       * @param ezcGraphRenderer $renderer Renderer
 239       * @param ezcGraphBoundings $boundings Remaining boundings
 240       * @return void
 241       */
 242      protected function renderData( ezcGraphRenderer $renderer, ezcGraphBoundings $boundings )
 243      {
 244          // Apply axis space
 245          $xAxisSpace = ( $boundings->x1 - $boundings->x0 ) * $this->axis->axisSpace;
 246          $yAxisSpace = ( $boundings->y1 - $boundings->y0 ) * $this->axis->axisSpace;
 247  
 248          $center = new ezcGraphCoordinate(
 249              ( $boundings->width / 2 ),
 250              ( $boundings->height / 2 )
 251          );
 252  
 253          // We do not differentiate between display types in radar charts.
 254          $nr = $count = count( $this->data );
 255  
 256          // Draw axis at major steps of virtual axis
 257          $steps = $this->elements['rotationAxis']->getSteps();
 258          $lastStepPosition = null;
 259          $axisColor = $this->elements['axis']->border;
 260          foreach ( $steps as $step )
 261          {
 262              $this->elements['axis']->label = $step->label;
 263              $this->drawRotatedAxis( $this->elements['axis'], $boundings, $center, $step->position, $lastStepPosition );
 264              $lastStepPosition = $step->position;
 265  
 266              if ( count( $step->childs ) )
 267              {
 268                  foreach ( $step->childs as $childStep )
 269                  {
 270                      $this->elements['axis']->label = null;
 271                      $this->elements['axis']->border = $this->childAxisColor;
 272  
 273                      $this->drawRotatedAxis( $this->elements['axis'], $boundings, $center, $childStep->position, $lastStepPosition );
 274                      $lastStepPosition = $childStep->position;
 275                  }
 276              }
 277  
 278              $this->elements['axis']->border = $axisColor;
 279          }
 280  
 281          // Display data
 282          $this->elements['axis']->position = ezcGraph::TOP;
 283          foreach ( $this->data as $datasetName => $data )
 284          {
 285              --$nr;
 286              // Determine fill color for dataset
 287              if ( $this->options->fillLines !== false )
 288              {
 289                  $fillColor = clone $data->color->default;
 290                  $fillColor->alpha = (int) round( ( 255 - $fillColor->alpha ) * ( $this->options->fillLines / 255 ) );
 291              }
 292              else
 293              {
 294                  $fillColor = null;
 295              }
 296  
 297              // Draw lines for dataset
 298              $lastPoint = false;
 299              foreach ( $data as $key => $value )
 300              {
 301                  $point = new ezcGraphCoordinate( 
 302                      $this->elements['rotationAxis']->getCoordinate( $key ),
 303                      $this->elements['axis']->getCoordinate( $value )
 304                  ); 
 305  
 306                  /* Transformation required for 3d like renderers ... 
 307                   * which axis should transform here?
 308                  $point = $this->elements['xAxis']->axisLabelRenderer->modifyChartDataPosition( 
 309                      $this->elements['yAxis']->axisLabelRenderer->modifyChartDataPosition(
 310                          new ezcGraphCoordinate( 
 311                              $this->elements['xAxis']->getCoordinate( $key ),
 312                              $this->elements['yAxis']->getCoordinate( $value )
 313                          )
 314                      )
 315                  ); 
 316                  // */
 317  
 318                  $renderer->drawRadarDataLine(
 319                      $boundings,
 320                      new ezcGraphContext( $datasetName, $key, $data->url[$key] ),
 321                      $data->color->default,
 322                      clone $center,
 323                      ( $lastPoint === false ? $point : $lastPoint ),
 324                      $point,
 325                      $nr,
 326                      $count,
 327                      $data->symbol[$key],
 328                      $data->color[$key],
 329                      $fillColor,
 330                      $this->options->lineThickness
 331                  );
 332  
 333                  $lastPoint = $point;
 334              }
 335          }
 336      }
 337  
 338      /**
 339       * Returns the default display type of the current chart type.
 340       * 
 341       * @return int Display type
 342       */
 343      public function getDefaultDisplayType()
 344      {
 345          return ezcGraph::LINE;
 346      }
 347  
 348      /**
 349       * Renders the basic elements of this chart type
 350       * 
 351       * @param int $width 
 352       * @param int $height 
 353       * @return void
 354       */
 355      protected function renderElements( $width, $height )
 356      {
 357          if ( !count( $this->data ) )
 358          {
 359              throw new ezcGraphNoDataException();
 360          }
 361  
 362          // Set image properties in driver
 363          $this->driver->options->width = $width;
 364          $this->driver->options->height = $height;
 365  
 366          // Calculate axis scaling and labeling
 367          foreach ( $this->data as $dataset )
 368          {
 369              $labels = array();
 370              $values = array();
 371              foreach ( $dataset as $label => $value )
 372              {
 373                  $labels[] = $label;
 374                  $values[] = $value;
 375              }
 376  
 377              $this->elements['axis']->addData( $values );
 378              $this->elements['rotationAxis']->addData( $labels );
 379          }
 380  
 381          $this->elements['axis']->calculateAxisBoundings();
 382          $this->elements['rotationAxis']->calculateAxisBoundings();
 383  
 384          // Generate legend
 385          $this->elements['legend']->generateFromDataSets( $this->data );
 386  
 387          // Get boundings from parameters
 388          $this->options->width = $width;
 389          $this->options->height = $height;
 390  
 391          // Render subelements
 392          $boundings = new ezcGraphBoundings();
 393          $boundings->x1 = $this->options->width;
 394          $boundings->y1 = $this->options->height;
 395  
 396          // Render subelements
 397          foreach ( $this->elements as $name => $element )
 398          {
 399              // Skip element, if it should not get rendered
 400              if ( $this->renderElement[$name] === false )
 401              {
 402                  continue;
 403              }
 404  
 405              $this->driver->options->font = $element->font;
 406              $boundings = $element->render( $this->renderer, $boundings );
 407          }
 408  
 409          // Render graph
 410          $this->renderData( $this->renderer, $boundings );
 411      }
 412  
 413      /**
 414       * Render the line chart
 415       *
 416       * Renders the chart into a file or stream. The width and height are 
 417       * needed to specify the dimensions of the resulting image. For direct
 418       * output use 'php://stdout' as output file.
 419       * 
 420       * @param int $width Image width
 421       * @param int $height Image height
 422       * @param string $file Output file
 423       * @apichange
 424       * @return void
 425       */
 426      public function render( $width, $height, $file = null )
 427      {
 428          $this->renderElements( $width, $height );
 429  
 430          if ( !empty( $file ) )
 431          {
 432              $this->renderer->render( $file );
 433          }
 434  
 435          $this->renderedFile = $file;
 436      }
 437  
 438      /**
 439       * Renders this chart to direct output
 440       * 
 441       * Does the same as ezcGraphChart::render(), but renders directly to 
 442       * output and not into a file.
 443       *
 444       * @param int $width
 445       * @param int $height
 446       * @apichange
 447       * @return void
 448       */
 449      public function renderToOutput( $width, $height )
 450      {
 451          // @TODO: merge this function with render an deprecate ommit of third 
 452          // argument in render() when API break is possible
 453          $this->renderElements( $width, $height );
 454          $this->renderer->render( null );
 455      }
 456  }
 457  ?>


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