source: contrib/ProjectManager/inc/jpgraph-1.5.2/src/jpgraph_spider.php @ 3594

Revision 3594, 16.5 KB checked in by afernandes, 13 years ago (diff)

Ticket #1416 - Disponibilizado o módulo ProjectManager? para a comunidade

  • Property svn:executable set to *
Line 
1<?php
2/*=======================================================================
3// File:        JPGRAPH_SPIDER.PHP
4// Description: Spider plot extension for JpGraph
5// Created:     2001-02-04
6// Author:      Johan Persson (johanp@aditus.nu)
7// Ver:         $Id: jpgraph_spider.php 18250 2005-05-07 14:13:43Z ralfbecker $
8//
9// License:     This code is released under GPL 2.0
10// Copyright (C) 2001 Johan Persson
11//========================================================================
12*/
13
14//===================================================
15// CLASS FontProp
16// Description: Utility class to enable the use
17// of a "title" instance variable for the spider axis.
18// This clas is only used to hold a font and a color
19// property for the axis title.
20//===================================================
21class FontProp {
22    var $font_family=FF_FONT1, $font_style=FS_NORMAL,$font_size=14,$font_color=array(0,0,0);   
23    function SetFont($family,$style=FS_NORMAL,$size=14) {
24        $this->font_family = $family;
25        $this->font_style = $style;
26        $this->font_size = $size;
27    }
28       
29    function SetColor($c) {
30        $this->font_color = $c;
31    }
32}
33
34class SpiderLogTicks extends Ticks {
35//---------------
36// CONSTRUCTOR
37    function SpiderLogTicks() {
38    }
39//---------------
40// PUBLIC METHODS       
41
42    // TODO: Add Argument grid
43    function Stroke(&$aImg,&$grid,$aPos,$aAxisAngle,&$aScale,&$aMajPos,&$aMajLabel) {
44        $start = $aScale->GetMinVal();
45        $limit = $aScale->GetMaxVal();
46        $nextMajor = 10*$start;
47        $step = $nextMajor / 10.0;
48        $count=1;
49                               
50        $ticklen_maj=5;
51        $dx_maj=round(sin($aAxisAngle)*$ticklen_maj);
52        $dy_maj=round(cos($aAxisAngle)*$ticklen_maj);
53        $ticklen_min=3;
54        $dx_min=round(sin($aAxisAngle)*$ticklen_min);
55        $dy_min=round(cos($aAxisAngle)*$ticklen_min);
56                       
57        $aMajPos=array();
58        $aMajLabel=array();
59                       
60        if( $this->supress_first )
61            $aMajLabel[]="";
62        else
63            $aMajLabel[]=$start;       
64        $yr=$aScale->RelTranslate($start);     
65        $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0];
66        $yt=$aPos-round($yr*sin($aAxisAngle));
67        $aMajPos[]=$xt+2*$dx_maj;
68        $aMajPos[]=$yt-$aImg->GetFontheight()/2;
69        $grid[]=$xt;
70        $grid[]=$yt;
71
72        $aImg->SetLineWeight($this->weight);                   
73               
74        for($y=$start; $y<=$limit; $y+=$step,++$count  ) {
75            $yr=$aScale->RelTranslate($y);     
76            $xt=round($yr*cos($aAxisAngle))+$aScale->scale_abs[0];
77            $yt=$aPos-round($yr*sin($aAxisAngle));
78            if( $count % 10 == 0 ) {
79                $grid[]=$xt;
80                $grid[]=$yt;
81                $aMajPos[]=$xt+2*$dx_maj;
82                $aMajPos[]=$yt-$aImg->GetFontheight()/2;                                                       
83                if( !$this->supress_tickmarks ) {               
84                    if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor);
85                    $aImg->Line($xt+$dx_maj,$yt+$dy_maj,$xt-$dx_maj,$yt-$dy_maj);
86                    if( $this->majcolor!="" ) $aImg->PopColor();
87                }
88                $aMajLabel[]=$nextMajor;       
89                $nextMajor *= 10;
90                $step *= 10;   
91                $count=1;                               
92            }
93            else
94                if( !$this->supress_minor_tickmarks )   {
95                    if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor);
96                    $aImg->Line($xt+$dx_min,$yt+$dy_min,$xt-$dx_min,$yt-$dy_min);
97                    if( $this->mincolor!="" ) $aImg->PopColor();
98                }
99        }               
100    }           
101}
102       
103class SpiderLinearTicks extends LinearTicks {
104//---------------
105// CONSTRUCTOR
106    function SpiderLinearTicks() {
107        // Empty
108    }
109
110//---------------
111// PUBLIC METHODS       
112
113    // TODO: Add argument grid
114    function Stroke(&$aImg,&$grid,$aPos,$aAxisAngle,&$aScale,&$aMajPos,&$aMajLabel) {
115        // Prepare to draw linear ticks
116        $maj_step_abs = abs($aScale->scale_factor*$this->major_step);   
117        $min_step_abs = abs($aScale->scale_factor*$this->minor_step);   
118        $nbrmaj = floor(($aScale->world_abs_size)/$maj_step_abs);
119        $nbrmin = floor(($aScale->world_abs_size)/$min_step_abs);
120        $skip = round($nbrmin/$nbrmaj); // Don't draw minor ontop of major
121
122        // Draw major ticks
123        $ticklen2=4;
124        $dx=round(sin($aAxisAngle)*$ticklen2);
125        $dy=round(cos($aAxisAngle)*$ticklen2);
126        $label=$aScale->scale[0]+$this->major_step;
127               
128        $aImg->SetLineWeight($this->weight);
129               
130        for($i=1; $i<=$nbrmaj; ++$i) {
131            $xt=round($i*$maj_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0];
132            $yt=$aPos-round($i*$maj_step_abs*sin($aAxisAngle));
133            $aMajLabel[]=$label;
134            $label += $this->major_step;
135            $grid[]=$xt;
136            $grid[]=$yt;
137            $aMajPos[($i-1)*2]=$xt+2*$dx;
138            $aMajPos[($i-1)*2+1]=$yt-$aImg->GetFontheight()/2;                         
139            if( !$this->supress_tickmarks ) {
140                if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor);
141                $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy);
142                if( $this->majcolor!="" ) $aImg->PopColor();
143            }
144        }
145
146        // Draw minor ticks
147        $ticklen2=3;
148        $dx=round(sin($aAxisAngle)*$ticklen2);
149        $dy=round(cos($aAxisAngle)*$ticklen2);
150        if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks)       {
151            if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor);                                               
152            for($i=1; $i<=$nbrmin; ++$i) {
153                if( ($i % $skip) == 0 ) continue;
154                $xt=round($i*$min_step_abs*cos($aAxisAngle))+$aScale->scale_abs[0];
155                $yt=$pos-round($i*$min_step_abs*sin($aAxisAngle));
156                $aImg->Line($xt+$dx,$yt+$dy,$xt-$dx,$yt-$dy);
157            }
158            if( $this->mincolor!="" ) $aImg->PopColor();
159        }
160    }
161}
162
163       
164
165//===================================================
166// CLASS SpiderAxis
167// Description: Implements axis for the spider graph
168//===================================================
169class SpiderAxis extends Axis {
170    var $title_color="navy";
171    var $title=null;
172//---------------
173// CONSTRUCTOR
174    function SpiderAxis(&$img,&$aScale,$color=array(0,0,0)) {
175        parent::Axis($img,$aScale,$color);
176        $this->len=$img->plotheight;
177        $this->font_size = FF_FONT1;
178        $this->title = new FontProp();
179        $this->color = array(0,0,0);
180    }
181//---------------
182// PUBLIC METHODS       
183    function SetTickLabels($l) {
184        $this->ticks_label = $l;
185    }
186       
187       
188    // Stroke the axis
189    // $pos                     = Vertical position of axis
190    // $aAxisAngle = Axis angle
191    // $grid                    = Returns an array with positions used to draw the grid
192    //  $lf                     = Label flag, TRUE if the axis should have labels
193    function Stroke($pos,$aAxisAngle,&$grid,$title,$lf) {
194        $this->img->SetColor($this->color);
195               
196        // Determine end points for the axis
197        $x=round($this->scale->world_abs_size*cos($aAxisAngle)+$this->scale->scale_abs[0]);
198        $y=round($pos-$this->scale->world_abs_size*sin($aAxisAngle));
199               
200        // Draw axis
201        $this->img->SetColor($this->color);
202        $this->img->SetLineWeight($this->weight);
203        if( !$this->hide )
204            $this->img->Line($this->scale->scale_abs[0],$pos,$x,$y);
205       
206        $this->scale->ticks->Stroke($this->img,$grid,$pos,$aAxisAngle,$this->scale,$majpos,$majlabel);
207               
208        // Draw labels
209        if( $lf && !$this->hide ) {
210            $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
211            $this->img->SetTextAlign("left","top");
212            $this->img->SetColor($this->color);
213                       
214            // majpos contsins (x,y) coordinates for labels
215            for($i=0; $i<count($majpos)/2; ++$i) {
216                if( $this->ticks_label != null )
217                    $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$this->ticks_label[$i]);
218                else
219                    $this->img->StrokeText($majpos[$i*2],$majpos[$i*2+1],$majlabel[$i]);
220            }
221        }
222        $this->_StrokeAxisTitle($pos,$aAxisAngle,$title);
223    }
224//---------------
225// PRIVATE METHODS     
226       
227    function _StrokeAxisTitle($pos,$aAxisAngle,$title) {
228        // Draw title of this axis
229        $this->img->SetFont($this->title->font_family,$this->title->font_style,$this->title->font_size);
230        $this->img->SetColor($this->title->font_color);
231        $marg=6;
232        $xt=round(($this->scale->world_abs_size+$marg)*cos($aAxisAngle)+$this->scale->scale_abs[0]);
233        $yt=round($pos-($this->scale->world_abs_size+$marg)*sin($aAxisAngle));
234
235        // Position the axis title.
236        // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
237        // that intersects with the extension of the corresponding axis. The code looks a little
238        // bit messy but this is really the only way of having a reasonable position of the
239        // axis titles.
240        $h=$this->img->GetFontHeight();
241        $w=$this->img->GetTextWidth($title);
242        while( $aAxisAngle > 2*M_PI ) $aAxisAngle -= 2*M_PI;
243        if( $aAxisAngle>=7*M_PI/4 || $aAxisAngle <= M_PI/4 ) $dx=0;
244        if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dx=($aAxisAngle-M_PI/4)*2/M_PI;
245        if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dx=1;
246        if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dx=(1-($aAxisAngle-M_PI*5/4)*2/M_PI);
247               
248        if( $aAxisAngle>=7*M_PI/4 ) $dy=(($aAxisAngle-M_PI)-3*M_PI/4)*2/M_PI;
249        if( $aAxisAngle<=M_PI/4 ) $dy=(1-$aAxisAngle*2/M_PI);
250        if( $aAxisAngle>=M_PI/4 && $aAxisAngle <= 3*M_PI/4 ) $dy=1;
251        if( $aAxisAngle>=3*M_PI/4 && $aAxisAngle <= 5*M_PI/4 ) $dy=(1-($aAxisAngle-3*M_PI/4)*2/M_PI);
252        if( $aAxisAngle>=5*M_PI/4 && $aAxisAngle <= 7*M_PI/4 ) $dy=0;
253               
254        if( !$this->hide )
255            $this->img->StrokeText($xt-$dx*$w,$yt-$dy*$h,$title);
256
257    }
258               
259       
260} // Class
261
262
263//===================================================
264// CLASS SpiderGrid
265// Description: Draws grid for the spider graph
266//===================================================
267class SpiderGrid extends Grid {
268//------------
269// CONSTRUCTOR
270    function SpiderGrid() {
271    }
272
273//----------------
274// PRIVATE METHODS     
275    function Stroke(&$img,&$grid) {
276        if( !$this->show ) return;
277        $nbrticks = count($grid[0])/2;
278        $nbrpnts = count($grid);
279        $img->SetColor($this->grid_color);
280        $img->SetLineWeight($this->weight);
281        for($i=0; $i<$nbrticks; ++$i) {
282            for($j=0; $j<$nbrpnts; ++$j) {
283                $pnts[$j*2]=$grid[$j][$i*2];
284                $pnts[$j*2+1]=$grid[$j][$i*2+1];
285            }
286            for($k=0; $k<$nbrpnts; ++$k ){
287                $l=($k+1)%$nbrpnts;
288                if( $this->type == "solid" )
289                    $img->Line($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1]);
290                elseif( $this->type == "dotted" )
291                    $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],1,6);
292                elseif( $this->type == "dashed" )
293                    $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],2,4);
294                elseif( $this->type == "longdashed" )
295                    $img->DashedLine($pnts[$k*2],$pnts[$k*2+1],$pnts[$l*2],$pnts[$l*2+1],8,6);
296            }
297            $pnts=array();
298        }
299    }
300} // Class
301
302
303//===================================================
304// CLASS SpiderPlot
305// Description: Plot a spiderplot
306//===================================================
307class SpiderPlot {
308    var $data=array();
309    var $fill=false, $fill_color=array(200,170,180);
310    var $color=array(0,0,0);
311    var $legend="";
312    var $weight=1;
313//---------------
314// CONSTRUCTOR
315    function SpiderPlot($data) {
316        $this->data = $data;
317    }
318
319//---------------
320// PUBLIC METHODS       
321    function Min() {
322        return Min($this->data);
323    }
324       
325    function Max() {
326        return Max($this->data);
327    }
328       
329    function SetLegend($legend) {
330        $this->legend=$legend;
331    }
332       
333    function SetFill($f=true) {
334        $this->fill = $f;
335    }
336       
337    function SetLineWeight($w) {
338        $this->weight=$w;
339    }
340               
341    function SetColor($color,$fill_color=array(160,170,180)) {
342        $this->color = $color;
343        $this->fill_color = $fill_color;
344    }
345       
346    function GetCSIMareas() {
347        JpGraphError::Raise("JpGraph Error: Client side image maps not supported for SpiderPlots.");
348    }
349       
350    function Stroke(&$img, $pos, &$scale, $startangle) {
351        $nbrpnts = count($this->data);
352        $astep=2*M_PI/$nbrpnts;         
353        $a=$startangle;
354               
355        // Rotate each point to the correct axis-angle
356        // TODO: Update for LogScale
357        for($i=0; $i<$nbrpnts; ++$i) {
358            //$c=$this->data[$i];
359            $cs=$scale->RelTranslate($this->data[$i]);
360            $x=round($cs*cos($a)+$scale->scale_abs[0]);
361            $y=round($pos-$cs*sin($a));
362            /*
363              $c=log10($c);
364              $x=round(($c-$scale->scale[0])*$scale->scale_factor*cos($a)+$scale->scale_abs[0]);
365              $y=round($pos-($c-$scale->scale[0])*$scale->scale_factor*sin($a));               
366            */
367            $pnts[$i*2]=$x;
368            $pnts[$i*2+1]=$y;
369            $a += $astep;
370        }
371        if( $this->fill ) {
372            $img->SetColor($this->fill_color);
373            $img->FilledPolygon($pnts);
374        }
375        $img->SetLineWeight($this->weight);
376        $img->SetColor($this->color);
377        $img->Polygon($pnts);
378    }
379       
380//---------------
381// PRIVATE METHODS
382    function GetCount() {
383        return count($this->data);
384    }
385       
386    function Legend(&$graph) {
387        if( $this->legend=="" ) return;
388        if( $this->fill )
389            $graph->legend->Add($this->legend,$this->fill_color);
390        else
391            $graph->legend->Add($this->legend,$this->color);   
392    }
393       
394} // Class
395
396//===================================================
397// CLASS SpiderGraph
398// Description: Main container for a spider graph
399//===================================================
400class SpiderGraph extends Graph {
401    var $posx;
402    var $posy;
403    var $len;           
404    var $plots=null, $axis_title=null;
405    var $grid,$axis=null;
406//---------------
407// CONSTRUCTOR
408    function SpiderGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) {
409        $this->Graph($width,$height,$cachedName,$timeout,$inline);
410        $this->posx=$width/2;
411        $this->posy=$height/2;
412        $this->len=min($width,$height)*0.35;
413        $this->SetColor(array(255,255,255));
414        $this->SetTickDensity(TICKD_NORMAL);
415        $this->SetScale("lin");
416    }
417
418//---------------
419// PUBLIC METHODS
420    function SupressTickMarks($f=true) {
421        $this->axis->scale->ticks->SupressTickMarks($f);
422    }
423       
424    function SetScale($axtype,$ymin=1,$ymax=1) {
425        if( $axtype != "lin" && $axtype != "log" ) {
426            JpGraphError::Raise("Illegal scale for spiderplot ($axtype). Must be \"lin\" or \"log\"");
427        }
428        if( $axtype=="lin" ) {
429            $this->yscale = & new LinearScale(1,1);
430            $this->yscale->ticks = & new SpiderLinearTicks();
431            $this->yscale->ticks->SupressMinorTickMarks();
432        }
433        elseif( $axtype=="log" ) {
434            $this->yscale = & new LogScale(1,1);
435            $this->yscale->ticks = & new SpiderLogTicks();
436            //JpGraphError::Raise("JpGraph Error: Logarithmic spider plots are not yet supported");
437        }
438               
439        $this->axis = & new SpiderAxis($this->img,$this->yscale);
440        $this->grid = & new SpiderGrid();               
441    }
442
443    function SetPlotSize($s) {
444        if( $s<0.1 || $s>1 )
445            JpGraphError::Raise("JpGraph Error: Spider Plot size must be between 0.1 and 1. (Your value=$s)");
446        $this->len=min($this->img->width,$this->img->height)*$s/2;
447    }
448
449    function SetTickDensity($densy=TICKD_NORMAL) {
450        $this->ytick_factor=25;         
451        switch( $densy ) {
452            case TICKD_DENSE:
453                $this->ytick_factor=12;                 
454            break;
455            case TICKD_NORMAL:
456                $this->ytick_factor=25;                 
457            break;
458            case TICKD_SPARSE:
459                $this->ytick_factor=40;                 
460            break;
461            case TICKD_VERYSPARSE:
462                $this->ytick_factor=70;                 
463            break;             
464            default:
465                JpGraphError::Raise("Unsupported Tick density: $densy");
466        }
467    }
468
469    function SetCenter($px,$py=0.5) {
470        assert($px > 0 && $py > 0 );
471        $this->posx=$this->img->width*$px;
472        $this->posy=$this->img->height*$py;
473    }
474
475    function SetColor($c) {
476        $this->SetMarginColor($c);
477    }
478                       
479    function SetTitles($title) {
480        $this->axis_title = $title;
481    }
482
483    function Add(&$splot) {
484        $this->plots[]=$splot;
485    }
486       
487    function GetPlotsYMinMax() {
488        $min=$this->plots[0]->Min();
489        $max=$this->plots[0]->Max();
490        foreach( $this->plots as $p ) {
491            $max=max($max,$p->Max());
492            $min=min($min,$p->Min());
493        }
494        if( $min < 0 )
495            JpGraphError::Raise("JpGraph Error: Minimum data $min (Spider plots only makes sence to use when all data points > 0)");
496        return array($min,$max);
497    }   
498
499    // Stroke the Spider graph
500    function Stroke($aStrokeFileName="") {
501        // Set Y-scale
502        if( !$this->yscale->IsSpecified() &&
503        count($this->plots)>0 ) {
504            list($min,$max) = $this->GetPlotsYMinMax();
505            $this->yscale->AutoScale($this->img,0,$max,$this->len/$this->ytick_factor);
506        }
507        // Set start position end length of scale (in absolute pixels)
508        $this->yscale->SetConstants($this->posx,$this->len);
509               
510        // We need as many axis as there are data points
511        $nbrpnts=$this->plots[0]->GetCount();
512               
513        // If we have no titles just number the axis 1,2,3,...
514        if( $this->axis_title==null ) {
515            for($i=0; $i<$nbrpnts; ++$i )
516                $this->axis_title[$i] = $i+1;
517        }
518        elseif(count($this->axis_title)<$nbrpnts)
519            JpGraphError::Raise("JpGraph: Number of titles does not match number of points in plot.");
520        for($i=0; $i<count($this->plots); ++$i )
521            if( $nbrpnts != $this->plots[$i]->GetCount() )
522                JpGraphError::Raise("JpGraph: Each spider plot must have the same number of data points.");
523
524        $this->StrokeFrame();
525        $astep=2*M_PI/$nbrpnts;
526
527        // Prepare legends
528        for($i=0; $i<count($this->plots); ++$i)
529            $this->plots[$i]->Legend($this);
530        $this->legend->Stroke($this->img);                     
531               
532        // Plot points
533        $a=M_PI/2;
534        for($i=0; $i<count($this->plots); ++$i )
535            $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a);
536               
537        // Draw axis and grid
538        for( $i=0,$a=M_PI/2; $i<$nbrpnts; ++$i, $a+=$astep ) {
539            $this->axis->Stroke($this->posy,$a,$grid[$i],$this->axis_title[$i],$i==0);
540        }       
541        $this->grid->Stroke($this->img,$grid);
542        $this->title->Center($this->img->left_margin,$this->img->width-$this->img->right_margin,5);
543        $this->title->Stroke($this->img);
544               
545        // Stroke texts
546        if( $this->texts != null )
547            foreach( $this->texts as $t)
548                $t->Stroke($this->img);
549       
550                       
551        // Finally output the image
552        $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);       
553    }
554} // Class
555
556/* EOF */
557?>
Note: See TracBrowser for help on using the repository browser.