1 | <?php |
---|
2 | /*======================================================================= |
---|
3 | // File: JPGRAPH_PIE3D.PHP |
---|
4 | // Description: 3D Pie plot extension for JpGraph |
---|
5 | // Created: 2001-03-24 |
---|
6 | // Author: Johan Persson (johanp@aditus.nu) |
---|
7 | // Ver: $Id: jpgraph_pie3d.php 18250 2005-05-07 14:13:43Z ralfbecker $ |
---|
8 | // |
---|
9 | // License: This code is released under GPL 2.0 |
---|
10 | // Copyright (C) 2001 Johan Persson |
---|
11 | //======================================================================== |
---|
12 | */ |
---|
13 | |
---|
14 | //=================================================== |
---|
15 | // CLASS PiePlot3D |
---|
16 | // Description: Plots a 3D pie with a specified projection |
---|
17 | // angle between 20 and 70 degrees. |
---|
18 | //=================================================== |
---|
19 | class PiePlot3D extends PiePlot { |
---|
20 | var $labelhintcolor="red",$showlabelhint=true,$labelmargin=0.30; |
---|
21 | var $angle=30; |
---|
22 | |
---|
23 | //--------------- |
---|
24 | // CONSTRUCTOR |
---|
25 | function PiePlot3d(&$data) { |
---|
26 | $this->data = $data; |
---|
27 | $this->title = new Text(""); |
---|
28 | $this->title->SetFont(FF_FONT1,FS_BOLD); |
---|
29 | } |
---|
30 | |
---|
31 | //--------------- |
---|
32 | // PUBLIC METHODS |
---|
33 | |
---|
34 | // Specify projection angle for 3D in degrees |
---|
35 | // Must be between 20 and 70 degrees |
---|
36 | function SetAngle($a) { |
---|
37 | if( $a<30 || $a>70 ) |
---|
38 | JpGraphError::Raise("JpGraph: 3D Pie projection angle must be between 30 and 70 degrees."); |
---|
39 | else |
---|
40 | $this->angle = $a; |
---|
41 | } |
---|
42 | |
---|
43 | function AddSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle |
---|
44 | |
---|
45 | //add coordinates of the centre to the map |
---|
46 | $coords = "$xc, $yc"; |
---|
47 | |
---|
48 | //add coordinates of the first point on the arc to the map |
---|
49 | $xp = floor($width*cos($sa)/2+$xc); |
---|
50 | $yp = floor($yc-$height*sin($sa)/2); |
---|
51 | $coords.= ", $xp, $yp"; |
---|
52 | |
---|
53 | //If on the front half, add the thickness offset |
---|
54 | if ($sa >= M_PI && $sa <= 2*M_PI*1.01) { |
---|
55 | $yp = floor($yp+($thick*$width)); |
---|
56 | $coords.= ", $xp, $yp"; |
---|
57 | } |
---|
58 | |
---|
59 | //add coordinates every 0.2 radians |
---|
60 | $a=$sa+0.2; |
---|
61 | while ($a<$ea) { |
---|
62 | $xp = floor($width*cos($a)/2+$xc); |
---|
63 | if ($a >= M_PI && $a <= 2*M_PI*1.01) { |
---|
64 | $yp = floor($yc-($height*sin($a)/2)+$thick*$width); |
---|
65 | } else { |
---|
66 | $yp = floor($yc-$height*sin($a)/2); |
---|
67 | } |
---|
68 | $coords.= ", $xp, $yp"; |
---|
69 | $a += 0.2; |
---|
70 | } |
---|
71 | |
---|
72 | //Add the last point on the arc |
---|
73 | $xp = floor($width*cos($ea)/2+$xc); |
---|
74 | $yp = floor($yc-$height*sin($ea)/2); |
---|
75 | |
---|
76 | //If on the front half, add the thickness offset |
---|
77 | if ($ea >= M_PI && $ea <= 2*M_PI*1.01) { |
---|
78 | $coords.= ", $xp, ".floor($yp+($thick*$width)); |
---|
79 | } |
---|
80 | $coords.= ", $xp, $yp"; |
---|
81 | if( !empty($this->csimalts[$i]) ) { |
---|
82 | $tmp=sprintf($this->csimalts[$i],$this->data[$i]); |
---|
83 | $alt="alt=\"$tmp\""; |
---|
84 | } |
---|
85 | if( !empty($this->csimtargets[$i]) ) |
---|
86 | $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\" $alt>\r\n"; |
---|
87 | } |
---|
88 | |
---|
89 | |
---|
90 | function ExplodeSlice($e) { |
---|
91 | JpGraphError::Raise("JpGraph Error: Exploding slices are not (yet) implemented for 3d pies graphs."); |
---|
92 | //$this->explode_slice=$e; |
---|
93 | } |
---|
94 | |
---|
95 | // Distance from the pie to the labels |
---|
96 | function SetLabelMargin($m) { |
---|
97 | assert($m>0 && $m<1); |
---|
98 | $this->labelmargin=$m; |
---|
99 | } |
---|
100 | |
---|
101 | // Show a thin line from the pie to the label for a specific slice |
---|
102 | function ShowLabelHint($f=true) { |
---|
103 | $this->showlabelhint=$f; |
---|
104 | } |
---|
105 | |
---|
106 | // Set color of hint line to label for each slice |
---|
107 | function SetLabelHintColor($c) { |
---|
108 | $this->labelhintcolor=$c; |
---|
109 | } |
---|
110 | |
---|
111 | function Stroke(&$img) { |
---|
112 | |
---|
113 | $colors = array_keys($img->rgb->rgb_table); |
---|
114 | sort($colors); |
---|
115 | $ta=$this->themearr[$this->theme]; |
---|
116 | |
---|
117 | if( $this->setslicecolors==null ) |
---|
118 | $numcolors=count($ta); |
---|
119 | else |
---|
120 | $numcolors=count($this->setslicecolors); |
---|
121 | |
---|
122 | // Draw the slices |
---|
123 | $sum=0; |
---|
124 | foreach($this->data as $d) |
---|
125 | $sum += $d; |
---|
126 | |
---|
127 | // Format the titles for each slice |
---|
128 | for( $i=0; $i<count($this->data); ++$i) { |
---|
129 | if( $this->labeltype==0 ) |
---|
130 | if( $sum != 0 ) |
---|
131 | $l = round(100*$this->data[$i]/$sum,$this->precision); |
---|
132 | else |
---|
133 | $l=0; |
---|
134 | else |
---|
135 | $l = $this->data[$i]; |
---|
136 | $l = sprintf($this->labelformat,$l); |
---|
137 | if( $this->show_psign ) $l .= "%"; |
---|
138 | $this->labels[$i]=$l; |
---|
139 | } |
---|
140 | |
---|
141 | // Set up the pie-circle with some heuristic constants |
---|
142 | $thick=0.16-($this->angle-20)/60*0.07; |
---|
143 | |
---|
144 | $width = floor(2.0*$this->radius*min($img->width,$img->height)); |
---|
145 | $height = ($this->angle/90.0)*$width; |
---|
146 | $xc = $this->posx*$img->width; |
---|
147 | $yc = $this->posy*$img->height; |
---|
148 | |
---|
149 | $img->SetColor($this->color); |
---|
150 | $img->Ellipse($xc,$yc,$width,$height); |
---|
151 | $img->Arc($xc,$yc+$width*$thick,$width,$height,0,180); |
---|
152 | $img->Line($xc+$width/2,$yc,$xc+$width/2,$yc+$width*$thick); |
---|
153 | $img->Line($xc-$width/2,$yc,$xc-$width/2,$yc+$width*$thick); |
---|
154 | $fillPerimeter[0] = array('x' => round((($xc - ($width / 2)) + 1)), |
---|
155 | 'y' => round(($yc + ($width * $thick) / 2))); |
---|
156 | |
---|
157 | // Draw the first slice first line |
---|
158 | $img->SetColor($this->color); |
---|
159 | $img->SetLineWeight($this->weight); |
---|
160 | $a = $this->startangle; |
---|
161 | |
---|
162 | $xp = $width*cos($a)/2+$xc; |
---|
163 | $yp = $yc-$height*sin($a)/2; |
---|
164 | $img->Line($xc,$yc,$xp,$yp); |
---|
165 | |
---|
166 | for($i=0; $sum>0 && $i<count($this->data); $i++) { |
---|
167 | $img->SetColor($this->color); |
---|
168 | $d = $this->data[$i]; |
---|
169 | $la = $a + M_PI*$d/$sum; |
---|
170 | $old_a = $a; |
---|
171 | $a += 2*M_PI*$d/$sum; |
---|
172 | |
---|
173 | if ($this->csimtargets[$i]) { |
---|
174 | $this->AddSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$old_a,$a); |
---|
175 | } |
---|
176 | |
---|
177 | $xp = $width*cos($a)/2+$xc; |
---|
178 | $yp = $yc-$height*sin($a)/2; |
---|
179 | |
---|
180 | if( $i<count($this->data)-1) |
---|
181 | $img->Line($xc,$yc,$xp,$yp); |
---|
182 | |
---|
183 | if( $a > M_PI && $a < 0.999*2*M_PI ) |
---|
184 | $img->Line($xp,$yp,$xp,$yp+$width*$thick-1); |
---|
185 | |
---|
186 | if($a < M_PI) { |
---|
187 | $fillPerimeter[$i + 1] = $fillPerimeter[$i]; |
---|
188 | } else { |
---|
189 | $fillPerimeter[$i + 1] = array('x' => round(($xp + 1)), |
---|
190 | 'y' => round(($yp + ($width * $thick) / 2))); |
---|
191 | } |
---|
192 | |
---|
193 | if( $this->setslicecolors==null ) |
---|
194 | $slicecolor=$colors[$ta[$i%$numcolors]]; |
---|
195 | else |
---|
196 | $slicecolor=$this->setslicecolors[$i%$numcolors]; |
---|
197 | |
---|
198 | if( $this->show_labels ) { |
---|
199 | $margin = 1 + $this->labelmargin; |
---|
200 | $xp = $width*cos($la)/2*$margin; |
---|
201 | $yp = $height*sin($la)/2*$margin; |
---|
202 | |
---|
203 | if( ($la >= 0 && $la <= M_PI) || $la>2*M_PI*0.98 ) { |
---|
204 | $this->StrokeLabels($this->labels[$i],$img,$la,$xc+$xp,$yc-$yp); |
---|
205 | if( $this->showlabelhint ) { |
---|
206 | $img->SetColor($this->labelhintcolor); |
---|
207 | $img->Line($xc+$xp/$margin,$yc-$yp/$margin,$xc+$xp,$yc-$yp); |
---|
208 | } |
---|
209 | } |
---|
210 | else { |
---|
211 | $this->StrokeLabels($this->labels[$i],$img,$la,$xc+$xp,$yc-$yp+$width*$thick); |
---|
212 | if( $this->showlabelhint ) { |
---|
213 | $img->SetColor($this->labelhintcolor); |
---|
214 | $img->Line($xc+$xp/$margin,$yc-$yp/$margin+$width*$thick,$xc+$xp,$yc-$yp+$width*$thick); |
---|
215 | } |
---|
216 | } |
---|
217 | |
---|
218 | |
---|
219 | $img->SetColor($slicecolor); |
---|
220 | $xp = $width*cos($la)/3+$xc; |
---|
221 | $yp = $yc-$height*sin($la)/3; |
---|
222 | $img->Fill(round($xp), round($yp)); |
---|
223 | |
---|
224 | // Make the edge color 35% darker |
---|
225 | $img->SetColor($slicecolor.":0.65"); |
---|
226 | |
---|
227 | if($fillPerimeter[$i]['x'] <= $xc + ($width / 2)) { |
---|
228 | $img->Fill($fillPerimeter[$i]['x'],$fillPerimeter[$i]['y']); |
---|
229 | } |
---|
230 | } |
---|
231 | } |
---|
232 | |
---|
233 | // Adjust title position |
---|
234 | $this->title->Pos($xc,$yc-$img->GetFontHeight()-$this->radius,"center","bottom"); |
---|
235 | $this->title->Stroke($img); |
---|
236 | |
---|
237 | // Draw the pie ellipse one more time since the filling might have |
---|
238 | // written partly on the lines due to the filling in the edges. |
---|
239 | $img->SetColor($this->color); |
---|
240 | $img->Ellipse($xc,$yc,$width,$height); |
---|
241 | $img->Arc($xc,$yc+$width*$thick,$width,$height,0,180); |
---|
242 | |
---|
243 | // Draw the first slice first line |
---|
244 | $a = $this->startangle; |
---|
245 | $xp = $width*cos($a)/2+$xc; |
---|
246 | $yp = $yc-$height*sin($a)/2; |
---|
247 | $img->Line($xc,$yc,$xp,$yp); |
---|
248 | |
---|
249 | // Draw the rest of the slice lines |
---|
250 | for($i=0, $a=0; $sum>0 && $i<count($this->data); $i++) { |
---|
251 | $d = $this->data[$i]; |
---|
252 | $la = $a + M_PI*$d/$sum; |
---|
253 | $old_a = $a; |
---|
254 | $a += 2*M_PI*$d/$sum; |
---|
255 | |
---|
256 | $xp = $width*cos($a)/2+$xc; |
---|
257 | $yp = $yc-$height*sin($a)/2; |
---|
258 | |
---|
259 | if( $a > M_PI && $a < 0.999*2*M_PI ) |
---|
260 | $img->Line($xp,$yp,$xp,$yp+$width*$thick-1); |
---|
261 | |
---|
262 | if( $i<count($this->data)-1) |
---|
263 | $img->Line($xc,$yc,$xp,$yp); |
---|
264 | } |
---|
265 | |
---|
266 | $img->Line($xc+$width/2,$yc,$xc+$width/2,$yc+$width*$thick); |
---|
267 | $img->Line($xc-$width/2,$yc,$xc-$width/2,$yc+$width*$thick); |
---|
268 | |
---|
269 | } |
---|
270 | |
---|
271 | //--------------- |
---|
272 | // PRIVATE METHODS |
---|
273 | |
---|
274 | // Position the labels of each slice |
---|
275 | function StrokeLabels($label,$img,$a,$xp,$yp) { |
---|
276 | |
---|
277 | $img->SetFont($this->font_family,$this->font_style,$this->font_size); |
---|
278 | $img->SetColor($this->font_color); |
---|
279 | $img->SetTextAlign("left","top"); |
---|
280 | $marg=6; |
---|
281 | |
---|
282 | // Position the axis title. |
---|
283 | // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text |
---|
284 | // that intersects with the extension of the corresponding axis. The code looks a little |
---|
285 | // bit messy but this is really the only way of having a reasonable position of the |
---|
286 | // axis titles. |
---|
287 | $h=$img->GetTextHeight($label); |
---|
288 | $w=$img->GetTextWidth($label); |
---|
289 | while( $a > 2*M_PI ) $a -= 2*M_PI; |
---|
290 | if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0; |
---|
291 | if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI; |
---|
292 | if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1; |
---|
293 | if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI); |
---|
294 | |
---|
295 | if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI; |
---|
296 | if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI); |
---|
297 | if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1; |
---|
298 | if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI); |
---|
299 | if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0; |
---|
300 | |
---|
301 | $img->StrokeText($xp-$dx*$w,$yp-$dy*$h,$label); |
---|
302 | } |
---|
303 | } // Class |
---|
304 | |
---|
305 | /* EOF */ |
---|
306 | ?> |
---|