Logo Search packages:      
Sourcecode: obm version File versions  Download package

Axis.class.php

<?php
/*
 * This work is hereby released into the Public Domain.
 * To view a copy of the public domain dedication,
 * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
 * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
 *
 */

require_once dirname(__FILE__)."/../Graph.class.php";

/**
 * Handle axis
 *
 * @package Artichow
 */
class awAxis {

      /**
       * Axis line
       *
       * @var Line
       */
      public $line;

      /**
       * Axis labels
       *
       * @var Label
       */
      public $label;

      /**
       * Axis title
       *
       * @var Label
       */
      public $title;

      /**
       * Title position
       *
       * @var float
       */
      protected $titlePosition = 0.5;

      /**
       * Labels number
       *
       * @var int
       */
      protected $labelNumber;

      /**
       * Axis ticks
       *
       * @var array
       */
      protected $ticks = array();

      /**
       * Axis and ticks color
       *
       * @var Color
       */
      protected $color;

      /**
       * Axis left and right padding
       *
       * @var Side
       */
      protected $padding;

      /**
       * Axis range
       *
       * @var array
       */
      protected $range;

      /**
       * Hide axis
       *
       * @var bool
       */
      protected $hide = FALSE;

      /**
       * Auto-scaling mode
       *
       * @var bool
       */
      protected $auto = TRUE;

      /**
       * Axis range callback function
       *
       * @var array
       */
      protected $rangeCallback = array(
            'toValue' => 'toProportionalValue',
            'toPosition' => 'toProportionalPosition'
      );

      /**
       * Build the axis
       *
       * @param float $min Begin of the range of the axis
       * @param float $max End of the range of the axis
       */
      public function __construct($min = NULL, $max = NULL) {

            $this->line = new awVector(
                  new awPoint(0, 0),
                  new awPoint(0, 0)
            );

            $this->label = new awLabel;
            $this->padding = new awSide;

            $this->title = new awLabel(
                  NULL,
                  NULL,
                  NULL,
                  0
            );

            $this->setColor(new awBlack);

            if($min !== NULL and $max !== NULL) {
                  $this->setRange($min, $max);
            }

      }

      /**
       * Enable/disable auto-scaling mode
       *
       * @param bool $auto
       */
      public function auto($auto) {
            $this->auto = (bool)$auto;
      }

      /**
       * Get auto-scaling mode status
       *
       * @return bool
       */
      public function isAuto() {
            return $this->auto;
      }

      /**
       * Hide axis
       *
       * @param bool $hide
       */
      public function hide($hide = TRUE) {
            $this->hide = (bool)$hide;
      }

      /**
       * Show axis
       *
       * @param bool $show
       */
      public function show($show = TRUE) {
            $this->hide = !(bool)$show;
      }

      /**
       * Return a tick object from its name
       *
       * @param string $name Tick object name
       * @return Tick
       */
      public function tick($name) {
            /* <php5> */
            return array_key_exists($name, $this->ticks) ? $this->ticks[$name] : NULL;
            /* </php5> */
            /* <php4> --
            if(array_key_exists($name, $this->ticks)) {
                  return $tick = &$this->ticks[$name];
            } else {
                  return NULL;
            }
            -- </php4> */
      }

      /**
       * Add a tick object
       *
       * @param string $name Tick object name
       * @param awTick $tick Tick object
       */
      public function addTick($name, awTick $tick) {
            /* <php5> */
            $this->ticks[$name] = $tick;
            /* </php5> */
            /* <php4> --
            $this->ticks[$name] = &$tick;
            -- </php4> */
      }

      /**
       * Delete a tick object
       *
       * @param string $name Tick object name
       */
      public function deleteTick($name) {
            if(array_key_exists($name, $this->ticks)) {
                  unset($this->ticks[$name]);
            }
      }

      /**
       * Hide all ticks
       *
       * @param bool $hide Hide or not ?
       */
      public function hideTicks($hide = TRUE) {
            /* <php5> */
            foreach($this->ticks as $tick) {
                  $tick->hide($hide);
            }
            /* </php5> */
            /* <php4> --
            foreach($this->ticks as $key => $tick) {
                  $this->ticks[$key]->hide($hide);
            }
            -- </php4> */
      }

      /**
       * Change ticks style
       *
       * @param int $style Ticks style
       */
      public function setTickStyle($style) {
            /* <php5> */
            foreach($this->ticks as $tick) {
                  $tick->setStyle($style);
            }
            /* </php5> */
            /* <php4> --
            foreach($this->ticks as $key => $tick) {
                  $this->ticks[$key]->setStyle($style);
            }
            -- </php4> */
      }

      /**
       * Change ticks interval
       *
       * @param int $interval Ticks interval
       */
      public function setTickInterval($interval) {
            /* <php5> */
            foreach($this->ticks as $tick) {
                  $tick->setInterval($interval);
            }
            /* </php5> */
            /* <php4> --
            foreach($this->ticks as $key => $tick) {
                  $this->ticks[$key]->setInterval($interval);
            }
            -- </php4> */
      }

      /**
       * Change number of ticks relative to others ticks
       *
       * @param awTick $to Change number of theses ticks
       * @param awTick $from Ticks reference
       * @param float $number Number of ticks by the reference
       */
      public function setNumberByTick($to, $from, $number) {
            $this->ticks[$to]->setNumberByTick($this->ticks[$from], $number);
      }

      /**
       * Reverse ticks style
       */
      public function reverseTickStyle() {
            /* <php5> */
            foreach($this->ticks as $tick) {
                  if($tick->getStyle() === awTick::IN) {
                        $tick->setStyle(awTick::OUT);
                  } else if($tick->getStyle() === awTick::OUT) {
                        $tick->setStyle(awTick::IN);
                  }
            }
            /* </php5> */
            /* <php4> --
            foreach($this->ticks as $key => $tick) {
                  if($this->ticks[$key]->getStyle() === awTick::IN) {
                        $this->ticks[$key]->setStyle(awTick::OUT);
                  } else if($this->ticks[$key]->getStyle() === awTick::OUT) {
                        $this->ticks[$key]->setStyle(awTick::IN);
                  }
            }
            -- </php4> */
      }

      /**
       * Change interval of labels
       *
       * @param int $interval Interval
       */
      public function setLabelInterval($interval) {
            $this->auto(FALSE);
            $this->setTickInterval($interval);
            $this->label->setInterval($interval);
      }

      /**
       * Change number of labels
       *
       * @param int $number Number of labels to display (can be NULL)
       */
      public function setLabelNumber($number) {
            $this->auto(FALSE);
            $this->labelNumber = is_null($number) ? NULL : (int)$number;
      }

      /**
       * Get number of labels
       *
       * @return int
       */
      public function getLabelNumber() {
            return $this->labelNumber;
      }

      /**
       * Change precision of labels
       *
       * @param int $precision Precision
       */
      public function setLabelPrecision($precision) {
            $this->auto(FALSE);
            $function = 'axis'.time().'_'.(microtime() * 1000000);
            eval('function '.$function.'($value) {
                  return sprintf("%.'.(int)$precision.'f", $value);
            }');
            $this->label->setCallbackFunction($function);
      }

      /**
       * Change text of labels
       *
       * @param array $texts Some texts
       */
      public function setLabelText($texts) {
            if(is_array($texts)) {
                  $this->auto(FALSE);
                  $function = 'axis'.time().'_'.(microtime() * 1000000);
                  eval('function '.$function.'($value) {
                        $texts = '.var_export($texts, TRUE).';
                        return isset($texts[$value]) ? $texts[$value] : \'?\';
                  }');
                  $this->label->setCallbackFunction($function);
            }
      }

      /**
       * Get the position of a point
       *
       * @param awAxis $xAxis X axis
       * @param awAxis $yAxis Y axis
       * @param awPoint $p Position of the point
       * @return Point Position on the axis
       */
      public static function toPosition(awAxis $xAxis, awAxis $yAxis, awPoint $p) {

            $p1 = $xAxis->getPointFromValue($p->x);
            $p2 = $yAxis->getPointFromValue($p->y);

            return new awPoint(
                  round($p1->x),
                  round($p2->y)
            );

      }

      /**
       * Change title alignment
       *
       * @param int $alignment New Alignment
       */
      public function setTitleAlignment($alignment) {

            switch($alignment) {

                  case awLabel::TOP :
                        $this->setTitlePosition(1);
                        $this->title->setAlign(NULL, awLabel::BOTTOM);
                        break;

                  case awLabel::BOTTOM :
                        $this->setTitlePosition(0);
                        $this->title->setAlign(NULL, awLabel::TOP);
                        break;

                  case awLabel::LEFT :
                        $this->setTitlePosition(0);
                        $this->title->setAlign(awLabel::LEFT);
                        break;

                  case awLabel::RIGHT :
                        $this->setTitlePosition(1);
                        $this->title->setAlign(awLabel::RIGHT);
                        break;

            }

      }

      /**
       * Change title position on the axis
       *
       * @param float $position A new awposition between 0 and 1
       */
      public function setTitlePosition($position) {
            $this->titlePosition = (float)$position;
      }

      /**
       * Change axis and axis title color
       *
       * @param awColor $color
       */
      public function setColor(awColor $color) {
            $this->color = $color;
            $this->title->setColor($color);
      }

      /**
       * Change axis padding
       *
       * @param int $left Left padding in pixels
       * @param int $right Right padding in pixels
       */
      public function setPadding($left, $right) {
            $this->padding->set($left, $right);
      }

      /**
       * Get axis padding
       *
       * @return Side
       */
      public function getPadding() {
            return $this->padding;
      }

      /**
       * Change axis range
       *
       * @param float $min
       * @param float $max
       */
      public function setRange($min, $max) {
            if($min !== NULL) {
                  $this->range[0] = (float)$min;
            }
            if($max !== NULL) {
                  $this->range[1] = (float)$max;
            }
      }

      /**
       * Get axis range
       *
       * @return array
       */
      public function getRange() {
            return $this->range;
      }

      /**
       * Change axis range callback function
       *
       * @param string $toValue Transform a position between 0 and 1 to a value
       * @param string $toPosition Transform a value to a position between 0 and 1 on the axis
       */
      public function setRangeCallback($toValue, $toPosition) {
            $this->rangeCallback = array(
                  'toValue' => (string)$toValue,
                  'toPosition' => (string)$toPosition
            );
      }

      /**
       * Center X values of the axis
       *
       * @param awAxis $axis An axis
       * @param float $value The reference value on the axis
       */
      public function setXCenter(awAxis $axis, $value) {

            // Check vector angle
            if($this->line->isVertical() === FALSE) {
                  awImage::drawError("Class Axis: setXCenter() can only be used on vertical axes.");
            }

            $p = $axis->getPointFromValue($value);

            $this->line->setX(
                  $p->x,
                  $p->x
            );

      }

      /**
       * Center Y values of the axis
       *
       * @param awAxis $axis An axis
       * @param float $value The reference value on the axis
       */
      public function setYCenter(awAxis $axis, $value) {

            // Check vector angle
            if($this->line->isHorizontal() === FALSE) {
                  awImage::drawError("Class Axis: setYCenter() can only be used on horizontal axes.");
            }

            $p = $axis->getPointFromValue($value);

            $this->line->setY(
                  $p->y,
                  $p->y
            );

      }

      /**
       * Get the distance between to values on the axis
       *
       * @param float $from The first value
       * @param float $to The last value
       * @return Point
       */
      public function getDistance($from, $to) {

            $p1 = $this->getPointFromValue($from);
            $p2 = $this->getPointFromValue($to);

            return $p1->getDistance($p2);

      }

      /**
       * Get a point on the axis from a value
       *
       * @param float $value
       * @return Point
       */
      protected function getPointFromValue($value) {

            $callback = $this->rangeCallback['toPosition'];

            list($min, $max) = $this->range;
            $position = $callback($value, $min, $max);

            return $this->getPointFromPosition($position);

      }

      /**
       * Get a point on the axis from a position
       *
       * @param float $position A position between 0 and 1
       * @return Point
       */
      protected function getPointFromPosition($position) {

            $vector = $this->getVector();

            $angle = $vector->getAngle();
            $size = $vector->getSize();

            return $vector->p1->move(
                  cos($angle) * $size * $position,
                  -1 * sin($angle) * $size * $position
            );

      }

      /**
       * Draw axis
       *
       * @param awDriver $driver A driver
       */
      public function draw(awDriver $driver) {

            if($this->hide) {
                  return;
            }

            $vector = $this->getVector();

            // Draw axis ticks
            $this->drawTicks($driver, $vector);

            // Draw axis line
            $this->line($driver);

            // Draw labels
            $this->drawLabels($driver);

            // Draw axis title
            $p = $this->getPointFromPosition($this->titlePosition);
            $this->title->draw($driver, $p);

      }

      public function autoScale() {

            if($this->isAuto() === FALSE) {
                  return;
            }

            list($min, $max) = $this->getRange();
            $interval = $max - $min;

            if($interval > 0) {
                  $partMax = $max / $interval;
                  $partMin = $min / $interval;
            } else {
                  $partMax = 0;
                  $partMin = 0;
            }

            $difference = log($interval) / log(10);
            $difference = floor($difference);

            $pow = pow(10, $difference);

            if($pow > 0) {
                  $intervalNormalize = $interval / $pow;
            } else {
                  $intervalNormalize = 0;
            }

            if($difference <= 0) {

                  $precision = $difference * -1 + 1;

                  if($intervalNormalize > 2) {
                        $precision--;
                  }

            } else {
                  $precision = 0;
            }

            if($min != 0 and $max != 0) {
                  $precision++;
            }

            if($this->label->getCallbackFunction() === NULL) {
                  $this->setLabelPrecision($precision);
            }

            if($intervalNormalize <= 1.5) {
                  $intervalReal = 1.5;
                  $labelNumber = 4;
            } else if($intervalNormalize <= 2) {
                  $intervalReal = 2;
                  $labelNumber = 5;
            } else if($intervalNormalize <= 3) {
                  $intervalReal = 3;
                  $labelNumber = 4;
            } else if($intervalNormalize <= 4) {
                  $intervalReal = 4;
                  $labelNumber = 5;
            } else if($intervalNormalize <= 5) {
                  $intervalReal = 5;
                  $labelNumber = 6;
            } else if($intervalNormalize <= 8) {
                  $intervalReal = 8;
                  $labelNumber = 5;
            } else if($intervalNormalize <= 10) {
                  $intervalReal = 10;
                  $labelNumber = 6;
            }

            if($min == 0) {

                  $this->setRange(
                        $min,
                        $intervalReal * $pow
                  );

            } else if($max == 0) {

                  $this->setRange(
                        $intervalReal * $pow * -1,
                        0
                  );

            }

            $this->setLabelNumber($labelNumber);

      }

      protected function line(awDriver $driver) {

            $driver->line(
                  $this->color,
                  $this->line
            );

      }

      protected function drawTicks(awDriver $driver, awVector $vector) {

            foreach($this->ticks as $tick) {
                  $tick->setColor($this->color);
                  $tick->draw($driver, $vector);
            }

      }

      protected function drawLabels($driver) {

            if($this->labelNumber !== NULL) {
                  list($min, $max) = $this->range;
                  $number = $this->labelNumber - 1;
                  if($number < 1) {
                        return;
                  }
                  $function = $this->rangeCallback['toValue'];
                  $labels = array();
                  for($i = 0; $i <= $number; $i++) {
                        $labels[] = $function($i / $number, $min, $max);
                  }
                  $this->label->set($labels);
            }

            $labels = $this->label->count();

            for($i = 0; $i < $labels; $i++) {

                  $p = $this->getPointFromValue($this->label->get($i));
                  $this->label->draw($driver, $p, $i);

            }

      }

      protected function getVector() {

            $angle = $this->line->getAngle();

            // Compute paddings
            $vector = new awVector(
                  $this->line->p1->move(
                        cos($angle) * $this->padding->left,
                        -1 * sin($angle) * $this->padding->left
                  ),
                  $this->line->p2->move(
                        -1 * cos($angle) * $this->padding->right,
                        -1 * -1 * sin($angle) * $this->padding->right
                  )
            );

            return $vector;

      }

      public function __clone() {

            $this->label = clone $this->label;
            $this->line = clone $this->line;
            $this->title = clone $this->title;

            foreach($this->ticks as $name => $tick) {
                  $this->ticks[$name] = clone $tick;
            }

      }

}

registerClass('Axis');

function toProportionalValue($position, $min, $max) {
      return $min + ($max - $min) * $position;
}

function toProportionalPosition($value, $min, $max) {
      if($max - $min == 0) {
            return 0;
      }
      return ($value - $min) / ($max - $min);
}
?>

Generated by  Doxygen 1.6.0   Back to index