]> git.llucax.com Git - mecon/meconlib.git/blob - lib/MECON/Graph/external/jpgraph/src/jpgraph_line.php
Bugfixes.
[mecon/meconlib.git] / lib / MECON / Graph / external / jpgraph / src / jpgraph_line.php
1 <?php
2 /*=======================================================================
3 // File:        JPGRAPH_LINE.PHP
4 // Description: Line plot extension for JpGraph
5 // Created:     2001-01-08
6 // Author:      Johan Persson (johanp@aditus.nu)
7 // Ver:         $Id: jpgraph_line.php,v 1.48.2.3 2003/08/23 22:01:56 aditus Exp $
8 //
9 // License:     This code is released under QPL
10 // Copyright (C) 2001,2002 Johan Persson
11 //========================================================================
12 */
13  
14 // constants for the (filled) area
15 DEFINE("LP_AREA_FILLED", true);
16 DEFINE("LP_AREA_NOT_FILLED", false);
17 DEFINE("LP_AREA_BORDER",false);
18 DEFINE("LP_AREA_NO_BORDER",true);
19
20 //===================================================
21 // CLASS LinePlot
22 // Description: 
23 //===================================================
24 class LinePlot extends Plot{
25     var $filled=false;
26     var $fill_color='blue';
27     var $mark=null;
28     var $step_style=false, $center=false;
29     var $line_style=1;  // Default to solid
30     var $filledAreas = array(); // array of arrays(with min,max,col,filled in them)
31     var $barcenter=false;  // When we mix line and bar. Should we center the line in the bar.
32     var $fillFromMin = false ;
33     var $fillgrad=false,$fillgrad_fromcolor='navy',$fillgrad_tocolor='silver',$fillgrad_numcolors=100;
34
35 //---------------
36 // CONSTRUCTOR
37     function LinePlot(&$datay,$datax=false) {
38         $this->Plot($datay,$datax);
39         $this->mark = new PlotMark();
40     }
41 //---------------
42 // PUBLIC METHODS       
43
44     // Set style, filled or open
45     function SetFilled($aFlag=true) {
46         JpGraphError::Raise('LinePlot::SetFilled() is deprecated. Use SetFillColor()');
47     }
48         
49     function SetBarCenter($aFlag=true) {
50         $this->barcenter=$aFlag;
51     }
52
53     function SetStyle($aStyle) {
54         $this->line_style=$aStyle;
55     }
56         
57     function SetStepStyle($aFlag=true) {
58         $this->step_style = $aFlag;
59     }
60         
61     function SetColor($aColor) {
62         parent::SetColor($aColor);
63     }
64         
65     function SetFillFromYMin($f=true) {
66         $this->fillFromMin = $f ;
67     }
68     
69     function SetFillColor($aColor,$aFilled=true) {
70         $this->fill_color=$aColor;
71         $this->filled=$aFilled;
72     }
73
74     function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) {
75         $this->fillgrad_fromcolor = $aFromColor;
76         $this->fillgrad_tocolor   = $aToColor;
77         $this->fillgrad_numcolors = $aNumColors;
78         $this->filled = $aFilled;
79         $this->fillgrad = true;
80     }
81         
82     function Legend(&$graph) {
83         if( $this->legend!="" ) {
84             if( $this->filled ) {
85                 $graph->legend->Add($this->legend,
86                                     $this->fill_color,$this->mark,0,
87                                     $this->legendcsimtarget,$this->legendcsimalt);
88             } else {
89                 $graph->legend->Add($this->legend,
90                                     $this->color,$this->mark,$this->line_style,
91                                     $this->legendcsimtarget,$this->legendcsimalt);
92             }
93         }       
94     }
95
96     function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) {
97         if($aMin > $aMax) {
98             // swap
99             $tmp = $aMin;
100             $aMin = $aMax;
101             $aMax = $tmp;
102         } 
103         $this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder);
104     }
105         
106     // Gets called before any axis are stroked
107     function PreStrokeAdjust(&$graph) {
108
109         // If another plot type have already adjusted the
110         // offset we don't touch it.
111         // (We check for empty in case the scale is  a log scale 
112         // and hence doesn't contain any xlabel_offset)
113         if( empty($graph->xaxis->scale->ticks->xlabel_offset) ||
114             $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {
115             if( $this->center ) {
116                 ++$this->numpoints;
117                 $a=0.5; $b=0.5;
118             } else {
119                 $a=0; $b=0;
120             }
121             $graph->xaxis->scale->ticks->SetXLabelOffset($a);
122             $graph->SetTextScaleOff($b);                                                
123             //$graph->xaxis->scale->ticks->SupressMinorTickMarks();
124         }
125     }
126         
127     function Stroke(&$img,&$xscale,&$yscale) {
128         $numpoints=count($this->coords[0]);
129         if( isset($this->coords[1]) ) {
130             if( count($this->coords[1])!=$numpoints )
131                 JpGraphError::Raise("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints");
132             else
133                 $exist_x = true;
134         }
135         else 
136             $exist_x = false;
137
138         if( $this->barcenter ) 
139             $textadj = 0.5-$xscale->text_scale_off;
140         else
141             $textadj = 0;
142
143         // Find the first numeric data point
144         $startpoint=0;
145         while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) )
146             ++$startpoint;
147
148         // Bail out if no data points
149         if( $startpoint == $numpoints ) 
150             return;
151
152         if( $exist_x )
153             $xs=$this->coords[1][$startpoint];
154         else
155             $xs= $textadj+$startpoint;
156
157         $img->SetStartPoint($xscale->Translate($xs),
158                             $yscale->Translate($this->coords[0][$startpoint]));
159
160                 
161         if( $this->filled ) {
162             $cord[] = $xscale->Translate($xs);
163             $min = $yscale->GetMinVal();
164             if( $min > 0 || $this->fillFromMin )
165                 $cord[] = $yscale->Translate($min);
166             else
167                 $cord[] = $yscale->Translate(0);
168         }
169         $xt = $xscale->Translate($xs);
170         $yt = $yscale->Translate($this->coords[0][$startpoint]);
171         $cord[] = $xt;
172         $cord[] = $yt;
173         $yt_old = $yt;
174
175         $this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt);
176
177         $img->SetColor($this->color);
178         $img->SetLineWeight($this->weight);
179         $img->SetLineStyle($this->line_style);
180         for( $pnts=$startpoint+1; $pnts<$numpoints; ++$pnts) {
181             
182             if( $exist_x ) $x=$this->coords[1][$pnts];
183             else $x=$pnts+$textadj;
184             $xt = $xscale->Translate($x);
185             $yt = $yscale->Translate($this->coords[0][$pnts]);
186             
187             $y=$this->coords[0][$pnts];
188             if( $this->step_style && is_numeric($y) ) {
189                 $img->StyleLineTo($xt,$yt_old);
190                 $img->StyleLineTo($xt,$yt);
191
192                 $cord[] = $xt;
193                 $cord[] = $yt_old;
194         
195                 $cord[] = $xt;
196                 $cord[] = $yt;
197
198             }
199             else {
200                 if( is_numeric($y) || (is_string($y) && $y != "-") ) {
201                     $tmp1=$this->coords[0][$pnts];
202                     $tmp2=$this->coords[0][$pnts-1];                                    
203                     if( is_numeric($tmp1)  && (is_numeric($tmp2) || $tmp2=="-" ) ) { 
204                         $img->StyleLineTo($xt,$yt);
205                     } 
206                     else {
207                         $img->SetStartPoint($xt,$yt);
208                     }
209                     if( is_numeric($tmp1)  && 
210                         (is_numeric($tmp2) || $tmp2=="-" || ($this->filled && $tmp2=='') ) ) { 
211                         $cord[] = $xt;
212                         $cord[] = $yt;
213                     } 
214                 }
215             }
216             $yt_old = $yt;
217
218             $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);
219         }       
220
221         if( $this->filled  ) {
222             $cord[] = $xt;
223             if( $min > 0 || $this->fillFromMin )
224                 $cord[] = $yscale->Translate($min);
225             else
226                 $cord[] = $yscale->Translate(0);
227             if( $this->fillgrad ) {
228                 $img->SetLineWeight(1);
229                 $grad = new Gradient($img);
230                 $grad->SetNumColors($this->fillgrad_numcolors);
231                 $grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor);
232                 $img->SetLineWeight($this->weight);
233             }
234             else {
235                 $img->SetColor($this->fill_color);      
236                 $img->FilledPolygon($cord);
237             }
238             if( $this->line_weight > 0 ) {
239                 $img->SetColor($this->color);
240                 $img->Polygon($cord);
241             }
242         }
243
244         if(!empty($this->filledAreas)) {
245
246             $minY = $yscale->Translate($yscale->GetMinVal());
247             $factor = ($this->step_style ? 4 : 2);
248
249             for($i = 0; $i < sizeof($this->filledAreas); ++$i) {
250                 // go through all filled area elements ordered by insertion
251                 // fill polygon array
252                 $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor];
253                 $areaCoords[] = $minY;
254
255                 $areaCoords =
256                     array_merge($areaCoords,
257                                 array_slice($cord,
258                                             $this->filledAreas[$i][0] * $factor,
259                                             ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1))  * $factor));
260                 $areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x
261                 $areaCoords[] = $minY; // last y
262             
263                 if($this->filledAreas[$i][3]) {
264                     $img->SetColor($this->filledAreas[$i][2]);
265                     $img->FilledPolygon($areaCoords);
266                     $img->SetColor($this->color);
267                 }
268                 // Check if we should draw the frame.
269                 // If not we still re-draw the line since it might have been
270                 // partially overwritten by the filled area and it doesn't look
271                 // very good.
272                 // TODO: The behaviour is undefined if the line does not have
273                 // any line at the position of the area.
274                 if( $this->filledAreas[$i][4] )
275                     $img->Polygon($areaCoords);
276                 else
277                     $img->Polygon($cord);
278
279                 $areaCoords = array();
280             }
281         }       
282
283         if( $this->mark->type == -1 || $this->mark->show == false )
284             return;
285
286         for( $pnts=0; $pnts<$numpoints; ++$pnts) {
287
288             if( $exist_x ) $x=$this->coords[1][$pnts];
289             else $x=$pnts+$textadj;
290             $xt = $xscale->Translate($x);
291             $yt = $yscale->Translate($this->coords[0][$pnts]);
292
293             if( is_numeric($this->coords[0][$pnts]) ) {
294                 if( !empty($this->csimtargets[$pnts]) ) {
295                     $this->mark->SetCSIMTarget($this->csimtargets[$pnts]);
296                     $this->mark->SetCSIMAlt($this->csimalts[$pnts]);
297                 }
298                 if( $exist_x )
299                     $x=$this->coords[1][$pnts];
300                 else
301                     $x=$pnts;
302                 $this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x);
303                 $this->mark->Stroke($img,$xt,$yt);      
304                 $this->csimareas .= $this->mark->GetCSIMAreas();
305                 $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);
306             }
307         }
308
309
310     }
311 } // Class
312
313
314 //===================================================
315 // CLASS AccLinePlot
316 // Description: 
317 //===================================================
318 class AccLinePlot extends Plot {
319     var $plots=null,$nbrplots=0,$numpoints=0;
320 //---------------
321 // CONSTRUCTOR
322     function AccLinePlot($plots) {
323         $this->plots = $plots;
324         $this->nbrplots = count($plots);
325         $this->numpoints = $plots[0]->numpoints;                
326     }
327
328 //---------------
329 // PUBLIC METHODS       
330     function Legend(&$graph) {
331         foreach( $this->plots as $p )
332             $p->DoLegend($graph);
333     }
334         
335     function Max() {
336         list($xmax) = $this->plots[0]->Max();
337         $nmax=0;
338         for($i=0; $i<count($this->plots); ++$i) {
339             $n = count($this->plots[$i]->coords[0]);
340             $nmax = max($nmax,$n);
341             list($x) = $this->plots[$i]->Max();
342             $xmax = Max($xmax,$x);
343         }
344         for( $i = 0; $i < $nmax; $i++ ) {
345             // Get y-value for line $i by adding the
346             // individual bars from all the plots added.
347             // It would be wrong to just add the
348             // individual plots max y-value since that
349             // would in most cases give to large y-value.
350             $y=$this->plots[0]->coords[0][$i];
351             for( $j = 1; $j < $this->nbrplots; $j++ ) {
352                 $y += $this->plots[ $j ]->coords[0][$i];
353             }
354             $ymax[$i] = $y;
355         }
356         $ymax = max($ymax);
357         return array($xmax,$ymax);
358     }   
359
360     function Min() {
361         $nmax=0;
362         list($xmin,$ysetmin) = $this->plots[0]->Min();
363         for($i=0; $i<count($this->plots); ++$i) {
364             $n = count($this->plots[$i]->coords[0]);
365             $nmax = max($nmax,$n);
366             list($x,$y) = $this->plots[$i]->Min();
367             $xmin = Min($xmin,$x);
368             $ysetmin = Min($y,$ysetmin);
369         }
370         for( $i = 0; $i < $nmax; $i++ ) {
371             // Get y-value for line $i by adding the
372             // individual bars from all the plots added.
373             // It would be wrong to just add the
374             // individual plots min y-value since that
375             // would in most cases give to small y-value.
376             $y=$this->plots[0]->coords[0][$i];
377             for( $j = 1; $j < $this->nbrplots; $j++ ) {
378                 $y += $this->plots[ $j ]->coords[0][$i];
379             }
380             $ymin[$i] = $y;
381         }
382         $ymin = Min($ysetmin,Min($ymin));
383         return array($xmin,$ymin);
384     }
385
386     // Gets called before any axis are stroked
387     function PreStrokeAdjust(&$graph) {
388
389         // If another plot type have already adjusted the
390         // offset we don't touch it.
391         // (We check for empty in case the scale is  a log scale 
392         // and hence doesn't contain any xlabel_offset)
393         
394         if( empty($graph->xaxis->scale->ticks->xlabel_offset) ||
395             $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {
396             if( $this->center ) {
397                 ++$this->numpoints;
398                 $a=0.5; $b=0.5;
399             } else {
400                 $a=0; $b=0;
401             }
402             $graph->xaxis->scale->ticks->SetXLabelOffset($a);
403             $graph->SetTextScaleOff($b);                                                
404             $graph->xaxis->scale->ticks->SupressMinorTickMarks();
405         }
406         
407     }
408
409     // To avoid duplicate of line drawing code here we just
410     // change the y-values for each plot and then restore it
411     // after we have made the stroke. We must do this copy since
412     // it wouldn't be possible to create an acc line plot
413     // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl));
414     // since this method would have a side effect.
415     function Stroke(&$img,&$xscale,&$yscale) {
416         $img->SetLineWeight($this->weight);
417         $this->numpoints = count($this->plots[0]->coords[0]);
418         // Allocate array
419         $coords[$this->nbrplots][$this->numpoints]=0;
420         for($i=0; $i<$this->numpoints; $i++) {
421             $coords[0][$i]=$this->plots[0]->coords[0][$i]; 
422             $accy=$coords[0][$i];
423             for($j=1; $j<$this->nbrplots; ++$j ) {
424                 $coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy; 
425                 $accy = $coords[$j][$i];
426             }
427         }
428         for($j=$this->nbrplots-1; $j>=0; --$j) {
429             $p=$this->plots[$j];
430             for( $i=0; $i<$this->numpoints; ++$i) {
431                 $tmp[$i]=$p->coords[0][$i];
432                 $p->coords[0][$i]=$coords[$j][$i];
433             }
434             $p->Stroke($img,$xscale,$yscale);
435             for( $i=0; $i<$this->numpoints; ++$i) 
436                 $p->coords[0][$i]=$tmp[$i];
437             $p->coords[0][]=$tmp;
438         }
439     }
440 } // Class
441
442
443 /* EOF */
444 ?>