Ignore:
Timestamp:
Apr 14, 2019, 2:31:40 PM (5 years ago)
Author:
roby
Message:
 
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/client/modules/Elezioni/grafici/jpgraph_pie.php

    r265 r267  
    11<?php
    22/*=======================================================================
    3  // File:        JPGRAPH_PIE.PHP
    4  // Description: Pie plot extension for JpGraph
    5  // Created:     2001-02-14
    6  // Ver:         $Id: jpgraph_pie.php 1926 2010-01-11 16:33:07Z ljp $
    7  //
    8  // Copyright (c) Asial Corporation. All rights reserved.
    9  //========================================================================
    10  */
     3// File:        JPGRAPH_PIE.PHP
     4// Description: Pie plot extension for JpGraph
     5// Created:     2001-02-14
     6// Ver:         $Id: jpgraph_pie.php 1091 2009-01-18 22:57:40Z ljp $
     7//
     8// Copyright (c) Aditus Consulting. All rights reserved.
     9//========================================================================
     10*/
    1111
    1212
     
    2424class PiePlot {
    2525    public $posx=0.5,$posy=0.5;
    26     public $is_using_plot_theme = false;
    27     public $theme="earth";
    28     protected $use_plot_theme_colors = false;
    2926    protected $radius=0.3;
    3027    protected $explode_radius=array(),$explode_all=false,$explode_r=20;
    3128    protected $labels=null, $legends=null;
    3229    protected $csimtargets=null,$csimwintargets=null;  // Array of targets for CSIM
    33     protected $csimareas='';  // Generated CSIM text
    34     protected $csimalts=null;  // ALT tags for corresponding target
     30    protected $csimareas='';            // Generated CSIM text 
     31    protected $csimalts=null;           // ALT tags for corresponding target
    3532    protected $data=null;
    3633    public $title;
     
    3936    protected $legend_margin=6,$show_labels=true;
    4037    protected $themearr = array(
    41  "earth"  => array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430),
    42  "pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38),
    43  "water"  => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388),
    44  "sand"   => array(27,168,34,170,19,50,65,72,131,209,46,393));
     38        "earth"         => array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430),
     39        "pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38),
     40        "water"  => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388),
     41        "sand"   => array(27,168,34,170,19,50,65,72,131,209,46,393));
     42    protected $theme="earth";
    4543    protected $setslicecolors=array();
    4644    protected $labeltype=0; // Default to percentage
     
    5654    protected $iGuideLineCurve = false,$iGuideVFactor=1.4,$iGuideLineRFactor=0.8;
    5755    protected $la = array(); // Holds the exact angle for each label
    58 
    59     //---------------
    60     // CONSTRUCTOR
    61     function __construct($data) {
    62         $this->data = array_reverse($data);
    63         $this->title = new Text("");
    64         $this->title->SetFont(FF_DEFAULT,FS_BOLD);
    65         $this->value = new DisplayValue();
    66         $this->value->Show();
    67         $this->value->SetFormat('%.1f%%');
    68         $this->guideline = new LineProperty();
    69     }
    70 
    71     //---------------
    72     // PUBLIC METHODS
     56       
     57//---------------
     58// CONSTRUCTOR
     59    function PiePlot($data) {
     60        $this->data = array_reverse($data);
     61        $this->title = new Text("");
     62        $this->title->SetFont(FF_FONT1,FS_BOLD);
     63        $this->value = new DisplayValue();
     64        $this->value->Show();
     65        $this->value->SetFormat('%.1f%%');
     66        $this->guideline = new LineProperty();
     67    }
     68
     69//---------------
     70// PUBLIC METHODS       
    7371    function SetCenter($x,$y=0.5) {
    74         $this->posx = $x;
    75         $this->posy = $y;
     72        $this->posx = $x;
     73        $this->posy = $y;
    7674    }
    7775
    7876    // Enable guideline and set drwaing policy
    7977    function SetGuideLines($aFlg=true,$aCurved=true,$aAlways=false) {
    80         $this->guideline->Show($aFlg);
    81         $this->iShowGuideLineForSingle = $aAlways;
    82         $this->iGuideLineCurve = $aCurved;
     78        $this->guideline->Show($aFlg);
     79        $this->iShowGuideLineForSingle = $aAlways;
     80        $this->iGuideLineCurve = $aCurved;
    8381    }
    8482
    8583    // Adjuste the distance between labels and labels and pie
    8684    function SetGuideLinesAdjust($aVFactor,$aRFactor=0.8) {
    87         $this->iGuideVFactor=$aVFactor;
    88         $this->iGuideLineRFactor=$aRFactor;
     85        $this->iGuideVFactor=$aVFactor;
     86        $this->iGuideLineRFactor=$aRFactor;
    8987    }
    9088
    9189    function SetColor($aColor) {
    92         $this->color = $aColor;
    93     }
    94 
     90        $this->color = $aColor;
     91    }
     92       
    9593    function SetSliceColors($aColors) {
    96         $this->setslicecolors = $aColors;
    97     }
    98 
     94        $this->setslicecolors = $aColors;
     95    }
     96       
    9997    function SetShadow($aColor='darkgray',$aDropWidth=4) {
    100         $this->ishadowcolor = $aColor;
    101         $this->ishadowdrop = $aDropWidth;
     98        $this->ishadowcolor = $aColor;
     99        $this->ishadowdrop = $aDropWidth;
    102100    }
    103101
    104102    function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') {
    105         $this->csimtargets=array_reverse($aTargets);
    106         if( is_array($aWinTargets) )
    107         $this->csimwintargets=array_reverse($aWinTargets);
    108         if( is_array($aAlts) )
    109         $this->csimalts=array_reverse($aAlts);
    110     }
    111 
     103        $this->csimtargets=array_reverse($aTargets);
     104        if( is_array($aWinTargets) )
     105            $this->csimwintargets=array_reverse($aWinTargets);
     106        if( is_array($aAlts) )
     107            $this->csimalts=array_reverse($aAlts);
     108    }
     109       
    112110    function GetCSIMareas() {
    113         return $this->csimareas;
    114     }
    115 
    116     function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) {
     111        return $this->csimareas;
     112    }
     113
     114    function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { 
    117115        //Slice number, ellipse centre (x,y), height, width, start angle, end angle
    118         while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;
    119         while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;
    120 
    121         $sa = 2*M_PI - $sa;
    122         $ea = 2*M_PI - $ea;
    123 
    124         // Special case when we have only one slice since then both start and end
    125         // angle will be == 0
    126         if( abs($sa - $ea) < 0.0001 ) {
    127             $sa=2*M_PI; $ea=0;
    128         }
    129 
    130         //add coordinates of the centre to the map
    131         $xc = floor($xc);$yc=floor($yc);
    132         $coords = "$xc, $yc";
    133 
    134         //add coordinates of the first point on the arc to the map
    135         $xp = floor(($radius*cos($ea))+$xc);
    136         $yp = floor($yc-$radius*sin($ea));
    137         $coords.= ", $xp, $yp";
    138 
    139         //add coordinates every 0.2 radians
    140         $a=$ea+0.2;
    141 
    142         // If we cross the 360-limit with a slice we need to handle
    143         // the fact that end angle is smaller than start
    144         if( $sa < $ea ) {
    145             while ($a <= 2*M_PI) {
    146                 $xp = floor($radius*cos($a)+$xc);
    147                 $yp = floor($yc-$radius*sin($a));
    148                 $coords.= ", $xp, $yp";
    149                 $a += 0.2;
    150             }
    151             $a -= 2*M_PI;
    152         }
    153 
    154 
    155         while ($a < $sa) {
    156             $xp = floor($radius*cos($a)+$xc);
    157             $yp = floor($yc-$radius*sin($a));
    158             $coords.= ", $xp, $yp";
    159             $a += 0.2;
    160         }
    161 
    162         //Add the last point on the arc
    163         $xp = floor($radius*cos($sa)+$xc);
    164         $yp = floor($yc-$radius*sin($sa));
    165         $coords.= ", $xp, $yp";
    166         if( !empty($this->csimtargets[$i]) ) {
    167             $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\"";
    168             $tmp="";
    169             if( !empty($this->csimwintargets[$i]) ) {
    170                 $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
    171             }
    172             if( !empty($this->csimalts[$i]) ) {
    173                 $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
    174                 $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" ";
    175             }
    176             $this->csimareas .= " />\n";
    177         }
    178     }
    179 
    180 
     116        while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;
     117        while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;
     118
     119        $sa = 2*M_PI - $sa;
     120        $ea = 2*M_PI - $ea;
     121
     122        // Special case when we have only one slice since then both start and end
     123        // angle will be == 0
     124        if( abs($sa - $ea) < 0.0001 ) {
     125            $sa=2*M_PI; $ea=0;
     126        }
     127
     128        //add coordinates of the centre to the map
     129        $xc = floor($xc);$yc=floor($yc);
     130        $coords = "$xc, $yc";
     131
     132        //add coordinates of the first point on the arc to the map
     133        $xp = floor(($radius*cos($ea))+$xc);
     134        $yp = floor($yc-$radius*sin($ea));
     135        $coords.= ", $xp, $yp";
     136       
     137        //add coordinates every 0.2 radians
     138        $a=$ea+0.2;
     139
     140        // If we cross the 360-limit with a slice we need to handle
     141        // the fact that end angle is smaller than start
     142        if( $sa < $ea ) {
     143            while ($a <= 2*M_PI) {
     144                $xp = floor($radius*cos($a)+$xc);
     145                $yp = floor($yc-$radius*sin($a));
     146                $coords.= ", $xp, $yp";
     147                $a += 0.2;
     148            }
     149            $a -= 2*M_PI;
     150        }
     151
     152
     153        while ($a < $sa) {
     154            $xp = floor($radius*cos($a)+$xc);
     155            $yp = floor($yc-$radius*sin($a));
     156            $coords.= ", $xp, $yp";
     157            $a += 0.2;
     158        }
     159               
     160        //Add the last point on the arc
     161        $xp = floor($radius*cos($sa)+$xc);
     162        $yp = floor($yc-$radius*sin($sa));
     163        $coords.= ", $xp, $yp";
     164        if( !empty($this->csimtargets[$i]) ) {
     165            $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\"";
     166            $tmp="";
     167            if( !empty($this->csimwintargets[$i]) ) {
     168                $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
     169            }
     170            if( !empty($this->csimalts[$i]) ) {
     171                $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
     172                $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" ";
     173            }
     174            $this->csimareas .= " />\n";
     175        }
     176    }
     177
     178       
    181179    function SetTheme($aTheme) {
    182 //        JpGraphError::RaiseL(15012,$aTheme);
    183 //        return;
    184 
    185         if( in_array($aTheme,array_keys($this->themearr)) ) {
    186             $this->theme = $aTheme;
    187             $this->is_using_plot_theme = true;
    188         } else {
    189             JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme");
    190         }
    191     }
    192 
     180        if( in_array($aTheme,array_keys($this->themearr)) )
     181            $this->theme = $aTheme;
     182        else
     183            JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme");
     184    }
     185       
    193186    function ExplodeSlice($e,$radius=20) {
    194         if( ! is_integer($e) )
    195         JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer');
    196         $this->explode_radius[$e]=$radius;
     187        if( ! is_integer($e) )
     188            JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer');
     189        $this->explode_radius[$e]=$radius;
    197190    }
    198191
    199192    function ExplodeAll($radius=20) {
    200         $this->explode_all=true;
    201         $this->explode_r = $radius;
     193        $this->explode_all=true;
     194        $this->explode_r = $radius;
    202195    }
    203196
    204197    function Explode($aExplodeArr) {
    205         if( !is_array($aExplodeArr) ) {
    206             JpGraphError::RaiseL(15003);
    207             //("Argument to PiePlot::Explode() must be an array with integer distances.");
    208         }
    209         $this->explode_radius = $aExplodeArr;
     198        if( !is_array($aExplodeArr) ) {
     199            JpGraphError::RaiseL(15003);
     200//("Argument to PiePlot::Explode() must be an array with integer distances.");
     201        }
     202        $this->explode_radius = $aExplodeArr;
    210203    }
    211204
    212205    function SetStartAngle($aStart) {
    213         if( $aStart < 0 || $aStart > 360 ) {
    214             JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.');
    215         }
    216         if( $aStart == 0 ) {
    217             $this->startangle = 0;
    218         }
    219         else {
    220             $this->startangle = 360-$aStart;
    221             $this->startangle *= M_PI/180;
    222         }
    223     }
    224 
     206        if( $aStart < 0 || $aStart > 360 ) {
     207            JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.');
     208        }
     209        $this->startangle = 360-$aStart;
     210        $this->startangle *= M_PI/180;
     211    }
     212       
     213    function SetFont($family,$style=FS_NORMAL,$size=10) {
     214        JpGraphError::RaiseL(15005);//('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.');
     215    }
     216       
    225217    // Size in percentage
    226218    function SetSize($aSize) {
    227         if( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) )
    228         $this->radius = $aSize;
    229         else
    230         JpGraphError::RaiseL(15006);
    231         //("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels  in the range [10, 1000]");
    232     }
    233 
     219        if( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) )
     220            $this->radius = $aSize;
     221        else
     222            JpGraphError::RaiseL(15006);
     223//("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels  in the range [10, 1000]");
     224    }
     225       
     226    function SetFontColor($aColor) {
     227        JpGraphError::RaiseL(15007);
     228//('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.');
     229    }
     230       
    234231    // Set label arrays
    235232    function SetLegends($aLegend) {
    236         $this->legends = $aLegend;
    237     }
    238 
    239     // Set text labels for slices
     233        $this->legends = $aLegend;
     234    }
     235
     236    // Set text labels for slices 
    240237    function SetLabels($aLabels,$aLblPosAdj="auto") {
    241         $this->labels = array_reverse($aLabels);
    242         $this->ilabelposadj=$aLblPosAdj;
     238        $this->labels = array_reverse($aLabels);
     239        $this->ilabelposadj=$aLblPosAdj;
    243240    }
    244241
    245242    function SetLabelPos($aLblPosAdj) {
    246         $this->ilabelposadj=$aLblPosAdj;
    247     }
    248 
     243        $this->ilabelposadj=$aLblPosAdj;
     244    }
     245       
    249246    // Should we display actual value or percentage?
    250     function SetLabelType($aType) {
    251         if( $aType < 0 || $aType > 2 )
    252                 JpGraphError::RaiseL(15008,$aType);
    253                 //("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t).");
    254         $this->labeltype = $aType;
    255     }
    256 
    257     // Deprecated.
     247    function SetLabelType($t) {
     248        if( $t < 0 || $t > 2 )
     249            JpGraphError::RaiseL(15008,$t);
     250//("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t).");
     251        $this->labeltype=$t;
     252    }
     253
     254    // Deprecated. 
    258255    function SetValueType($aType) {
    259         $this->SetLabelType($aType);
     256        $this->SetLabelType($aType);
    260257    }
    261258
    262259    // Should the circle around a pie plot be displayed
    263260    function ShowBorder($exterior=true,$interior=true) {
    264         $this->pie_border = $exterior;
    265         $this->pie_interior_border = $interior;
    266     }
    267 
     261        $this->pie_border = $exterior;
     262        $this->pie_interior_border = $interior;
     263    }
     264       
    268265    // Setup the legends
    269266    function Legend($graph) {
    270         $colors = array_keys($graph->img->rgb->rgb_table);
    271         sort($colors);
    272         $ta=$this->themearr[$this->theme];
    273         $n = count($this->data);
    274 
    275         if( $this->setslicecolors==null ) {
    276             $numcolors=count($ta);
    277             if( class_exists('PiePlot3D',false) && ($this instanceof PiePlot3D) ) {
    278                 $ta = array_reverse(array_slice($ta,0,$n));
    279             }
    280         }
    281         else {
    282             $this->setslicecolors = array_slice($this->setslicecolors,0,$n);
    283             $numcolors=count($this->setslicecolors);
    284             if( $graph->pieaa && !($this instanceof PiePlot3D) ) {
    285                 $this->setslicecolors = array_reverse($this->setslicecolors);
    286             }
    287         }
    288 
    289         $sum=0;
    290         for($i=0; $i < $n; ++$i)
    291             $sum += $this->data[$i];
    292 
    293         // Bail out with error if the sum is 0
    294         if( $sum==0 )
    295         JpGraphError::RaiseL(15009);//("Illegal pie plot. Sum of all data is zero for Pie!");
    296 
    297         // Make sure we don't plot more values than data points
    298         // (in case the user added more legends than data points)
    299         $legendsCount = is_array($this->legends) ? count($this->legends) : 0;
    300         $n = min($legendsCount,count($this->data));
    301         if( $this->legends != "" ) {
    302             $this->legends = array_reverse(array_slice($this->legends,0,$n));
    303         }
    304         for( $i=$n-1; $i >= 0; --$i ) {
    305             $l = $this->legends[$i];
    306             // Replace possible format with actual values
    307             $count = is_array($this->csimalts) ? count($this->csimalts) : 0;
    308             if( $count > $i ) {
    309                 $fmt = $this->csimalts[$i];
    310             }
    311             else {
    312                 $fmt = "%d"; // Deafult Alt if no other has been specified
    313             }
    314             if( $this->labeltype==0 ) {
    315                 $l = sprintf($l,100*$this->data[$i]/$sum);
    316                 $alt = sprintf($fmt,$this->data[$i]);
    317 
    318             }
    319             elseif( $this->labeltype == 1)  {
    320                 $l = sprintf($l,$this->data[$i]);
    321                 $alt = sprintf($fmt,$this->data[$i]);
    322 
    323             }
    324             else {
    325                 $l = sprintf($l,$this->adjusted_data[$i]);
    326                 $alt = sprintf($fmt,$this->adjusted_data[$i]);
    327             }
    328 
    329             if( empty($this->csimwintargets[$i]) ) {
    330                 $wintarg = '';
    331             }
    332             else {
    333                 $wintarg = $this->csimwintargets[$i];
    334             }
    335 
    336             if( $this->setslicecolors==null ) {
    337                 $graph->legend->Add($l,$colors[$ta[$i%$numcolors]],"",0,$this->csimtargets[$i],$alt,$wintarg);
    338             }
    339             else {
    340                 $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],"",0,$this->csimtargets[$i],$alt,$wintarg);
    341             }
    342         }
    343     }
    344 
     267        $colors = array_keys($graph->img->rgb->rgb_table);
     268        sort($colors); 
     269        $ta=$this->themearr[$this->theme];     
     270        $n = count($this->data);
     271
     272        if( $this->setslicecolors==null ) {
     273            $numcolors=count($ta);
     274            if( class_exists('PiePlot3D',false) && ($this instanceof PiePlot3D) ) {
     275                $ta = array_reverse(array_slice($ta,0,$n));
     276            }
     277        }
     278        else {
     279            $this->setslicecolors = array_slice($this->setslicecolors,0,$n);
     280            $numcolors=count($this->setslicecolors);
     281            if( $graph->pieaa && !($this instanceof PiePlot3D) ) {
     282                $this->setslicecolors = array_reverse($this->setslicecolors);
     283            }
     284        }
     285               
     286        $sum=0;
     287        for($i=0; $i < $n; ++$i)
     288            $sum += $this->data[$i];
     289
     290        // Bail out with error if the sum is 0
     291        if( $sum==0 )
     292            JpGraphError::RaiseL(15009);//("Illegal pie plot. Sum of all data is zero for Pie!");
     293
     294        // Make sure we don't plot more values than data points
     295        // (in case the user added more legends than data points)
     296        $n = min(count($this->legends),count($this->data));
     297        if( $this->legends != "" ) {
     298            $this->legends = array_reverse(array_slice($this->legends,0,$n));
     299        }
     300        for( $i=$n-1; $i >= 0; --$i ) {
     301            $l = $this->legends[$i];
     302            // Replace possible format with actual values
     303            if( count($this->csimalts) > $i ) {
     304                $fmt = $this->csimalts[$i];
     305            }
     306            else {
     307                $fmt = "%d"; // Deafult Alt if no other has been specified
     308            }
     309            if( $this->labeltype==0 ) {
     310                $l = sprintf($l,100*$this->data[$i]/$sum);
     311                $alt = sprintf($fmt,$this->data[$i]);
     312               
     313            }
     314            elseif( $this->labeltype == 1)  {
     315                $l = sprintf($l,$this->data[$i]);
     316                $alt = sprintf($fmt,$this->data[$i]);
     317               
     318            }
     319            else {
     320                $l = sprintf($l,$this->adjusted_data[$i]);
     321                $alt = sprintf($fmt,$this->adjusted_data[$i]);
     322            }
     323
     324            if( empty($this->csimwintargets[$i]) ) {
     325                $wintarg = '';
     326            }
     327            else {
     328                $wintarg = $this->csimwintargets[$i];
     329            }
     330
     331            if( $this->setslicecolors==null ) {
     332                $graph->legend->Add($l,$colors[$ta[$i%$numcolors]],"",0,$this->csimtargets[$i],$alt,$wintarg);
     333            }
     334            else {
     335                $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],"",0,$this->csimtargets[$i],$alt,$wintarg);
     336            }
     337        }
     338    }
     339       
    345340    // Adjust the rounded percetage value so that the sum of
    346341    // of the pie slices are always 100%
    347342    // Using the Hare/Niemeyer method
    348343    function AdjPercentage($aData,$aPrec=0) {
    349         $mul=100;
    350         if( $aPrec > 0 && $aPrec < 3 ) {
    351             if( $aPrec == 1 )
    352             $mul=1000;
    353             else
    354             $mul=10000;
    355         }
    356 
    357         $tmp = array();
    358         $result = array();
    359         $quote_sum=0;
    360         $n = count($aData) ;
    361         for( $i=0, $sum=0; $i < $n; ++$i )
    362         $sum+=$aData[$i];
    363         foreach($aData as $index => $value) {
    364             $tmp_percentage=$value/$sum*$mul;
    365             $result[$index]=floor($tmp_percentage);
    366             $tmp[$index]=$tmp_percentage-$result[$index];
    367             $quote_sum+=$result[$index];
    368         }
    369         if( $quote_sum == $mul) {
    370             if( $mul > 100 ) {
    371                 $tmp = $mul / 100;
    372                 for( $i=0; $i < $n; ++$i ) {
    373                     $result[$i] /= $tmp ;
    374                 }
    375             }
    376             return $result;
    377         }
    378         arsort($tmp,SORT_NUMERIC);
    379         reset($tmp);
    380         for($i=0; $i < $mul-$quote_sum; $i++)
    381         {
    382             $result[key($tmp)]++;
    383             next($tmp);
    384         }
    385         if( $mul > 100 ) {
    386             $tmp = $mul / 100;
    387             for( $i=0; $i < $n; ++$i ) {
    388                 $result[$i] /= $tmp ;
    389             }
    390         }
    391         return $result;
     344        $mul=100;
     345        if( $aPrec > 0 && $aPrec < 3 ) {
     346            if( $aPrec == 1 )
     347                $mul=1000;
     348                else
     349                    $mul=10000;
     350        }
     351       
     352        $tmp = array();
     353        $result = array();
     354        $quote_sum=0;
     355        $n = count($aData) ;
     356        for( $i=0, $sum=0; $i < $n; ++$i )
     357            $sum+=$aData[$i];
     358        foreach($aData as $index => $value) {
     359            $tmp_percentage=$value/$sum*$mul;
     360            $result[$index]=floor($tmp_percentage);
     361            $tmp[$index]=$tmp_percentage-$result[$index];
     362            $quote_sum+=$result[$index];
     363        }
     364        if( $quote_sum == $mul) {
     365            if( $mul > 100 ) {
     366                $tmp = $mul / 100;
     367                for( $i=0; $i < $n; ++$i ) {
     368                    $result[$i] /= $tmp ;
     369                }
     370            }
     371            return $result;
     372        }
     373        arsort($tmp,SORT_NUMERIC);
     374        reset($tmp);
     375        for($i=0; $i < $mul-$quote_sum; $i++)
     376        {
     377            $result[key($tmp)]++;
     378            next($tmp);
     379        }
     380        if( $mul > 100 ) {
     381            $tmp = $mul / 100;
     382            for( $i=0; $i < $n; ++$i ) {
     383                $result[$i] /= $tmp ;
     384            }
     385        }
     386        return $result;
    392387    }
    393388
    394389
    395390    function Stroke($img,$aaoption=0) {
    396         // aaoption is used to handle antialias
    397         // aaoption == 0 a normal pie
    398         // aaoption == 1 just the body
    399         // aaoption == 2 just the values
    400 
    401         // Explode scaling. If anti alias we scale the image
    402         // twice and we also need to scale the exploding distance
    403         $expscale = $aaoption === 1 ? 2 : 1;
    404 
    405         if( $this->labeltype == 2 ) {
    406             // Adjust the data so that it will add up to 100%
    407             $this->adjusted_data = $this->AdjPercentage($this->data);
    408         }
    409 
    410         if ($this->use_plot_theme_colors) {
    411             $this->setslicecolors = null;
    412         }
    413 
    414         $colors = array_keys($img->rgb->rgb_table);
    415         sort($colors);
    416         $ta=$this->themearr[$this->theme];
    417         $n = count($this->data);
    418 
    419         if( $this->setslicecolors==null ) {
    420             $numcolors=count($ta);
    421         }
    422         else {
    423             // We need to create an array of colors as long as the data
    424             // since we need to reverse it to get the colors in the right order
    425             $numcolors=count($this->setslicecolors);
    426             $i = 2*$numcolors;
    427             while( $n > $i ) {
    428                 $this->setslicecolors = array_merge($this->setslicecolors,$this->setslicecolors);
    429                 $i += $n;
    430             }
    431             $tt = array_slice($this->setslicecolors,0,$n % $numcolors);
    432             $this->setslicecolors = array_merge($this->setslicecolors,$tt);
    433             $this->setslicecolors = array_reverse($this->setslicecolors);
    434         }
    435 
    436         // Draw the slices
    437         $sum=0;
    438         for($i=0; $i < $n; ++$i)
    439             $sum += $this->data[$i];
    440 
    441         // Bail out with error if the sum is 0
    442         if( $sum==0 ) {
    443             JpGraphError::RaiseL(15009);//("Sum of all data is 0 for Pie.");
    444         }
    445 
    446         // Set up the pie-circle
    447         if( $this->radius <= 1 ) {
    448             $radius = floor($this->radius*min($img->width,$img->height));
    449         }
    450         else {
    451             $radius = $aaoption === 1 ? $this->radius*2 : $this->radius;
    452         }
    453 
    454         if( $this->posx <= 1 && $this->posx > 0 ) {
    455             $xc = round($this->posx*$img->width);
    456         }
    457         else {
    458             $xc = $this->posx ;
    459         }
    460 
    461         if( $this->posy <= 1 && $this->posy > 0 ) {
    462             $yc = round($this->posy*$img->height);
    463         }
    464         else {
    465             $yc = $this->posy ;
    466         }
    467 
    468         $n = count($this->data);
    469 
    470         if( $this->explode_all ) {
    471             for($i=0; $i < $n; ++$i) {
    472                 $this->explode_radius[$i]=$this->explode_r;
    473             }
    474         }
    475 
    476         // If we have a shadow and not just drawing the labels
    477         if( $this->ishadowcolor != "" && $aaoption !== 2) {
    478             $accsum=0;
    479             $angle2 = $this->startangle;
    480             $img->SetColor($this->ishadowcolor);
    481             for($i=0; $sum > 0 && $i < $n; ++$i) {
    482                 $j = $n-$i-1;
    483                 $d = $this->data[$i];
    484                 $angle1 = $angle2;
    485                 $accsum += $d;
    486                 $angle2 = $this->startangle+2*M_PI*$accsum/$sum;
    487                 if( empty($this->explode_radius[$j]) ) {
    488                     $this->explode_radius[$j]=0;
    489                 }
    490 
    491                 if( $d < 0.00001 ) continue;
    492 
    493                 $la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);
    494 
    495                 $xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale;
    496                 $ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale;
    497 
    498                 $xcm += $this->ishadowdrop*$expscale;
    499                 $ycm += $this->ishadowdrop*$expscale;
    500 
    501                 $_sa = round($angle1*180/M_PI);
    502                 $_ea = round($angle2*180/M_PI);
    503 
    504                 // The CakeSlice method draws a full circle in case of start angle = end angle
    505                 // for pie slices we don't want this behaviour unless we only have one
    506                 // slice in the pie in case it is the wanted behaviour
    507                 if( $_ea-$_sa > 0.1 || $n==1 ) {
    508                     $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,
    509                     $angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor);
    510                 }
    511             }
    512         }
    513 
    514         //--------------------------------------------------------------------------------
    515         // This is the main loop to draw each cake slice
    516         //--------------------------------------------------------------------------------
    517 
    518         // Set up the accumulated sum, start angle for first slice and border color
    519         $accsum=0;
    520         $angle2 = $this->startangle;
    521         $img->SetColor($this->color);
    522 
    523         // Loop though all the slices if there is a pie to draw (sum>0)
    524         // There are n slices in total
    525         for($i=0; $sum>0 && $i < $n; ++$i) {
    526 
    527             // $j is the actual index used for the slice
    528             $j = $n-$i-1;
    529 
    530             // Make sure we havea  valid distance to explode the slice
    531             if( empty($this->explode_radius[$j]) ) {
    532                 $this->explode_radius[$j]=0;
    533             }
    534 
    535             // The actual numeric value for the slice
    536             $d = $this->data[$i];
    537 
    538             $angle1 = $angle2;
    539 
    540             // Accumlate the sum
    541             $accsum += $d;
    542 
    543             // The new angle when we add the "size" of this slice
    544             // angle1 is then the start and angle2 the end of this slice
    545             $angle2 = $this->NormAngle($this->startangle+2*M_PI*$accsum/$sum);
    546 
    547             // We avoid some trouble by not allowing end angle to be 0, in that case
    548             // we translate to 360
    549 
    550             // la is used to hold the label angle, which is centered on the slice
    551             if( $angle2 < 0.0001 && $angle1 > 0.0001 ) {
    552                 $this->la[$i] = 2*M_PI - (abs(2*M_PI-$angle1)/2.0+$angle1);
    553             }
    554             elseif( $angle1 > $angle2 ) {
    555                 // The case where the slice crosses the 3 a'clock line
    556                 // Remember that the slices are counted clockwise and
    557                 // labels are counted counter clockwise so we need to revert with 2 PI
    558                 $this->la[$i] = 2*M_PI-$this->NormAngle($angle1 + ((2*M_PI - $angle1)+$angle2)/2);
    559             }
    560             else {
    561                 $this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);
    562             }
    563 
    564             // Too avoid rounding problems we skip the slice if it is too small
    565             if( $d < 0.00001 ) continue;
    566 
    567             // If the user has specified an array of colors for each slice then use
    568             // that a color otherwise use the theme array (ta) of colors
    569             if( $this->setslicecolors==null ) {
    570                 $slicecolor=$colors[$ta[$i%$numcolors]];
    571             }
    572             else {
    573                 $slicecolor=$this->setslicecolors[$i%$numcolors];
    574             }
    575 
    576 //            $_sa = round($angle1*180/M_PI);
    577 //            $_ea = round($angle2*180/M_PI);
    578 //            $_la = round($this->la[$i]*180/M_PI);
    579 //            echo "Slice#$i: ang1=$_sa , ang2=$_ea, la=$_la, color=$slicecolor<br>";
    580 
    581 
    582             // If we have enabled antialias then we don't draw any border so
    583             // make the bordedr color the same as the slice color
    584             if( $this->pie_interior_border && $aaoption===0 ) {
    585                 $img->SetColor($this->color);
    586             }
    587             else {
    588                 $img->SetColor($slicecolor);
    589             }
    590             $arccolor = $this->pie_border && $aaoption===0 ? $this->color : "";
    591 
    592             // Calculate the x,y coordinates for the base of this slice taking
    593             // the exploded distance into account. Here we use the mid angle as the
    594             // ray of extension and we have the mid angle handy as it is also the
    595             // label angle
    596             $xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale;
    597             $ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale;
    598 
    599             // If we are not just drawing the labels then draw this cake slice
    600             if( $aaoption !== 2 ) {
    601 
    602                 $_sa = round($angle1*180/M_PI);
    603                 $_ea = round($angle2*180/M_PI);
    604                 $_la = round($this->la[$i]*180/M_PI);
    605                 //echo "[$i] sa=$_sa, ea=$_ea, la[$i]=$_la, (color=$slicecolor)<br>";
    606 
    607                 // The CakeSlice method draws a full circle in case of start angle = end angle
    608                 // for pie slices we want this in case the slice have a value larger than 99% of the
    609                 // total sum
    610                 if( abs($_ea-$_sa) >= 1 || $d == $sum ) {
    611                     $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,$_sa,$_ea,$slicecolor,$arccolor);
    612                 }
    613             }
    614 
    615             // If the CSIM is used then make sure we register a CSIM area for this slice as well
    616             if( $this->csimtargets && $aaoption !== 1 ) {
    617                 $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2);
    618             }
    619         }
    620 
    621         // Format the titles for each slice
    622         if( $aaoption !== 2 ) {
    623             for( $i=0; $i < $n; ++$i) {
    624                 if( $this->labeltype==0 ) {
    625                     if( $sum != 0 )
    626                     $l = 100.0*$this->data[$i]/$sum;
    627                     else
    628                     $l = 0.0;
    629                 }
    630                 elseif( $this->labeltype==1 ) {
    631                     $l = $this->data[$i]*1.0;
    632                 }
    633                 else {
    634                     $l = $this->adjusted_data[$i];
    635                 }
    636                 if( isset($this->labels[$i]) && is_string($this->labels[$i]) )
    637                 $this->labels[$i]=sprintf($this->labels[$i],$l);
    638                 else
    639                 $this->labels[$i]=$l;
    640             }
    641         }
    642 
    643         if( $this->value->show && $aaoption !== 1 ) {
    644             $this->StrokeAllLabels($img,$xc,$yc,$radius);
    645         }
    646 
    647         // Adjust title position
    648         if( $aaoption !== 1 ) {
    649             $this->title->SetPos($xc,
    650             $yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin,
    651      "center","bottom");
    652             $this->title->Stroke($img);
    653         }
    654 
    655     }
    656 
    657     //---------------
    658     // PRIVATE METHODS
     391        // aaoption is used to handle antialias
     392        // aaoption == 0 a normal pie
     393        // aaoption == 1 just the body
     394        // aaoption == 2 just the values
     395
     396        // Explode scaling. If anti anti alias we scale the image
     397        // twice and we also need to scale the exploding distance
     398        $expscale = $aaoption === 1 ? 2 : 1;
     399
     400        if( $this->labeltype == 2 ) {
     401            // Adjust the data so that it will add up to 100%
     402            $this->adjusted_data = $this->AdjPercentage($this->data);
     403        }
     404
     405        $colors = array_keys($img->rgb->rgb_table);
     406        sort($colors); 
     407        $ta=$this->themearr[$this->theme];     
     408        $n = count($this->data);
     409       
     410        if( $this->setslicecolors==null ) {
     411            $numcolors=count($ta);
     412        }
     413        else {
     414            // We need to create an array of colors as long as the data
     415            // since we need to reverse it to get the colors in the right order
     416            $numcolors=count($this->setslicecolors);
     417            $i = 2*$numcolors;
     418            while( $n > $i ) {
     419                $this->setslicecolors = array_merge($this->setslicecolors,$this->setslicecolors);
     420                $i += $n;
     421            }
     422            $tt = array_slice($this->setslicecolors,0,$n % $numcolors);
     423            $this->setslicecolors = array_merge($this->setslicecolors,$tt);
     424            $this->setslicecolors = array_reverse($this->setslicecolors);
     425        }
     426
     427        // Draw the slices
     428        $sum=0;
     429        for($i=0; $i < $n; ++$i)
     430            $sum += $this->data[$i];
     431       
     432        // Bail out with error if the sum is 0
     433        if( $sum==0 )
     434            JpGraphError::RaiseL(15009);//("Sum of all data is 0 for Pie.");
     435       
     436        // Set up the pie-circle
     437        if( $this->radius <= 1 )
     438            $radius = floor($this->radius*min($img->width,$img->height));
     439        else {
     440            $radius = $aaoption === 1 ? $this->radius*2 : $this->radius;
     441        }
     442
     443        if( $this->posx <= 1 && $this->posx > 0 )
     444            $xc = round($this->posx*$img->width);
     445        else
     446            $xc = $this->posx ;
     447       
     448        if( $this->posy <= 1 && $this->posy > 0 )
     449            $yc = round($this->posy*$img->height);
     450        else
     451            $yc = $this->posy ;
     452               
     453        $n = count($this->data);
     454
     455        if( $this->explode_all )
     456            for($i=0; $i < $n; ++$i)
     457                $this->explode_radius[$i]=$this->explode_r;
     458
     459        // If we have a shadow and not just drawing the labels
     460        if( $this->ishadowcolor != "" && $aaoption !== 2) {
     461            $accsum=0;
     462            $angle2 = $this->startangle;
     463            $img->SetColor($this->ishadowcolor);
     464            for($i=0; $sum > 0 && $i < $n; ++$i) {
     465                $j = $n-$i-1;
     466                $d = $this->data[$i];
     467                $angle1 = $angle2;
     468                $accsum += $d;
     469                $angle2 = $this->startangle+2*M_PI*$accsum/$sum;
     470                if( empty($this->explode_radius[$j]) )
     471                    $this->explode_radius[$j]=0;
     472
     473                if( $d < 0.00001 ) continue;
     474
     475                $la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);
     476
     477                $xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale;
     478                $ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale;
     479               
     480                $xcm += $this->ishadowdrop*$expscale;
     481                $ycm += $this->ishadowdrop*$expscale;
     482
     483                $_sa = round($angle1*180/M_PI);
     484                $_ea = round($angle2*180/M_PI);
     485
     486                // The CakeSlice method draws a full circle in case of start angle = end angle
     487                // for pie slices we don't want this behaviour unless we only have one
     488                // slice in the pie in case it is the wanted behaviour
     489                if( $_ea-$_sa > 0.1 || $n==1 ) {
     490                    $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,
     491                                    $angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor);
     492                }
     493            }
     494        }
     495
     496        //--------------------------------------------------------------------------------
     497        // This is the main loop to draw each cake slice
     498        //--------------------------------------------------------------------------------
     499
     500        // Set up the accumulated sum, start angle for first slice and border color
     501        $accsum=0;
     502        $angle2 = $this->startangle;
     503        $img->SetColor($this->color);
     504
     505        // Loop though all the slices if there is a pie to draw (sum>0)
     506        // There are n slices in total
     507        for($i=0; $sum>0 && $i < $n; ++$i) {
     508
     509            // $j is the actual index used for the slice
     510            $j = $n-$i-1;
     511
     512            // Make sure we havea  valid distance to explode the slice
     513            if( empty($this->explode_radius[$j]) )
     514                $this->explode_radius[$j]=0;
     515
     516            // The actual numeric value for the slice
     517            $d = $this->data[$i];
     518
     519            $angle1 = $angle2;
     520
     521            // Accumlate the sum
     522            $accsum += $d;
     523
     524            // The new angle when we add the "size" of this slice
     525            // angle1 is then the start and angle2 the end of this slice
     526            $angle2 = $this->NormAngle($this->startangle+2*M_PI*$accsum/$sum);
     527
     528            // We avoid some trouble by not allowing end angle to be 0, in that case
     529            // we translate to 360
     530
     531
     532            // la is used to hold the label angle, which is centered on the slice
     533            if( $angle2 < 0.0001 && $angle1 > 0.0001 ) {
     534                $this->la[$i] = 2*M_PI - (abs(2*M_PI-$angle1)/2.0+$angle1);
     535            }
     536            elseif( $angle1 > $angle2 ) {
     537                // The case where the slice crosses the 3 a'clock line
     538                // Remember that the slices are counted clockwise and
     539                // labels are counted counter clockwise so we need to revert with 2 PI
     540                $this->la[$i] = 2*M_PI-$this->NormAngle($angle1 + ((2*M_PI - $angle1)+$angle2)/2);
     541            }
     542            else {
     543                $this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);
     544            }
     545
     546            // Too avoid rounding problems we skip the slice if it is too small
     547            if( $d < 0.00001 ) continue;
     548
     549            // If the user has specified an array of colors for each slice then use
     550            // that a color otherwise use the theme array (ta) of colors
     551            if( $this->setslicecolors==null )
     552                $slicecolor=$colors[$ta[$i%$numcolors]];
     553            else
     554                $slicecolor=$this->setslicecolors[$i%$numcolors];
     555           
     556
     557           
     558//$_sa = round($angle1*180/M_PI);
     559//$_ea = round($angle2*180/M_PI);
     560//$_la = round($this->la[$i]*180/M_PI);
     561//echo "ang1=$_sa , ang2=$_ea, la=$_la, color=$slicecolor<br>";
     562
     563
     564            // If we have enabled antialias then we don't draw any border so
     565            // make the bordedr color the same as the slice color
     566            if( $this->pie_interior_border && $aaoption===0 )
     567                $img->SetColor($this->color);
     568            else
     569                $img->SetColor($slicecolor);       
     570            $arccolor = $this->pie_border && $aaoption===0 ? $this->color : "";
     571
     572            // Calculate the x,y coordinates for the base of this slice taking
     573            // the exploded distance into account. Here we use the mid angle as the
     574            // ray of extension and we have the mid angle handy as it is also the
     575            // label angle
     576            $xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale;
     577            $ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale;
     578
     579            // If we are not just drawing the labels then draw this cake slice
     580            if( $aaoption !== 2 ) {
     581
     582               
     583                $_sa = round($angle1*180/M_PI);
     584                $_ea = round($angle2*180/M_PI);
     585                $_la = round($this->la[$i]*180/M_PI);
     586                //echo "[$i] sa=$_sa, ea=$_ea, la[$i]=$_la, (color=$slicecolor)<br>";
     587               
     588
     589                // The CakeSlice method draws a full circle in case of start angle = end angle
     590                // for pie slices we don't want this behaviour unless we only have one
     591                // slice in the pie in case it is the wanted behaviour
     592                if( abs($_ea-$_sa) > 0.1 || $n==1 ) {
     593                    $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,$_sa,$_ea,$slicecolor,$arccolor);
     594                }
     595            }
     596
     597            // If the CSIM is used then make sure we register a CSIM area for this slice as well
     598            if( $this->csimtargets && $aaoption !== 1 ) {
     599                $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2);
     600            }
     601        }
     602
     603        // Format the titles for each slice
     604        if( $aaoption !== 2 ) {
     605            for( $i=0; $i < $n; ++$i) {
     606                if( $this->labeltype==0 ) {
     607                    if( $sum != 0 )
     608                        $l = 100.0*$this->data[$i]/$sum;
     609                    else
     610                        $l = 0.0;
     611                }
     612                elseif( $this->labeltype==1 ) {
     613                    $l = $this->data[$i]*1.0;
     614                }
     615                else {
     616                    $l = $this->adjusted_data[$i];
     617                }
     618                if( isset($this->labels[$i]) && is_string($this->labels[$i]) )
     619                    $this->labels[$i]=sprintf($this->labels[$i],$l);
     620                else
     621                    $this->labels[$i]=$l;
     622            }
     623        }
     624
     625        if( $this->value->show && $aaoption !== 1 ) {
     626            $this->StrokeAllLabels($img,$xc,$yc,$radius);
     627        }
     628
     629        // Adjust title position
     630        if( $aaoption !== 1 ) {
     631            $this->title->SetPos($xc,
     632                          $yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin,
     633                          "center","bottom");
     634            $this->title->Stroke($img);
     635        }
     636
     637    }
     638
     639//---------------
     640// PRIVATE METHODS     
    659641
    660642    function NormAngle($a) {
    661         while( $a < 0 ) $a += 2*M_PI;
    662         while( $a > 2*M_PI ) $a -= 2*M_PI;
    663         return $a;
     643        while( $a < 0 ) $a += 2*M_PI;
     644        while( $a > 2*M_PI ) $a -= 2*M_PI;
     645        return $a;
    664646    }
    665647
    666648    function Quadrant($a) {
    667         $a=$this->NormAngle($a);
    668         if( $a > 0 && $a <= M_PI/2 )
    669         return 0;
    670         if( $a > M_PI/2 && $a <= M_PI )
    671         return 1;
    672         if( $a > M_PI && $a <= 1.5*M_PI )
    673         return 2;
    674         if( $a > 1.5*M_PI )
    675         return 3;
     649        $a=$this->NormAngle($a);
     650        if( $a > 0 && $a <= M_PI/2 )
     651            return 0;
     652        if( $a > M_PI/2 && $a <= M_PI )
     653            return 1;
     654        if( $a > M_PI && $a <= 1.5*M_PI )
     655            return 2;
     656        if( $a > 1.5*M_PI )
     657            return 3;
    676658    }
    677659
    678660    function StrokeGuideLabels($img,$xc,$yc,$radius) {
    679         $n = count($this->labels);
    680 
    681         //-----------------------------------------------------------------------
    682         // Step 1 of the algorithm is to construct a number of clusters
    683         // a cluster is defined as all slices within the same quadrant (almost)
    684         // that has an angular distance less than the treshold
    685         //-----------------------------------------------------------------------
    686         $tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster
    687         $incluster=false; // flag if we are currently in a cluster or not
    688         $clusters = array(); // array of clusters
    689         $cidx=-1;  // running cluster index
    690 
    691         // Go through all the labels and construct a number of clusters
    692         for($i=0; $i < $n-1; ++$i) {
    693             // Calc the angle distance between two consecutive slices
    694             $a1=$this->la[$i];
    695             $a2=$this->la[$i+1];
    696             $q1 = $this->Quadrant($a1);
    697             $q2 = $this->Quadrant($a2);
    698             $diff = abs($a1-$a2);
    699             if( $diff < $tresh_hold ) {
    700                 if( $incluster ) {
    701                     $clusters[$cidx][1]++;
    702                     // Each cluster can only cover one quadrant
    703                     // Do we cross a quadrant ( and must break the cluster)
    704                     if( $q1 !=  $q2 ) {
    705                         // If we cross a quadrant boundary we normally start a
    706                         // new cluster. However we need to take the 12'a clock
    707                         // and 6'a clock positions into a special consideration.
    708                         // Case 1: WE go from q=1 to q=2 if the last slice on
    709                         // the cluster for q=1 is close to 12'a clock and the
    710                         // first slice in q=0 is small we extend the previous
    711                         // cluster
    712                         if( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) {
    713                             if( $i < $n-2 ) {
    714                                 $a3 = $this->la[$i+2];
    715                                 // If there isn't a cluster coming up with the next-next slice
    716                                 // we extend the previous cluster to cover this slice as well
    717                                 if( abs($a3-$a2) >= $tresh_hold ) {
    718                                     $clusters[$cidx][1]++;
    719                                     $i++;
    720                                 }
    721                             }
    722                         }
    723                         elseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) {
    724                             if( $i < $n-2 ) {
    725                                 $a3 = $this->la[$i+2];
    726                                 // If there isn't a cluster coming up with the next-next slice
    727                                 // we extend the previous cluster to cover this slice as well
    728                                 if( abs($a3-$a2) >= $tresh_hold ) {
    729                                     $clusters[$cidx][1]++;
    730                                     $i++;
    731                                 }
    732                             }
    733                         }
    734 
    735                         if( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) {
    736                             $clusters[$cidx][1]++;
    737                             $i++;
    738                         }
    739 
    740                         $incluster = false;
    741                     }
    742                 }
    743                 elseif( $q1 == $q2)  {
    744                     $incluster = true;
    745                     // Now we have a special case for quadrant 0. If we previously
    746                     // have a cluster of one in quadrant 0 we just extend that
    747                     // cluster. If we don't do this then we risk that the label
    748                     // for the cluster of one will cross the guide-line
    749                     if( $q1 == 0 && $cidx > -1 &&
    750                     $clusters[$cidx][1] == 1 &&
    751                     $this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) {
    752                         $clusters[$cidx][1]++;
    753                     }
    754                     else {
    755                         $cidx++;
    756                         $clusters[$cidx][0] = $i;
    757                         $clusters[$cidx][1] = 1;
    758                     }
    759                 }
    760                 else {
    761                     // Create a "cluster" of one since we are just crossing
    762                     // a quadrant
    763                     $cidx++;
    764                     $clusters[$cidx][0] = $i;
    765                     $clusters[$cidx][1] = 1;
    766                 }
    767             }
    768             else {
    769                 if( $incluster ) {
    770                     // Add the last slice
    771                     $clusters[$cidx][1]++;
    772                     $incluster = false;
    773                 }
    774                 else { // Create a "cluster" of one
    775                     $cidx++;
    776                     $clusters[$cidx][0] = $i;
    777                     $clusters[$cidx][1] = 1;
    778                 }
    779             }
    780         }
    781         // Handle the very last slice
    782         if( $incluster ) {
    783             $clusters[$cidx][1]++;
    784         }
    785         else { // Create a "cluster" of one
    786             $cidx++;
    787             $clusters[$cidx][0] = $i;
    788             $clusters[$cidx][1] = 1;
    789         }
    790 
    791         /*
    792          if( true ) {
    793          // Debug printout in labels
    794          for( $i=0; $i <= $cidx; ++$i ) {
    795          for( $j=0; $j < $clusters[$i][1]; ++$j ) {
    796          $a = $this->la[$clusters[$i][0]+$j];
    797          $aa = round($a*180/M_PI);
    798          $q = $this->Quadrant($a);
    799          $this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j";
    800          }
    801          }
    802          }
    803          */
    804 
    805         //-----------------------------------------------------------------------
    806         // Step 2 of the algorithm is use the clusters and draw the labels
    807         // and guidelines
    808         //-----------------------------------------------------------------------
    809 
    810         // We use the font height as the base factor for how far we need to
    811         // spread the labels in the Y-direction.
    812         $this->value->ApplyFont($img);
    813         $fh = $img->GetFontHeight();
    814         $origvstep=$fh*$this->iGuideVFactor;
    815         $this->value->SetMargin(0);
    816 
    817         // Number of clusters found
    818         $nc = count($clusters);
    819 
    820         // Walk through all the clusters
    821         for($i=0; $i < $nc; ++$i) {
    822 
    823             // Start angle and number of slices in this cluster
    824             $csize = $clusters[$i][1];
    825             $a = $this->la[$clusters[$i][0]];
    826             $q = $this->Quadrant($a);
    827 
    828             // Now set up the start and end conditions to make sure that
    829             // in each cluster we walk through the all the slices starting with the slice
    830             // closest to the equator. Since all slices are numbered clockwise from "3'a clock"
    831             // we have different conditions depending on in which quadrant the slice lies within.
    832             if( $q == 0 ) {
    833                 $start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep;
    834             }
    835             elseif( $q == 1 ) {
    836                 $start = 0; $idx = $start; $step = 1; $vstep = -$origvstep;
    837             }
    838             elseif( $q == 2 ) {
    839                 $start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep;
    840             }
    841             elseif( $q == 3 ) {
    842                 $start = 0; $idx = $start; $step = 1; $vstep = $origvstep;
    843             }
    844 
    845             // Walk through all slices within this cluster
    846             for($j=0; $j < $csize; ++$j) {
    847                 // Now adjust the position of the labels in each cluster starting
    848                 // with the slice that is closest to the equator of the pie
    849                 $a = $this->la[$clusters[$i][0]+$idx];
    850 
    851                 // Guide line start in the center of the arc of the slice
    852                 $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];
    853                 $x = round($r*cos($a)+$xc);
    854                 $y = round($yc-$r*sin($a));
    855 
    856                 // The distance from the arc depends on chosen font and the "R-Factor"
    857                 $r += $fh*$this->iGuideLineRFactor;
    858 
    859                 // Should the labels be placed curved along the pie or in straight columns
    860                 // outside the pie?
    861                 if( $this->iGuideLineCurve )
    862                 $xt=round($r*cos($a)+$xc);
    863 
    864                 // If this is the first slice in the cluster we need some first time
    865                 // proessing
    866                 if( $idx == $start ) {
    867                     if( ! $this->iGuideLineCurve )
    868                     $xt=round($r*cos($a)+$xc);
    869                     $yt=round($yc-$r*sin($a));
    870 
    871                     // Some special consideration in case this cluster starts
    872                     // in quadrant 1 or 3 very close to the "equator" (< 20 degrees)
    873                     // and the previous clusters last slice is within the tolerance.
    874                     // In that case we add a font height to this labels Y-position
    875                     // so it doesn't collide with
    876                     // the slice in the previous cluster
    877                     $prevcluster = ($i + ($nc-1) ) % $nc;
    878                     $previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1;
    879                     if( $q == 1 && $a > 160*M_PI/180 ) {
    880                         // Get the angle for the previous clusters last slice
    881                         $diff = abs($a-$this->la[$previdx]);
    882                         if( $diff < $tresh_hold ) {
    883                             $yt -= $fh;
    884                         }
    885                     }
    886                     elseif( $q == 3 && $a > 340*M_PI/180 ) {
    887                         // We need to subtract 360 to compare angle distance between
    888                         // q=0 and q=3
    889                         $diff = abs($a-$this->la[$previdx]-360*M_PI/180);
    890                         if( $diff < $tresh_hold ) {
    891                             $yt += $fh;
    892                         }
    893                     }
    894 
    895                 }
    896                 else {
    897                     // The step is at minimum $vstep but if the slices are relatively large
    898                     // we make sure that we add at least a step that corresponds to the vertical
    899                     // distance between the centers at the arc on the slice
    900                     $prev_a = $this->la[$clusters[$i][0]+($idx-$step)];
    901                     $dy = abs($radius*(sin($a)-sin($prev_a))*1.2);
    902                     if( $vstep > 0 )
    903                     $yt += max($vstep,$dy);
    904                     else
    905                     $yt += min($vstep,-$dy);
    906                 }
    907 
    908                 $label = $this->labels[$clusters[$i][0]+$idx];
    909 
    910                 if( $csize == 1 ) {
    911                     // A "meta" cluster with only one slice
    912                     $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];
    913                     $rr = $r+$img->GetFontHeight()/2;
    914                     $xt=round($rr*cos($a)+$xc);
    915                     $yt=round($yc-$rr*sin($a));
    916                     $this->StrokeLabel($label,$img,$xc,$yc,$a,$r);
    917                     if( $this->iShowGuideLineForSingle )
    918                     $this->guideline->Stroke($img,$x,$y,$xt,$yt);
    919                 }
    920                 else {
    921                     $this->guideline->Stroke($img,$x,$y,$xt,$yt);
    922                     if( $q==1 || $q==2 ) {
    923                         // Left side of Pie
    924                         $this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt);
    925                         $lbladj = -$this->guidelinemargin-5;
    926                         $this->value->halign = "right";
    927                         $this->value->valign = "center";
    928                     }
    929                     else {
    930                         // Right side of pie
    931                         $this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt);
    932                         $lbladj = $this->guidelinemargin+5;
    933                         $this->value->halign = "left";
    934                         $this->value->valign = "center";
    935                     }
    936                     $this->value->Stroke($img,$label,$xt+$lbladj,$yt);
    937                 }
    938 
    939                 // Udate idx to point to next slice in the cluster to process
    940                 $idx += $step;
    941             }
    942         }
     661        $n = count($this->labels);
     662
     663        //-----------------------------------------------------------------------
     664        // Step 1 of the algorithm is to construct a number of clusters
     665        // a cluster is defined as all slices within the same quadrant (almost)
     666        // that has an angular distance less than the treshold
     667        //-----------------------------------------------------------------------
     668        $tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster
     669        $incluster=false;       // flag if we are currently in a cluster or not
     670        $clusters = array();    // array of clusters
     671        $cidx=-1;               // running cluster index
     672
     673        // Go through all the labels and construct a number of clusters
     674        for($i=0; $i < $n-1; ++$i) {
     675            // Calc the angle distance between two consecutive slices
     676            $a1=$this->la[$i];
     677            $a2=$this->la[$i+1];
     678            $q1 = $this->Quadrant($a1);
     679            $q2 = $this->Quadrant($a2);
     680            $diff = abs($a1-$a2);
     681            if( $diff < $tresh_hold ) {
     682                if( $incluster ) {
     683                    $clusters[$cidx][1]++;
     684                    // Each cluster can only cover one quadrant
     685                    // Do we cross a quadrant ( and must break the cluster)
     686                    if( $q1 !=  $q2 ) {
     687                        // If we cross a quadrant boundary we normally start a
     688                        // new cluster. However we need to take the 12'a clock
     689                        // and 6'a clock positions into a special consideration.
     690                        // Case 1: WE go from q=1 to q=2 if the last slice on
     691                        // the cluster for q=1 is close to 12'a clock and the
     692                        // first slice in q=0 is small we extend the previous
     693                        // cluster
     694                        if( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) {
     695                            if( $i < $n-2 ) {
     696                                $a3 = $this->la[$i+2];
     697                                // If there isn't a cluster coming up with the next-next slice
     698                                // we extend the previous cluster to cover this slice as well
     699                                if( abs($a3-$a2) >= $tresh_hold ) {
     700                                    $clusters[$cidx][1]++;
     701                                    $i++;
     702                                }
     703                            }
     704                        }
     705                        elseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) {
     706                            if( $i < $n-2 ) {
     707                                $a3 = $this->la[$i+2];
     708                                // If there isn't a cluster coming up with the next-next slice
     709                                // we extend the previous cluster to cover this slice as well
     710                                if( abs($a3-$a2) >= $tresh_hold ) {
     711                                    $clusters[$cidx][1]++;
     712                                    $i++;
     713                                }
     714                            }
     715                        }
     716
     717                        if( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) {
     718                            $clusters[$cidx][1]++;
     719                            $i++;                           
     720                        }
     721                       
     722                        $incluster = false;
     723                    }
     724                }
     725                elseif( $q1 == $q2)  {
     726                    $incluster = true;
     727                    // Now we have a special case for quadrant 0. If we previously
     728                    // have a cluster of one in quadrant 0 we just extend that
     729                    // cluster. If we don't do this then we risk that the label
     730                    // for the cluster of one will cross the guide-line
     731                    if( $q1 == 0 && $cidx > -1 &&
     732                        $clusters[$cidx][1] == 1 &&
     733                        $this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) {
     734                        $clusters[$cidx][1]++;
     735                    }
     736                    else {
     737                        $cidx++;
     738                        $clusters[$cidx][0] = $i;
     739                        $clusters[$cidx][1] = 1;
     740                    }
     741                }
     742                else { 
     743                    // Create a "cluster" of one since we are just crossing
     744                    // a quadrant
     745                    $cidx++;
     746                    $clusters[$cidx][0] = $i;
     747                    $clusters[$cidx][1] = 1;       
     748                }
     749            }
     750            else {
     751                if( $incluster ) {
     752                    // Add the last slice
     753                    $clusters[$cidx][1]++;
     754                    $incluster = false;
     755                }
     756                else { // Create a "cluster" of one
     757                    $cidx++;
     758                    $clusters[$cidx][0] = $i;
     759                    $clusters[$cidx][1] = 1;       
     760                }
     761            }
     762        }
     763        // Handle the very last slice
     764        if( $incluster ) {
     765            $clusters[$cidx][1]++;
     766        }
     767        else { // Create a "cluster" of one
     768            $cidx++;
     769            $clusters[$cidx][0] = $i;
     770            $clusters[$cidx][1] = 1;       
     771        }
     772
     773        /*
     774        if( true ) {
     775            // Debug printout in labels
     776            for( $i=0; $i <= $cidx; ++$i ) {
     777                for( $j=0; $j < $clusters[$i][1]; ++$j ) {
     778                    $a = $this->la[$clusters[$i][0]+$j];
     779                    $aa = round($a*180/M_PI);
     780                    $q = $this->Quadrant($a);
     781                    $this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j";
     782                }
     783            }
     784        }
     785        */
     786
     787        //-----------------------------------------------------------------------
     788        // Step 2 of the algorithm is use the clusters and draw the labels
     789        // and guidelines
     790        //-----------------------------------------------------------------------
     791
     792        // We use the font height as the base factor for how far we need to
     793        // spread the labels in the Y-direction.
     794        $this->value->ApplyFont($img);
     795        $fh = $img->GetFontHeight();
     796        $origvstep=$fh*$this->iGuideVFactor;
     797        $this->value->SetMargin(0);
     798
     799        // Number of clusters found
     800        $nc = count($clusters);
     801
     802        // Walk through all the clusters
     803        for($i=0; $i < $nc; ++$i) {
     804
     805            // Start angle and number of slices in this cluster
     806            $csize = $clusters[$i][1];
     807            $a = $this->la[$clusters[$i][0]];
     808            $q = $this->Quadrant($a);
     809
     810            // Now set up the start and end conditions to make sure that
     811            // in each cluster we walk through the all the slices starting with the slice
     812            // closest to the equator. Since all slices are numbered clockwise from "3'a clock"
     813            // we have different conditions depending on in which quadrant the slice lies within.
     814            if( $q == 0 ) {
     815                $start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep;
     816            }
     817            elseif( $q == 1 ) {
     818                $start = 0; $idx = $start; $step = 1; $vstep = -$origvstep;
     819            }
     820            elseif( $q == 2 ) {
     821                $start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep;
     822            }
     823            elseif( $q == 3 ) {
     824                $start = 0; $idx = $start; $step = 1; $vstep = $origvstep;
     825            }
     826
     827            // Walk through all slices within this cluster
     828            for($j=0; $j < $csize; ++$j) {   
     829                // Now adjust the position of the labels in each cluster starting
     830                // with the slice that is closest to the equator of the pie
     831                $a = $this->la[$clusters[$i][0]+$idx];
     832                   
     833                // Guide line start in the center of the arc of the slice
     834                $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];
     835                $x = round($r*cos($a)+$xc);
     836                $y = round($yc-$r*sin($a));
     837               
     838                // The distance from the arc depends on chosen font and the "R-Factor"
     839                $r += $fh*$this->iGuideLineRFactor;
     840
     841                // Should the labels be placed curved along the pie or in straight columns
     842                // outside the pie?
     843                if( $this->iGuideLineCurve )
     844                    $xt=round($r*cos($a)+$xc);
     845
     846                // If this is the first slice in the cluster we need some first time
     847                // proessing
     848                if( $idx == $start ) {
     849                    if( ! $this->iGuideLineCurve )
     850                        $xt=round($r*cos($a)+$xc);
     851                    $yt=round($yc-$r*sin($a));
     852
     853                    // Some special consideration in case this cluster starts
     854                    // in quadrant 1 or 3 very close to the "equator" (< 20 degrees)
     855                    // and the previous clusters last slice is within the tolerance.
     856                    // In that case we add a font height to this labels Y-position
     857                    // so it doesn't collide with
     858                    // the slice in the previous cluster
     859                    $prevcluster = ($i + ($nc-1) ) % $nc;
     860                    $previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1;
     861                    if( $q == 1 && $a > 160*M_PI/180 ) {
     862                        // Get the angle for the previous clusters last slice
     863                        $diff = abs($a-$this->la[$previdx]);
     864                        if( $diff < $tresh_hold ) {
     865                             $yt -= $fh;
     866                        }
     867                    }
     868                    elseif( $q == 3 && $a > 340*M_PI/180 ) {
     869                        // We need to subtract 360 to compare angle distance between
     870                        // q=0 and q=3
     871                        $diff = abs($a-$this->la[$previdx]-360*M_PI/180);
     872                        if( $diff < $tresh_hold ) {
     873                             $yt += $fh;
     874                        }
     875                    }
     876
     877                }
     878                else {
     879                    // The step is at minimum $vstep but if the slices are relatively large
     880                    // we make sure that we add at least a step that corresponds to the vertical
     881                    // distance between the centers at the arc on the slice
     882                    $prev_a = $this->la[$clusters[$i][0]+($idx-$step)];
     883                    $dy = abs($radius*(sin($a)-sin($prev_a))*1.2);
     884                    if( $vstep > 0 )
     885                        $yt += max($vstep,$dy);
     886                    else
     887                        $yt += min($vstep,-$dy);
     888                }
     889
     890                $label = $this->labels[$clusters[$i][0]+$idx];
     891
     892                if( $csize == 1 ) {
     893                    // A "meta" cluster with only one slice
     894                    $r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];
     895                    $rr = $r+$img->GetFontHeight()/2;
     896                    $xt=round($rr*cos($a)+$xc);
     897                    $yt=round($yc-$rr*sin($a));
     898                    $this->StrokeLabel($label,$img,$xc,$yc,$a,$r);
     899                    if( $this->iShowGuideLineForSingle )
     900                        $this->guideline->Stroke($img,$x,$y,$xt,$yt);
     901                }
     902                else {
     903                    $this->guideline->Stroke($img,$x,$y,$xt,$yt);
     904                    if( $q==1 || $q==2 ) {
     905                        // Left side of Pie
     906                        $this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt);
     907                        $lbladj = -$this->guidelinemargin-5;
     908                        $this->value->halign = "right";
     909                        $this->value->valign = "center";
     910                    }
     911                    else {
     912                        // Right side of pie
     913                        $this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt);
     914                        $lbladj = $this->guidelinemargin+5;
     915                        $this->value->halign = "left";
     916                        $this->value->valign = "center";
     917                    }
     918                    $this->value->Stroke($img,$label,$xt+$lbladj,$yt);
     919                }
     920
     921                // Udate idx to point to next slice in the cluster to process
     922                $idx += $step;
     923            }
     924        }
    943925    }
    944926
    945927    function StrokeAllLabels($img,$xc,$yc,$radius) {
    946         // First normalize all angles for labels
    947         $n = count($this->la);
    948         for($i=0; $i < $n; ++$i) {
    949             $this->la[$i] = $this->NormAngle($this->la[$i]);
    950         }
    951         if( $this->guideline->iShow ) {
    952             $this->StrokeGuideLabels($img,$xc,$yc,$radius);
    953         }
    954         else {
    955             $n = count($this->labels);
    956             for($i=0; $i < $n; ++$i) {
    957                 $this->StrokeLabel($this->labels[$i],$img,$xc,$yc,
    958                 $this->la[$i],
    959                 $radius + $this->explode_radius[$n-1-$i]);
    960             }
    961         }
     928        // First normalize all angles for labels
     929        $n = count($this->la);
     930        for($i=0; $i < $n; ++$i) {
     931            $this->la[$i] = $this->NormAngle($this->la[$i]);
     932        }
     933        if( $this->guideline->iShow ) {
     934            $this->StrokeGuideLabels($img,$xc,$yc,$radius);
     935        }
     936        else {
     937            $n = count($this->labels);
     938            for($i=0; $i < $n; ++$i) {
     939                $this->StrokeLabel($this->labels[$i],$img,$xc,$yc,
     940                                   $this->la[$i],
     941                                   $radius + $this->explode_radius[$n-1-$i]);
     942            }
     943        }
    962944    }
    963945
     
    965947    function StrokeLabel($label,$img,$xc,$yc,$a,$r) {
    966948
    967         // Default value
    968         if( $this->ilabelposadj === 'auto' )
    969         $this->ilabelposadj = 0.65;
    970 
    971         // We position the values diferently depending on if they are inside
    972         // or outside the pie
    973         if( $this->ilabelposadj < 1.0 ) {
    974 
    975             $this->value->SetAlign('center','center');
    976             $this->value->margin = 0;
    977 
    978             $xt=round($this->ilabelposadj*$r*cos($a)+$xc);
    979             $yt=round($yc-$this->ilabelposadj*$r*sin($a));
    980 
    981             $this->value->Stroke($img,$label,$xt,$yt);
    982         }
    983         else {
    984 
    985             $this->value->halign = "left";
    986             $this->value->valign = "top";
    987             $this->value->margin = 0;
    988 
    989             // Position the axis title.
    990             // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
    991             // that intersects with the extension of the corresponding axis. The code looks a little
    992             // bit messy but this is really the only way of having a reasonable position of the
    993             // axis titles.
    994             $this->value->ApplyFont($img);
    995             $h=$img->GetTextHeight($label);
    996             // For numeric values the format of the display value
    997             // must be taken into account
    998             if( is_numeric($label) ) {
    999                 if( $label > 0 )
    1000                 $w=$img->GetTextWidth(sprintf($this->value->format,$label));
    1001                 else
    1002                 $w=$img->GetTextWidth(sprintf($this->value->negformat,$label));
    1003             }
    1004             else
    1005             $w=$img->GetTextWidth($label);
    1006 
    1007             if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) {
    1008                 $r *= $this->ilabelposadj;
    1009             }
    1010 
    1011             $r += $img->GetFontHeight()/1.5;
    1012 
    1013             $xt=round($r*cos($a)+$xc);
    1014             $yt=round($yc-$r*sin($a));
    1015 
    1016             // Normalize angle
    1017             while( $a < 0 ) $a += 2*M_PI;
    1018             while( $a > 2*M_PI ) $a -= 2*M_PI;
    1019 
    1020             if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;
    1021             if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI;
    1022             if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;
    1023             if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);
    1024 
    1025             if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;
    1026             if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);
    1027             if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;
    1028             if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);
    1029             if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;
    1030 
    1031             $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h);
    1032         }
    1033     }
    1034 
    1035     function UsePlotThemeColors($flag = true) {
    1036         $this->use_plot_theme_colors = $flag;
    1037     }
     949        // Default value
     950        if( $this->ilabelposadj === 'auto' )
     951            $this->ilabelposadj = 0.65;
     952
     953        // We position the values diferently depending on if they are inside
     954        // or outside the pie
     955        if( $this->ilabelposadj < 1.0 ) {
     956
     957            $this->value->SetAlign('center','center');
     958            $this->value->margin = 0;
     959           
     960            $xt=round($this->ilabelposadj*$r*cos($a)+$xc);
     961            $yt=round($yc-$this->ilabelposadj*$r*sin($a));
     962           
     963            $this->value->Stroke($img,$label,$xt,$yt);
     964        }
     965        else {
     966
     967            $this->value->halign = "left";
     968            $this->value->valign = "top";
     969            $this->value->margin = 0;
     970                   
     971            // Position the axis title.
     972            // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
     973            // that intersects with the extension of the corresponding axis. The code looks a little
     974            // bit messy but this is really the only way of having a reasonable position of the
     975            // axis titles.
     976            $this->value->ApplyFont($img);
     977            $h=$img->GetTextHeight($label);
     978            // For numeric values the format of the display value
     979            // must be taken into account
     980            if( is_numeric($label) ) {
     981                if( $label > 0 )
     982                    $w=$img->GetTextWidth(sprintf($this->value->format,$label));
     983                else
     984                    $w=$img->GetTextWidth(sprintf($this->value->negformat,$label));
     985            }
     986            else
     987                $w=$img->GetTextWidth($label);
     988
     989            if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) {
     990                $r *= $this->ilabelposadj;
     991            }
     992           
     993            $r += $img->GetFontHeight()/1.5;
     994
     995            $xt=round($r*cos($a)+$xc);
     996            $yt=round($yc-$r*sin($a));
     997
     998            // Normalize angle
     999            while( $a < 0 ) $a += 2*M_PI;
     1000            while( $a > 2*M_PI ) $a -= 2*M_PI;
     1001
     1002            if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;
     1003            if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI;
     1004            if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;
     1005            if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);
     1006           
     1007            if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;
     1008            if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);
     1009            if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;
     1010            if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);
     1011            if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;
     1012           
     1013            $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h);
     1014        }
     1015    }   
    10381016} // Class
    10391017
     
    10411019//===================================================
    10421020// CLASS PiePlotC
    1043 // Description: Same as a normal pie plot but with a
     1021// Description: Same as a normal pie plot but with a 
    10441022// filled circle in the center
    10451023//===================================================
    10461024class PiePlotC extends PiePlot {
    1047     private $imidsize=0.5;  // Fraction of total width
     1025    private $imidsize=0.5;              // Fraction of total width
    10481026    private $imidcolor='white';
    10491027    public $midtitle='';
    10501028    private $middlecsimtarget='',$middlecsimwintarget='',$middlecsimalt='';
    10511029
    1052     function __construct($data,$aCenterTitle='') {
    1053         parent::__construct($data);
    1054         $this->midtitle = new Text();
    1055         $this->midtitle->ParagraphAlign('center');
     1030    function PiePlotC($data,$aCenterTitle='') {
     1031        parent::PiePlot($data);
     1032        $this->midtitle = new Text();
     1033        $this->midtitle->ParagraphAlign('center');
    10561034    }
    10571035
    10581036    function SetMid($aTitle,$aColor='white',$aSize=0.5) {
    1059         $this->midtitle->Set($aTitle);
    1060 
    1061         $this->imidsize = $aSize ;
    1062         $this->imidcolor = $aColor ;
     1037        $this->midtitle->Set($aTitle);
     1038
     1039        $this->imidsize = $aSize ;
     1040        $this->imidcolor = $aColor ;
    10631041    }
    10641042
    10651043    function SetMidTitle($aTitle) {
    1066         $this->midtitle->Set($aTitle);
     1044        $this->midtitle->Set($aTitle);
    10671045    }
    10681046
    10691047    function SetMidSize($aSize) {
    1070         $this->imidsize = $aSize ;
     1048        $this->imidsize = $aSize ;
    10711049    }
    10721050
    10731051    function SetMidColor($aColor) {
    1074         $this->imidcolor = $aColor ;
     1052        $this->imidcolor = $aColor ;
    10751053    }
    10761054
    10771055    function SetMidCSIM($aTarget,$aAlt='',$aWinTarget='') {
    1078         $this->middlecsimtarget = $aTarget;
    1079         $this->middlecsimwintarget = $aWinTarget;
    1080         $this->middlecsimalt = $aAlt;
    1081     }
    1082 
    1083     function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) {
     1056        $this->middlecsimtarget = $aTarget;
     1057        $this->middlecsimwintarget = $aWinTarget;
     1058        $this->middlecsimalt = $aAlt;
     1059    }
     1060
     1061    function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { 
    10841062        //Slice number, ellipse centre (x,y), radius, start angle, end angle
    1085         while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;
    1086         while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;
    1087 
    1088         $sa = 2*M_PI - $sa;
    1089         $ea = 2*M_PI - $ea;
    1090 
    1091         // Special case when we have only one slice since then both start and end
    1092         // angle will be == 0
    1093         if( abs($sa - $ea) < 0.0001 ) {
    1094             $sa=2*M_PI; $ea=0;
    1095         }
    1096 
    1097         // Add inner circle first point
    1098         $xp = floor(($this->imidsize*$radius*cos($ea))+$xc);
    1099         $yp = floor($yc-($this->imidsize*$radius*sin($ea)));
    1100         $coords = "$xp, $yp";
    1101 
    1102         //add coordinates every 0.25 radians
    1103         $a=$ea+0.25;
    1104 
    1105         // If we cross the 360-limit with a slice we need to handle
    1106         // the fact that end angle is smaller than start
    1107         if( $sa < $ea ) {
    1108             while ($a <= 2*M_PI) {
    1109                 $xp = floor($radius*cos($a)+$xc);
    1110                 $yp = floor($yc-$radius*sin($a));
    1111                 $coords.= ", $xp, $yp";
    1112                 $a += 0.25;
    1113             }
    1114             $a -= 2*M_PI;
    1115         }
    1116 
    1117         while ($a < $sa) {
    1118             $xp = floor(($this->imidsize*$radius*cos($a)+$xc));
    1119             $yp = floor($yc-($this->imidsize*$radius*sin($a)));
    1120             $coords.= ", $xp, $yp";
    1121             $a += 0.25;
    1122         }
    1123 
    1124         // Make sure we end at the last point
    1125         $xp = floor(($this->imidsize*$radius*cos($sa)+$xc));
    1126         $yp = floor($yc-($this->imidsize*$radius*sin($sa)));
    1127         $coords.= ", $xp, $yp";
    1128 
    1129         // Straight line to outer circle
    1130         $xp = floor($radius*cos($sa)+$xc);
    1131         $yp = floor($yc-$radius*sin($sa));
    1132         $coords.= ", $xp, $yp";
    1133 
    1134         //add coordinates every 0.25 radians
    1135         $a=$sa - 0.25;
    1136         while ($a > $ea) {
    1137             $xp = floor($radius*cos($a)+$xc);
    1138             $yp = floor($yc-$radius*sin($a));
    1139             $coords.= ", $xp, $yp";
    1140             $a -= 0.25;
    1141         }
    1142 
    1143         //Add the last point on the arc
    1144         $xp = floor($radius*cos($ea)+$xc);
    1145         $yp = floor($yc-$radius*sin($ea));
    1146         $coords.= ", $xp, $yp";
    1147 
    1148         // Close the arc
    1149         $xp = floor(($this->imidsize*$radius*cos($ea))+$xc);
    1150         $yp = floor($yc-($this->imidsize*$radius*sin($ea)));
    1151         $coords .= ", $xp, $yp";
    1152 
    1153         if( !empty($this->csimtargets[$i]) ) {
    1154             $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".
    1155             $this->csimtargets[$i]."\"";
    1156             if( !empty($this->csimwintargets[$i]) ) {
    1157                 $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
    1158             }
    1159             if( !empty($this->csimalts[$i]) ) {
    1160                 $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
    1161                 $this->csimareas .= " title=\"$tmp\"  alt=\"$tmp\" ";
    1162             }
    1163             $this->csimareas .= " />\n";
    1164         }
     1063        while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;
     1064        while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;
     1065
     1066        $sa = 2*M_PI - $sa;
     1067        $ea = 2*M_PI - $ea;
     1068
     1069        // Special case when we have only one slice since then both start and end
     1070        // angle will be == 0
     1071        if( abs($sa - $ea) < 0.0001 ) {
     1072            $sa=2*M_PI; $ea=0;
     1073        }
     1074
     1075        // Add inner circle first point
     1076        $xp = floor(($this->imidsize*$radius*cos($ea))+$xc);
     1077        $yp = floor($yc-($this->imidsize*$radius*sin($ea)));
     1078        $coords = "$xp, $yp";
     1079       
     1080        //add coordinates every 0.25 radians
     1081        $a=$ea+0.25;
     1082
     1083        // If we cross the 360-limit with a slice we need to handle
     1084        // the fact that end angle is smaller than start
     1085        if( $sa < $ea ) {
     1086            while ($a <= 2*M_PI) {
     1087                $xp = floor($radius*cos($a)+$xc);
     1088                $yp = floor($yc-$radius*sin($a));
     1089                $coords.= ", $xp, $yp";
     1090                $a += 0.25;
     1091            }
     1092            $a -= 2*M_PI;
     1093        }
     1094
     1095        while ($a < $sa) {
     1096            $xp = floor(($this->imidsize*$radius*cos($a)+$xc));
     1097            $yp = floor($yc-($this->imidsize*$radius*sin($a)));
     1098            $coords.= ", $xp, $yp";
     1099            $a += 0.25;
     1100        }
     1101
     1102        // Make sure we end at the last point
     1103        $xp = floor(($this->imidsize*$radius*cos($sa)+$xc));
     1104        $yp = floor($yc-($this->imidsize*$radius*sin($sa)));
     1105        $coords.= ", $xp, $yp";
     1106
     1107        // Straight line to outer circle
     1108        $xp = floor($radius*cos($sa)+$xc);
     1109        $yp = floor($yc-$radius*sin($sa));
     1110        $coords.= ", $xp, $yp";
     1111
     1112        //add coordinates every 0.25 radians
     1113        $a=$sa - 0.25;
     1114        while ($a > $ea) {
     1115            $xp = floor($radius*cos($a)+$xc);
     1116            $yp = floor($yc-$radius*sin($a));
     1117            $coords.= ", $xp, $yp";
     1118            $a -= 0.25;
     1119        }
     1120               
     1121        //Add the last point on the arc
     1122        $xp = floor($radius*cos($ea)+$xc);
     1123        $yp = floor($yc-$radius*sin($ea));
     1124        $coords.= ", $xp, $yp";
     1125
     1126        // Close the arc
     1127        $xp = floor(($this->imidsize*$radius*cos($ea))+$xc);
     1128        $yp = floor($yc-($this->imidsize*$radius*sin($ea)));
     1129        $coords .= ", $xp, $yp";
     1130
     1131        if( !empty($this->csimtargets[$i]) ) {
     1132            $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".
     1133                $this->csimtargets[$i]."\"";
     1134            if( !empty($this->csimwintargets[$i]) ) {
     1135                $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
     1136            }
     1137            if( !empty($this->csimalts[$i]) ) {
     1138                $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
     1139                $this->csimareas .= " title=\"$tmp\"  alt=\"$tmp\" ";
     1140            }
     1141            $this->csimareas .= " />\n";
     1142        }
    11651143    }
    11661144
     
    11681146    function Stroke($img,$aaoption=0) {
    11691147
    1170         // Stroke the pie but don't stroke values
    1171         $tmp =  $this->value->show;
    1172         $this->value->show = false;
    1173         parent::Stroke($img,$aaoption);
    1174         $this->value->show = $tmp;
    1175 
    1176         $xc = round($this->posx*$img->width);
    1177         $yc = round($this->posy*$img->height);
    1178 
    1179         $radius = floor($this->radius * min($img->width,$img->height)) ;
    1180 
    1181 
    1182         if( $this->imidsize > 0 && $aaoption !== 2 ) {
    1183 
    1184             if( $this->ishadowcolor != "" ) {
    1185                 $img->SetColor($this->ishadowcolor);
    1186                 $img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop,
    1187                 round($radius*$this->imidsize));
    1188             }
    1189 
    1190             $img->SetColor($this->imidcolor);
    1191             $img->FilledCircle($xc,$yc,round($radius*$this->imidsize));
    1192 
    1193             if(  $this->pie_border && $aaoption === 0 ) {
    1194                 $img->SetColor($this->color);
    1195                 $img->Circle($xc,$yc,round($radius*$this->imidsize));
    1196             }
    1197 
    1198             if( !empty($this->middlecsimtarget) )
    1199             $this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize));
    1200 
    1201         }
    1202 
    1203         if( $this->value->show && $aaoption !== 1) {
    1204             $this->StrokeAllLabels($img,$xc,$yc,$radius);
    1205             $this->midtitle->SetPos($xc,$yc,'center','center');
    1206             $this->midtitle->Stroke($img);
    1207         }
     1148        // Stroke the pie but don't stroke values
     1149        $tmp =  $this->value->show;
     1150        $this->value->show = false;
     1151        parent::Stroke($img,$aaoption);
     1152        $this->value->show = $tmp;
     1153
     1154        $xc = round($this->posx*$img->width);
     1155        $yc = round($this->posy*$img->height);
     1156
     1157        $radius = floor($this->radius * min($img->width,$img->height)) ;
     1158
     1159
     1160        if( $this->imidsize > 0 && $aaoption !== 2 ) {
     1161
     1162            if( $this->ishadowcolor != "" ) {
     1163                $img->SetColor($this->ishadowcolor);
     1164                $img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop,
     1165                                   round($radius*$this->imidsize));
     1166            }
     1167
     1168            $img->SetColor($this->imidcolor);
     1169            $img->FilledCircle($xc,$yc,round($radius*$this->imidsize));
     1170
     1171            if(  $this->pie_border && $aaoption === 0 ) {
     1172                $img->SetColor($this->color);
     1173                $img->Circle($xc,$yc,round($radius*$this->imidsize));
     1174            }
     1175
     1176            if( !empty($this->middlecsimtarget) )
     1177                $this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize));
     1178
     1179        }
     1180
     1181        if( $this->value->show && $aaoption !== 1) {
     1182            $this->StrokeAllLabels($img,$xc,$yc,$radius);
     1183            $this->midtitle->SetPos($xc,$yc,'center','center');
     1184            $this->midtitle->Stroke($img);
     1185        }
    12081186
    12091187    }
    12101188
    12111189    function AddMiddleCSIM($xc,$yc,$r) {
    1212         $xc=round($xc);$yc=round($yc);$r=round($r);
    1213         $this->csimareas .= "<area shape=\"circle\" coords=\"$xc,$yc,$r\" href=\"".
    1214         $this->middlecsimtarget."\"";
    1215         if( !empty($this->middlecsimwintarget) ) {
    1216             $this->csimareas .= " target=\"".$this->middlecsimwintarget."\"";
    1217         }
    1218         if( !empty($this->middlecsimalt) ) {
    1219             $tmp = $this->middlecsimalt;
    1220             $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" ";
    1221         }
    1222         $this->csimareas .= " />\n";
     1190        $xc=round($xc);$yc=round($yc);$r=round($r);
     1191        $this->csimareas .= "<area shape=\"circle\" coords=\"$xc,$yc,$r\" href=\"".
     1192            $this->middlecsimtarget."\"";
     1193        if( !empty($this->middlecsimwintarget) ) {
     1194            $this->csimareas .= " target=\"".$this->middlecsimwintarget."\"";
     1195        }
     1196        if( !empty($this->middlecsimalt) ) {
     1197            $tmp = $this->middlecsimalt;
     1198            $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" ";
     1199        }
     1200        $this->csimareas .= " />\n";
    12231201    }
    12241202
    12251203    function StrokeLabel($label,$img,$xc,$yc,$a,$r) {
    12261204
    1227         if( $this->ilabelposadj === 'auto' )
    1228         $this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize;
    1229 
    1230         parent::StrokeLabel($label,$img,$xc,$yc,$a,$r);
     1205        if( $this->ilabelposadj === 'auto' )
     1206            $this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize;
     1207
     1208        parent::StrokeLabel($label,$img,$xc,$yc,$a,$r);
    12311209
    12321210    }
     
    12371215//===================================================
    12381216// CLASS PieGraph
    1239 // Description:
     1217// Description: 
    12401218//===================================================
    12411219class PieGraph extends Graph {
    1242     private $posx, $posy, $radius;
    1243     private $legends=array();
     1220    private $posx, $posy, $radius;             
     1221    private $legends=array();   
    12441222    public $plots=array();
    12451223    public $pieaa = false ;
    1246     //---------------
    1247     // CONSTRUCTOR
    1248     function __construct($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) {
    1249         parent::__construct($width,$height,$cachedName,$timeout,$inline);
    1250         $this->posx=$width/2;
    1251         $this->posy=$height/2;
    1252         $this->SetColor(array(255,255,255));
    1253 
    1254         if ($this->graph_theme) {
    1255           $this->graph_theme->ApplyGraph($this);
    1256         }
    1257     }
    1258 
    1259     //---------------
    1260     // PUBLIC METHODS
     1224//---------------
     1225// CONSTRUCTOR
     1226    function PieGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) {
     1227        $this->Graph($width,$height,$cachedName,$timeout,$inline);
     1228        $this->posx=$width/2;
     1229        $this->posy=$height/2;
     1230        $this->SetColor(array(255,255,255));           
     1231    }
     1232
     1233//---------------
     1234// PUBLIC METHODS       
    12611235    function Add($aObj) {
    12621236
    1263         if( is_array($aObj) && count($aObj) > 0 )
    1264         $cl = $aObj[0];
    1265         else
    1266         $cl = $aObj;
    1267 
    1268         if( $cl instanceof Text )
    1269         $this->AddText($aObj);
    1270         elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) )
    1271         $this->AddIcon($aObj);
    1272         else {
    1273             if( is_array($aObj) ) {
    1274                 $n = count($aObj);
    1275                 for($i=0; $i < $n; ++$i ) {
    1276                     //if ($aObj[$i]->theme) {
    1277                     //    $this->ClearTheme();
    1278                     //}
    1279                     $this->plots[] = $aObj[$i];
    1280                 }
    1281             }
    1282             else {
    1283                 //if ($aObj->theme) {
    1284                 //    $this->ClearTheme();
    1285                 //}
    1286                 $this->plots[] = $aObj;
    1287             }
    1288         }
    1289 
    1290         if ($this->graph_theme) {
    1291             $this->graph_theme->SetupPlot($aObj);
    1292             if ($aObj->is_using_plot_theme) {
    1293                 $aObj->UsePlotThemeColors();
    1294             }
    1295         }
     1237        if( is_array($aObj) && count($aObj) > 0 )
     1238            $cl = $aObj[0];
     1239        else
     1240            $cl = $aObj;
     1241
     1242        if( $cl instanceof Text )
     1243            $this->AddText($aObj);
     1244        elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) )
     1245            $this->AddIcon($aObj);
     1246        else {
     1247            if( is_array($aObj) ) {
     1248                $n = count($aObj);
     1249                for($i=0; $i < $n; ++$i ) {
     1250                    $this->plots[] = $aObj[$i];
     1251                }
     1252            }
     1253            else {
     1254                $this->plots[] = $aObj;
     1255            }
     1256        }
    12961257    }
    12971258
    12981259    function SetAntiAliasing($aFlg=true) {
    1299         $this->pieaa = $aFlg;
    1300     }
    1301 
     1260        $this->pieaa = $aFlg;
     1261    }
     1262       
    13021263    function SetColor($c) {
    1303         $this->SetMarginColor($c);
     1264        $this->SetMarginColor($c);
    13041265    }
    13051266
    13061267
    13071268    function DisplayCSIMAreas() {
    1308         $csim="";
    1309         foreach($this->plots as $p ) {
    1310             $csim .= $p->GetCSIMareas();
    1311         }
    1312        
    1313         $csim.= $this->legend->GetCSIMareas();
    1314         if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) {
    1315             $this->img->SetColor($this->csimcolor);
    1316             $n = count($coords[0]);
    1317             for ($i=0; $i < $n; $i++) {
    1318                 if ($coords[1][$i]=="poly") {
    1319                     preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts);
    1320                     $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
    1321                     $m = count($pts[0]);
    1322                     for ($j=0; $j < $m; $j++) {
    1323                         $this->img->LineTo($pts[1][$j],$pts[2][$j]);
    1324                     }
    1325                 } else if ($coords[1][$i]=="rect") {
    1326                     $pts = preg_split('/,/', $coords[2][$i]);
    1327                     $this->img->SetStartPoint($pts[0],$pts[1]);
    1328                     $this->img->LineTo($pts[2],$pts[1]);
    1329                     $this->img->LineTo($pts[2],$pts[3]);
    1330                     $this->img->LineTo($pts[0],$pts[3]);
    1331                     $this->img->LineTo($pts[0],$pts[1]);
    1332 
    1333                 }
    1334             }
    1335         }
     1269            $csim="";
     1270            foreach($this->plots as $p ) {
     1271                $csim .= $p->GetCSIMareas();
     1272            }
     1273            //$csim.= $this->legend->GetCSIMareas();
     1274            if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) {
     1275                $this->img->SetColor($this->csimcolor);
     1276                $n = count($coords[0]);
     1277                for ($i=0; $i < $n; $i++) {
     1278                    if ($coords[1][$i]=="poly") {
     1279                        preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts);
     1280                        $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
     1281                        $m = count($pts[0]);
     1282                        for ($j=0; $j < $m; $j++) {
     1283                            $this->img->LineTo($pts[1][$j],$pts[2][$j]);
     1284                        }
     1285                    } else if ($coords[1][$i]=="rect") {
     1286                        $pts = preg_split('/,/', $coords[2][$i]);
     1287                        $this->img->SetStartPoint($pts[0],$pts[1]);
     1288                        $this->img->LineTo($pts[2],$pts[1]);
     1289                        $this->img->LineTo($pts[2],$pts[3]);
     1290                        $this->img->LineTo($pts[0],$pts[3]);
     1291                        $this->img->LineTo($pts[0],$pts[1]);
     1292                                               
     1293                    }
     1294                }
     1295            }
    13361296    }
    13371297
    13381298    // Method description
    13391299    function Stroke($aStrokeFileName="") {
    1340 
    1341         // If the filename is the predefined value = '_csim_special_'
    1342         // we assume that the call to stroke only needs to do enough
    1343         // to correctly generate the CSIM maps.
    1344         // We use this variable to skip things we don't strictly need
    1345         // to do to generate the image map to improve performance
    1346         // a best we can. Therefor you will see a lot of tests !$_csim in the
    1347         // code below.
    1348         $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
    1349 
    1350         // If we are called the second time (perhaps the user has called GetHTMLImageMap()
    1351         // himself then the legends have alsready been populated once in order to get the
    1352         // CSIM coordinats. Since we do not want the legends to be populated a second time
    1353         // we clear the legends
    1354         $this->legend->Clear();
    1355 
    1356         // We need to know if we have stroked the plot in the
    1357         // GetCSIMareas. Otherwise the CSIM hasn't been generated
    1358         // and in the case of GetCSIM called before stroke to generate
    1359         // CSIM without storing an image to disk GetCSIM must call Stroke.
    1360         $this->iHasStroked = true;
    1361 
    1362         $n = count($this->plots);
    1363 
    1364         if( $this->pieaa ) {
    1365 
    1366             if( !$_csim ) {
    1367                 if( $this->background_image != "" ) {
    1368                     $this->StrokeFrameBackground();
    1369                 }
    1370                 else {
    1371                     $this->StrokeFrame();
    1372                     $this->StrokeBackgroundGrad();
    1373                 }
    1374             }
    1375 
    1376 
    1377             $w = $this->img->width;
    1378             $h = $this->img->height;
    1379             $oldimg = $this->img->img;
    1380 
    1381             $this->img->CreateImgCanvas(2*$w,2*$h);
    1382 
    1383             $this->img->SetColor( $this->margin_color );
    1384             $this->img->FilledRectangle(0,0,2*$w-1,2*$h-1);
    1385 
    1386             // Make all icons *2 i size since we will be scaling down the
    1387             // imahe to do the anti aliasing
    1388             $ni = count($this->iIcons);
    1389             for($i=0; $i < $ni; ++$i) {
    1390                 $this->iIcons[$i]->iScale *= 2 ;
    1391                 if( $this->iIcons[$i]->iX > 1 )
    1392                 $this->iIcons[$i]->iX *= 2 ;
    1393                 if( $this->iIcons[$i]->iY > 1 )
    1394                 $this->iIcons[$i]->iY *= 2 ;
    1395             }
    1396 
    1397             $this->StrokeIcons();
    1398 
    1399             for($i=0; $i < $n; ++$i) {
    1400                 if( $this->plots[$i]->posx > 1 )
    1401                 $this->plots[$i]->posx *= 2 ;
    1402                 if( $this->plots[$i]->posy > 1 )
    1403                 $this->plots[$i]->posy *= 2 ;
    1404 
    1405                 $this->plots[$i]->Stroke($this->img,1);
    1406 
    1407                 if( $this->plots[$i]->posx > 1 )
    1408                 $this->plots[$i]->posx /= 2 ;
    1409                 if( $this->plots[$i]->posy > 1 )
    1410                 $this->plots[$i]->posy /= 2 ;
    1411             }
    1412 
    1413             $indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ;
    1414             $indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ;
    1415             $this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent,
    1416             $w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent));
    1417 
    1418             $this->img->img = $oldimg ;
    1419             $this->img->width = $w ;
    1420             $this->img->height = $h ;
    1421 
    1422             for($i=0; $i < $n; ++$i) {
    1423                 $this->plots[$i]->Stroke($this->img,2); // Stroke labels
    1424                 $this->plots[$i]->Legend($this);
    1425             }
    1426 
    1427         }
    1428         else {
    1429 
    1430             if( !$_csim ) {
    1431                 if( $this->background_image != "" ) {
    1432                     $this->StrokeFrameBackground();
    1433                 }
    1434                 else {
    1435                     $this->StrokeFrame();
    1436                     $this->StrokeBackgroundGrad();
    1437                 }
    1438             }
    1439 
    1440             $this->StrokeIcons();
    1441 
    1442             for($i=0; $i < $n; ++$i) {
    1443                 $this->plots[$i]->Stroke($this->img);
    1444                 $this->plots[$i]->Legend($this);
    1445             }
    1446         }
    1447 
    1448         $this->legend->Stroke($this->img);
    1449         $this->footer->Stroke($this->img);
    1450         $this->StrokeTitles();
    1451 
    1452         if( !$_csim ) {
    1453 
    1454             // Stroke texts
    1455             if( $this->texts != null ) {
    1456                 $n = count($this->texts);
    1457                 for($i=0; $i < $n; ++$i ) {
    1458                     $this->texts[$i]->Stroke($this->img);
    1459                 }
    1460             }
    1461 
    1462             if( _JPG_DEBUG ) {
    1463                 $this->DisplayCSIMAreas();
    1464             }
    1465 
    1466             // Should we do any final image transformation
    1467             if( $this->iImgTrans ) {
    1468                 if( !class_exists('ImgTrans',false) ) {
    1469                     require_once('jpgraph_imgtrans.php');
    1470                     //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');
    1471                 }
    1472 
    1473                 $tform = new ImgTrans($this->img->img);
    1474                 $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
    1475                 $this->iImgTransDirection,$this->iImgTransHighQ,
    1476                 $this->iImgTransMinSize,$this->iImgTransFillColor,
    1477                 $this->iImgTransBorder);
    1478             }
    1479 
    1480 
    1481             // If the filename is given as the special "__handle"
    1482             // then the image handler is returned and the image is NOT
    1483             // streamed back
    1484             if( $aStrokeFileName == _IMG_HANDLER ) {
    1485                 return $this->img->img;
    1486             }
    1487             else {
    1488                 // Finally stream the generated picture
    1489                 $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,
    1490                 $aStrokeFileName);
    1491             }
    1492         }
     1300        // If the filename is the predefined value = '_csim_special_'
     1301        // we assume that the call to stroke only needs to do enough
     1302        // to correctly generate the CSIM maps.
     1303        // We use this variable to skip things we don't strictly need
     1304        // to do to generate the image map to improve performance
     1305        // a best we can. Therefor you will see a lot of tests !$_csim in the
     1306        // code below.
     1307        $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
     1308
     1309        // We need to know if we have stroked the plot in the
     1310        // GetCSIMareas. Otherwise the CSIM hasn't been generated
     1311        // and in the case of GetCSIM called before stroke to generate
     1312        // CSIM without storing an image to disk GetCSIM must call Stroke.
     1313        $this->iHasStroked = true;
     1314
     1315        $n = count($this->plots);
     1316
     1317        if( $this->pieaa ) {
     1318
     1319            if( !$_csim ) {
     1320                if( $this->background_image != "" ) {
     1321                    $this->StrokeFrameBackground();             
     1322                }
     1323                else {
     1324                    $this->StrokeFrame();               
     1325                    $this->StrokeBackgroundGrad();
     1326                }
     1327            }
     1328
     1329
     1330            $w = $this->img->width;
     1331            $h = $this->img->height;
     1332            $oldimg = $this->img->img;
     1333
     1334            $this->img->CreateImgCanvas(2*$w,2*$h);
     1335           
     1336            $this->img->SetColor( $this->margin_color );
     1337            $this->img->FilledRectangle(0,0,2*$w-1,2*$h-1);
     1338
     1339            // Make all icons *2 i size since we will be scaling down the
     1340            // imahe to do the anti aliasing
     1341            $ni = count($this->iIcons);
     1342            for($i=0; $i < $ni; ++$i) {
     1343                $this->iIcons[$i]->iScale *= 2 ;
     1344                if( $this->iIcons[$i]->iX > 1 )
     1345                    $this->iIcons[$i]->iX *= 2 ;
     1346                if( $this->iIcons[$i]->iY > 1 )
     1347                    $this->iIcons[$i]->iY *= 2 ;
     1348            }
     1349
     1350            $this->StrokeIcons();
     1351
     1352            for($i=0; $i < $n; ++$i) {
     1353                if( $this->plots[$i]->posx > 1 )
     1354                    $this->plots[$i]->posx *= 2 ;
     1355                if( $this->plots[$i]->posy > 1 )
     1356                    $this->plots[$i]->posy *= 2 ;
     1357
     1358                $this->plots[$i]->Stroke($this->img,1);
     1359
     1360                if( $this->plots[$i]->posx > 1 )
     1361                    $this->plots[$i]->posx /= 2 ;
     1362                if( $this->plots[$i]->posy > 1 )
     1363                    $this->plots[$i]->posy /= 2 ;
     1364            }
     1365
     1366            $indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ;
     1367            $indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ;
     1368            $this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent,
     1369                                    $w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent));
     1370
     1371            $this->img->img = $oldimg ;
     1372            $this->img->width = $w ;
     1373            $this->img->height = $h ;
     1374
     1375            for($i=0; $i < $n; ++$i) {
     1376                $this->plots[$i]->Stroke($this->img,2); // Stroke labels
     1377                $this->plots[$i]->Legend($this);
     1378            }
     1379
     1380        }
     1381        else {
     1382
     1383            if( !$_csim ) {
     1384                if( $this->background_image != "" ) {
     1385                    $this->StrokeFrameBackground();             
     1386                }
     1387                else {
     1388                    $this->StrokeFrame();               
     1389                }
     1390            }
     1391
     1392            $this->StrokeIcons();
     1393
     1394            for($i=0; $i < $n; ++$i) {
     1395                $this->plots[$i]->Stroke($this->img);
     1396                $this->plots[$i]->Legend($this);
     1397            }
     1398        }
     1399
     1400        $this->legend->Stroke($this->img);
     1401        $this->footer->Stroke($this->img);
     1402        $this->StrokeTitles();
     1403
     1404        if( !$_csim ) {
     1405
     1406            // Stroke texts
     1407            if( $this->texts != null ) {
     1408                $n = count($this->texts);
     1409                for($i=0; $i < $n; ++$i ) {
     1410                    $this->texts[$i]->Stroke($this->img);
     1411                }
     1412            }
     1413
     1414            if( _JPG_DEBUG ) {
     1415                $this->DisplayCSIMAreas();
     1416            }
     1417
     1418            // Should we do any final image transformation
     1419            if( $this->iImgTrans ) {
     1420                if( !class_exists('ImgTrans',false) ) {
     1421                    require_once('jpgraph_imgtrans.php');
     1422                    //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');
     1423                }
     1424               
     1425                $tform = new ImgTrans($this->img->img);
     1426                $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
     1427                                                 $this->iImgTransDirection,$this->iImgTransHighQ,
     1428                                                 $this->iImgTransMinSize,$this->iImgTransFillColor,
     1429                                                 $this->iImgTransBorder);
     1430            }
     1431
     1432
     1433            // If the filename is given as the special "__handle"
     1434            // then the image handler is returned and the image is NOT
     1435            // streamed back
     1436            if( $aStrokeFileName == _IMG_HANDLER ) {
     1437                return $this->img->img;
     1438            }
     1439            else {
     1440                // Finally stream the generated picture                                 
     1441                $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,
     1442                                           $aStrokeFileName);           
     1443            }
     1444        }
    14931445    }
    14941446} // Class
Note: See TracChangeset for help on using the changeset viewer.