1<?php
2 /*
3     pPie - class to draw pie charts
4
5     Version     : 2.1.0
6     Made by     : Jean-Damien POGOLOTTI
7     Last Update : 26/01/11
8
9     This file can be distributed under the license you can find at :
10
11                       http://www.pchart.net/license
12
13     You can find the whole class documentation on the pChart web site.
14 */
15
16 /* Class return codes */
17 define("PIE_NO_ABSCISSA"	, 140001);
18 define("PIE_NO_DATASERIE"	, 140002);
19 define("PIE_SUMISNULL"		, 140003);
20 define("PIE_RENDERED"		, 140000);
21
22 define("PIE_LABEL_COLOR_AUTO"	, 140010);
23 define("PIE_LABEL_COLOR_MANUAL", 140011);
24
25 define("PIE_VALUE_NATURAL"	, 140020);
26 define("PIE_VALUE_PERCENTAGE"	, 140021);
27
28 /* pPie class definition */
29 class pPie
30  {
31   var $pChartObject;
32   var $pDataObject;
33
34   /* Class creator */
35   function pPie($Object,$pDataObject)
36    {
37     /* Cache the pChart object reference */
38     $this->pChartObject = $Object;
39
40     /* Cache the pData object reference */
41     $this->pDataObject  = $pDataObject;
42    }
43
44   /* Draw a pie chart */
45   function draw2DPie($X,$Y,$Format="")
46    {
47     /* Rendering layout */
48     $Radius		= isset($Format["Radius"]) ? $Format["Radius"] : 60;
49     $DataGapAngle	= isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
50     $DataGapRadius	= isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
51     $SecondPass	= isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE;
52     $Border		= isset($Format["Border"]) ? $Format["Border"] : FALSE;
53     $BorderR		= isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
54     $BorderG		= isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
55     $BorderB		= isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
56     $Shadow		= isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
57     $DrawLabels	= isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
58     $LabelColor	= isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
59     $LabelR		= isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
60     $LabelG		= isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
61     $LabelB		= isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
62     $LabelAlpha	= isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
63
64     /* Data Processing */
65     $Data    = $this->pDataObject->getData();
66     $Palette = $this->pDataObject->getPalette();
67
68     /* Do we have an abscissa serie defined? */
69     if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
70
71     /* Try to find the data serie */
72     $DataSerie = "";
73     foreach ($Data["Series"] as $SerieName => $SerieData)
74      { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
75
76     /* Do we have data to compute? */
77     if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
78
79     /* Compute the pie sum */
80     $SerieSum = $this->pDataObject->getSum($DataSerie);
81
82     /* Do we have data to draw? */
83     if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
84
85     /* Dump the real number of data to draw */
86     $Values = "";
87     $PaletteAux = array(); // Fix to store only necesary colors
88     foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
89      { if ($Value != 0) { $Values[$Key] = $Value; $PaletteAux[] = $Palette[$Key]; } }
90
91	 $Palette = $PaletteAux;
92
93     /* Compute the wasted angular space between series */
94     if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
95
96     /* Compute the scale */
97     $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
98
99     $RestoreShadow = $this->pChartObject->Shadow;
100     if ( $this->pChartObject->Shadow )
101      {
102       $this->pChartObject->Shadow = FALSE;
103
104       $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE;
105       $this->draw2DPie($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat);
106      }
107
108     /* Draw the polygon pie elements */
109     $Step = 360 / (2 * PI * $Radius);
110     $Offset = 0; $ID = 0;
111     foreach($Values as $Key => $Value)
112      {
113       if ( $Shadow )
114        $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
115       else
116        $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
117
118       if ( !$SecondPass && !$Shadow )
119        {
120         if ( !$Border )
121          $Settings["Surrounding"] = 10;
122         else
123          { $Settings["BorderR"] = $BorderR; $Settings["BorderG"] = $BorderG; $Settings["BorderB"] = $BorderB; }
124        }
125
126       $Plots = "";
127       $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
128
129       $Angle = ($EndAngle - $Offset)/2 + $Offset;
130       if ($DataGapAngle == 0)
131        { $X0 = $X; $Y0 = $Y; }
132       else
133        {
134         $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
135         $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y;
136        }
137
138       $Plots[] = $X0; $Plots[] = $Y0;
139
140
141       for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
142        {
143         $Xc = cos(($i-90)*PI/180) * $Radius + $X;
144         $Yc = sin(($i-90)*PI/180) * $Radius + $Y;
145
146         if ( $SecondPass && ( $i<90 )) { $Yc++; }
147         if ( $SecondPass && ( $i>180 && $i<270 )) { $Xc++; }
148         if ( $SecondPass && ( $i>=270 )) { $Xc++; $Yc++; }
149
150         $Plots[] = $Xc; $Plots[] = $Yc;
151        }
152
153       $this->pChartObject->drawPolygon($Plots,$Settings);
154
155       if ( $DrawLabels && !$Shadow && !$SecondPass )
156        {
157         if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
158          { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
159         else
160          { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
161
162         $Angle = ($EndAngle - $Offset)/2 + $Offset;
163         $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
164         $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y;
165
166         $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
167
168         $Settings["Angle"]  = 360-$Angle;
169         $Settings["Length"] = 25;
170         $Settings["Size"]   = 8;
171         $this->pChartObject->drawArrowLabel($Xc,$Yc," ".$Label." ",$Settings);
172        }
173
174       $Offset = $i + $DataGapAngle; $ID++;
175      }
176
177     /* Second pass to smooth the angles */
178     if ( $SecondPass )
179      {
180       $Step = 360 / (2 * PI * $Radius);
181       $Offset = 0; $ID = 0;
182       foreach($Values as $Key => $Value)
183        {
184         $FirstPoint = TRUE;
185         if ( $Shadow )
186          $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
187         else
188          {
189           if ( $Border )
190            $Settings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB);
191           else
192            $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
193          }
194
195         $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
196
197         if ($DataGapAngle == 0)
198          { $X0 = $X; $Y0 = $Y; }
199         else
200          {
201           $Angle = ($EndAngle - $Offset)/2 + $Offset;
202           $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
203           $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y;
204          }
205         $Plots[] = $X0; $Plots[] = $Y0;
206
207         for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
208          {
209           $Xc = cos(($i-90)*PI/180) * $Radius + $X;
210           $Yc = sin(($i-90)*PI/180) * $Radius + $Y;
211
212           if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; }
213
214           $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
215          }
216         $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings);
217
218         if ( $DrawLabels && !$Shadow )
219          {
220           if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
221            { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
222           else
223            { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
224
225           $Angle = ($EndAngle - $Offset)/2 + $Offset;
226           $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
227           $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y;
228
229           $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
230
231           $Settings["Angle"]  = 360-$Angle;
232           $Settings["Length"] = 25;
233           $Settings["Size"]   = 8;
234
235           $this->pChartObject->drawArrowLabel($Xc,$Yc," ".$Label." ",$Settings);
236          }
237
238         $Offset = $i + $DataGapAngle; $ID++;
239        }
240      }
241
242     $this->pChartObject->Shadow = $RestoreShadow;
243
244     return(PIE_RENDERED);
245    }
246
247   /* Draw a 3D pie chart */
248   function draw3DPie($X,$Y,$Format="")
249    {
250     /* Rendering layout */
251     $Radius		= isset($Format["Radius"]) ? $Format["Radius"] : 80;
252     $SkewFactor	= isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .5;
253     $SliceHeight	= isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 20;
254     $DataGapAngle	= isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
255     $DataGapRadius	= isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
256     $SecondPass	= isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE;
257     $Border		= isset($Format["Border"]) ? $Format["Border"] : FALSE;
258     $Shadow		= isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
259     $DrawLabels	= isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
260     $LabelColor	= isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
261     $LabelR		= isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
262     $LabelG		= isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
263     $LabelB		= isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
264     $LabelAlpha	= isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
265     $WriteValues	= isset($Format["WriteValues"]) ? $Format["WriteValues"] : PIE_VALUE_PERCENTAGE;
266     $ValueSuffix	= isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
267     $ValueR		= isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
268     $ValueG		= isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
269     $ValueB		= isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
270     $ValueAlpha	= isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
271
272     /* Error correction for overlaying rounded corners */
273     if ( $SkewFactor < .5 ) { $SkewFactor = .5; }
274
275     /* Data Processing */
276     $Data    = $this->pDataObject->getData();
277     $Palette = $this->pDataObject->getPalette();
278
279     /* Do we have an abscissa serie defined? */
280     if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
281
282     /* Try to find the data serie */
283     $DataSerie = "";
284     foreach ($Data["Series"] as $SerieName => $SerieData)
285      { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
286
287     /* Do we have data to compute? */
288     if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
289
290     /* Compute the pie sum */
291     $SerieSum = $this->pDataObject->getSum($DataSerie);
292
293     /* Do we have data to draw? */
294     if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
295
296     /* Dump the real number of data to draw */
297     $Values = "";
298     $PaletteAux = array(); // Fix to store only necesary colors
299     foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
300      { if ($Value != 0) { $Values[$Key] = $Value; $PaletteAux[] = $Palette[$Key]; } }
301
302	 $Palette = $PaletteAux;
303
304     /* Compute the wasted angular space between series */
305     if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
306
307     /* Compute the scale */
308     $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
309
310     $RestoreShadow = $this->pChartObject->Shadow;
311     if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; }
312
313     /* Draw the polygon pie elements */
314     $Step   = 360 / (2 * PI * $Radius);
315     $Offset = 360;
316
317	 $ID = count($Values)-1;
318
319     $Values = array_reverse($Values);
320     $Slice  = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = "";
321     foreach($Values as $Key => $Value)
322      {
323
324       $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
325       $SliceColors[$Slice] = $Settings;
326
327       $StartAngle = $Offset;
328       $EndAngle   = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
329
330       if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; }
331       if ( $EndAngle < 180 )   { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; }
332
333       if ($DataGapAngle == 0)
334        { $X0 = $X; $Y0 = $Y; }
335       else
336        {
337         $Angle = ($EndAngle - $Offset)/2 + $Offset;
338         $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
339         $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y;
340        }
341       $Slices[$Slice][] = $X0; $Slices[$Slice][] = $Y0; $SliceAngle[$Slice][] = 0;
342
343       for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
344        {
345         $Xc = cos(($i-90)*PI/180) * $Radius + $X;
346         $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y;
347
348         if ( ($SecondPass || $RestoreShadow ) && ( $i<90 )) { $Yc++; }
349         if ( ($SecondPass || $RestoreShadow ) && ( $i>90 && $i<180 )) { $Xc++; }
350         if ( ($SecondPass || $RestoreShadow ) && ( $i>180 && $i<270 )) { $Xc++; }
351         if ( ($SecondPass || $RestoreShadow ) && ( $i>=270 )) { $Xc++; $Yc++; }
352
353         $Slices[$Slice][] = $Xc; $Slices[$Slice][] = $Yc; $SliceAngle[$Slice][] = $i;
354        }
355
356       $Offset = $i - $DataGapAngle; $ID--; $Slice++;
357      }
358
359     /* Draw the bottom shadow if needed */
360     if ( $RestoreShadow && ($this->pChartObject->ShadowX != 0 || $this->pChartObject->ShadowY !=0 ))
361      {
362       foreach($Slices as $SliceID => $Plots)
363        {
364         $ShadowPie = "";
365         for($i=0;$i<count($Plots);$i=$i+2)
366          { $ShadowPie[] = $Plots[$i]+$this->pChartObject->ShadowX; $ShadowPie[] = $Plots[$i+1]+$this->pChartObject->ShadowY; }
367
368         $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa,"NoBorder"=>TRUE);
369         $this->pChartObject->drawPolygon($ShadowPie,$Settings);
370        }
371
372       $Step = 360 / (2 * PI * $Radius);
373       $Offset = 360;
374       foreach($Values as $Key => $Value)
375        {
376         $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
377
378         for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
379          {
380           $Xc = cos(($i-90)*PI/180) * $Radius + $X + $this->pChartObject->ShadowX;
381           $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y + $this->pChartObject->ShadowY;
382
383           $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
384          }
385
386         $Offset = $i - $DataGapAngle; $ID--;
387        }
388      }
389
390     /* Draw the bottom pie splice */
391     foreach($Slices as $SliceID => $Plots)
392      {
393       $Settings = $SliceColors[$SliceID];  $Settings["NoBorder"] = TRUE;
394       $this->pChartObject->drawPolygon($Plots,$Settings);
395
396       if ( $SecondPass )
397        {
398         $Settings = $SliceColors[$SliceID];
399         if ( $Border )
400          { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30;; }
401
402         $Angle = $SliceAngle[$SliceID][1];
403         $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
404         $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
405         $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings);
406
407         $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1];
408         $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
409         $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
410         $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings);
411        }
412      }
413
414     /* Draw the two vertical edges */
415     $Slices      = array_reverse($Slices);
416     $SliceColors = array_reverse($SliceColors);
417     foreach($Slices as $SliceID => $Plots)
418      {
419       $Settings = $SliceColors[$SliceID];
420       $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
421
422       if ( $Visible[$SliceID]["Start"] )
423        {
424         $this->pChartObject->drawLine($Plots[2],$Plots[3],$Plots[2],$Plots[3]- $SliceHeight,array("R"=>255,"G"=>255,"B"=>255));
425         $Border = "";
426         $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight;
427         $Border[] = $Plots[2]; $Border[] = $Plots[3] - $SliceHeight; $Border[] = $Plots[2]; $Border[] = $Plots[3];
428         $this->pChartObject->drawPolygon($Border,$Settings);
429        }
430      }
431
432     $Slices      = array_reverse($Slices);
433     $SliceColors = array_reverse($SliceColors);
434     foreach($Slices as $SliceID => $Plots)
435      {
436       $Settings = $SliceColors[$SliceID];
437       $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
438       if ( $Visible[$SliceID]["End"] )
439        {
440         $this->pChartObject->drawLine($Plots[count($Plots)-2],$Plots[count($Plots)-1],$Plots[count($Plots)-2],$Plots[count($Plots)-1]- $SliceHeight,array("R"=>255,"G"=>255,"B"=>255));
441
442         $Border = "";
443         $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight;
444         $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1] - $SliceHeight; $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1];
445         $this->pChartObject->drawPolygon($Border,$Settings);
446        }
447      }
448
449     /* Draw the rounded edges */
450     foreach($Slices as $SliceID => $Plots)
451      {
452       $Settings = $SliceColors[$SliceID];
453       $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
454
455       for ($j=2;$j<count($Plots)-2;$j=$j+2)
456        {
457         $Angle = $SliceAngle[$SliceID][$j/2];
458         if ( $Angle < 270 && $Angle > 90 )
459          {
460           $Border = "";
461           $Border[] = $Plots[$j];   $Border[] = $Plots[$j+1];
462           $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3];
463           $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3] - $SliceHeight;
464           $Border[] = $Plots[$j];   $Border[] = $Plots[$j+1] - $SliceHeight;
465           $this->pChartObject->drawPolygon($Border,$Settings);
466          }
467        }
468
469       if ( $SecondPass )
470        {
471         $Settings = $SliceColors[$SliceID];
472         if ( $Border )
473          { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30; }
474
475         $Angle = $SliceAngle[$SliceID][1];
476         if ( $Angle < 270 && $Angle > 90 )
477          {
478           $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
479           $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
480           $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
481          }
482
483         $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1];
484         if ( $Angle < 270 && $Angle > 90 )
485          {
486           $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
487           $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
488           $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
489          }
490
491         if ( $SliceAngle[$SliceID][1] > 270 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 270 )
492          {
493           $Xc = cos((270-90)*PI/180) * $Radius + $X;
494           $Yc = sin((270-90)*PI/180) * $Radius*$SkewFactor + $Y;
495           $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
496          }
497
498         if ( $SliceAngle[$SliceID][1] > 90 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 90 )
499          {
500           $Xc = cos((0)*PI/180) * $Radius + $X;
501           $Yc = sin((0)*PI/180) * $Radius*$SkewFactor + $Y;
502           $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
503          }
504
505        }
506      }
507
508     /* Draw the top splice */
509     foreach($Slices as $SliceID => $Plots)
510      {
511       $Settings = $SliceColors[$SliceID];
512       $Settings["R"]+= 20; $Settings["G"]+= 20; $Settings["B"]+= 20;
513
514       $Top = "";
515       for($j=0;$j<count($Plots);$j=$j+2) { $Top[] = $Plots[$j]; $Top[] = $Plots[$j+1]- $SliceHeight; }
516       $this->pChartObject->drawPolygon($Top,$Settings);
517      }
518
519
520		/* Second pass to smooth the angles */
521		if ( $SecondPass )
522		{
523			$Step = 360 / (2 * PI * $Radius);
524			$Offset = 360;
525			$ID = count($Values)-1;
526			foreach($Values as $Key => $Value)
527			{
528				$FirstPoint = TRUE;
529				if ( $Shadow )
530					$Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
531				else
532				{
533					if ( $Border )
534					{
535						$Settings = array(
536							"R" => $Palette[$ID]["R"] + 30,
537							"G" => $Palette[$ID]["G"] + 30,
538							"B" => $Palette[$ID]["B"] + 30,
539							"Alpha" => $Palette[$ID]["Alpha"]);
540					}
541					else
542						$Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
543				}
544
545				$EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
546
547				if ($DataGapAngle == 0)
548				{ $X0 = $X; $Y0 = $Y- $SliceHeight; }
549				else
550				{
551					$Angle = ($EndAngle - $Offset)/2 + $Offset;
552					$X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
553					$Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y - $SliceHeight;
554				}
555				$Plots[] = $X0; $Plots[] = $Y0;
556
557				for ($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
558				{
559					$Xc = cos(($i-90)*PI/180) * $Radius + $X;
560					$Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight;
561
562					if ( $FirstPoint )
563					{ $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); }
564					else
565					{ $FirstPoint = FALSE; }
566
567					$this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
568					if ($i < 270 && $i > 90 )
569					{ $this->pChartObject->drawAntialiasPixel($Xc,$Yc+$SliceHeight,$Settings); }
570				}
571				$this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings);
572
573				$Offset = $i - $DataGapAngle; $ID--;
574			}
575		}
576
577     if ( $WriteValues != NULL )
578      {
579       $Step = 360 / (2 * PI * $Radius);
580       $Offset = 360; $ID = count($Values)-1;
581       $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha);
582       foreach($Values as $Key => $Value)
583        {
584         $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
585
586         $Angle = ($EndAngle - $Offset)/2 + $Offset;
587         $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X;
588         $Yc = sin(($Angle-90)*PI/180) * ($Radius*$SkewFactor)/2 + $Y - $SliceHeight;
589
590         if ( $WriteValues == PIE_VALUE_PERCENTAGE )
591          $Display = round(( 100 / $SerieSum ) * $Value)."%";
592         elseif ( $WriteValues == PIE_VALUE_NATURAL )
593          $Display = $Value.$ValueSuffix;
594
595         $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings);
596
597         $Offset = $EndAngle - $DataGapAngle; $ID--;
598        }
599      }
600
601     if ( $DrawLabels )
602      {
603       $Step = 360 / (2 * PI * $Radius);
604       $Offset = 360; $ID = count($Values)-1;
605       foreach($Values as $Key => $Value)
606        {
607         if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
608          { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
609         else
610          { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
611
612         $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
613
614         $Angle = ($EndAngle - $Offset)/2 + $Offset;
615         $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
616         $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight;
617
618         if ( isset($Data["Series"][$Data["Abscissa"]]["Data"][$ID]) )
619          {
620           $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$ID];
621
622           $Settings["Angle"]  = 360-$Angle;
623           $Settings["Length"] = 25;
624           $Settings["Size"]   = 8;
625           $this->pChartObject->drawArrowLabel($Xc,$Yc," ".$Label." ",$Settings);
626          }
627
628         $Offset = $EndAngle - $DataGapAngle; $ID--;
629        }
630      }
631
632     $this->pChartObject->Shadow = $RestoreShadow;
633
634     return(PIE_RENDERED);
635    }
636
637   /* Draw the legend of pie chart */
638   function drawPieLegend($X,$Y,$Format="")
639    {
640     $FontName		= isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName;
641     $FontSize		= isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize;
642     $FontR		= isset($Format["FontR"]) ? $Format["FontR"] : $this->pChartObject->FontColorR;
643     $FontG		= isset($Format["FontG"]) ? $Format["FontG"] : $this->pChartObject->FontColorG;
644     $FontB		= isset($Format["FontB"]) ? $Format["FontB"] : $this->pChartObject->FontColorB;
645     $BoxSize		= isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5;
646     $Margin		= isset($Format["Margin"]) ? $Format["Margin"] : 5;
647     $R			= isset($Format["R"]) ? $Format["R"] : 200;
648     $G			= isset($Format["G"]) ? $Format["G"] : 200;
649     $B			= isset($Format["B"]) ? $Format["B"] : 200;
650     $Alpha		= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
651     $BorderR		= isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
652     $BorderG		= isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
653     $BorderB		= isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
654     $Surrounding	= isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;
655     $Style		= isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND;
656     $Mode		= isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL;
657
658     if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; }
659
660     $YStep = max($this->pChartObject->FontSize,$BoxSize) + 5;
661     $XStep = $BoxSize + 5;
662
663     /* Data Processing */
664     $Data    = $this->pDataObject->getData();
665     $Palette = $this->pDataObject->getPalette();
666
667     /* Do we have an abscissa serie defined? */
668     if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
669
670     $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X;
671     foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value)
672      {
673       $BoxArray = $this->pChartObject->getTextBox($vX+$BoxSize+4,$vY+$BoxSize/2,$FontName,$FontSize,0,$Value);
674
675       if ( $Mode == LEGEND_VERTICAL )
676        {
677         if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; }
678         if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; }
679         if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; }
680         $vY=$vY+$YStep;
681        }
682       elseif ( $Mode == LEGEND_HORIZONTAL )
683        {
684         if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; }
685         if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; }
686         if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; }
687         $vX=$Boundaries["R"]+$XStep;
688        }
689      }
690     $vY=$vY-$YStep; $vX=$vX-$XStep;
691
692     $TopOffset  = $Y - $Boundaries["T"];
693     if ( $Boundaries["B"]-($vY+$BoxSize) < $TopOffset ) { $Boundaries["B"] = $vY+$BoxSize+$TopOffset; }
694
695     if ( $Style == LEGEND_ROUND )
696      $this->pChartObject->drawRoundedFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB));
697     elseif ( $Style == LEGEND_BOX )
698      $this->pChartObject->drawFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB));
699
700     $RestoreShadow = $this->pChartObject->Shadow; $this->pChartObject->Shadow = FALSE;
701     foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value)
702      {
703       $R = $Palette[$Key]["R"]; $G = $Palette[$Key]["G"]; $B = $Palette[$Key]["B"];
704
705       $this->pChartObject->drawFilledRectangle($X+1,$Y+1,$X+$BoxSize+1,$Y+$BoxSize+1,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20));
706       $this->pChartObject->drawFilledRectangle($X,$Y,$X+$BoxSize,$Y+$BoxSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20));
707       if ( $Mode == LEGEND_VERTICAL )
708        {
709         $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT));
710         $Y=$Y+$YStep;
711        }
712       elseif ( $Mode == LEGEND_HORIZONTAL )
713        {
714         $BoxArray = $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT));
715         $X=$BoxArray[1]["X"]+2+$XStep;
716        }
717      }
718
719     $this->Shadow = $RestoreShadow;
720    }
721
722   /* Set the color of the specified slice */
723   function setSliceColor($SliceID,$Format="")
724    {
725     $R		= isset($Format["R"]) ? $Format["R"] : 0;
726     $G		= isset($Format["G"]) ? $Format["G"] : 0;
727     $B		= isset($Format["B"]) ? $Format["B"] : 0;
728     $Alpha	= isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
729
730     $this->pDataObject->Palette[$SliceID]["R"]     = $R;
731     $this->pDataObject->Palette[$SliceID]["G"]     = $G;
732     $this->pDataObject->Palette[$SliceID]["B"]     = $B;
733     $this->pDataObject->Palette[$SliceID]["Alpha"] = $Alpha;
734    }
735  }
736?>
737