source: trunk/client/modules/Elezioni/grafici/jpgraph_plotband.php@ 417

Last change on this file since 417 was 284, checked in by roby, 6 years ago
File size: 20.6 KB
RevLine 
[2]1<?php
2//=======================================================================
[284]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 $
[2]7//
[284]8// Copyright (c) Asial Corporation. All rights reserved.
[2]9//========================================================================
10
11// Constants for types of static bands in plot area
[284]12define("BAND_RDIAG",1); // Right diagonal lines
[2]13define("BAND_LDIAG",2); // Left diagonal lines
14define("BAND_SOLID",3); // Solid one color
15define("BAND_VLINE",4); // Vertical lines
16define("BAND_HLINE",5); // Horizontal lines
17define("BAND_3DPLANE",6); // "3D" Plane
18define("BAND_HVCROSS",7); // Vertical/Hor crosses
19define("BAND_DIAGCROSS",8); // Diagonal crosses
20
21
22// Utility class to hold coordinates for a rectangle
23class Rectangle {
24 public $x,$y,$w,$h;
25 public $xe, $ye;
[284]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;
[2]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//=====================================================================
43class RectPattern {
44 protected $color;
45 protected $weight;
46 protected $rect=null;
47 protected $doframe=true;
[284]48 protected $linespacing; // Line spacing in pixels
[2]49 protected $iBackgroundColor=-1; // Default is no background fill
[284]50
51 function __construct($aColor,$aWeight=1) {
52 $this->color = $aColor;
53 $this->weight = $aWeight;
[2]54 }
55
56 function SetBackground($aBackgroundColor) {
[284]57 $this->iBackgroundColor=$aBackgroundColor;
[2]58 }
59
60 function SetPos($aRect) {
[284]61 $this->rect = $aRect;
[2]62 }
[284]63
[2]64 function ShowFrame($aShow=true) {
[284]65 $this->doframe=$aShow;
[2]66 }
67
68 function SetDensity($aDens) {
[284]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;
[2]75
76 }
77
78 function Stroke($aImg) {
[284]79 if( $this->rect == null )
80 JpGraphError::RaiseL(16002);
81 //(" No positions specified for pattern.");
[2]82
[284]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 }
[2]87
[284]88 $aImg->SetColor($this->color);
89 $aImg->SetLineWeight($this->weight);
[2]90
[284]91 // Virtual function implemented by subclass
92 $this->DoPattern($aImg);
[2]93
[284]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);
[2]97 }
98
99}
100
101
102//=====================================================================
103// Class RectPatternSolid
104// Implements a solid band
105//=====================================================================
106class RectPatternSolid extends RectPattern {
107
[284]108 function __construct($aColor="black",$aWeight=1) {
109 parent::__construct($aColor,$aWeight);
[2]110 }
111
112 function DoPattern($aImg) {
[284]113 $aImg->SetColor($this->color);
114 $aImg->FilledRectangle($this->rect->x,$this->rect->y,
115 $this->rect->xe,$this->rect->ye);
[2]116 }
117}
118
119//=====================================================================
120// Class RectPatternHor
121// Implements horizontal line pattern
122//=====================================================================
123class RectPatternHor extends RectPattern {
[284]124
125 function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) {
126 parent::__construct($aColor,$aWeight);
127 $this->linespacing = $aLineSpacing;
[2]128 }
[284]129
[2]130 function DoPattern($aImg) {
[284]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 }
[2]138 }
139}
140
141//=====================================================================
142// Class RectPatternVert
143// Implements vertical line pattern
144//=====================================================================
145class RectPatternVert extends RectPattern {
[284]146
147 function __construct($aColor="black",$aWeight=1,$aLineSpacing=7) {
148 parent::__construct($aColor,$aWeight);
149 $this->linespacing = $aLineSpacing;
[2]150 }
151
152 //--------------------
153 // Private methods
154 //
155 function DoPattern($aImg) {
[284]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 }
[2]163 }
164}
165
166
167//=====================================================================
168// Class RectPatternRDiag
169// Implements right diagonal pattern
170//=====================================================================
171class RectPatternRDiag extends RectPattern {
[284]172
173 function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) {
174 parent::__construct($aColor,$aWeight);
175 $this->linespacing = $aLineSpacing;
[2]176 }
177
178 function DoPattern($aImg) {
[284]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);
[2]190
[284]191 while($x0<=$xe && $y1<=$ye) {
192 $aImg->Line($x0,$y0,$x1,$y1);
193 $x0 += $this->linespacing;
194 $y1 += $this->linespacing;
195 }
[2]196
[284]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 }
[2]227
[284]228 while( $y0 <= $ye ) {
229 $aImg->Line($x0,$y0,$x1,$y1);
230 $y0 += $this->linespacing;
231 $x1 += $this->linespacing;
232 }
[2]233 }
234}
[284]235
[2]236//=====================================================================
237// Class RectPatternLDiag
238// Implements left diagonal pattern
239//=====================================================================
240class RectPatternLDiag extends RectPattern {
[284]241
242 function __construct($aColor="black",$aWeight=1,$aLineSpacing=12) {
243 $this->linespacing = $aLineSpacing;
244 parent::__construct($aColor,$aWeight);
[2]245 }
246
247 function DoPattern($aImg) {
[284]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);
[2]259
[284]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 }
[2]297 }
298}
299
300//=====================================================================
301// Class RectPattern3DPlane
302// Implements "3D" plane pattern
303//=====================================================================
304class 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
[284]310 function __construct($aColor="black",$aWeight=1) {
311 parent::__construct($aColor,$aWeight);
312 $this->SetDensity(10); // Slightly larger default
[2]313 }
314
315 function SetHorizon($aHorizon) {
[284]316 $this->alpha=$aHorizon;
[2]317 }
[284]318
[2]319 function DoPattern($aImg) {
[284]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;
[2]327
[284]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;
[2]334
[284]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
[2]339
[284]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 }
[2]353
[284]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 }
[2]414 }
415}
416
417//=====================================================================
418// Class RectPatternCross
419// Vert/Hor crosses
420//=====================================================================
421class RectPatternCross extends RectPattern {
422 private $vert=null;
423 private $hor=null;
[284]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);
[2]428 }
429
430 function SetOrder($aDepth) {
[284]431 $this->vert->SetOrder($aDepth);
432 $this->hor->SetOrder($aDepth);
[2]433 }
434
435 function SetPos($aRect) {
[284]436 parent::SetPos($aRect);
437 $this->vert->SetPos($aRect);
438 $this->hor->SetPos($aRect);
[2]439 }
440
441 function SetDensity($aDens) {
[284]442 $this->vert->SetDensity($aDens);
443 $this->hor->SetDensity($aDens);
[2]444 }
445
446 function DoPattern($aImg) {
[284]447 $this->vert->DoPattern($aImg);
448 $this->hor->DoPattern($aImg);
[2]449 }
450}
451
452//=====================================================================
453// Class RectPatternDiagCross
454// Vert/Hor crosses
455//=====================================================================
456
457class RectPatternDiagCross extends RectPattern {
458 private $left=null;
459 private $right=null;
[284]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);
[2]464 }
465
466 function SetOrder($aDepth) {
[284]467 $this->left->SetOrder($aDepth);
468 $this->right->SetOrder($aDepth);
[2]469 }
470
471 function SetPos($aRect) {
[284]472 parent::SetPos($aRect);
473 $this->left->SetPos($aRect);
474 $this->right->SetPos($aRect);
[2]475 }
476
477 function SetDensity($aDens) {
[284]478 $this->left->SetDensity($aDens);
479 $this->right->SetDensity($aDens);
[2]480 }
481
482 function DoPattern($aImg) {
[284]483 $this->left->DoPattern($aImg);
484 $this->right->DoPattern($aImg);
[2]485 }
486
487}
488
489//=====================================================================
490// Class RectPatternFactory
[284]491// Factory class for rectangular pattern
[2]492//=====================================================================
493class RectPatternFactory {
[284]494 function __construct() {
495 // Empty
[2]496 }
497 function Create($aPattern,$aColor,$aWeight=1) {
[284]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;
[2]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//=====================================================================
538class PlotBand {
539 public $depth; // Determine if band should be over or under the plots
540 private $prect=null;
541 private $dir, $min, $max;
542
[284]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;
[2]553 }
[284]554
[2]555 // Set position. aRect contains absolute image coordinates
556 function SetPos($aRect) {
[284]557 assert( $this->prect != null ) ;
558 $this->prect->SetPos($aRect);
[2]559 }
[284]560
[2]561 function ShowFrame($aFlag=true) {
[284]562 $this->prect->ShowFrame($aFlag);
[2]563 }
564
565 // Set z-order. In front of pplot or in the back
566 function SetOrder($aDepth) {
[284]567 $this->depth=$aDepth;
[2]568 }
[284]569
[2]570 function SetDensity($aDens) {
[284]571 $this->prect->SetDensity($aDens);
[2]572 }
[284]573
[2]574 function GetDir() {
[284]575 return $this->dir;
[2]576 }
[284]577
[2]578 function GetMin() {
[284]579 return $this->min;
[2]580 }
[284]581
[2]582 function GetMax() {
[284]583 return $this->max;
[2]584 }
585
586 function PreStrokeAdjust($aGraph) {
[284]587 // Nothing to do
[2]588 }
[284]589
[2]590 // Display band
591 function Stroke($aImg,$aXScale,$aYScale) {
[284]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();
[2]596
597 // Only draw the bar if it actually appears in the range
598 if ($this->min < $aYScale->GetMaxVal() && $this->max > $aYScale->GetMinVal()) {
[284]599
600 // Trucate to limit of axis
601 $this->min = max($this->min, $aYScale->GetMinVal());
602 $this->max = min($this->max, $aYScale->GetMaxVal());
[2]603
[284]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);
[2]610 }
[284]611 }
612 else { // VERTICAL
613 if( $this->min === 'min' ) $this->min = $aXScale->GetMinVal();
614 if( $this->max === 'max' ) $this->max = $aXScale->GetMaxVal();
615
[2]616 // Only draw the bar if it actually appears in the range
[284]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());
[2]622
[284]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);
[2]629 }
[284]630 }
[2]631 }
632}
633
634
635?>
Note: See TracBrowser for help on using the repository browser.