linea21-externals
[ class tree: linea21-externals ] [ index: linea21-externals ] [ all elements ]

Source for file Plot.class.php

Documentation is available at Plot.class.php

  1. <?php
  2. /*
  3.  * This work is hereby released into the Public Domain.
  4.  * To view a copy of the public domain dedication,
  5.  * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
  6.  * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
  7.  *
  8.  */
  9.  
  10. require_once dirname(__FILE__)."/Component.class.php";
  11.  
  12. /* <php4> */
  13.  
  14. define("PLOT_LEFT", 'left');
  15. define("PLOT_RIGHT", 'right');
  16. define("PLOT_TOP", 'top');
  17. define("PLOT_BOTTOM", 'bottom');
  18. define("PLOT_BOTH", 'both');
  19.  
  20. /* </php4> */
  21.  
  22. /**
  23.  * Graph using X and Y axis
  24.  *
  25.  * @package linea21.externals
  26.  * @subpackage artichow
  27.  */
  28. abstract class awPlot extends awComponent {
  29.  
  30.   /**
  31.    * Values for Y axis
  32.    *
  33.    * @var array 
  34.    */
  35.   protected $datay;
  36.  
  37.   /**
  38.    * Values for X axis
  39.    *
  40.    * @var array 
  41.    */
  42.   protected $datax;
  43.  
  44.   /**
  45.    * Grid properties
  46.    *
  47.    * @var Grid 
  48.    */
  49.   public $grid;
  50.  
  51.   /**
  52.    * X axis
  53.    *
  54.    * @var Axis 
  55.    */
  56.   public $xAxis;
  57.  
  58.   /**
  59.    * Y axis
  60.    *
  61.    * @var Axis 
  62.    */
  63.   public $yAxis;
  64.  
  65.   /**
  66.    * Position of X axis
  67.    *
  68.    * @var int 
  69.    */
  70.   protected $xAxisPosition = awPlot::BOTTOM;
  71.  
  72.   /**
  73.    * Set X axis on zero ?
  74.    *
  75.    * @var bool 
  76.    */
  77.   protected $xAxisZero = TRUE;
  78.  
  79.   /**
  80.    * Set Y axis on zero ?
  81.    *
  82.    * @var bool 
  83.    */
  84.   protected $yAxisZero = FALSE;
  85.  
  86.   /**
  87.    * Position of Y axis
  88.    *
  89.    * @var int 
  90.    */
  91.   protected $yAxisPosition = awPlot::LEFT;
  92.  
  93.   /**
  94.    * Change min value for Y axis
  95.    *
  96.    * @var mixed 
  97.    */
  98.   private $yMin = NULL;
  99.  
  100.   /**
  101.    * Change max value for Y axis
  102.    *
  103.    * @var mixed 
  104.    */
  105.   private $yMax = NULL;
  106.  
  107.   /**
  108.    * Change min value for X axis
  109.    *
  110.    * @var mixed 
  111.    */
  112.   private $xMin = NULL;
  113.  
  114.   /**
  115.    * Change max value for X axis
  116.    *
  117.    * @var mixed 
  118.    */
  119.   private $xMax = NULL;
  120.  
  121.   /**
  122.    * Left axis
  123.    *
  124.    * @var int 
  125.    */
  126.   const LEFT = 'left';
  127.  
  128.   /**
  129.    * Right axis
  130.    *
  131.    * @var int 
  132.    */
  133.   const RIGHT = 'right';
  134.  
  135.   /**
  136.    * Top axis
  137.    *
  138.    * @var int 
  139.    */
  140.   const TOP = 'top';
  141.  
  142.   /**
  143.    * Bottom axis
  144.    *
  145.    * @var int 
  146.    */
  147.   const BOTTOM = 'bottom';
  148.  
  149.   /**
  150.    * Both left/right or top/bottom axis
  151.    *
  152.    * @var int 
  153.    */
  154.   const BOTH = 'both';
  155.  
  156.   /**
  157.    * Build the plot
  158.    *
  159.    */
  160.   public function __construct() {
  161.  
  162.     parent::__construct();
  163.  
  164.     $this->grid = new awGrid;
  165.     $this->grid->setBackgroundColor(new awWhite);
  166.  
  167.     $this->padding->add(20, 0, 0, 20);
  168.  
  169.     $this->xAxis = new awAxis;
  170.     $this->xAxis->addTick('major', new awTick(0, 5));
  171.     $this->xAxis->addTick('minor', new awTick(0, 3));
  172.     $this->xAxis->setTickStyle(awTick::OUT);
  173.     $this->xAxis->label->setFont(new awTuffy(7));
  174.  
  175.     $this->yAxis = new awAxis;
  176.     $this->yAxis->auto(TRUE);
  177.     $this->yAxis->addTick('major', new awTick(0, 5));
  178.     $this->yAxis->addTick('minor', new awTick(0, 3));
  179.     $this->yAxis->setTickStyle(awTick::OUT);
  180.     $this->yAxis->setNumberByTick('minor', 'major', 3);
  181.     $this->yAxis->label->setFont(new awTuffy(7));
  182.     $this->yAxis->title->setAngle(90);
  183.  
  184.   }
  185.  
  186.   /**
  187.    * Get plot values
  188.    *
  189.    * @return array 
  190.    */
  191.   public function getValues() {
  192.     return $this->datay;
  193.   }
  194.  
  195.   /**
  196.    * Reduce number of values in the plot
  197.    *
  198.    * @param int $number Reduce number of values to $number
  199.    */
  200.   public function reduce($number) {
  201.  
  202.     $count = count($this->datay);
  203.     $ratio = ceil($count / $number);
  204.  
  205.     if($ratio > 1) {
  206.  
  207.       $tmpy = $this->datay;
  208.       $datay = array();
  209.           
  210.       $datax = array();
  211.       $cbLabel = $this->xAxis->label->getCallbackFunction();
  212.           
  213.       for($i = 0; $i < $count; $i += $ratio) {
  214.             
  215.         $slice = array_slice($tmpy, $i, $ratio);
  216.         $datay[] = array_sum($slice) / count($slice);
  217.  
  218.         // Reduce data on X axis if needed
  219.         if($cbLabel !== NULL) {
  220.           $datax[] = $cbLabel($i + round($ratio / 2));
  221.         }
  222.  
  223.       }
  224.           
  225.       $this->setValues($datay);
  226.           
  227.       if($cbLabel !== NULL) {
  228.         $this->xAxis->setLabelText($datax);
  229.       }
  230.           
  231.           
  232.     }
  233.  
  234.   }
  235.  
  236.   /**
  237.    * Count values in the plot
  238.    *
  239.    * @return int 
  240.    */
  241.   public function getXAxisNumber() {
  242.     list($min, $max) = $this->xAxis->getRange();
  243.     return ($max - $min + 1);
  244.   }
  245.  
  246.   /**
  247.    * Change X axis
  248.    *
  249.    * @param int $axis 
  250.    */
  251.   public function setXAxis($axis) {
  252.     $this->xAxisPosition = $axis;
  253.   }
  254.  
  255.   /**
  256.    * Get X axis
  257.    *
  258.    * @return int 
  259.    */
  260.   public function getXAxis() {
  261.     return $this->xAxisPosition;
  262.   }
  263.  
  264.   /**
  265.    * Set X axis on zero
  266.    *
  267.    * @param bool $zero 
  268.    */
  269.   public function setXAxisZero($zero) {
  270.     $this->xAxisZero = (bool)$zero;
  271.   }
  272.  
  273.   /**
  274.    * Set Y axis on zero
  275.    *
  276.    * @param bool $zero 
  277.    */
  278.   public function setYAxisZero($zero) {
  279.     $this->yAxisZero = (bool)$zero;
  280.   }
  281.  
  282.   /**
  283.    * Change Y axis
  284.    *
  285.    * @param int $axis 
  286.    */
  287.   public function setYAxis($axis) {
  288.     $this->yAxisPosition = $axis;
  289.   }
  290.  
  291.   /**
  292.    * Get Y axis
  293.    *
  294.    * @return int 
  295.    */
  296.   public function getYAxis() {
  297.     return $this->yAxisPosition;
  298.   }
  299.  
  300.   /**
  301.    * Change min value for Y axis
  302.    * Set NULL for auto selection.
  303.    *
  304.    * @param float $value 
  305.    */
  306.   public function setYMin($value) {
  307.     $this->yMin = $value;
  308.     $this->yAxis->auto(FALSE);
  309.     $this->updateAxis();
  310.   }
  311.  
  312.   /**
  313.    * Change max value for Y axis
  314.    * Set NULL for auto selection.
  315.    *
  316.    * @param float $value 
  317.    */
  318.   public function setYMax($value) {
  319.     $this->yMax = $value;
  320.     $this->yAxis->auto(FALSE);
  321.     $this->updateAxis();
  322.   }
  323.  
  324.   /**
  325.    * Change min value for X axis
  326.    * Set NULL for auto selection.
  327.    *
  328.    * @param float $value 
  329.    */
  330.   public function setXMin($value) {
  331.     $this->xMin = $value;
  332.     $this->updateAxis();
  333.   }
  334.  
  335.   /**
  336.    * Change max value for X axis
  337.    * Set NULL for auto selection.
  338.    *
  339.    * @param float $value 
  340.    */
  341.   public function setXMax($value) {
  342.     $this->xMax = $value;
  343.     $this->updateAxis();
  344.   }
  345.  
  346.   /**
  347.    * Get min value for Y axis
  348.    *
  349.    * @return float $value
  350.    */
  351.   public function getYMin() {
  352.     if($this->auto) {
  353.       if(is_null($this->yMin)) {
  354.         $min = array_min($this->datay);
  355.         if($min > 0) {
  356.           return 0;
  357.         }
  358.       }
  359.     }
  360.     return is_null($this->yMin) ? array_min($this->datay) : (float)$this->yMin;
  361.   }
  362.  
  363.   /**
  364.    * Get max value for Y axis
  365.    *
  366.    * @return float $value
  367.    */
  368.   public function getYMax() {
  369.     if($this->auto) {
  370.       if(is_null($this->yMax)) {
  371.         $max = array_max($this->datay);
  372.         if($max < 0) {
  373.           return 0;
  374.         }
  375.       }
  376.     }
  377.     return is_null($this->yMax) ? array_max($this->datay) : (float)$this->yMax;
  378.   }
  379.  
  380.   /**
  381.    * Get min value for X axis
  382.    *
  383.    * @return float $value
  384.    */
  385.   public function getXMin() {
  386.     return floor(is_null($this->xMin) ? array_min($this->datax) : $this->xMin);
  387.   }
  388.  
  389.   /**
  390.    * Get max value for X axis
  391.    *
  392.    * @return float $value
  393.    */
  394.   public function getXMax() {
  395.     return (ceil(is_null($this->xMax) ? array_max($this->datax) : (float)$this->xMax)) + ($this->getXCenter() ? 1 : 0);
  396.   }
  397.  
  398.   /**
  399.    * Get min value with spaces for Y axis
  400.    *
  401.    * @return float $value
  402.    */
  403.   public function getRealYMin() {
  404.     $min = $this->getYMin();
  405.     if($this->space->bottom !== NULL) {
  406.       $interval = ($this->getYMax() - $min) * $this->space->bottom / 100;
  407.       return $min - $interval;
  408.     } else {
  409.       return is_null($this->yMin) ? $min : (float)$this->yMin;
  410.     }
  411.   }
  412.  
  413.   /**
  414.    * Get max value with spaces for Y axis
  415.    *
  416.    * @return float $value
  417.    */
  418.   public function getRealYMax() {
  419.     $max = $this->getYMax();
  420.     if($this->space->top !== NULL) {
  421.       $interval = ($max - $this->getYMin()) * $this->space->top / 100;
  422.       return $max + $interval;
  423.     } else {
  424.       return is_null($this->yMax) ? $max : (float)$this->yMax;
  425.     }
  426.   }
  427.  
  428.   public function init(awDriver $driver) {
  429.  
  430.     list($x1, $y1, $x2, $y2) = $this->getPosition();
  431.  
  432.     // Get space informations
  433.     list($leftSpace, $rightSpace, $topSpace, $bottomSpace) = $this->getSpace($x2 - $x1, $y2 - $y1);
  434.  
  435.     $this->xAxis->setPadding($leftSpace, $rightSpace);
  436.  
  437.     if($this->space->bottom > 0 or $this->space->top > 0) {
  438.  
  439.       list($min, $max) = $this->yAxis->getRange();
  440.       $interval = $max - $min;
  441.           
  442.       $this->yAxis->setRange(
  443.       $min - $interval * $this->space->bottom / 100,
  444.       $max + $interval * $this->space->top / 100
  445.       );
  446.           
  447.     }
  448.  
  449.     // Auto-scaling mode
  450.     $this->yAxis->autoScale();
  451.  
  452.     // Number of labels is not specified
  453.     if($this->yAxis->getLabelNumber() === NULL) {
  454.       $number = round(($y2 - $y1) / 75) + 2;
  455.       $this->yAxis->setLabelNumber($number);
  456.     }
  457.  
  458.     $this->xAxis->line->setX($x1, $x2);
  459.     $this->yAxis->line->setY($y2, $y1);
  460.  
  461.     // Set ticks
  462.     /* <php5> */
  463.     $this->xAxis->tick('major')->setNumber($this->getXAxisNumber());
  464.     $this->yAxis->tick('major')->setNumber($this->yAxis->getLabelNumber());
  465.     /* </php5> */
  466.     /* <php4> --
  467.      $this->xAxis->ticks['major']->setNumber($this->getXAxisNumber());
  468.      $this->yAxis->ticks['major']->setNumber($this->yAxis->getLabelNumber());
  469.      -- </php4> */
  470.  
  471.     // Center X axis on zero
  472.     if($this->xAxisZero) {
  473.       $this->xAxis->setYCenter($this->yAxis, 0);
  474.     }
  475.  
  476.     // Center Y axis on zero
  477.     if($this->yAxisZero) {
  478.       $this->yAxis->setXCenter($this->xAxis, 0);
  479.     }
  480.  
  481.     // Set axis labels
  482.     $labels = array();
  483.  
  484.     list($xMin, $xMax) = $this->xAxis->getRange();
  485.     for($i = $xMin; $i <= $xMax; $i++) {
  486.       $labels[] = $i;
  487.     }
  488.     $this->xAxis->label->set($labels);
  489.  
  490.     parent::init($driver);
  491.  
  492.     list($x1, $y1, $x2, $y2) = $this->getPosition();
  493.  
  494.     list($leftSpace, $rightSpace) = $this->getSpace($x2 - $x1, $y2 - $y1);
  495.  
  496.     // Create the grid
  497.     $this->createGrid();
  498.  
  499.     // Draw the grid
  500.     $this->grid->setSpace($leftSpace, $rightSpace, 0, 0);
  501.     $this->grid->draw($driver, $x1, $y1, $x2, $y2);
  502.  
  503.   }
  504.  
  505.   public function drawEnvelope(awDriver $driver) {
  506.  
  507.     list($x1, $y1, $x2, $y2) = $this->getPosition();
  508.  
  509.     if($this->getXCenter()) {
  510.       $size = $this->xAxis->getDistance(0, 1);
  511.       $this->xAxis->label->move($size / 2, 0);
  512.       $this->xAxis->label->hideLast(TRUE);
  513.     }
  514.  
  515.     // Draw top axis
  516.     if($this->xAxisPosition === awPlot::TOP or $this->xAxisPosition === awPlot::BOTH) {
  517.       $top = clone $this->xAxis;
  518.       if($this->xAxisZero === FALSE) {
  519.         $top->line->setY($y1, $y1);
  520.       }
  521.       $top->label->setAlign(NULL, awLabel::TOP);
  522.       $top->label->move(0, -3);
  523.       $top->title->move(0, -25);
  524.       $top->draw($driver);
  525.     }
  526.  
  527.     // Draw bottom axis
  528.     if($this->xAxisPosition === awPlot::BOTTOM or $this->xAxisPosition === awPlot::BOTH) {
  529.       $bottom = clone $this->xAxis;
  530.       if($this->xAxisZero === FALSE) {
  531.         $bottom->line->setY($y2, $y2);
  532.       }
  533.       $bottom->label->setAlign(NULL, awLabel::BOTTOM);
  534.       $bottom->label->move(0, 3);
  535.       $bottom->reverseTickStyle();
  536.       $bottom->title->move(0, 25);
  537.       $bottom->draw($driver);
  538.     }
  539.  
  540.     // Draw left axis
  541.     if($this->yAxisPosition === awPlot::LEFT or $this->yAxisPosition === awPlot::BOTH) {
  542.       $left = clone $this->yAxis;
  543.       if($this->yAxisZero === FALSE) {
  544.         $left->line->setX($x1, $x1);
  545.       }
  546.       $left->label->setAlign(awLabel::RIGHT);
  547.       $left->label->move(-6, 0);
  548.       $left->title->move(-25, 0);
  549.       $left->draw($driver);
  550.     }
  551.  
  552.     // Draw right axis
  553.     if($this->yAxisPosition === awPlot::RIGHT or $this->yAxisPosition === awPlot::BOTH) {
  554.       $right = clone $this->yAxis;
  555.       if($this->yAxisZero === FALSE) {
  556.         $right->line->setX($x2, $x2);
  557.       }
  558.       $right->label->setAlign(awLabel::LEFT);
  559.       $right->label->move(6, 0);
  560.       $right->reverseTickStyle();
  561.       $right->title->move(25, 0);
  562.       $right->draw($driver);
  563.     }
  564.  
  565.   }
  566.  
  567.   protected function createGrid() {
  568.  
  569.     $max = $this->getRealYMax();
  570.     $min = $this->getRealYMin();
  571.  
  572.     $number = $this->yAxis->getLabelNumber() - 1;
  573.  
  574.     if($number < 1) {
  575.       return;
  576.     }
  577.  
  578.     // Horizontal lines of the grid
  579.  
  580.     $h = array();
  581.     for($i = 0; $i <= $number; $i++) {
  582.       $h[] = $i / $number;
  583.     }
  584.  
  585.     // Vertical lines
  586.  
  587.     $major = $this->yAxis->tick('major');
  588.     $interval = $major->getInterval();
  589.     $number = $this->getXAxisNumber() - 1;
  590.  
  591.     $w = array();
  592.  
  593.     if($number > 0) {
  594.           
  595.       for($i = 0; $i <= $number; $i++) {
  596.         if($i%$interval === 0) {
  597.           $w[] = $i / $number;
  598.         }
  599.       }
  600.           
  601.     }
  602.  
  603.     $this->grid->setGrid($w, $h);
  604.  
  605.   }
  606.  
  607.   /**
  608.    * Change values of Y axis
  609.    * This method ignores not numeric values
  610.    *
  611.    * @param array $datay 
  612.    * @param array $datax 
  613.    */
  614.   public function setValues($datay, $datax = NULL) {
  615.  
  616.     $this->checkArray($datay);
  617.  
  618.     foreach($datay as $key => $value) {
  619.       unset($datay[$key]);
  620.       $datay[(int)$key] = $value;
  621.     }
  622.  
  623.     if($datax === NULL) {
  624.       $datax = array();
  625.       for($i = 0; $i < count($datay); $i++) {
  626.         $datax[] = $i;
  627.       }
  628.     } else {
  629.       foreach($datax as $key => $value) {
  630.         unset($datax[$key]);
  631.         $datax[(int)$key] = $value;
  632.       }
  633.     }
  634.  
  635.     $this->checkArray($datax);
  636.  
  637.     if(count($datay) === count($datax)) {
  638.  
  639.       // Set values
  640.       $this->datay = $datay;
  641.       $this->datax = $datax;
  642.       // Update axis with the new awvalues
  643.       $this->updateAxis();
  644.     } else {
  645.       awImage::drawError("Class Plot: Plots must have the same number of X and Y points.");
  646.     }
  647.  
  648.   }
  649.  
  650.   /**
  651.    * Return begin and end values
  652.    *
  653.    * @return array 
  654.    */
  655.   protected function getLimit() {
  656.  
  657.     $i = 0;
  658.     while(array_key_exists($i, $this->datay) and $this->datay[$i] === NULL) {
  659.       $i++;
  660.     }
  661.     $start = $i;
  662.     $i = count($this->datay) - 1;
  663.     while(array_key_exists($i, $this->datay) and $this->datay[$i] === NULL) {
  664.       $i--;
  665.     }
  666.     $stop = $i;
  667.  
  668.     return array($start, $stop);
  669.  
  670.   }
  671.  
  672.   /**
  673.    * Return TRUE if labels must be centered on X axis, FALSE otherwise
  674.    *
  675.    * @return bool 
  676.    */
  677.   abstract public function getXCenter();
  678.  
  679.   private function updateAxis() {
  680.  
  681.     $this->xAxis->setRange(
  682.     $this->getXMin(),
  683.     $this->getXMax()
  684.     );
  685.     $this->yAxis->setRange(
  686.     $this->getRealYMin(),
  687.     $this->getRealYMax()
  688.     );
  689.  
  690.   }
  691.  
  692.   private function checkArray(&$array) {
  693.  
  694.     if(is_array($array) === FALSE) {
  695.       awImage::drawError("Class Plot: You tried to set a value that is not an array.");
  696.     }
  697.  
  698.     foreach($array as $key => $value) {
  699.       if(is_numeric($value) === FALSE and is_null($value) === FALSE) {
  700.         awImage::drawError("Class Plot: Expected numeric values for the plot.");
  701.       }
  702.     }
  703.  
  704.     if(count($array) < 1) {
  705.       awImage::drawError("Class Plot: Your plot must have at least 1 value.");
  706.     }
  707.  
  708.   }
  709.  
  710. }
  711.  
  712. registerClass('Plot', TRUE);
  713.  
  714. class awPlotAxis {
  715.  
  716.   /**
  717.    * Left axis
  718.    *
  719.    * @var Axis 
  720.    */
  721.   public $left;
  722.  
  723.   /**
  724.    * Right axis
  725.    *
  726.    * @var Axis 
  727.    */
  728.   public $right;
  729.  
  730.   /**
  731.    * Top axis
  732.    *
  733.    * @var Axis 
  734.    */
  735.   public $top;
  736.  
  737.   /**
  738.    * Bottom axis
  739.    *
  740.    * @var Axis 
  741.    */
  742.   public $bottom;
  743.  
  744.   /**
  745.    * Build the group of axis
  746.    */
  747.   public function __construct() {
  748.  
  749.     $this->left = new awAxis;
  750.     $this->left->auto(TRUE);
  751.     $this->left->label->setAlign(awLabel::RIGHT);
  752.     $this->left->label->move(-6, 0);
  753.     $this->yAxis($this->left);
  754.     $this->left->setTickStyle(awTick::OUT);
  755.     $this->left->title->move(-25, 0);
  756.  
  757.     $this->right = new awAxis;
  758.     $this->right->auto(TRUE);
  759.     $this->right->label->setAlign(awLabel::LEFT);
  760.     $this->right->label->move(6, 0);
  761.     $this->yAxis($this->right);
  762.     $this->right->setTickStyle(awTick::IN);
  763.     $this->right->title->move(25, 0);
  764.  
  765.     $this->top = new awAxis;
  766.     $this->top->label->setAlign(NULL, awLabel::TOP);
  767.     $this->top->label->move(0, -3);
  768.     $this->xAxis($this->top);
  769.     $this->top->setTickStyle(awTick::OUT);
  770.     $this->top->title->move(0, -25);
  771.  
  772.     $this->bottom = new awAxis;
  773.     $this->bottom->label->setAlign(NULL, awLabel::BOTTOM);
  774.     $this->bottom->label->move(0, 3);
  775.     $this->xAxis($this->bottom);
  776.     $this->bottom->setTickStyle(awTick::IN);
  777.     $this->bottom->title->move(0, 25);
  778.  
  779.   }
  780.  
  781.   protected function xAxis(awAxis $axis) {
  782.  
  783.     $axis->addTick('major', new awTick(0, 5));
  784.     $axis->addTick('minor', new awTick(0, 3));
  785.     $axis->label->setFont(new awTuffy(7));
  786.  
  787.   }
  788.  
  789.   protected function yAxis(awAxis $axis) {
  790.  
  791.     $axis->addTick('major', new awTick(0, 5));
  792.     $axis->addTick('minor', new awTick(0, 3));
  793.     $axis->setNumberByTick('minor', 'major', 3);
  794.     $axis->label->setFont(new awTuffy(7));
  795.     $axis->title->setAngle(90);
  796.  
  797.   }
  798.  
  799. }
  800.  
  801. registerClass('PlotAxis');
  802.  
  803. /**
  804.  * A graph with axis can contain some groups of components
  805.  *
  806.  * @package linea21.externals
  807.  * @subpackage artichow
  808.  */
  809. class awPlotGroup extends awComponentGroup {
  810.  
  811.   /**
  812.    * Grid properties
  813.    *
  814.    * @var Grid 
  815.    */
  816.   public $grid;
  817.  
  818.   /**
  819.    * Left, right, top and bottom axis
  820.    *
  821.    * @var PlotAxis 
  822.    */
  823.   public $axis;
  824.  
  825.   /**
  826.    * Set the X axis on zero
  827.    *
  828.    * @var bool 
  829.    */
  830.   protected $xAxisZero = TRUE;
  831.  
  832.   /**
  833.    * Set the Y axis on zero
  834.    *
  835.    * @var bool 
  836.    */
  837.   protected $yAxisZero = FALSE;
  838.  
  839.   /**
  840.    * Real axis used for Y axis
  841.    *
  842.    * @var string 
  843.    */
  844.   private $yRealAxis = awPlot::LEFT;
  845.  
  846.   /**
  847.    * Real axis used for X axis
  848.    *
  849.    * @var string 
  850.    */
  851.   private $xRealAxis = awPlot::BOTTOM;
  852.  
  853.   /**
  854.    * Change min value for Y axis
  855.    *
  856.    * @var mixed 
  857.    */
  858.   private $yMin = NULL;
  859.  
  860.   /**
  861.    * Change max value for Y axis
  862.    *
  863.    * @var mixed 
  864.    */
  865.   private $yMax = NULL;
  866.  
  867.   /**
  868.    * Change min value for X axis
  869.    *
  870.    * @var mixed 
  871.    */
  872.   private $xMin = NULL;
  873.  
  874.   /**
  875.    * Change max value for X axis
  876.    *
  877.    * @var mixed 
  878.    */
  879.   private $xMax = NULL;
  880.  
  881.   /**
  882.    * Build the PlotGroup
  883.    *
  884.    */
  885.   public function __construct() {
  886.  
  887.     parent::__construct();
  888.  
  889.     $this->grid = new awGrid;
  890.     $this->grid->setBackgroundColor(new awWhite);
  891.  
  892.     $this->axis = new awPlotAxis;
  893.  
  894.   }
  895.  
  896.   /**
  897.    * Set the X axis on zero or not
  898.    *
  899.    * @param bool $zero 
  900.    */
  901.   public function setXAxisZero($zero) {
  902.     $this->xAxisZero = (bool)$zero;
  903.   }
  904.  
  905.   /**
  906.    * Set the Y axis on zero or not
  907.    *
  908.    * @param bool $zero 
  909.    */
  910.   public function setYAxisZero($zero) {
  911.     $this->yAxisZero = (bool)$zero;
  912.   }
  913.  
  914.   /**
  915.    * Change min value for Y axis
  916.    * Set NULL for auto selection.
  917.    *
  918.    * @param float $value 
  919.    */
  920.   public function setYMin($value) {
  921.     $this->axis->left->auto(FALSE);
  922.     $this->axis->right->auto(FALSE);
  923.     $this->yMin = $value;
  924.   }
  925.  
  926.   /**
  927.    * Change max value for Y axis
  928.    * Set NULL for auto selection.
  929.    *
  930.    * @param float $value 
  931.    */
  932.   public function setYMax($value) {
  933.     $this->axis->left->auto(FALSE);
  934.     $this->axis->right->auto(FALSE);
  935.     $this->yMax = $value;
  936.   }
  937.  
  938.   /**
  939.    * Change min value for X axis
  940.    * Set NULL for auto selection.
  941.    *
  942.    * @param float $value 
  943.    */
  944.   public function setXMin($value) {
  945.     $this->xMin = $value;
  946.   }
  947.  
  948.   /**
  949.    * Change max value for X axis
  950.    * Set NULL for auto selection.
  951.    *
  952.    * @param float $value 
  953.    */
  954.   public function setXMax($value) {
  955.     $this->xMax = $value;
  956.   }
  957.  
  958.   /**
  959.    * Get min value for X axis
  960.    *
  961.    * @return float $value
  962.    */
  963.   public function getXMin() {
  964.  
  965.     return $this->getX('min');
  966.  
  967.   }
  968.  
  969.   /**
  970.    * Get max value for X axis
  971.    *
  972.    * @return float $value
  973.    */
  974.   public function getXMax() {
  975.  
  976.     return $this->getX('max');
  977.  
  978.   }
  979.  
  980.   private function getX($type) {
  981.  
  982.     switch($type) {
  983.       case 'max' :
  984.         if($this->xMax !== NULL) {
  985.           return $this->xMax;
  986.         }
  987.         break;
  988.       case 'min' :
  989.         if($this->xMin !== NULL) {
  990.           return $this->xMin;
  991.         }
  992.         break;
  993.     }
  994.  
  995.     $value = NULL;
  996.     $get = 'getX'.ucfirst($type);
  997.  
  998.     for($i = 0; $i < count($this->components); $i++) {
  999.  
  1000.       $component = $this->components[$i];
  1001.  
  1002.       if($value === NULL) {
  1003.         $value = $component->$get();
  1004.       } else {
  1005.         $value = $type($value, $component->$get());
  1006.       }
  1007.           
  1008.     }
  1009.  
  1010.     return $value;
  1011.  
  1012.   }
  1013.  
  1014.   /**
  1015.    * Get min value with spaces for Y axis
  1016.    *
  1017.    * @param string $axis Axis name
  1018.    * @return float $value
  1019.    */
  1020.   public function getRealYMin($axis = NULL) {
  1021.  
  1022.     if($axis === NULL) {
  1023.       return NULL;
  1024.     }
  1025.  
  1026.     $min = $this->getRealY('min', $axis);
  1027.     $max = $this->getRealY('max', $axis);
  1028.  
  1029.     if($this->space->bottom !== NULL) {
  1030.       $interval = ($min - $max) * $this->space->bottom / 100;
  1031.       return $min + $interval;
  1032.     } else {
  1033.       return $min;
  1034.     }
  1035.  
  1036.   }
  1037.  
  1038.   /**
  1039.    * Get max value with spaces for Y axis
  1040.    *
  1041.    * @param string $axis Axis name
  1042.    * @return float $value
  1043.    */
  1044.   public function getRealYMax($axis = NULL) {
  1045.  
  1046.     if($axis === NULL) {
  1047.       return NULL;
  1048.     }
  1049.  
  1050.     $min = $this->getRealY('min', $axis);
  1051.     $max = $this->getRealY('max', $axis);
  1052.  
  1053.     if($this->space->top !== NULL) {
  1054.       $interval = ($max - $min) * $this->space->top / 100;
  1055.       return $max + $interval;
  1056.     } else {
  1057.       return $max;
  1058.     }
  1059.  
  1060.   }
  1061.  
  1062.   private function getRealY($type, $axis) {
  1063.  
  1064.     switch($type) {
  1065.       case 'max' :
  1066.         if($this->yMax !== NULL) {
  1067.           return $this->yMax;
  1068.         }
  1069.         break;
  1070.       case 'min' :
  1071.         if($this->yMin !== NULL) {
  1072.           return $this->yMin;
  1073.         }
  1074.         break;
  1075.     }
  1076.  
  1077.     $value = NULL;
  1078.     $get = 'getY'.ucfirst($type);
  1079.  
  1080.     for($i = 0; $i < count($this->components); $i++) {
  1081.  
  1082.       $component = $this->components[$i];
  1083.           
  1084.       switch($axis) {
  1085.             
  1086.         case awPlot::LEFT :
  1087.         case awPlot::RIGHT :
  1088.           $test = ($component->getYAxis() === $axis);
  1089.           break;
  1090.         default :
  1091.           $test = FALSE;
  1092.               
  1093.       }
  1094.           
  1095.       if($test) {
  1096.  
  1097.         $auto = $component->yAxis->isAuto();
  1098.         $this->axis->{$axis}->auto($auto);
  1099.  
  1100.         if($value === NULL) {
  1101.           $value = $component->$get();
  1102.         } else {
  1103.           $value = $type($value, $component->$get());
  1104.         }
  1105.  
  1106.       }
  1107.           
  1108.     }
  1109.  
  1110.     return $value;
  1111.  
  1112.   }
  1113.  
  1114.   public function init(awDriver $driver) {
  1115.  
  1116.     list($x1, $y1, $x2, $y2) = $this->getPosition();
  1117.  
  1118.     // Get PlotGroup space
  1119.     list($leftSpace, $rightSpace, $topSpace, $bottomSpace) = $this->getSpace($x2 - $x1, $y2 - $y1);
  1120.  
  1121.     // Count values in the group
  1122.     $values = $this->getXAxisNumber();
  1123.  
  1124.     // Init the PlotGroup
  1125.     $this->axis->top->line->setX($x1, $x2);
  1126.     $this->axis->bottom->line->setX($x1, $x2);
  1127.     $this->axis->left->line->setY($y2, $y1);
  1128.     $this->axis->right->line->setY($y2, $y1);
  1129.  
  1130.     $this->axis->top->setPadding($leftSpace, $rightSpace);
  1131.     $this->axis->bottom->setPadding($leftSpace, $rightSpace);
  1132.  
  1133.     $xMin = $this->getXMin();
  1134.     $xMax = $this->getXMax();
  1135.  
  1136.     $this->axis->top->setRange($xMin, $xMax);
  1137.     $this->axis->bottom->setRange($xMin, $xMax);
  1138.  
  1139.     for($i = 0; $i < count($this->components); $i++) {
  1140.  
  1141.       /* <php5> */
  1142.       $component = $this->components[$i];
  1143.       /* </php5> */
  1144.       /* <php4> --
  1145.        $component = &$this->components[$i];
  1146.        -- </php4> */
  1147.       $component->auto($this->auto);
  1148.           
  1149.       // Copy space to the component
  1150.           
  1151.       $component->setSpace($this->space->left, $this->space->right, $this->space->top, $this->space->bottom);
  1152.           
  1153.       $component->xAxis->setPadding($leftSpace, $rightSpace);
  1154.       $component->xAxis->line->setX($x1, $x2);
  1155.           
  1156.       $component->yAxis->line->setY($y2, $y1);
  1157.           
  1158.     }
  1159.  
  1160.     // Set Y axis range
  1161.     foreach(array('left', 'right') as $axis) {
  1162.  
  1163.       if($this->isAxisUsed($axis)) {
  1164.             
  1165.         $min = $this->getRealYMin($axis);
  1166.         $max = $this->getRealYMax($axis);
  1167.  
  1168.         $interval = $max - $min;
  1169.  
  1170.         $this->axis->{$axis}->setRange(
  1171.         $min - $interval * $this->space->bottom / 100,
  1172.         $max + $interval * $this->space->top / 100
  1173.         );
  1174.  
  1175.         // Auto-scaling mode
  1176.         if($this->axis->{$axis}->isAuto()) {
  1177.           $this->axis->{$axis}->autoScale();
  1178.         }
  1179.  
  1180.       }
  1181.           
  1182.     }
  1183.  
  1184.     if($this->axis->left->getLabelNumber() === NULL) {
  1185.       $number = round(($y2 - $y1) / 75) + 2;
  1186.       $this->axis->left->setLabelNumber($number);
  1187.     }
  1188.  
  1189.     if($this->axis->right->getLabelNumber() === NULL) {
  1190.       $number = round(($y2 - $y1) / 75) + 2;
  1191.       $this->axis->right->setLabelNumber($number);
  1192.     }
  1193.  
  1194.     // Center labels on X axis if needed
  1195.     $test = array(awPlot::TOP => FALSE, awPlot::BOTTOM => FALSE);
  1196.  
  1197.     for($i = 0; $i < count($this->components); $i++) {
  1198.  
  1199.       /* <php5> */
  1200.       $component = $this->components[$i];
  1201.       /* </php5> */
  1202.       /* <php4> --
  1203.        $component = &$this->components[$i];
  1204.        -- </php4> */
  1205.           
  1206.       if($component->getValues() !== NULL) {
  1207.  
  1208.         $axis = $component->getXAxis();
  1209.  
  1210.         if($test[$axis] === FALSE) {
  1211.  
  1212.           // Center labels for bar plots
  1213.           if($component->getXCenter()) {
  1214.             $size = $this->axis->{$axis}->getDistance(0, 1);
  1215.             $this->axis->{$axis}->label->move($size / 2, 0);
  1216.             $this->axis->{$axis}->label->hideLast(TRUE);
  1217.             $test[$axis] = TRUE;
  1218.           }
  1219.               
  1220.         }
  1221.  
  1222.       }
  1223.           
  1224.           
  1225.     }
  1226.  
  1227.     // Set axis labels
  1228.     $labels = array();
  1229.     for($i = $xMin; $i <= $xMax; $i++) {
  1230.       $labels[] = $i;
  1231.     }
  1232.     if($this->axis->top->label->count() === 0) {
  1233.       $this->axis->top->label->set($labels);
  1234.     }
  1235.     if($this->axis->bottom->label->count() === 0) {
  1236.       $this->axis->bottom->label->set($labels);
  1237.     }
  1238.  
  1239.     // Set ticks
  1240.     /* <php5> */
  1241.     $this->axis->top->tick('major')->setNumber($values);
  1242.     $this->axis->bottom->tick('major')->setNumber($values);
  1243.     $this->axis->left->tick('major')->setNumber($this->axis->left->getLabelNumber());
  1244.     $this->axis->right->tick('major')->setNumber($this->axis->right->getLabelNumber());
  1245.     /* </php5> */
  1246.     /* <php4> --
  1247.      $this->axis->top->ticks['major']->setNumber($values);
  1248.      $this->axis->bottom->ticks['major']->setNumber($values);
  1249.      $this->axis->left->ticks['major']->setNumber($this->axis->left->getLabelNumber());
  1250.      $this->axis->right->ticks['major']->setNumber($this->axis->right->getLabelNumber());
  1251.      -- </php4> */
  1252.  
  1253.     // Set X axis on zero
  1254.     if($this->xAxisZero) {
  1255.       $axis = $this->selectYAxis();
  1256.       $this->axis->bottom->setYCenter($axis, 0);
  1257.       $this->axis->top->setYCenter($axis, 0);
  1258.     }
  1259.  
  1260.     // Set Y axis on zero
  1261.     if($this->yAxisZero) {
  1262.       $axis = $this->selectXAxis();
  1263.       $this->axis->left->setXCenter($axis, 1);
  1264.       $this->axis->right->setXCenter($axis, 1);
  1265.     }
  1266.  
  1267.     parent::init($driver);
  1268.  
  1269.     list($leftSpace, $rightSpace, $topSpace, $bottomSpace) = $this->getSpace($x2 - $x1, $y2 - $y1);
  1270.  
  1271.     // Create the grid
  1272.     $this->createGrid();
  1273.  
  1274.     // Draw the grid
  1275.     $this->grid->setSpace($leftSpace, $rightSpace, 0, 0);
  1276.     $this->grid->draw($driver, $x1, $y1, $x2, $y2);
  1277.  
  1278.   }
  1279.  
  1280.   public function drawComponent(awDriver $driver, $x1, $y1, $x2, $y2, $aliasing) {
  1281.  
  1282.     $xMin = $this->getXMin();
  1283.     $xMax = $this->getXMax();
  1284.  
  1285.     $maxLeft = $this->getRealYMax(awPlot::LEFT);
  1286.     $maxRight = $this->getRealYMax(awPlot::RIGHT);
  1287.  
  1288.     $minLeft = $this->getRealYMin(awPlot::LEFT);
  1289.     $minRight = $this->getRealYMin(awPlot::RIGHT);
  1290.  
  1291.     foreach($this->components as $component) {
  1292.  
  1293.       $min = $component->getYMin();
  1294.       $max = $component->getYMax();
  1295.           
  1296.       // Set component minimum and maximum
  1297.       if($component->getYAxis() === awPlot::LEFT) {
  1298.             
  1299.         list($min, $max) = $this->axis->left->getRange();
  1300.             
  1301.         $component->setYMin($min);
  1302.         $component->setYMax($max);
  1303.  
  1304.       } else {
  1305.             
  1306.         list($min, $max) = $this->axis->right->getRange();
  1307.  
  1308.         $component->setYMin($min);
  1309.         $component->setYMax($max);
  1310.  
  1311.       }
  1312.           
  1313.       $component->setXAxisZero($this->xAxisZero);
  1314.       $component->setYAxisZero($this->yAxisZero);
  1315.           
  1316.       $component->xAxis->setRange($xMin, $xMax);
  1317.  
  1318.       $component->drawComponent(
  1319.       $driver,
  1320.       $x1, $y1,
  1321.       $x2, $y2,
  1322.       $aliasing
  1323.       );
  1324.           
  1325.       $component->setYMin($min);
  1326.       $component->setYMax($max);
  1327.           
  1328.     }
  1329.  
  1330.   }
  1331.  
  1332.   public function drawEnvelope(awDriver $driver) {
  1333.  
  1334.     list($x1, $y1, $x2, $y2) = $this->getPosition();
  1335.  
  1336.     // Hide unused axis
  1337.     foreach(array(awPlot::LEFT, awPlot::RIGHT, awPlot::TOP, awPlot::BOTTOM) as $axis) {
  1338.       if($this->isAxisUsed($axis) === FALSE) {
  1339.         $this->axis->{$axis}->hide(TRUE);
  1340.       }
  1341.     }
  1342.  
  1343.     // Draw top axis
  1344.     $top = $this->axis->top;
  1345.     if($this->xAxisZero === FALSE) {
  1346.       $top->line->setY($y1, $y1);
  1347.     }
  1348.     $top->draw($driver);
  1349.  
  1350.     // Draw bottom axis
  1351.     $bottom = $this->axis->bottom;
  1352.     if($this->xAxisZero === FALSE) {
  1353.       $bottom->line->setY($y2, $y2);
  1354.     }
  1355.     $bottom->draw($driver);
  1356.  
  1357.     // Draw left axis
  1358.     $left = $this->axis->left;
  1359.     if($this->yAxisZero === FALSE) {
  1360.       $left->line->setX($x1, $x1);
  1361.     }
  1362.     $left->draw($driver);
  1363.  
  1364.     // Draw right axis
  1365.     $right = $this->axis->right;
  1366.     if($this->yAxisZero === FALSE) {
  1367.       $right->line->setX($x2, $x2);
  1368.     }
  1369.     $right->draw($driver);
  1370.  
  1371.   }
  1372.  
  1373.   /**
  1374.    * Is the specified axis used ?
  1375.    *
  1376.    * @param string $axis Axis name
  1377.    * @return bool 
  1378.    */
  1379.   protected function isAxisUsed($axis) {
  1380.  
  1381.     for($i = 0; $i < count($this->components); $i++) {
  1382.  
  1383.       $component = $this->components[$i];
  1384.           
  1385.       switch($axis) {
  1386.             
  1387.         case awPlot::LEFT :
  1388.         case awPlot::RIGHT :
  1389.           if($component->getYAxis() === $axis) {
  1390.             return TRUE;
  1391.           }
  1392.           break;
  1393.               
  1394.         case awPlot::TOP :
  1395.         case awPlot::BOTTOM :
  1396.           if($component->getXAxis() === $axis) {
  1397.             return TRUE;
  1398.           }
  1399.           break;
  1400.               
  1401.       }
  1402.           
  1403.     }
  1404.  
  1405.     return FALSE;
  1406.  
  1407.   }
  1408.  
  1409.   protected function createGrid() {
  1410.  
  1411.     $max = $this->getRealYMax(awPlot::LEFT);
  1412.     $min = $this->getRealYMin(awPlot::RIGHT);
  1413.  
  1414.     // Select axis (left if possible, right otherwise)
  1415.     $axis = $this->selectYAxis();
  1416.  
  1417.     $number = $axis->getLabelNumber() - 1;
  1418.  
  1419.     if($number < 1) {
  1420.       return;
  1421.     }
  1422.  
  1423.     // Horizontal lines of grid
  1424.  
  1425.     $h = array();
  1426.     for($i = 0; $i <= $number; $i++) {
  1427.       $h[] = $i / $number;
  1428.     }
  1429.  
  1430.     // Vertical lines
  1431.  
  1432.     $major = $axis->tick('major');
  1433.     $interval = $major->getInterval();
  1434.     $number = $this->getXAxisNumber() - 1;
  1435.  
  1436.     $w = array();
  1437.  
  1438.     if($number > 0) {
  1439.           
  1440.       for($i = 0; $i <= $number; $i++) {
  1441.         if($i%$interval === 0) {
  1442.           $w[] = $i / $number;
  1443.         }
  1444.       }
  1445.           
  1446.     }
  1447.  
  1448.     $this->grid->setGrid($w, $h);
  1449.  
  1450.   }
  1451.  
  1452.   protected function selectYAxis(){
  1453.  
  1454.     // Select axis (left if possible, right otherwise)
  1455.     if($this->isAxisUsed(awPlot::LEFT)) {
  1456.       $axis = $this->axis->left;
  1457.     } else {
  1458.       $axis = $this->axis->right;
  1459.     }
  1460.  
  1461.     return $axis;
  1462.  
  1463.   }
  1464.  
  1465.   protected function selectXAxis(){
  1466.  
  1467.     // Select axis (bottom if possible, top otherwise)
  1468.     if($this->isAxisUsed(awPlot::BOTTOM)) {
  1469.       $axis = $this->axis->bottom;
  1470.     } else {
  1471.       $axis = $this->axis->top;
  1472.     }
  1473.  
  1474.     return $axis;
  1475.  
  1476.   }
  1477.  
  1478.   protected function getXAxisNumber() {
  1479.     $offset = $this->components[0];
  1480.     $max = $offset->getXAxisNumber();
  1481.     for($i = 1; $i < count($this->components); $i++) {
  1482.       $offset = $this->components[$i];
  1483.       $max = max($max, $offset->getXAxisNumber());
  1484.     }
  1485.     return $max;
  1486.   }
  1487.  
  1488. }
  1489.  
  1490. registerClass('PlotGroup');
  1491. ?>

Documentation generated on Thu, 03 May 2012 15:07:24 +0200 by phpDocumentor 1.4.1