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_PLOTBAND.PHP
4
// Description: PHP4 Graph Plotting library. Extension module.
5
// Created:     2004-02-18
6
// Ver:         $Id: jpgraph_plotband.php 1106 2009-02-22 20:16:35Z ljp $
7
//
8
// Copyright (c) Aditus Consulting. All rights reserved.
9
//========================================================================
10
 
11
// Constants for types of static bands in plot area
12
define("BAND_RDIAG",1); // Right diagonal lines
13
define("BAND_LDIAG",2); // Left diagonal lines
14
define("BAND_SOLID",3); // Solid one color
15
define("BAND_VLINE",4); // Vertical lines
16
define("BAND_HLINE",5);  // Horizontal lines
17
define("BAND_3DPLANE",6);  // "3D" Plane
18
define("BAND_HVCROSS",7);  // Vertical/Hor crosses
19
define("BAND_DIAGCROSS",8); // Diagonal crosses
20
 
21
 
22
// Utility class to hold coordinates for a rectangle
23
class Rectangle {
24
    public $x,$y,$w,$h;
25
    public $xe, $ye;
26
    function __construct($aX,$aY,$aWidth,$aHeight) {
27
        $this->x=$aX;
28
        $this->y=$aY;
29
        $this->w=$aWidth;
30
        $this->h=$aHeight;
31
        $this->xe=$aX+$aWidth-1;
32
        $this->ye=$aY+$aHeight-1;
33
    }
34
}
35
 
36
//=====================================================================
37
// Class RectPattern
38
// Base class for pattern hierarchi that is used to display patterned
39
// bands on the graph. Any subclass that doesn't override Stroke()
40
// must at least implement method DoPattern($aImg) which is responsible
41
// for drawing the pattern onto the graph.
42
//=====================================================================
43
class RectPattern {
44
    protected $color;
45
    protected $weight;
46
    protected $rect=null;
47
    protected $doframe=true;
48
    protected $linespacing; // Line spacing in pixels
49
    protected $iBackgroundColor=-1;  // Default is no background fill
50
 
51
    function __construct($aColor,$aWeight=1) {
52
        $this->color = $aColor;
53
        $this->weight = $aWeight;
54
    }
55
 
56
    function SetBackground($aBackgroundColor) {
57
        $this->iBackgroundColor=$aBackgroundColor;
58
    }
59
 
60
    function SetPos($aRect) {
61
        $this->rect = $aRect;
62
    }
63
 
64
    function ShowFrame($aShow=true) {
65
        $this->doframe=$aShow;
66
    }
67
 
68
    function SetDensity($aDens) {
69
        if( $aDens < 1 || $aDens > 100 )
70
        JpGraphError::RaiseL(16001,$aDens);
71
        //(" Desity for pattern must be between 1 and 100. (You tried $aDens)");
72
        // 1% corresponds to linespacing=50
73
        // 100 % corresponds to linespacing 1
74
        $this->linespacing = floor(((100-$aDens)/100.0)*50)+1;
75
 
76
    }
77
 
78
    function Stroke($aImg) {
79
        if( $this->rect == null )
80
        JpGraphError::RaiseL(16002);
81
        //(" No positions specified for pattern.");
82
 
83
        if( !(is_numeric($this->iBackgroundColor) && $this->iBackgroundColor==-1) ) {
84
            $aImg->SetColor($this->iBackgroundColor);
85
            $aImg->FilledRectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye);
86
        }
87
 
88
        $aImg->SetColor($this->color);
89
        $aImg->SetLineWeight($this->weight);
90
 
91
        // Virtual function implemented by subclass
92
        $this->DoPattern($aImg);
93
 
94
        // Frame around the pattern area
95
        if( $this->doframe )
96
        $aImg->Rectangle($this->rect->x,$this->rect->y,$this->rect->xe,$this->rect->ye);
97
    }
98
 
99
}
100
 
101
 
102
//=====================================================================
103
// Class RectPatternSolid
104
// Implements a solid band
105
//=====================================================================
106
class RectPatternSolid extends RectPattern {
107
 
108
    function __construct($aColor="black",$aWeight=1) {
109
        parent::__construct($aColor,$aWeight);
110
    }
111
 
112
    function DoPattern($aImg) {
113
        $aImg->SetColor($this->color);
114
        $aImg->FilledRectangle($this->rect->x,$this->rect->y,
115
        $this->rect->xe,$this->rect->ye);
116
    }
117
}
118
 
119
//=====================================================================
120
// Class RectPatternHor
121
// Implements horizontal line pattern
122
//=====================================================================
123
class RectPatternHor extends RectPattern {
124
 
125
    function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) {
126
        parent::__construct($aColor,$aWeight);
127
        $this->linespacing = $aLineSpacing;
128
    }
129
 
130
    function DoPattern($aImg) {
131
        $x0 = $this->rect->x;
132
        $x1 = $this->rect->xe;
133
        $y = $this->rect->y;
134
        while( $y < $this->rect->ye ) {
135
            $aImg->Line($x0,$y,$x1,$y);
136
            $y += $this->linespacing;
137
        }
138
    }
139
}
140
 
141
//=====================================================================
142
// Class RectPatternVert
143
// Implements vertical line pattern
144
//=====================================================================
145
class RectPatternVert extends RectPattern {
146
 
147
    function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) {
148
        parent::__construct($aColor,$aWeight);
149
        $this->linespacing = $aLineSpacing;
150
    }
151
 
152
    //--------------------
153
    // Private methods
154
    //
155
    function DoPattern($aImg) {
156
        $x = $this->rect->x;
157
        $y0 = $this->rect->y;
158
        $y1 = $this->rect->ye;
159
        while( $x < $this->rect->xe ) {
160
            $aImg->Line($x,$y0,$x,$y1);
161
            $x += $this->linespacing;
162
        }
163
    }
164
}
165
 
166
 
167
//=====================================================================
168
// Class RectPatternRDiag
169
// Implements right diagonal pattern
170
//=====================================================================
171
class RectPatternRDiag extends RectPattern {
172
 
173
    function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) {
174
        parent::__construct($aColor,$aWeight);
175
        $this->linespacing = $aLineSpacing;
176
    }
177
 
178
    function DoPattern($aImg) {
179
        //  --------------------
180
        //  | /   /   /   /   /|
181
        //  |/   /   /   /   / |
182
        //  |   /   /   /   /  |
183
        //  --------------------
184
        $xe = $this->rect->xe;
185
        $ye = $this->rect->ye;
186
        $x0 = $this->rect->x + round($this->linespacing/2);
187
        $y0 = $this->rect->y;
188
        $x1 = $this->rect->x;
189
        $y1 = $this->rect->y + round($this->linespacing/2);
190
 
191
        while($x0<=$xe && $y1<=$ye) {
192
            $aImg->Line($x0,$y0,$x1,$y1);
193
            $x0 += $this->linespacing;
194
            $y1 += $this->linespacing;
195
        }
196
 
197
        if( $xe-$x1 > $ye-$y0 ) {
198
            // Width larger than height
199
            $x1 = $this->rect->x + ($y1-$ye);
200
            $y1 = $ye;
201
            $y0 = $this->rect->y;
202
            while( $x0 <= $xe ) {
203
                $aImg->Line($x0,$y0,$x1,$y1);
204
                $x0 += $this->linespacing;
205
                $x1 += $this->linespacing;
206
            }
207
 
208
            $y0=$this->rect->y + ($x0-$xe);
209
            $x0=$xe;
210
        }
211
        else {
212
            // Height larger than width
213
            $diff = $x0-$xe;
214
            $y0 = $diff+$this->rect->y;
215
            $x0 = $xe;
216
            $x1 = $this->rect->x;
217
            while( $y1 <= $ye ) {
218
                $aImg->Line($x0,$y0,$x1,$y1);
219
                $y1 += $this->linespacing;
220
                $y0 += $this->linespacing;
221
            }
222
 
223
            $diff = $y1-$ye;
224
            $y1 = $ye;
225
            $x1 = $diff + $this->rect->x;
226
        }
227
 
228
        while( $y0 <= $ye ) {
229
            $aImg->Line($x0,$y0,$x1,$y1);
230
            $y0 += $this->linespacing;
231
            $x1 += $this->linespacing;
232
        }
233
    }
234
}
235
 
236
//=====================================================================
237
// Class RectPatternLDiag
238
// Implements left diagonal pattern
239
//=====================================================================
240
class RectPatternLDiag extends RectPattern {
241
 
242
    function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) {
243
        $this->linespacing = $aLineSpacing;
244
        parent::__construct($aColor,$aWeight);
245
    }
246
 
247
    function DoPattern($aImg) {
248
        //  --------------------
249
        //  |\   \   \   \   \ |
250
        //  | \   \   \   \   \|
251
        //  |  \   \   \   \   |
252
        //  |------------------|
253
        $xe = $this->rect->xe;
254
        $ye = $this->rect->ye;
255
        $x0 = $this->rect->x + round($this->linespacing/2);
256
        $y0 = $this->rect->ye;
257
        $x1 = $this->rect->x;
258
        $y1 = $this->rect->ye - round($this->linespacing/2);
259
 
260
        while($x0<=$xe && $y1>=$this->rect->y) {
261
            $aImg->Line($x0,$y0,$x1,$y1);
262
            $x0 += $this->linespacing;
263
            $y1 -= $this->linespacing;
264
        }
265
        if( $xe-$x1 > $ye-$this->rect->y ) {
266
            // Width larger than height
267
            $x1 = $this->rect->x + ($this->rect->y-$y1);
268
            $y0=$ye; $y1=$this->rect->y;
269
            while( $x0 <= $xe ) {
270
                $aImg->Line($x0,$y0,$x1,$y1);
271
                $x0 += $this->linespacing;
272
                $x1 += $this->linespacing;
273
            }
274
 
275
            $y0=$this->rect->ye - ($x0-$xe);
276
            $x0=$xe;
277
        }
278
        else {
279
            // Height larger than width
280
            $diff = $x0-$xe;
281
            $y0 = $ye-$diff;
282
            $x0 = $xe;
283
            while( $y1 >= $this->rect->y ) {
284
                $aImg->Line($x0,$y0,$x1,$y1);
285
                $y0 -= $this->linespacing;
286
                $y1 -= $this->linespacing;
287
            }
288
            $diff = $this->rect->y - $y1;
289
            $x1 = $this->rect->x + $diff;
290
            $y1 = $this->rect->y;
291
        }
292
        while( $y0 >= $this->rect->y ) {
293
            $aImg->Line($x0,$y0,$x1,$y1);
294
            $y0 -= $this->linespacing;
295
            $x1 += $this->linespacing;
296
        }
297
    }
298
}
299
 
300
//=====================================================================
301
// Class RectPattern3DPlane
302
// Implements "3D" plane pattern
303
//=====================================================================
304
class RectPattern3DPlane extends RectPattern {
305
    private $alpha=50;  // Parameter that specifies the distance
306
    // to "simulated" horizon in pixel from the
307
    // top of the band. Specifies how fast the lines
308
    // converge.
309
 
310
    function __construct($aColor="black",$aWeight=1) {
311
        parent::__construct($aColor,$aWeight);
312
        $this->SetDensity(10);  // Slightly larger default
313
    }
314
 
315
    function SetHorizon($aHorizon) {
316
        $this->alpha=$aHorizon;
317
    }
318
 
319
    function DoPattern($aImg) {
320
        // "Fake" a nice 3D grid-effect.
321
        $x0 = $this->rect->x + $this->rect->w/2;
322
        $y0 = $this->rect->y;
323
        $x1 = $x0;
324
        $y1 = $this->rect->ye;
325
        $x0_right = $x0;
326
        $x1_right = $x1;
327
 
328
        // BTW "apa" means monkey in Swedish but is really a shortform for
329
        // "alpha+a" which was the labels I used on paper when I derived the
330
        // geometric to get the 3D perspective right.
331
        // $apa is the height of the bounding rectangle plus the distance to the
332
        // artifical horizon (alpha)
333
        $apa = $this->rect->h + $this->alpha;
334
 
335
        // Three cases and three loops
336
        // 1) The endpoint of the line ends on the bottom line
337
        // 2) The endpoint ends on the side
338
        // 3) Horizontal lines
339
 
340
        // Endpoint falls on bottom line
341
        $middle=$this->rect->x + $this->rect->w/2;
342
        $dist=$this->linespacing;
343
        $factor=$this->alpha /($apa);
344
        while($x1>$this->rect->x) {
345
            $aImg->Line($x0,$y0,$x1,$y1);
346
            $aImg->Line($x0_right,$y0,$x1_right,$y1);
347
            $x1 = $middle - $dist;
348
            $x0 = $middle - $dist * $factor;
349
            $x1_right = $middle + $dist;
350
            $x0_right =  $middle + $dist * $factor;
351
            $dist += $this->linespacing;
352
        }
353
 
354
        // Endpoint falls on sides
355
        $dist -= $this->linespacing;
356
        $d=$this->rect->w/2;
357
        $c = $apa - $d*$apa/$dist;
358
        while( $x0>$this->rect->x ) {
359
            $aImg->Line($x0,$y0,$this->rect->x,$this->rect->ye-$c);
360
            $aImg->Line($x0_right,$y0,$this->rect->xe,$this->rect->ye-$c);
361
            $dist += $this->linespacing;
362
            $x0 = $middle - $dist * $factor;
363
            $x1 = $middle - $dist;
364
            $x0_right =  $middle + $dist * $factor;
365
            $c = $apa - $d*$apa/$dist;
366
        }
367
 
368
        // Horizontal lines
369
        // They need some serious consideration since they are a function
370
        // of perspective depth (alpha) and density (linespacing)
371
        $x0=$this->rect->x;
372
        $x1=$this->rect->xe;
373
        $y=$this->rect->ye;
374
 
375
        // The first line is drawn directly. Makes the loop below slightly
376
        // more readable.
377
        $aImg->Line($x0,$y,$x1,$y);
378
        $hls = $this->linespacing;
379
 
380
        // A correction factor for vertical "brick" line spacing to account for
381
        // a) the difference in number of pixels hor vs vert
382
        // b) visual apperance to make the first layer of "bricks" look more
383
        // square.
384
        $vls = $this->linespacing*0.6;
385
 
386
        $ds = $hls*($apa-$vls)/$apa;
387
        // Get the slope for the "perspective line" going from bottom right
388
        // corner to top left corner of the "first" brick.
389
 
390
        // Uncomment the following lines if you want to get a visual understanding
391
        // of what this helpline does. BTW this mimics the way you would get the
392
        // perspective right when drawing on paper.
393
        /*
394
        $x0 = $middle;
395
        $y0 = $this->rect->ye;
396
        $len=floor(($this->rect->ye-$this->rect->y)/$vls);
397
        $x1 = $middle+round($len*$ds);
398
        $y1 = $this->rect->ye-$len*$vls;
399
        $aImg->PushColor("red");
400
        $aImg->Line($x0,$y0,$x1,$y1);
401
        $aImg->PopColor();
402
        */
403
 
404
        $y -= $vls;
405
        $k=($this->rect->ye-($this->rect->ye-$vls))/($middle-($middle-$ds));
406
        $dist = $hls;
407
        while( $y>$this->rect->y ) {
408
            $aImg->Line($this->rect->x,$y,$this->rect->xe,$y);
409
            $adj = $k*$dist/(1+$dist*$k/$apa);
410
            if( $adj < 2 ) $adj=1;
411
            $y = $this->rect->ye - round($adj);
412
            $dist += $hls;
413
        }
414
    }
415
}
416
 
417
//=====================================================================
418
// Class RectPatternCross
419
// Vert/Hor crosses
420
//=====================================================================
421
class RectPatternCross extends RectPattern {
422
    private $vert=null;
423
    private $hor=null;
424
    function __construct($aColor="black",$aWeight=1) {
425
        parent::__construct($aColor,$aWeight);
426
        $this->vert = new RectPatternVert($aColor,$aWeight);
427
        $this->hor  = new RectPatternHor($aColor,$aWeight);
428
    }
429
 
430
    function SetOrder($aDepth) {
431
        $this->vert->SetOrder($aDepth);
432
        $this->hor->SetOrder($aDepth);
433
    }
434
 
435
    function SetPos($aRect) {
436
        parent::SetPos($aRect);
437
        $this->vert->SetPos($aRect);
438
        $this->hor->SetPos($aRect);
439
    }
440
 
441
    function SetDensity($aDens) {
442
        $this->vert->SetDensity($aDens);
443
        $this->hor->SetDensity($aDens);
444
    }
445
 
446
    function DoPattern($aImg) {
447
        $this->vert->DoPattern($aImg);
448
        $this->hor->DoPattern($aImg);
449
    }
450
}
451
 
452
//=====================================================================
453
// Class RectPatternDiagCross
454
// Vert/Hor crosses
455
//=====================================================================
456
 
457
class RectPatternDiagCross extends RectPattern {
458
    private $left=null;
459
    private $right=null;
460
    function __construct($aColor="black",$aWeight=1) {
461
        parent::__construct($aColor,$aWeight);
462
        $this->right = new RectPatternRDiag($aColor,$aWeight);
463
        $this->left  = new RectPatternLDiag($aColor,$aWeight);
464
    }
465
 
466
    function SetOrder($aDepth) {
467
        $this->left->SetOrder($aDepth);
468
        $this->right->SetOrder($aDepth);
469
    }
470
 
471
    function SetPos($aRect) {
472
        parent::SetPos($aRect);
473
        $this->left->SetPos($aRect);
474
        $this->right->SetPos($aRect);
475
    }
476
 
477
    function SetDensity($aDens) {
478
        $this->left->SetDensity($aDens);
479
        $this->right->SetDensity($aDens);
480
    }
481
 
482
    function DoPattern($aImg) {
483
        $this->left->DoPattern($aImg);
484
        $this->right->DoPattern($aImg);
485
    }
486
 
487
}
488
 
489
//=====================================================================
490
// Class RectPatternFactory
491
// Factory class for rectangular pattern
492
//=====================================================================
493
class RectPatternFactory {
494
    function __construct() {
495
        // Empty
496
    }
497
    function Create($aPattern,$aColor,$aWeight=1) {
498
        switch($aPattern) {
499
            case BAND_RDIAG:
500
                $obj =  new RectPatternRDiag($aColor,$aWeight);
501
                break;
502
            case BAND_LDIAG:
503
                $obj =  new RectPatternLDiag($aColor,$aWeight);
504
                break;
505
            case BAND_SOLID:
506
                $obj =  new RectPatternSolid($aColor,$aWeight);
507
                break;
508
            case BAND_VLINE:
509
                $obj =  new RectPatternVert($aColor,$aWeight);
510
                break;
511
            case BAND_HLINE:
512
                $obj =  new RectPatternHor($aColor,$aWeight);
513
                break;
514
            case BAND_3DPLANE:
515
                $obj =  new RectPattern3DPlane($aColor,$aWeight);
516
                break;
517
            case BAND_HVCROSS:
518
                $obj =  new RectPatternCross($aColor,$aWeight);
519
                break;
520
            case BAND_DIAGCROSS:
521
                $obj =  new RectPatternDiagCross($aColor,$aWeight);
522
                break;
523
            default:
524
                JpGraphError::RaiseL(16003,$aPattern);
525
                //(" Unknown pattern specification ($aPattern)");
526
        }
527
        return $obj;
528
    }
529
}
530
 
531
 
532
//=====================================================================
533
// Class PlotBand
534
// Factory class which is used by the client.
535
// It is responsible for factoring the corresponding pattern
536
// concrete class.
537
//=====================================================================
538
class PlotBand {
539
    public $depth; // Determine if band should be over or under the plots
540
    private $prect=null;
541
    private $dir, $min, $max;
542
 
543
    function __construct($aDir,$aPattern,$aMin,$aMax,$aColor="black",$aWeight=1,$aDepth=DEPTH_BACK) {
544
        $f =  new RectPatternFactory();
545
        $this->prect = $f->Create($aPattern,$aColor,$aWeight);
546
        if( is_numeric($aMin) && is_numeric($aMax) && ($aMin > $aMax) )
547
        JpGraphError::RaiseL(16004);
548
        //('Min value for plotband is larger than specified max value. Please correct.');
549
        $this->dir = $aDir;
550
        $this->min = $aMin;
551
        $this->max = $aMax;
552
        $this->depth=$aDepth;
553
    }
554
 
555
    // Set position. aRect contains absolute image coordinates
556
    function SetPos($aRect) {
557
        assert( $this->prect != null ) ;
558
        $this->prect->SetPos($aRect);
559
    }
560
 
561
    function ShowFrame($aFlag=true) {
562
        $this->prect->ShowFrame($aFlag);
563
    }
564
 
565
    // Set z-order. In front of pplot or in the back
566
    function SetOrder($aDepth) {
567
        $this->depth=$aDepth;
568
    }
569
 
570
    function SetDensity($aDens) {
571
        $this->prect->SetDensity($aDens);
572
    }
573
 
574
    function GetDir() {
575
        return $this->dir;
576
    }
577
 
578
    function GetMin() {
579
        return $this->min;
580
    }
581
 
582
    function GetMax() {
583
        return $this->max;
584
    }
585
 
586
    function PreStrokeAdjust($aGraph) {
587
        // Nothing to do
588
    }
589
 
590
    // Display band
591
    function Stroke($aImg,$aXScale,$aYScale) {
592
        assert( $this->prect != null ) ;
593
        if( $this->dir == HORIZONTAL ) {
594
            if( $this->min === 'min' ) $this->min = $aYScale->GetMinVal();
595
            if( $this->max === 'max' ) $this->max = $aYScale->GetMaxVal();
596
 
597
            // Only draw the bar if it actually appears in the range
598
            if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) {
599
 
600
                // Trucate to limit of axis
601
                $this->min = max($this->min, $aYScale->GetMinVal());
602
                $this->max = min($this->max, $aYScale->GetMaxVal());
603
 
604
                $x=$aXScale->scale_abs[0];
605
                $y=$aYScale->Translate($this->max);
606
                $width=$aXScale->scale_abs[1]-$aXScale->scale_abs[0]+1;
607
                $height=abs($y-$aYScale->Translate($this->min))+1;
608
                $this->prect->SetPos(new Rectangle($x,$y,$width,$height));
609
                $this->prect->Stroke($aImg);
610
            }
611
        }
612
        else { // VERTICAL
613
            if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal();
614
            if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal();
615
 
616
            // Only draw the bar if it actually appears in the range
617
            if ($this->min < $aXScale->GetMaxVal() && $this->max > $aXScale->GetMinVal()) {
618
 
619
                // Trucate to limit of axis
620
                $this->min = max($this->min, $aXScale->GetMinVal());
621
                $this->max = min($this->max, $aXScale->GetMaxVal());
622
 
623
                $y=$aYScale->scale_abs[1];
624
                $x=$aXScale->Translate($this->min);
625
                $height=abs($aYScale->scale_abs[1]-$aYScale->scale_abs[0]);
626
                $width=abs($x-$aXScale->Translate($this->max));
627
                $this->prect->SetPos(new Rectangle($x,$y,$width,$height));
628
                $this->prect->Stroke($aImg);
629
            }
630
        }
631
    }
632
}
633
 
634
 
635
?>