vendor/amenadiel/jpgraph/src/plot/LinePlot.php line 496

  1. <?php
  2. /**
  3.  * JPGraph v4.0.3
  4.  */
  5. namespace Amenadiel\JpGraph\Plot;
  6. use Amenadiel\JpGraph\Util;
  7. /*
  8.  * File:           JPGRAPH_LINE.PHP
  9.  * // Description: Line plot extension for JpGraph
  10.  * // Created:       2001-01-08
  11.  * // Ver:           $Id: jpgraph_line.php 1921 2009-12-11 11:46:39Z ljp $
  12.  * //
  13.  * // Copyright (c) Asial Corporation. All rights reserved.
  14.  */
  15. // constants for the (filled) area
  16. define('LP_AREA_FILLED'true);
  17. define('LP_AREA_NOT_FILLED'false);
  18. define('LP_AREA_BORDER'false);
  19. define('LP_AREA_NO_BORDER'true);
  20. /**
  21.  * @class LinePlot
  22.  * // Description:
  23.  */
  24. class LinePlot extends Plot
  25. {
  26.     public $mark;
  27.     protected $filled             false;
  28.     protected $fill_color         'blue';
  29.     protected $step_style         false;
  30.     protected $center             false;
  31.     protected $line_style         1// Default to solid
  32.     protected $filledAreas        = []; // array of arrays(with min,max,col,filled in them)
  33.     public $barcenter             false// When we mix line and bar. Should we center the line in the bar.
  34.     protected $fillFromMin        false;
  35.     protected $fillFromMax        false;
  36.     protected $fillgrad           false;
  37.     protected $fillgrad_fromcolor 'navy';
  38.     protected $fillgrad_tocolor   'silver';
  39.     protected $fillgrad_numcolors 100;
  40.     protected $iFastStroke        false;
  41.     /**
  42.      * CONSTRUCTOR.
  43.      *
  44.      * @param mixed $datay
  45.      * @param mixed $datax
  46.      */
  47.     public function __construct($datay$datax false)
  48.     {
  49.         parent::__construct($datay$datax);
  50.         $this->mark       = new PlotMark();
  51.         $this->color      Util\ColorFactory::getColor();
  52.         $this->fill_color $this->color;
  53.     }
  54.     /**
  55.      * PUBLIC METHODS.
  56.      *
  57.      * @param mixed $aFlg
  58.      */
  59.     public function SetFilled($aFlg true)
  60.     {
  61.         $this->filled $aFlg;
  62.     }
  63.     public function SetBarCenter($aFlag true)
  64.     {
  65.         $this->barcenter $aFlag;
  66.     }
  67.     public function SetStyle($aStyle)
  68.     {
  69.         $this->line_style $aStyle;
  70.     }
  71.     public function SetStepStyle($aFlag true)
  72.     {
  73.         $this->step_style $aFlag;
  74.     }
  75.     public function SetColor($aColor)
  76.     {
  77.         parent::SetColor($aColor);
  78.     }
  79.     public function SetFillFromYMin($f true)
  80.     {
  81.         $this->fillFromMin $f;
  82.     }
  83.     public function SetFillFromYMax($f true)
  84.     {
  85.         $this->fillFromMax $f;
  86.     }
  87.     public function SetFillColor($aColor$aFilled true)
  88.     {
  89.         //$this->color = $aColor;
  90.         $this->fill_color $aColor;
  91.         $this->filled     $aFilled;
  92.     }
  93.     public function SetFillGradient($aFromColor$aToColor$aNumColors 100$aFilled true)
  94.     {
  95.         $this->fillgrad_fromcolor $aFromColor;
  96.         $this->fillgrad_tocolor   $aToColor;
  97.         $this->fillgrad_numcolors $aNumColors;
  98.         $this->filled             $aFilled;
  99.         $this->fillgrad           true;
  100.     }
  101.     public function Legend($graph)
  102.     {
  103.         if ($this->legend != '') {
  104.             if ($this->filled && !$this->fillgrad) {
  105.                 $graph->legend->Add(
  106.                     $this->legend,
  107.                     $this->fill_color,
  108.                     $this->mark,
  109.                     0,
  110.                     $this->legendcsimtarget,
  111.                     $this->legendcsimalt,
  112.                     $this->legendcsimwintarget
  113.                 );
  114.             } elseif ($this->fillgrad) {
  115.                 $color = [$this->fillgrad_fromcolor$this->fillgrad_tocolor];
  116.                 // In order to differentiate between gradients and cooors specified as an Image\RGB triple
  117.                 $graph->legend->Add(
  118.                     $this->legend,
  119.                     $color,
  120.                     '',
  121.                     -2/* -GRAD_HOR */,
  122.                     $this->legendcsimtarget,
  123.                     $this->legendcsimalt,
  124.                     $this->legendcsimwintarget
  125.                 );
  126.             } else {
  127.                 $graph->legend->Add(
  128.                     $this->legend,
  129.                     $this->color,
  130.                     $this->mark,
  131.                     $this->line_style,
  132.                     $this->legendcsimtarget,
  133.                     $this->legendcsimalt,
  134.                     $this->legendcsimwintarget
  135.                 );
  136.             }
  137.         }
  138.     }
  139.     public function AddArea($aMin 0$aMax 0$aFilled LP_AREA_NOT_FILLED$aColor 'gray9'$aBorder LP_AREA_BORDER)
  140.     {
  141.         if ($aMin $aMax) {
  142.             // swap
  143.             $tmp  $aMin;
  144.             $aMin $aMax;
  145.             $aMax $tmp;
  146.         }
  147.         $this->filledAreas[] = [$aMin$aMax$aColor$aFilled$aBorder];
  148.     }
  149.     // Gets called before any axis are stroked
  150.     public function PreStrokeAdjust($graph)
  151.     {
  152.         // If another plot type have already adjusted the
  153.         // offset we don't touch it.
  154.         // (We check for empty in case the scale is  a log scale
  155.         // and hence doesn't contain any xlabel_offset)
  156.         if (empty($graph->xaxis->scale->ticks->xlabel_offset) || $graph->xaxis->scale->ticks->xlabel_offset == 0) {
  157.             if ($this->center) {
  158.                 ++$this->numpoints;
  159.                 $a 0.5;
  160.                 $b 0.5;
  161.             } else {
  162.                 $a 0;
  163.                 $b 0;
  164.             }
  165.             $graph->xaxis->scale->ticks->SetXLabelOffset($a);
  166.             $graph->SetTextScaleOff($b);
  167.             //$graph->xaxis->scale->ticks->SupressMinorTickMarks();
  168.         }
  169.     }
  170.     public function SetFastStroke($aFlg true)
  171.     {
  172.         $this->iFastStroke $aFlg;
  173.     }
  174.     public function FastStroke($img$xscale$yscale$aStartPoint 0$exist_x true)
  175.     {
  176.         // An optimized stroke for many data points with no extra
  177.         // features but 60% faster. You can't have values or line styles, or null
  178.         // values in plots.
  179.         $numpoints safe_count($this->coords[0]);
  180.         if ($this->barcenter) {
  181.             $textadj 0.5 $xscale->text_scale_off;
  182.         } else {
  183.             $textadj 0;
  184.         }
  185.         $img->SetColor($this->color);
  186.         $img->SetLineWeight($this->weight);
  187.         $pnts $aStartPoint;
  188.         while ($pnts $numpoints) {
  189.             if ($exist_x) {
  190.                 $x $this->coords[1][$pnts];
  191.             } else {
  192.                 $x $pnts $textadj;
  193.             }
  194.             $xt $xscale->Translate($x);
  195.             $y  $this->coords[0][$pnts];
  196.             $yt $yscale->Translate($y);
  197.             if (is_numeric($y)) {
  198.                 $cord[] = $xt;
  199.                 $cord[] = $yt;
  200.             } elseif ($y == '-' && $pnts 0) {
  201.                 // Just ignore
  202.             } else {
  203.                 Util\JpGraphError::RaiseL(10002); //('Plot too complicated for fast line Stroke. Use standard Stroke()');
  204.             }
  205.             ++$pnts;
  206.         } // WHILE
  207.         $img->Polygon($cordfalsetrue);
  208.     }
  209.     public function Stroke($img$xscale$yscale)
  210.     {
  211.         $idx       0;
  212.         $numpoints safe_count($this->coords[0]);
  213.         if (isset($this->coords[1])) {
  214.             if (safe_count($this->coords[1]) != $numpoints) {
  215.                 Util\JpGraphError::RaiseL(2003safe_count($this->coords[1]), $numpoints);
  216.             //("Number of X and Y points are not equal. Number of X-points:". safe_count($this->coords[1])." Number of Y-points:$numpoints");
  217.             } else {
  218.                 $exist_x true;
  219.             }
  220.         } else {
  221.             $exist_x false;
  222.         }
  223.         if ($this->barcenter) {
  224.             $textadj 0.5 $xscale->text_scale_off;
  225.         } else {
  226.             $textadj 0;
  227.         }
  228.         // Find the first numeric data point
  229.         $startpoint 0;
  230.         while ($startpoint $numpoints && !is_numeric($this->coords[0][$startpoint])) {
  231.             ++$startpoint;
  232.         }
  233.         // Bail out if no data points
  234.         if ($startpoint == $numpoints) {
  235.             return;
  236.         }
  237.         if ($this->iFastStroke) {
  238.             $this->FastStroke($img$xscale$yscale$startpoint$exist_x);
  239.             return;
  240.         }
  241.         if ($exist_x) {
  242.             $xs $this->coords[1][$startpoint];
  243.         } else {
  244.             $xs $textadj $startpoint;
  245.         }
  246.         $img->SetStartPoint(
  247.             $xscale->Translate($xs),
  248.             $yscale->Translate($this->coords[0][$startpoint])
  249.         );
  250.         if ($this->filled) {
  251.             if ($this->fillFromMax) {
  252.                 //$max = $yscale->GetMaxVal();
  253.                 $cord[$idx++] = $xscale->Translate($xs);
  254.                 $cord[$idx++] = $yscale->scale_abs[1];
  255.             } else {
  256.                 $min $yscale->GetMinVal();
  257.                 if ($min || $this->fillFromMin) {
  258.                     $fillmin $yscale->scale_abs[0]; //Translate($min);
  259.                 } else {
  260.                     $fillmin $yscale->Translate(0);
  261.                 }
  262.                 $cord[$idx++] = $xscale->Translate($xs);
  263.                 $cord[$idx++] = $fillmin;
  264.             }
  265.         }
  266.         $xt           $xscale->Translate($xs);
  267.         $yt           $yscale->Translate($this->coords[0][$startpoint]);
  268.         $cord[$idx++] = $xt;
  269.         $cord[$idx++] = $yt;
  270.         $yt_old       $yt;
  271.         $xt_old       $xt;
  272.         $y_old        $this->coords[0][$startpoint];
  273.         $this->value->Stroke($img$this->coords[0][$startpoint], $xt$yt);
  274.         $img->SetColor($this->color);
  275.         $img->SetLineWeight($this->weight);
  276.         $img->SetLineStyle($this->line_style);
  277.         $pnts           $startpoint 1;
  278.         $firstnonumeric false;
  279.         while ($pnts $numpoints) {
  280.             if ($exist_x) {
  281.                 $x $this->coords[1][$pnts];
  282.             } else {
  283.                 $x $pnts $textadj;
  284.             }
  285.             $xt $xscale->Translate($x);
  286.             $yt $yscale->Translate($this->coords[0][$pnts]);
  287.             $y $this->coords[0][$pnts];
  288.             if ($this->step_style) {
  289.                 // To handle null values within step style we need to record the
  290.                 // first non numeric value so we know from where to start if the
  291.                 // non value is '-'.
  292.                 if (is_numeric($y)) {
  293.                     $firstnonumeric false;
  294.                     if (is_numeric($y_old)) {
  295.                         $img->StyleLine($xt_old$yt_old$xt$yt_old);
  296.                         $img->StyleLine($xt$yt_old$xt$yt);
  297.                     } elseif ($y_old == '-') {
  298.                         $img->StyleLine($xt_first$yt_first$xt$yt_first);
  299.                         $img->StyleLine($xt$yt_first$xt$yt);
  300.                     } else {
  301.                         $yt_old $yt;
  302.                         $xt_old $xt;
  303.                     }
  304.                     $cord[$idx++] = $xt;
  305.                     $cord[$idx++] = $yt_old;
  306.                     $cord[$idx++] = $xt;
  307.                     $cord[$idx++] = $yt;
  308.                 } elseif ($firstnonumeric == false) {
  309.                     $firstnonumeric true;
  310.                     $yt_first       $yt_old;
  311.                     $xt_first       $xt_old;
  312.                 }
  313.             } else {
  314.                 $tmp1 $y;
  315.                 $prev $this->coords[0][$pnts 1];
  316.                 if ($tmp1 === '' || $tmp1 === null || $tmp1 === 'X') {
  317.                     $tmp1 'x';
  318.                 }
  319.                 if ($prev === '' || $prev === null || $prev === 'X') {
  320.                     $prev 'x';
  321.                 }
  322.                 if (is_numeric($y) || (is_string($y) && $y != '-')) {
  323.                     if (is_numeric($y) && (is_numeric($prev) || $prev === '-')) {
  324.                         $img->StyleLineTo($xt$yt);
  325.                     } else {
  326.                         $img->SetStartPoint($xt$yt);
  327.                     }
  328.                 }
  329.                 if ($this->filled && $tmp1 !== '-') {
  330.                     if ($tmp1 === 'x') {
  331.                         $cord[$idx++] = $cord[$idx 3];
  332.                         $cord[$idx++] = $fillmin;
  333.                     } elseif ($prev === 'x') {
  334.                         $cord[$idx++] = $xt;
  335.                         $cord[$idx++] = $fillmin;
  336.                         $cord[$idx++] = $xt;
  337.                         $cord[$idx++] = $yt;
  338.                     } else {
  339.                         $cord[$idx++] = $xt;
  340.                         $cord[$idx++] = $yt;
  341.                     }
  342.                 } else {
  343.                     if (is_numeric($tmp1) && (is_numeric($prev) || $prev === '-')) {
  344.                         $cord[$idx++] = $xt;
  345.                         $cord[$idx++] = $yt;
  346.                     }
  347.                 }
  348.             }
  349.             $yt_old $yt;
  350.             $xt_old $xt;
  351.             $y_old  $y;
  352.             $this->StrokeDataValue($img$this->coords[0][$pnts], $xt$yt);
  353.             ++$pnts;
  354.         }
  355.         if ($this->filled) {
  356.             $cord[$idx++] = $xt;
  357.             if ($this->fillFromMax) {
  358.                 $cord[$idx++] = $yscale->scale_abs[1];
  359.             } else {
  360.                 if ($min || $this->fillFromMin) {
  361.                     $cord[$idx++] = $yscale->Translate($min);
  362.                 } else {
  363.                     $cord[$idx++] = $yscale->Translate(0);
  364.                 }
  365.             }
  366.             if ($this->fillgrad) {
  367.                 $img->SetLineWeight(1);
  368.                 $grad = new Gradient($img);
  369.                 $grad->SetNumColors($this->fillgrad_numcolors);
  370.                 $grad->FilledFlatPolygon($cord$this->fillgrad_fromcolor$this->fillgrad_tocolor);
  371.                 $img->SetLineWeight($this->weight);
  372.             } else {
  373.                 $img->SetColor($this->fill_color);
  374.                 $img->FilledPolygon($cord);
  375.             }
  376.             if ($this->weight 0) {
  377.                 $img->SetLineWeight($this->weight);
  378.                 $img->SetColor($this->color);
  379.                 // Remove first and last coordinate before drawing the line
  380.                 // sine we otherwise get the vertical start and end lines which
  381.                 // doesn't look appropriate
  382.                 $img->Polygon(array_slice($cord2safe_count($cord) - 4));
  383.             }
  384.         }
  385.         if (!empty($this->filledAreas)) {
  386.             $minY   $yscale->Translate($yscale->GetMinVal());
  387.             $factor = ($this->step_style 2);
  388.             for ($i 0$i safe_count($this->filledAreas); ++$i) {
  389.                 // go through all filled area elements ordered by insertion
  390.                 // fill polygon array
  391.                 $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor];
  392.                 $areaCoords[] = $minY;
  393.                 $areaCoords =
  394.                     array_merge(
  395.                         $areaCoords,
  396.                         array_slice(
  397.                             $cord,
  398.                             $this->filledAreas[$i][0] * $factor,
  399.                             ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style 1)) * $factor
  400.                         )
  401.                     );
  402.                 $areaCoords[] = $areaCoords[safe_count($areaCoords) - 2]; // last x
  403.                 $areaCoords[] = $minY// last y
  404.                 if ($this->filledAreas[$i][3]) {
  405.                     $img->SetColor($this->filledAreas[$i][2]);
  406.                     $img->FilledPolygon($areaCoords);
  407.                     $img->SetColor($this->color);
  408.                 }
  409.                 // Check if we should draw the frame.
  410.                 // If not we still re-draw the line since it might have been
  411.                 // partially overwritten by the filled area and it doesn't look
  412.                 // very good.
  413.                 if ($this->filledAreas[$i][4]) {
  414.                     $img->Polygon($areaCoords);
  415.                 } else {
  416.                     $img->Polygon($cord);
  417.                 }
  418.                 $areaCoords = [];
  419.             }
  420.         }
  421.         if (!is_object($this->mark) || $this->mark->type == -|| $this->mark->show == false) {
  422.             return;
  423.         }
  424.         for ($pnts 0$pnts $numpoints; ++$pnts) {
  425.             if ($exist_x) {
  426.                 $x $this->coords[1][$pnts];
  427.             } else {
  428.                 $x $pnts $textadj;
  429.             }
  430.             $xt $xscale->Translate($x);
  431.             $yt $yscale->Translate($this->coords[0][$pnts]);
  432.             if (is_numeric($this->coords[0][$pnts])) {
  433.                 if (!empty($this->csimtargets[$pnts])) {
  434.                     if (!empty($this->csimwintargets[$pnts])) {
  435.                         $this->mark->SetCSIMTarget($this->csimtargets[$pnts], $this->csimwintargets[$pnts]);
  436.                     } else {
  437.                         $this->mark->SetCSIMTarget($this->csimtargets[$pnts]);
  438.                     }
  439.                     $this->mark->SetCSIMAlt($this->csimalts[$pnts]);
  440.                 }
  441.                 if ($exist_x) {
  442.                     $x $this->coords[1][$pnts];
  443.                 } else {
  444.                     $x $pnts;
  445.                 }
  446.                 $this->mark->SetCSIMAltVal($this->coords[0][$pnts], $x);
  447.                 $this->mark->Stroke($img$xt$yt);
  448.                 $this->csimareas .= $this->mark->GetCSIMAreas();
  449.             }
  450.         }
  451.     }
  452. // @class