Subversion Repositories Applications.annuaire

Rev

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

Rev Author Line No. Line
66 aurelien 1
<?php
2
/*=======================================================================
3
 // File:  		 JPGRAPH_LINE.PHP
4
 // Description: Line plot extension for JpGraph
5
 // Created:  	 2001-01-08
6
 // Ver:  		 $Id: jpgraph_line.php 1921 2009-12-11 11:46:39Z ljp $
7
 //
8
 // Copyright (c) Aditus Consulting. All rights reserved.
9
 //========================================================================
10
 */
11
 
12
require_once ('jpgraph_plotmark.inc.php');
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
    public $mark=null;
26
    protected $filled=false;
27
    protected $fill_color='blue';
28
    protected $step_style=false, $center=false;
29
    protected $line_style=1; // Default to solid
30
    protected $filledAreas = array(); // array of arrays(with min,max,col,filled in them)
31
    public $barcenter=false;  // When we mix line and bar. Should we center the line in the bar.
32
    protected $fillFromMin = false, $fillFromMax = false;
33
    protected $fillgrad=false,$fillgrad_fromcolor='navy',$fillgrad_tocolor='silver',$fillgrad_numcolors=100;
34
    protected $iFastStroke=false;
35
 
36
    //---------------
37
    // CONSTRUCTOR
38
    function LinePlot($datay,$datax=false) {
39
        parent::__construct($datay,$datax);
40
        $this->mark = new PlotMark() ;
41
        $this->color = ColorFactory::getColor();
42
        $this->fill_color = $this->color;
43
    }
44
    //---------------
45
    // PUBLIC METHODS
46
 
47
    function SetFilled($aFlg=true) {
48
		$this->filled = $aFlg;
49
    }
50
 
51
    function SetBarCenter($aFlag=true) {
52
        $this->barcenter=$aFlag;
53
    }
54
 
55
    function SetStyle($aStyle) {
56
        $this->line_style=$aStyle;
57
    }
58
 
59
    function SetStepStyle($aFlag=true) {
60
        $this->step_style = $aFlag;
61
    }
62
 
63
    function SetColor($aColor) {
64
        parent::SetColor($aColor);
65
    }
66
 
67
    function SetFillFromYMin($f=true) {
68
        $this->fillFromMin = $f ;
69
    }
70
 
71
    function SetFillFromYMax($f=true) {
72
        $this->fillFromMax = $f ;
73
    }
74
 
75
    function SetFillColor($aColor,$aFilled=true) {
76
    	//$this->color = $aColor;
77
        $this->fill_color=$aColor;
78
        $this->filled=$aFilled;
79
    }
80
 
81
    function SetFillGradient($aFromColor,$aToColor,$aNumColors=100,$aFilled=true) {
82
        $this->fillgrad_fromcolor = $aFromColor;
83
        $this->fillgrad_tocolor   = $aToColor;
84
        $this->fillgrad_numcolors = $aNumColors;
85
        $this->filled = $aFilled;
86
        $this->fillgrad = true;
87
    }
88
 
89
    function Legend($graph) {
90
        if( $this->legend!="" ) {
91
            if( $this->filled && !$this->fillgrad ) {
92
                $graph->legend->Add($this->legend,
93
                $this->fill_color,$this->mark,0,
94
                $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
95
            }
96
            elseif( $this->fillgrad ) {
97
                $color=array($this->fillgrad_fromcolor,$this->fillgrad_tocolor);
98
                // In order to differentiate between gradients and cooors specified as an RGB triple
99
                $graph->legend->Add($this->legend,$color,"",-2 /* -GRAD_HOR */,
100
                $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
101
            } else {
102
                $graph->legend->Add($this->legend,
103
                $this->color,$this->mark,$this->line_style,
104
                $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget);
105
            }
106
        }
107
    }
108
 
109
    function AddArea($aMin=0,$aMax=0,$aFilled=LP_AREA_NOT_FILLED,$aColor="gray9",$aBorder=LP_AREA_BORDER) {
110
        if($aMin > $aMax) {
111
            // swap
112
            $tmp = $aMin;
113
            $aMin = $aMax;
114
            $aMax = $tmp;
115
        }
116
        $this->filledAreas[] = array($aMin,$aMax,$aColor,$aFilled,$aBorder);
117
    }
118
 
119
    // Gets called before any axis are stroked
120
    function PreStrokeAdjust($graph) {
121
 
122
        // If another plot type have already adjusted the
123
        // offset we don't touch it.
124
        // (We check for empty in case the scale is  a log scale
125
        // and hence doesn't contain any xlabel_offset)
126
        if( empty($graph->xaxis->scale->ticks->xlabel_offset) || $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {
127
            if( $this->center ) {
128
                ++$this->numpoints;
129
                $a=0.5; $b=0.5;
130
            } else {
131
                $a=0; $b=0;
132
            }
133
            $graph->xaxis->scale->ticks->SetXLabelOffset($a);
134
            $graph->SetTextScaleOff($b);
135
            //$graph->xaxis->scale->ticks->SupressMinorTickMarks();
136
        }
137
    }
138
 
139
    function SetFastStroke($aFlg=true) {
140
        $this->iFastStroke = $aFlg;
141
    }
142
 
143
    function FastStroke($img,$xscale,$yscale,$aStartPoint=0,$exist_x=true) {
144
        // An optimized stroke for many data points with no extra
145
        // features but 60% faster. You can't have values or line styles, or null
146
        // values in plots.
147
        $numpoints=count($this->coords[0]);
148
        if( $this->barcenter ) {
149
            $textadj = 0.5-$xscale->text_scale_off;
150
        }
151
        else {
152
            $textadj = 0;
153
        }
154
 
155
        $img->SetColor($this->color);
156
        $img->SetLineWeight($this->weight);
157
        $pnts=$aStartPoint;
158
        while( $pnts < $numpoints ) {
159
            if( $exist_x ) {
160
                $x=$this->coords[1][$pnts];
161
            }
162
            else {
163
                $x=$pnts+$textadj;
164
            }
165
            $xt = $xscale->Translate($x);
166
            $y=$this->coords[0][$pnts];
167
            $yt = $yscale->Translate($y);
168
            if( is_numeric($y) ) {
169
                $cord[] = $xt;
170
                $cord[] = $yt;
171
            }
172
            elseif( $y == '-' && $pnts > 0 ) {
173
                // Just ignore
174
            }
175
            else {
176
                JpGraphError::RaiseL(10002);//('Plot too complicated for fast line Stroke. Use standard Stroke()');
177
            }
178
            ++$pnts;
179
        } // WHILE
180
 
181
        $img->Polygon($cord,false,true);
182
    }
183
 
184
    function Stroke($img,$xscale,$yscale) {
185
        $idx=0;
186
        $numpoints=count($this->coords[0]);
187
        if( isset($this->coords[1]) ) {
188
            if( count($this->coords[1])!=$numpoints ) {
189
                JpGraphError::RaiseL(2003,count($this->coords[1]),$numpoints);
190
            //("Number of X and Y points are not equal. Number of X-points:".count($this->coords[1])." Number of Y-points:$numpoints");
191
            }
192
            else {
193
                $exist_x = true;
194
            }
195
        }
196
        else {
197
            $exist_x = false;
198
        }
199
 
200
        if( $this->barcenter ) {
201
            $textadj = 0.5-$xscale->text_scale_off;
202
        }
203
        else {
204
            $textadj = 0;
205
        }
206
 
207
        // Find the first numeric data point
208
        $startpoint=0;
209
        while( $startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint]) ) {
210
            ++$startpoint;
211
        }
212
 
213
        // Bail out if no data points
214
        if( $startpoint == $numpoints ) return;
215
 
216
        if( $this->iFastStroke ) {
217
            $this->FastStroke($img,$xscale,$yscale,$startpoint,$exist_x);
218
            return;
219
        }
220
 
221
        if( $exist_x ) {
222
            $xs=$this->coords[1][$startpoint];
223
        }
224
        else {
225
            $xs= $textadj+$startpoint;
226
        }
227
 
228
        $img->SetStartPoint($xscale->Translate($xs),
229
        $yscale->Translate($this->coords[0][$startpoint]));
230
 
231
        if( $this->filled ) {
232
            if( $this->fillFromMax ) {
233
                //$max = $yscale->GetMaxVal();
234
                $cord[$idx++] = $xscale->Translate($xs);
235
                $cord[$idx++] = $yscale->scale_abs[1];
236
            }
237
            else {
238
                $min = $yscale->GetMinVal();
239
                if( $min > 0 || $this->fillFromMin ) {
240
                    $fillmin = $yscale->scale_abs[0];//Translate($min);
241
                }
242
                else {
243
                    $fillmin = $yscale->Translate(0);
244
                }
245
 
246
                $cord[$idx++] = $xscale->Translate($xs);
247
                $cord[$idx++] = $fillmin;
248
            }
249
        }
250
        $xt = $xscale->Translate($xs);
251
        $yt = $yscale->Translate($this->coords[0][$startpoint]);
252
        $cord[$idx++] = $xt;
253
        $cord[$idx++] = $yt;
254
        $yt_old = $yt;
255
        $xt_old = $xt;
256
        $y_old = $this->coords[0][$startpoint];
257
 
258
        $this->value->Stroke($img,$this->coords[0][$startpoint],$xt,$yt);
259
 
260
        $img->SetColor($this->color);
261
        $img->SetLineWeight($this->weight);
262
        $img->SetLineStyle($this->line_style);
263
        $pnts=$startpoint+1;
264
        $firstnonumeric = false;
265
 
266
 
267
        while( $pnts < $numpoints ) {
268
 
269
            if( $exist_x ) {
270
                $x=$this->coords[1][$pnts];
271
            }
272
            else {
273
                $x=$pnts+$textadj;
274
            }
275
            $xt = $xscale->Translate($x);
276
            $yt = $yscale->Translate($this->coords[0][$pnts]);
277
 
278
            $y=$this->coords[0][$pnts];
279
            if( $this->step_style ) {
280
                // To handle null values within step style we need to record the
281
                // first non numeric value so we know from where to start if the
282
                // non value is '-'.
283
                if( is_numeric($y) ) {
284
                    $firstnonumeric = false;
285
                    if( is_numeric($y_old) ) {
286
                        $img->StyleLine($xt_old,$yt_old,$xt,$yt_old);
287
                        $img->StyleLine($xt,$yt_old,$xt,$yt);
288
                    }
289
                    elseif( $y_old == '-' ) {
290
                        $img->StyleLine($xt_first,$yt_first,$xt,$yt_first);
291
                        $img->StyleLine($xt,$yt_first,$xt,$yt);
292
                    }
293
                    else {
294
                        $yt_old = $yt;
295
                        $xt_old = $xt;
296
                    }
297
                    $cord[$idx++] = $xt;
298
                    $cord[$idx++] = $yt_old;
299
                    $cord[$idx++] = $xt;
300
                    $cord[$idx++] = $yt;
301
                }
302
                elseif( $firstnonumeric==false ) {
303
                    $firstnonumeric = true;
304
                    $yt_first = $yt_old;
305
                    $xt_first = $xt_old;
306
                }
307
            }
308
            else {
309
                $tmp1=$y;
310
                $prev=$this->coords[0][$pnts-1];
311
                if( $tmp1==='' || $tmp1===NULL || $tmp1==='X' ) $tmp1 = 'x';
312
                if( $prev==='' || $prev===null || $prev==='X' ) $prev = 'x';
313
 
314
                if( is_numeric($y) || (is_string($y) && $y != '-') ) {
315
                    if( is_numeric($y) && (is_numeric($prev) || $prev === '-' ) ) {
316
                        $img->StyleLineTo($xt,$yt);
317
                    }
318
                    else {
319
                        $img->SetStartPoint($xt,$yt);
320
                    }
321
                }
322
                if( $this->filled && $tmp1 !== '-' ) {
323
                    if( $tmp1 === 'x' ) {
324
                        $cord[$idx++] = $cord[$idx-3];
325
                        $cord[$idx++] = $fillmin;
326
                    }
327
                    elseif( $prev === 'x' ) {
328
                        $cord[$idx++] = $xt;
329
                        $cord[$idx++] = $fillmin;
330
                        $cord[$idx++] = $xt;
331
                        $cord[$idx++] = $yt;
332
                    }
333
                    else {
334
                        $cord[$idx++] = $xt;
335
                        $cord[$idx++] = $yt;
336
                    }
337
                }
338
                else {
339
                    if( is_numeric($tmp1)  && (is_numeric($prev) || $prev === '-' ) ) {
340
                        $cord[$idx++] = $xt;
341
                        $cord[$idx++] = $yt;
342
                    }
343
                }
344
            }
345
            $yt_old = $yt;
346
            $xt_old = $xt;
347
            $y_old = $y;
348
 
349
            $this->StrokeDataValue($img,$this->coords[0][$pnts],$xt,$yt);
350
 
351
            ++$pnts;
352
        }
353
 
354
        if( $this->filled  ) {
355
            $cord[$idx++] = $xt;
356
            if( $this->fillFromMax ) {
357
                $cord[$idx++] = $yscale->scale_abs[1];
358
            }
359
            else {
360
                if( $min > 0 || $this->fillFromMin ) {
361
                    $cord[$idx++] = $yscale->Translate($min);
362
                }
363
                else {
364
                    $cord[$idx++] = $yscale->Translate(0);
365
                }
366
            }
367
            if( $this->fillgrad ) {
368
                $img->SetLineWeight(1);
369
                $grad = new Gradient($img);
370
                $grad->SetNumColors($this->fillgrad_numcolors);
371
                $grad->FilledFlatPolygon($cord,$this->fillgrad_fromcolor,$this->fillgrad_tocolor);
372
                $img->SetLineWeight($this->weight);
373
            }
374
            else {
375
                $img->SetColor($this->fill_color);
376
                $img->FilledPolygon($cord);
377
            }
378
            if( $this->weight > 0 ) {
379
                $img->SetLineWeight($this->weight);
380
                $img->SetColor($this->color);
381
                // Remove first and last coordinate before drawing the line
382
                // sine we otherwise get the vertical start and end lines which
383
                // doesn't look appropriate
384
                $img->Polygon(array_slice($cord,2,count($cord)-4));
385
            }
386
        }
387
 
388
        if(!empty($this->filledAreas)) {
389
 
390
            $minY = $yscale->Translate($yscale->GetMinVal());
391
            $factor = ($this->step_style ? 4 : 2);
392
 
393
            for($i = 0; $i < sizeof($this->filledAreas); ++$i) {
394
                // go through all filled area elements ordered by insertion
395
                // fill polygon array
396
                $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor];
397
                $areaCoords[] = $minY;
398
 
399
                $areaCoords =
400
                array_merge($areaCoords,
401
                array_slice($cord,
402
                $this->filledAreas[$i][0] * $factor,
403
                ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1))  * $factor));
404
                $areaCoords[] = $areaCoords[sizeof($areaCoords)-2]; // last x
405
                $areaCoords[] = $minY; // last y
406
 
407
                if($this->filledAreas[$i][3]) {
408
                    $img->SetColor($this->filledAreas[$i][2]);
409
                    $img->FilledPolygon($areaCoords);
410
                    $img->SetColor($this->color);
411
                }
412
                // Check if we should draw the frame.
413
                // If not we still re-draw the line since it might have been
414
                // partially overwritten by the filled area and it doesn't look
415
                // very good.
416
                if( $this->filledAreas[$i][4] ) {
417
                    $img->Polygon($areaCoords);
418
                }
419
                else {
420
                    $img->Polygon($cord);
421
                }
422
 
423
                $areaCoords = array();
424
            }
425
        }
426
 
427
        if( $this->mark->type == -1 || $this->mark->show == false )
428
        return;
429
 
430
        for( $pnts=0; $pnts<$numpoints; ++$pnts) {
431
 
432
            if( $exist_x ) {
433
                $x=$this->coords[1][$pnts];
434
            }
435
            else {
436
                $x=$pnts+$textadj;
437
            }
438
            $xt = $xscale->Translate($x);
439
            $yt = $yscale->Translate($this->coords[0][$pnts]);
440
 
441
            if( is_numeric($this->coords[0][$pnts]) ) {
442
                if( !empty($this->csimtargets[$pnts]) ) {
443
                    if( !empty($this->csimwintargets[$pnts]) ) {
444
                        $this->mark->SetCSIMTarget($this->csimtargets[$pnts],$this->csimwintargets[$pnts]);
445
                    }
446
                    else {
447
                        $this->mark->SetCSIMTarget($this->csimtargets[$pnts]);
448
                    }
449
                    $this->mark->SetCSIMAlt($this->csimalts[$pnts]);
450
                }
451
                if( $exist_x ) {
452
                    $x=$this->coords[1][$pnts];
453
                }
454
                else {
455
                    $x=$pnts;
456
                }
457
                $this->mark->SetCSIMAltVal($this->coords[0][$pnts],$x);
458
                $this->mark->Stroke($img,$xt,$yt);
459
                $this->csimareas .= $this->mark->GetCSIMAreas();
460
            }
461
        }
462
    }
463
} // Class
464
 
465
 
466
//===================================================
467
// CLASS AccLinePlot
468
// Description:
469
//===================================================
470
class AccLinePlot extends Plot {
471
    protected $plots=null,$nbrplots=0;
472
    private $iStartEndZero=true;
473
    //---------------
474
    // CONSTRUCTOR
475
    function __construct($plots) {
476
        $this->plots = $plots;
477
        $this->nbrplots = count($plots);
478
        $this->numpoints = $plots[0]->numpoints;
479
 
480
        // Verify that all plots have the same number of data points
481
        for( $i=1; $i < $this->nbrplots; ++$i ) {
482
            if( $plots[$i]->numpoints != $this->numpoints ) {
483
                JpGraphError::RaiseL(10003);//('Each plot in an accumulated lineplot must have the same number of data points',0)
484
            }
485
        }
486
 
487
        for($i=0; $i < $this->nbrplots; ++$i ) {
488
            $this->LineInterpolate($this->plots[$i]->coords[0]);
489
        }
490
    }
491
 
492
    //---------------
493
    // PUBLIC METHODS
494
    function Legend($graph) {
495
        foreach( $this->plots as $p ) {
496
            $p->DoLegend($graph);
497
        }
498
    }
499
 
500
    function Max() {
501
        list($xmax) = $this->plots[0]->Max();
502
        $nmax=0;
503
        $n = count($this->plots);
504
        for($i=0; $i < $n; ++$i) {
505
            $nc = count($this->plots[$i]->coords[0]);
506
            $nmax = max($nmax,$nc);
507
            list($x) = $this->plots[$i]->Max();
508
            $xmax = Max($xmax,$x);
509
        }
510
        for( $i = 0; $i < $nmax; $i++ ) {
511
            // Get y-value for line $i by adding the
512
            // individual bars from all the plots added.
513
            // It would be wrong to just add the
514
            // individual plots max y-value since that
515
            // would in most cases give to large y-value.
516
            $y=$this->plots[0]->coords[0][$i];
517
            for( $j = 1; $j < $this->nbrplots; $j++ ) {
518
                $y += $this->plots[ $j ]->coords[0][$i];
519
            }
520
            $ymax[$i] = $y;
521
        }
522
        $ymax = max($ymax);
523
        return array($xmax,$ymax);
524
    }
525
 
526
    function Min() {
527
        $nmax=0;
528
        list($xmin,$ysetmin) = $this->plots[0]->Min();
529
        $n = count($this->plots);
530
        for($i=0; $i < $n; ++$i) {
531
            $nc = count($this->plots[$i]->coords[0]);
532
            $nmax = max($nmax,$nc);
533
            list($x,$y) = $this->plots[$i]->Min();
534
            $xmin = Min($xmin,$x);
535
            $ysetmin = Min($y,$ysetmin);
536
        }
537
        for( $i = 0; $i < $nmax; $i++ ) {
538
            // Get y-value for line $i by adding the
539
            // individual bars from all the plots added.
540
            // It would be wrong to just add the
541
            // individual plots min y-value since that
542
            // would in most cases give to small y-value.
543
            $y=$this->plots[0]->coords[0][$i];
544
            for( $j = 1; $j < $this->nbrplots; $j++ ) {
545
                $y += $this->plots[ $j ]->coords[0][$i];
546
            }
547
            $ymin[$i] = $y;
548
        }
549
        $ymin = Min($ysetmin,Min($ymin));
550
        return array($xmin,$ymin);
551
    }
552
 
553
    // Gets called before any axis are stroked
554
    function PreStrokeAdjust($graph) {
555
 
556
        // If another plot type have already adjusted the
557
        // offset we don't touch it.
558
        // (We check for empty in case the scale is  a log scale
559
        // and hence doesn't contain any xlabel_offset)
560
 
561
        if( empty($graph->xaxis->scale->ticks->xlabel_offset) ||
562
        $graph->xaxis->scale->ticks->xlabel_offset == 0 ) {
563
            if( $this->center ) {
564
                ++$this->numpoints;
565
                $a=0.5; $b=0.5;
566
            } else {
567
                $a=0; $b=0;
568
            }
569
            $graph->xaxis->scale->ticks->SetXLabelOffset($a);
570
            $graph->SetTextScaleOff($b);
571
            $graph->xaxis->scale->ticks->SupressMinorTickMarks();
572
        }
573
 
574
    }
575
 
576
    function SetInterpolateMode($aIntMode) {
577
        $this->iStartEndZero=$aIntMode;
578
    }
579
 
580
    // Replace all '-' with an interpolated value. We use straightforward
581
    // linear interpolation. If the data starts with one or several '-' they
582
    // will be replaced by the the first valid data point
583
    function LineInterpolate(&$aData) {
584
 
585
        $n=count($aData);
586
        $i=0;
587
 
588
        // If first point is undefined we will set it to the same as the first
589
        // valid data
590
        if( $aData[$i]==='-' ) {
591
            // Find the first valid data
592
            while( $i < $n && $aData[$i]==='-' ) {
593
                ++$i;
594
            }
595
            if( $i < $n ) {
596
                for($j=0; $j < $i; ++$j ) {
597
                    if( $this->iStartEndZero )
598
                    $aData[$i] = 0;
599
                    else
600
                    $aData[$j] = $aData[$i];
601
                }
602
            }
603
            else {
604
                // All '-' => Error
605
                return false;
606
            }
607
        }
608
 
609
        while($i < $n) {
610
            while( $i < $n && $aData[$i] !== '-' ) {
611
                ++$i;
612
            }
613
            if( $i < $n ) {
614
                $pstart=$i-1;
615
 
616
                // Now see how long this segment of '-' are
617
                while( $i < $n && $aData[$i] === '-' ) {
618
                    ++$i;
619
                }
620
                if( $i < $n ) {
621
                    $pend=$i;
622
                    $size=$pend-$pstart;
623
                    $k=($aData[$pend]-$aData[$pstart])/$size;
624
                    // Replace the segment of '-' with a linear interpolated value.
625
                    for($j=1; $j < $size; ++$j ) {
626
                        $aData[$pstart+$j] = $aData[$pstart] + $j*$k ;
627
                    }
628
                }
629
                else {
630
                    // There are no valid end point. The '-' goes all the way to the end
631
                    // In that case we just set all the remaining values the the same as the
632
                    // last valid data point.
633
                    for( $j=$pstart+1; $j < $n; ++$j )
634
                    if( $this->iStartEndZero ) {
635
                        $aData[$j] = 0;
636
                    }
637
                    else {
638
                        $aData[$j] = $aData[$pstart] ;
639
                    }
640
                }
641
            }
642
        }
643
        return true;
644
    }
645
 
646
    // To avoid duplicate of line drawing code here we just
647
    // change the y-values for each plot and then restore it
648
    // after we have made the stroke. We must do this copy since
649
    // it wouldn't be possible to create an acc line plot
650
    // with the same graphs, i.e AccLinePlot(array($pl,$pl,$pl));
651
    // since this method would have a side effect.
652
    function Stroke($img,$xscale,$yscale) {
653
        $img->SetLineWeight($this->weight);
654
        $this->numpoints = count($this->plots[0]->coords[0]);
655
        // Allocate array
656
        $coords[$this->nbrplots][$this->numpoints]=0;
657
        for($i=0; $i<$this->numpoints; $i++) {
658
            $coords[0][$i]=$this->plots[0]->coords[0][$i];
659
            $accy=$coords[0][$i];
660
            for($j=1; $j<$this->nbrplots; ++$j ) {
661
                $coords[$j][$i] = $this->plots[$j]->coords[0][$i]+$accy;
662
                $accy = $coords[$j][$i];
663
            }
664
        }
665
        for($j=$this->nbrplots-1; $j>=0; --$j) {
666
            $p=$this->plots[$j];
667
            for( $i=0; $i<$this->numpoints; ++$i) {
668
                $tmp[$i]=$p->coords[0][$i];
669
                $p->coords[0][$i]=$coords[$j][$i];
670
            }
671
            $p->Stroke($img,$xscale,$yscale);
672
            for( $i=0; $i<$this->numpoints; ++$i) {
673
                $p->coords[0][$i]=$tmp[$i];
674
            }
675
            $p->coords[0][]=$tmp;
676
        }
677
    }
678
} // Class
679
 
680
 
681
/* EOF */
682
?>