Subversion Repositories Sites.tela-botanica.org

Rev

Rev 609 | Details | Compare with Previous | Last modification | View Log | RSS feed

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