[3594] | 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 | ?> |
---|