[2] | 1 | <?php
|
---|
| 2 | /*=======================================================================
|
---|
[284] | 3 | // File: JPGRAPH_PIE3D.PHP
|
---|
| 4 | // Description: 3D Pie plot extension for JpGraph
|
---|
| 5 | // Created: 2001-03-24
|
---|
| 6 | // Ver: $Id: jpgraph_pie3d.php 1329 2009-06-20 19:23:30Z ljp $
|
---|
| 7 | //
|
---|
| 8 | // Copyright (c) Asial Corporation. All rights reserved.
|
---|
| 9 | //========================================================================
|
---|
| 10 | */
|
---|
[2] | 11 |
|
---|
| 12 | //===================================================
|
---|
| 13 | // CLASS PiePlot3D
|
---|
[284] | 14 | // Description: Plots a 3D pie with a specified projection
|
---|
[2] | 15 | // angle between 20 and 70 degrees.
|
---|
| 16 | //===================================================
|
---|
| 17 | class PiePlot3D extends PiePlot {
|
---|
| 18 | private $labelhintcolor="red",$showlabelhint=true;
|
---|
[284] | 19 | private $angle=50;
|
---|
[2] | 20 | private $edgecolor="", $edgeweight=1;
|
---|
| 21 | private $iThickness=false;
|
---|
[284] | 22 |
|
---|
| 23 | //---------------
|
---|
| 24 | // CONSTRUCTOR
|
---|
| 25 | function __construct($data) {
|
---|
| 26 | $this->radius = 0.5;
|
---|
| 27 | $this->data = $data;
|
---|
| 28 | $this->title = new Text("");
|
---|
| 29 | $this->title->SetFont(FF_FONT1,FS_BOLD);
|
---|
| 30 | $this->value = new DisplayValue();
|
---|
| 31 | $this->value->Show();
|
---|
| 32 | $this->value->SetFormat('%.0f%%');
|
---|
[2] | 33 | }
|
---|
| 34 |
|
---|
[284] | 35 | //---------------
|
---|
| 36 | // PUBLIC METHODS
|
---|
| 37 |
|
---|
[2] | 38 | // Set label arrays
|
---|
| 39 | function SetLegends($aLegend) {
|
---|
[284] | 40 | $this->legends = array_reverse(array_slice($aLegend,0,count($this->data)));
|
---|
[2] | 41 | }
|
---|
| 42 |
|
---|
| 43 | function SetSliceColors($aColors) {
|
---|
[284] | 44 | $this->setslicecolors = $aColors;
|
---|
[2] | 45 | }
|
---|
| 46 |
|
---|
| 47 | function Legend($aGraph) {
|
---|
[284] | 48 | parent::Legend($aGraph);
|
---|
| 49 | $aGraph->legend->txtcol = array_reverse($aGraph->legend->txtcol);
|
---|
[2] | 50 | }
|
---|
| 51 |
|
---|
| 52 | function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') {
|
---|
[284] | 53 | $this->csimtargets = $aTargets;
|
---|
| 54 | $this->csimwintargets = $aWinTargets;
|
---|
| 55 | $this->csimalts = $aAlts;
|
---|
[2] | 56 | }
|
---|
| 57 |
|
---|
| 58 | // Should the slices be separated by a line? If color is specified as "" no line
|
---|
| 59 | // will be used to separate pie slices.
|
---|
| 60 | function SetEdge($aColor='black',$aWeight=1) {
|
---|
[284] | 61 | $this->edgecolor = $aColor;
|
---|
| 62 | $this->edgeweight = $aWeight;
|
---|
[2] | 63 | }
|
---|
| 64 |
|
---|
| 65 | // Specify projection angle for 3D in degrees
|
---|
| 66 | // Must be between 20 and 70 degrees
|
---|
| 67 | function SetAngle($a) {
|
---|
[284] | 68 | if( $a<5 || $a>90 ) {
|
---|
| 69 | JpGraphError::RaiseL(14002);
|
---|
| 70 | //("PiePlot3D::SetAngle() 3D Pie projection angle must be between 5 and 85 degrees.");
|
---|
| 71 | }
|
---|
| 72 | else {
|
---|
| 73 | $this->angle = $a;
|
---|
| 74 | }
|
---|
[2] | 75 | }
|
---|
| 76 |
|
---|
| 77 | function Add3DSliceToCSIM($i,$xc,$yc,$height,$width,$thick,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle
|
---|
| 78 |
|
---|
[284] | 79 | $sa *= M_PI/180;
|
---|
| 80 | $ea *= M_PI/180;
|
---|
[2] | 81 |
|
---|
[284] | 82 | //add coordinates of the centre to the map
|
---|
| 83 | $coords = "$xc, $yc";
|
---|
[2] | 84 |
|
---|
[284] | 85 | //add coordinates of the first point on the arc to the map
|
---|
| 86 | $xp = floor($width*cos($sa)/2+$xc);
|
---|
| 87 | $yp = floor($yc-$height*sin($sa)/2);
|
---|
| 88 | $coords.= ", $xp, $yp";
|
---|
[2] | 89 |
|
---|
[284] | 90 | //If on the front half, add the thickness offset
|
---|
| 91 | if ($sa >= M_PI && $sa <= 2*M_PI*1.01) {
|
---|
| 92 | $yp = floor($yp+$thick);
|
---|
| 93 | $coords.= ", $xp, $yp";
|
---|
| 94 | }
|
---|
[2] | 95 |
|
---|
[284] | 96 | //add coordinates every 0.2 radians
|
---|
| 97 | $a=$sa+0.2;
|
---|
| 98 | while ($a<$ea) {
|
---|
| 99 | $xp = floor($width*cos($a)/2+$xc);
|
---|
| 100 | if ($a >= M_PI && $a <= 2*M_PI*1.01) {
|
---|
| 101 | $yp = floor($yc-($height*sin($a)/2)+$thick);
|
---|
| 102 | } else {
|
---|
| 103 | $yp = floor($yc-$height*sin($a)/2);
|
---|
| 104 | }
|
---|
| 105 | $coords.= ", $xp, $yp";
|
---|
| 106 | $a += 0.2;
|
---|
| 107 | }
|
---|
[2] | 108 |
|
---|
[284] | 109 | //Add the last point on the arc
|
---|
| 110 | $xp = floor($width*cos($ea)/2+$xc);
|
---|
| 111 | $yp = floor($yc-$height*sin($ea)/2);
|
---|
[2] | 112 |
|
---|
| 113 |
|
---|
[284] | 114 | if ($ea >= M_PI && $ea <= 2*M_PI*1.01) {
|
---|
| 115 | $coords.= ", $xp, ".floor($yp+$thick);
|
---|
| 116 | }
|
---|
| 117 | $coords.= ", $xp, $yp";
|
---|
| 118 | $alt='';
|
---|
| 119 |
|
---|
| 120 | if( !empty($this->csimtargets[$i]) ) {
|
---|
| 121 | $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\"";
|
---|
| 122 |
|
---|
| 123 | if( !empty($this->csimwintargets[$i]) ) {
|
---|
| 124 | $this->csimareas .= " target=\"".$this->csimwintargets[$i]."\" ";
|
---|
| 125 | }
|
---|
| 126 |
|
---|
| 127 | if( !empty($this->csimalts[$i]) ) {
|
---|
| 128 | $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
|
---|
| 129 | $this->csimareas .= "alt=\"$tmp\" title=\"$tmp\" ";
|
---|
| 130 | }
|
---|
| 131 | $this->csimareas .= " />\n";
|
---|
| 132 | }
|
---|
| 133 |
|
---|
[2] | 134 | }
|
---|
| 135 |
|
---|
| 136 | function SetLabels($aLabels,$aLblPosAdj="auto") {
|
---|
[284] | 137 | $this->labels = $aLabels;
|
---|
| 138 | $this->ilabelposadj=$aLblPosAdj;
|
---|
[2] | 139 | }
|
---|
| 140 |
|
---|
[284] | 141 |
|
---|
[2] | 142 | // Distance from the pie to the labels
|
---|
| 143 | function SetLabelMargin($m) {
|
---|
[284] | 144 | $this->value->SetMargin($m);
|
---|
[2] | 145 | }
|
---|
[284] | 146 |
|
---|
[2] | 147 | // Show a thin line from the pie to the label for a specific slice
|
---|
| 148 | function ShowLabelHint($f=true) {
|
---|
[284] | 149 | $this->showlabelhint=$f;
|
---|
[2] | 150 | }
|
---|
[284] | 151 |
|
---|
[2] | 152 | // Set color of hint line to label for each slice
|
---|
| 153 | function SetLabelHintColor($c) {
|
---|
[284] | 154 | $this->labelhintcolor=$c;
|
---|
[2] | 155 | }
|
---|
| 156 |
|
---|
| 157 | function SetHeight($aHeight) {
|
---|
[284] | 158 | $this->iThickness = $aHeight;
|
---|
[2] | 159 | }
|
---|
| 160 |
|
---|
| 161 |
|
---|
[284] | 162 | // Normalize Angle between 0-360
|
---|
[2] | 163 | function NormAngle($a) {
|
---|
[284] | 164 | // Normalize anle to 0 to 2M_PI
|
---|
| 165 | //
|
---|
| 166 | if( $a > 0 ) {
|
---|
| 167 | while($a > 360) $a -= 360;
|
---|
| 168 | }
|
---|
| 169 | else {
|
---|
| 170 | while($a < 0) $a += 360;
|
---|
| 171 | }
|
---|
| 172 | if( $a < 0 )
|
---|
| 173 | $a = 360 + $a;
|
---|
[2] | 174 |
|
---|
[284] | 175 | if( $a == 360 ) $a=0;
|
---|
| 176 | return $a;
|
---|
[2] | 177 | }
|
---|
| 178 |
|
---|
| 179 |
|
---|
[284] | 180 |
|
---|
| 181 | // Draw one 3D pie slice at position ($xc,$yc) with height $z
|
---|
[2] | 182 | function Pie3DSlice($img,$xc,$yc,$w,$h,$sa,$ea,$z,$fillcolor,$shadow=0.65) {
|
---|
| 183 |
|
---|
[284] | 184 | // Due to the way the 3D Pie algorithm works we are
|
---|
| 185 | // guaranteed that any slice we get into this method
|
---|
| 186 | // belongs to either the left or right side of the
|
---|
| 187 | // pie ellipse. Hence, no slice will cross 90 or 270
|
---|
| 188 | // point.
|
---|
| 189 | if( ($sa < 90 && $ea > 90) || ( ($sa > 90 && $sa < 270) && $ea > 270) ) {
|
---|
| 190 | JpGraphError::RaiseL(14003);//('Internal assertion failed. Pie3D::Pie3DSlice');
|
---|
| 191 | exit(1);
|
---|
| 192 | }
|
---|
[2] | 193 |
|
---|
[284] | 194 | $p[] = array();
|
---|
[2] | 195 |
|
---|
[284] | 196 | // Setup pre-calculated values
|
---|
| 197 | $rsa = $sa/180*M_PI; // to Rad
|
---|
| 198 | $rea = $ea/180*M_PI; // to Rad
|
---|
| 199 | $sinsa = sin($rsa);
|
---|
| 200 | $cossa = cos($rsa);
|
---|
| 201 | $sinea = sin($rea);
|
---|
| 202 | $cosea = cos($rea);
|
---|
[2] | 203 |
|
---|
[284] | 204 | // p[] is the points for the overall slice and
|
---|
| 205 | // pt[] is the points for the top pie
|
---|
[2] | 206 |
|
---|
[284] | 207 | // Angular step when approximating the arc with a polygon train.
|
---|
| 208 | $step = 0.05;
|
---|
[2] | 209 |
|
---|
[284] | 210 | if( $sa >= 270 ) {
|
---|
| 211 | if( $ea > 360 || ($ea > 0 && $ea <= 90) ) {
|
---|
| 212 | if( $ea > 0 && $ea <= 90 ) {
|
---|
| 213 | // Adjust angle to simplify conditions in loops
|
---|
| 214 | $rea += 2*M_PI;
|
---|
| 215 | }
|
---|
[2] | 216 |
|
---|
[284] | 217 | $p = array($xc,$yc,$xc,$yc+$z,
|
---|
| 218 | $xc+$w*$cossa,$z+$yc-$h*$sinsa);
|
---|
| 219 | $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
|
---|
[2] | 220 |
|
---|
[284] | 221 | for( $a=$rsa; $a < 2*M_PI; $a += $step ) {
|
---|
| 222 | $tca = cos($a);
|
---|
| 223 | $tsa = sin($a);
|
---|
| 224 | $p[] = $xc+$w*$tca;
|
---|
| 225 | $p[] = $z+$yc-$h*$tsa;
|
---|
| 226 | $pt[] = $xc+$w*$tca;
|
---|
| 227 | $pt[] = $yc-$h*$tsa;
|
---|
| 228 | }
|
---|
[2] | 229 |
|
---|
[284] | 230 | $pt[] = $xc+$w;
|
---|
| 231 | $pt[] = $yc;
|
---|
[2] | 232 |
|
---|
[284] | 233 | $p[] = $xc+$w;
|
---|
| 234 | $p[] = $z+$yc;
|
---|
| 235 | $p[] = $xc+$w;
|
---|
| 236 | $p[] = $yc;
|
---|
| 237 | $p[] = $xc;
|
---|
| 238 | $p[] = $yc;
|
---|
[2] | 239 |
|
---|
[284] | 240 | for( $a=2*M_PI+$step; $a < $rea; $a += $step ) {
|
---|
| 241 | $pt[] = $xc + $w*cos($a);
|
---|
| 242 | $pt[] = $yc - $h*sin($a);
|
---|
| 243 | }
|
---|
[2] | 244 |
|
---|
[284] | 245 | $pt[] = $xc+$w*$cosea;
|
---|
| 246 | $pt[] = $yc-$h*$sinea;
|
---|
| 247 | $pt[] = $xc;
|
---|
| 248 | $pt[] = $yc;
|
---|
[2] | 249 |
|
---|
[284] | 250 | }
|
---|
| 251 | else {
|
---|
| 252 | $p = array($xc,$yc,$xc,$yc+$z,
|
---|
| 253 | $xc+$w*$cossa,$z+$yc-$h*$sinsa);
|
---|
| 254 | $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
|
---|
[2] | 255 |
|
---|
[284] | 256 | $rea = $rea == 0.0 ? 2*M_PI : $rea;
|
---|
| 257 | for( $a=$rsa; $a < $rea; $a += $step ) {
|
---|
| 258 | $tca = cos($a);
|
---|
| 259 | $tsa = sin($a);
|
---|
| 260 | $p[] = $xc+$w*$tca;
|
---|
| 261 | $p[] = $z+$yc-$h*$tsa;
|
---|
| 262 | $pt[] = $xc+$w*$tca;
|
---|
| 263 | $pt[] = $yc-$h*$tsa;
|
---|
| 264 | }
|
---|
[2] | 265 |
|
---|
[284] | 266 | $pt[] = $xc+$w*$cosea;
|
---|
| 267 | $pt[] = $yc-$h*$sinea;
|
---|
| 268 | $pt[] = $xc;
|
---|
| 269 | $pt[] = $yc;
|
---|
[2] | 270 |
|
---|
[284] | 271 | $p[] = $xc+$w*$cosea;
|
---|
| 272 | $p[] = $z+$yc-$h*$sinea;
|
---|
| 273 | $p[] = $xc+$w*$cosea;
|
---|
| 274 | $p[] = $yc-$h*$sinea;
|
---|
| 275 | $p[] = $xc;
|
---|
| 276 | $p[] = $yc;
|
---|
| 277 | }
|
---|
| 278 | }
|
---|
| 279 | elseif( $sa >= 180 ) {
|
---|
| 280 | $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);
|
---|
| 281 | $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
|
---|
[2] | 282 |
|
---|
[284] | 283 | for( $a=$rea; $a>$rsa; $a -= $step ) {
|
---|
| 284 | $tca = cos($a);
|
---|
| 285 | $tsa = sin($a);
|
---|
| 286 | $p[] = $xc+$w*$tca;
|
---|
| 287 | $p[] = $z+$yc-$h*$tsa;
|
---|
| 288 | $pt[] = $xc+$w*$tca;
|
---|
| 289 | $pt[] = $yc-$h*$tsa;
|
---|
| 290 | }
|
---|
[2] | 291 |
|
---|
[284] | 292 | $pt[] = $xc+$w*$cossa;
|
---|
| 293 | $pt[] = $yc-$h*$sinsa;
|
---|
| 294 | $pt[] = $xc;
|
---|
| 295 | $pt[] = $yc;
|
---|
[2] | 296 |
|
---|
[284] | 297 | $p[] = $xc+$w*$cossa;
|
---|
| 298 | $p[] = $z+$yc-$h*$sinsa;
|
---|
| 299 | $p[] = $xc+$w*$cossa;
|
---|
| 300 | $p[] = $yc-$h*$sinsa;
|
---|
| 301 | $p[] = $xc;
|
---|
| 302 | $p[] = $yc;
|
---|
[2] | 303 |
|
---|
[284] | 304 | }
|
---|
| 305 | elseif( $sa >= 90 ) {
|
---|
| 306 | if( $ea > 180 ) {
|
---|
| 307 | $p = array($xc,$yc,$xc,$yc+$z,$xc+$w*$cosea,$z+$yc-$h*$sinea);
|
---|
| 308 | $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
|
---|
[2] | 309 |
|
---|
[284] | 310 | for( $a=$rea; $a > M_PI; $a -= $step ) {
|
---|
| 311 | $tca = cos($a);
|
---|
| 312 | $tsa = sin($a);
|
---|
| 313 | $p[] = $xc+$w*$tca;
|
---|
| 314 | $p[] = $z + $yc - $h*$tsa;
|
---|
| 315 | $pt[] = $xc+$w*$tca;
|
---|
| 316 | $pt[] = $yc-$h*$tsa;
|
---|
| 317 | }
|
---|
[2] | 318 |
|
---|
[284] | 319 | $p[] = $xc-$w;
|
---|
| 320 | $p[] = $z+$yc;
|
---|
| 321 | $p[] = $xc-$w;
|
---|
| 322 | $p[] = $yc;
|
---|
| 323 | $p[] = $xc;
|
---|
| 324 | $p[] = $yc;
|
---|
[2] | 325 |
|
---|
[284] | 326 | $pt[] = $xc-$w;
|
---|
| 327 | $pt[] = $z+$yc;
|
---|
| 328 | $pt[] = $xc-$w;
|
---|
| 329 | $pt[] = $yc;
|
---|
[2] | 330 |
|
---|
[284] | 331 | for( $a=M_PI-$step; $a > $rsa; $a -= $step ) {
|
---|
| 332 | $pt[] = $xc + $w*cos($a);
|
---|
| 333 | $pt[] = $yc - $h*sin($a);
|
---|
| 334 | }
|
---|
[2] | 335 |
|
---|
[284] | 336 | $pt[] = $xc+$w*$cossa;
|
---|
| 337 | $pt[] = $yc-$h*$sinsa;
|
---|
| 338 | $pt[] = $xc;
|
---|
| 339 | $pt[] = $yc;
|
---|
[2] | 340 |
|
---|
[284] | 341 | }
|
---|
| 342 | else { // $sa >= 90 && $ea <= 180
|
---|
| 343 | $p = array($xc,$yc,$xc,$yc+$z,
|
---|
| 344 | $xc+$w*$cosea,$z+$yc-$h*$sinea,
|
---|
| 345 | $xc+$w*$cosea,$yc-$h*$sinea,
|
---|
| 346 | $xc,$yc);
|
---|
[2] | 347 |
|
---|
[284] | 348 | $pt = array($xc,$yc,$xc+$w*$cosea,$yc-$h*$sinea);
|
---|
[2] | 349 |
|
---|
[284] | 350 | for( $a=$rea; $a>$rsa; $a -= $step ) {
|
---|
| 351 | $pt[] = $xc + $w*cos($a);
|
---|
| 352 | $pt[] = $yc - $h*sin($a);
|
---|
| 353 | }
|
---|
| 354 |
|
---|
| 355 | $pt[] = $xc+$w*$cossa;
|
---|
| 356 | $pt[] = $yc-$h*$sinsa;
|
---|
| 357 | $pt[] = $xc;
|
---|
| 358 | $pt[] = $yc;
|
---|
| 359 |
|
---|
| 360 | }
|
---|
| 361 | }
|
---|
| 362 | else { // sa > 0 && ea < 90
|
---|
| 363 |
|
---|
| 364 | $p = array($xc,$yc,$xc,$yc+$z,
|
---|
| 365 | $xc+$w*$cossa,$z+$yc-$h*$sinsa,
|
---|
| 366 | $xc+$w*$cossa,$yc-$h*$sinsa,
|
---|
| 367 | $xc,$yc);
|
---|
| 368 |
|
---|
| 369 | $pt = array($xc,$yc,$xc+$w*$cossa,$yc-$h*$sinsa);
|
---|
| 370 |
|
---|
| 371 | for( $a=$rsa; $a < $rea; $a += $step ) {
|
---|
| 372 | $pt[] = $xc + $w*cos($a);
|
---|
| 373 | $pt[] = $yc - $h*sin($a);
|
---|
| 374 | }
|
---|
| 375 |
|
---|
| 376 | $pt[] = $xc+$w*$cosea;
|
---|
| 377 | $pt[] = $yc-$h*$sinea;
|
---|
| 378 | $pt[] = $xc;
|
---|
| 379 | $pt[] = $yc;
|
---|
| 380 | }
|
---|
| 381 |
|
---|
| 382 | $img->PushColor($fillcolor.":".$shadow);
|
---|
| 383 | $img->FilledPolygon($p);
|
---|
| 384 | $img->PopColor();
|
---|
| 385 |
|
---|
| 386 | $img->PushColor($fillcolor);
|
---|
| 387 | $img->FilledPolygon($pt);
|
---|
| 388 | $img->PopColor();
|
---|
[2] | 389 | }
|
---|
| 390 |
|
---|
| 391 | function SetStartAngle($aStart) {
|
---|
[284] | 392 | if( $aStart < 0 || $aStart > 360 ) {
|
---|
| 393 | JpGraphError::RaiseL(14004);//('Slice start angle must be between 0 and 360 degrees.');
|
---|
| 394 | }
|
---|
| 395 | $this->startangle = $aStart;
|
---|
[2] | 396 | }
|
---|
[284] | 397 |
|
---|
| 398 | // Draw a 3D Pie
|
---|
[2] | 399 | function Pie3D($aaoption,$img,$data,$colors,$xc,$yc,$d,$angle,$z,
|
---|
[284] | 400 | $shadow=0.65,$startangle=0,$edgecolor="",$edgeweight=1) {
|
---|
[2] | 401 |
|
---|
[284] | 402 | //---------------------------------------------------------------------------
|
---|
| 403 | // As usual the algorithm get more complicated than I originally
|
---|
| 404 | // envisioned. I believe that this is as simple as it is possible
|
---|
| 405 | // to do it with the features I want. It's a good exercise to start
|
---|
| 406 | // thinking on how to do this to convince your self that all this
|
---|
| 407 | // is really needed for the general case.
|
---|
| 408 | //
|
---|
| 409 | // The algorithm two draw 3D pies without "real 3D" is done in
|
---|
| 410 | // two steps.
|
---|
| 411 | // First imagine the pie cut in half through a thought line between
|
---|
| 412 | // 12'a clock and 6'a clock. It now easy to imagine that we can plot
|
---|
| 413 | // the individual slices for each half by starting with the topmost
|
---|
| 414 | // pie slice and continue down to 6'a clock.
|
---|
| 415 | //
|
---|
| 416 | // In the algortithm this is done in three principal steps
|
---|
| 417 | // Step 1. Do the knife cut to ensure by splitting slices that extends
|
---|
| 418 | // over the cut line. This is done by splitting the original slices into
|
---|
| 419 | // upto 3 subslices.
|
---|
| 420 | // Step 2. Find the top slice for each half
|
---|
| 421 | // Step 3. Draw the slices from top to bottom
|
---|
| 422 | //
|
---|
| 423 | // The thing that slightly complicates this scheme with all the
|
---|
| 424 | // angle comparisons below is that we can have an arbitrary start
|
---|
| 425 | // angle so we must take into account the different equivalence classes.
|
---|
| 426 | // For the same reason we must walk through the angle array in a
|
---|
| 427 | // modulo fashion.
|
---|
| 428 | //
|
---|
| 429 | // Limitations of algorithm:
|
---|
| 430 | // * A small exploded slice which crosses the 270 degree point
|
---|
| 431 | // will get slightly nagged close to the center due to the fact that
|
---|
| 432 | // we print the slices in Z-order and that the slice left part
|
---|
| 433 | // get printed first and might get slightly nagged by a larger
|
---|
| 434 | // slice on the right side just before the right part of the small
|
---|
| 435 | // slice. Not a major problem though.
|
---|
| 436 | //---------------------------------------------------------------------------
|
---|
[2] | 437 |
|
---|
| 438 |
|
---|
[284] | 439 | // Determine the height of the ellippse which gives an
|
---|
| 440 | // indication of the inclination angle
|
---|
| 441 | $h = ($angle/90.0)*$d;
|
---|
| 442 | $sum = 0;
|
---|
| 443 | for($i=0; $i<count($data); ++$i ) {
|
---|
| 444 | $sum += $data[$i];
|
---|
| 445 | }
|
---|
[2] | 446 |
|
---|
[284] | 447 | // Special optimization
|
---|
| 448 | if( $sum==0 ) return;
|
---|
[2] | 449 |
|
---|
[284] | 450 | if( $this->labeltype == 2 ) {
|
---|
| 451 | $this->adjusted_data = $this->AdjPercentage($data);
|
---|
| 452 | }
|
---|
[2] | 453 |
|
---|
[284] | 454 | // Setup the start
|
---|
| 455 | $accsum = 0;
|
---|
| 456 | $a = $startangle;
|
---|
| 457 | $a = $this->NormAngle($a);
|
---|
[2] | 458 |
|
---|
[284] | 459 | //
|
---|
| 460 | // Step 1 . Split all slices that crosses 90 or 270
|
---|
| 461 | //
|
---|
| 462 | $idx=0;
|
---|
| 463 | $adjexplode=array();
|
---|
| 464 | $numcolors = count($colors);
|
---|
| 465 | for($i=0; $i<count($data); ++$i, ++$idx ) {
|
---|
| 466 | $da = $data[$i]/$sum * 360;
|
---|
[2] | 467 |
|
---|
[284] | 468 | if( empty($this->explode_radius[$i]) ) {
|
---|
| 469 | $this->explode_radius[$i]=0;
|
---|
| 470 | }
|
---|
[2] | 471 |
|
---|
[284] | 472 | $expscale=1;
|
---|
| 473 | if( $aaoption == 1 ) {
|
---|
| 474 | $expscale=2;
|
---|
| 475 | }
|
---|
[2] | 476 |
|
---|
[284] | 477 | $la = $a + $da/2;
|
---|
| 478 | $explode = array( $xc + $this->explode_radius[$i]*cos($la*M_PI/180)*$expscale,
|
---|
| 479 | $yc - $this->explode_radius[$i]*sin($la*M_PI/180) * ($h/$d) *$expscale );
|
---|
| 480 | $adjexplode[$idx] = $explode;
|
---|
| 481 | $labeldata[$i] = array($la,$explode[0],$explode[1]);
|
---|
| 482 | $originalangles[$i] = array($a,$a+$da);
|
---|
[2] | 483 |
|
---|
[284] | 484 | $ne = $this->NormAngle($a+$da);
|
---|
| 485 | if( $da <= 180 ) {
|
---|
| 486 | // If the slice size is <= 90 it can at maximum cut across
|
---|
| 487 | // one boundary (either 90 or 270) where it needs to be split
|
---|
| 488 | $split=-1; // no split
|
---|
| 489 | if( ($da<=90 && ($a <= 90 && $ne > 90)) ||
|
---|
| 490 | (($da <= 180 && $da >90) && (($a < 90 || $a >= 270) && $ne > 90)) ) {
|
---|
| 491 | $split = 90;
|
---|
| 492 | }
|
---|
| 493 | elseif( ($da<=90 && ($a <= 270 && $ne > 270)) ||
|
---|
| 494 | (($da<=180 && $da>90) && ($a >= 90 && $a < 270 && ($a+$da) > 270 )) ) {
|
---|
| 495 | $split = 270;
|
---|
| 496 | }
|
---|
| 497 | if( $split > 0 ) { // split in two
|
---|
| 498 | $angles[$idx] = array($a,$split);
|
---|
| 499 | $adjcolors[$idx] = $colors[$i % $numcolors];
|
---|
| 500 | $adjexplode[$idx] = $explode;
|
---|
| 501 | $angles[++$idx] = array($split,$ne);
|
---|
| 502 | $adjcolors[$idx] = $colors[$i % $numcolors];
|
---|
| 503 | $adjexplode[$idx] = $explode;
|
---|
| 504 | }
|
---|
| 505 | else { // no split
|
---|
| 506 | $angles[$idx] = array($a,$ne);
|
---|
| 507 | $adjcolors[$idx] = $colors[$i % $numcolors];
|
---|
| 508 | $adjexplode[$idx] = $explode;
|
---|
| 509 | }
|
---|
| 510 | }
|
---|
| 511 | else {
|
---|
| 512 | // da>180
|
---|
| 513 | // Slice may, depending on position, cross one or two
|
---|
| 514 | // bonudaries
|
---|
[2] | 515 |
|
---|
[284] | 516 | if( $a < 90 ) $split = 90;
|
---|
| 517 | elseif( $a <= 270 ) $split = 270;
|
---|
| 518 | else $split = 90;
|
---|
[2] | 519 |
|
---|
[284] | 520 | $angles[$idx] = array($a,$split);
|
---|
| 521 | $adjcolors[$idx] = $colors[$i % $numcolors];
|
---|
| 522 | $adjexplode[$idx] = $explode;
|
---|
| 523 | //if( $a+$da > 360-$split ) {
|
---|
| 524 | // For slices larger than 270 degrees we might cross
|
---|
| 525 | // another boundary as well. This means that we must
|
---|
| 526 | // split the slice further. The comparison gets a little
|
---|
| 527 | // bit complicated since we must take into accound that
|
---|
| 528 | // a pie might have a startangle >0 and hence a slice might
|
---|
| 529 | // wrap around the 0 angle.
|
---|
| 530 | // Three cases:
|
---|
| 531 | // a) Slice starts before 90 and hence gets a split=90, but
|
---|
| 532 | // we must also check if we need to split at 270
|
---|
| 533 | // b) Slice starts after 90 but before 270 and slices
|
---|
| 534 | // crosses 90 (after a wrap around of 0)
|
---|
| 535 | // c) If start is > 270 (hence the firstr split is at 90)
|
---|
| 536 | // and the slice is so large that it goes all the way
|
---|
| 537 | // around 270.
|
---|
| 538 | if( ($a < 90 && ($a+$da > 270)) || ($a > 90 && $a<=270 && ($a+$da>360+90) ) || ($a > 270 && $this->NormAngle($a+$da)>270) ) {
|
---|
| 539 | $angles[++$idx] = array($split,360-$split);
|
---|
| 540 | $adjcolors[$idx] = $colors[$i % $numcolors];
|
---|
| 541 | $adjexplode[$idx] = $explode;
|
---|
| 542 | $angles[++$idx] = array(360-$split,$ne);
|
---|
| 543 | $adjcolors[$idx] = $colors[$i % $numcolors];
|
---|
| 544 | $adjexplode[$idx] = $explode;
|
---|
| 545 | }
|
---|
| 546 | else {
|
---|
| 547 | // Just a simple split to the previous decided
|
---|
| 548 | // angle.
|
---|
| 549 | $angles[++$idx] = array($split,$ne);
|
---|
| 550 | $adjcolors[$idx] = $colors[$i % $numcolors];
|
---|
| 551 | $adjexplode[$idx] = $explode;
|
---|
| 552 | }
|
---|
| 553 | }
|
---|
| 554 | $a += $da;
|
---|
| 555 | $a = $this->NormAngle($a);
|
---|
| 556 | }
|
---|
[2] | 557 |
|
---|
[284] | 558 | // Total number of slices
|
---|
| 559 | $n = count($angles);
|
---|
[2] | 560 |
|
---|
[284] | 561 | for($i=0; $i<$n; ++$i) {
|
---|
| 562 | list($dbgs,$dbge) = $angles[$i];
|
---|
| 563 | }
|
---|
[2] | 564 |
|
---|
[284] | 565 | //
|
---|
| 566 | // Step 2. Find start index (first pie that starts in upper left quadrant)
|
---|
| 567 | //
|
---|
| 568 | $minval = $angles[0][0];
|
---|
| 569 | $min = 0;
|
---|
| 570 | for( $i=0; $i<$n; ++$i ) {
|
---|
| 571 | if( $angles[$i][0] < $minval ) {
|
---|
| 572 | $minval = $angles[$i][0];
|
---|
| 573 | $min = $i;
|
---|
| 574 | }
|
---|
| 575 | }
|
---|
| 576 | $j = $min;
|
---|
| 577 | $cnt = 0;
|
---|
| 578 | while( $angles[$j][1] <= 90 ) {
|
---|
| 579 | $j++;
|
---|
| 580 | if( $j>=$n) {
|
---|
| 581 | $j=0;
|
---|
| 582 | }
|
---|
| 583 | if( $cnt > $n ) {
|
---|
| 584 | JpGraphError::RaiseL(14005);
|
---|
| 585 | //("Pie3D Internal error (#1). Trying to wrap twice when looking for start index");
|
---|
| 586 | }
|
---|
| 587 | ++$cnt;
|
---|
| 588 | }
|
---|
| 589 | $start = $j;
|
---|
[2] | 590 |
|
---|
[284] | 591 | //
|
---|
| 592 | // Step 3. Print slices in z-order
|
---|
| 593 | //
|
---|
| 594 | $cnt = 0;
|
---|
[2] | 595 |
|
---|
[284] | 596 | // First stroke all the slices between 90 and 270 (left half circle)
|
---|
| 597 | // counterclockwise
|
---|
| 598 |
|
---|
| 599 | while( $angles[$j][0] < 270 && $aaoption !== 2 ) {
|
---|
[2] | 600 |
|
---|
[284] | 601 | list($x,$y) = $adjexplode[$j];
|
---|
[2] | 602 |
|
---|
[284] | 603 | $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],
|
---|
| 604 | $z,$adjcolors[$j],$shadow);
|
---|
[2] | 605 |
|
---|
[284] | 606 | $last = array($x,$y,$j);
|
---|
[2] | 607 |
|
---|
[284] | 608 | $j++;
|
---|
| 609 | if( $j >= $n ) $j=0;
|
---|
| 610 | if( $cnt > $n ) {
|
---|
| 611 | JpGraphError::RaiseL(14006);
|
---|
| 612 | //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.");
|
---|
| 613 | }
|
---|
| 614 | ++$cnt;
|
---|
| 615 | }
|
---|
| 616 |
|
---|
| 617 | $slice_left = $n-$cnt;
|
---|
| 618 | $j=$start-1;
|
---|
| 619 | if($j<0) $j=$n-1;
|
---|
| 620 | $cnt = 0;
|
---|
[2] | 621 |
|
---|
[284] | 622 | // The stroke all slices from 90 to -90 (right half circle)
|
---|
| 623 | // clockwise
|
---|
| 624 | while( $cnt < $slice_left && $aaoption !== 2 ) {
|
---|
[2] | 625 |
|
---|
[284] | 626 | list($x,$y) = $adjexplode[$j];
|
---|
[2] | 627 |
|
---|
[284] | 628 | $this->Pie3DSlice($img,$x,$y,$d,$h,$angles[$j][0],$angles[$j][1],
|
---|
| 629 | $z,$adjcolors[$j],$shadow);
|
---|
| 630 | $j--;
|
---|
| 631 | if( $cnt > $n ) {
|
---|
| 632 | JpGraphError::RaiseL(14006);
|
---|
| 633 | //("Pie3D Internal Error: Z-Sorting algorithm for 3D Pies is not working properly (2). Trying to wrap twice while stroking.");
|
---|
| 634 | }
|
---|
| 635 | if($j<0) $j=$n-1;
|
---|
| 636 | $cnt++;
|
---|
| 637 | }
|
---|
[2] | 638 |
|
---|
[284] | 639 | // Now do a special thing. Stroke the last slice on the left
|
---|
| 640 | // halfcircle one more time. This is needed in the case where
|
---|
| 641 | // the slice close to 270 have been exploded. In that case the
|
---|
| 642 | // part of the slice close to the center of the pie might be
|
---|
| 643 | // slightly nagged.
|
---|
| 644 | if( $aaoption !== 2 )
|
---|
| 645 | $this->Pie3DSlice($img,$last[0],$last[1],$d,$h,$angles[$last[2]][0],
|
---|
| 646 | $angles[$last[2]][1],$z,$adjcolors[$last[2]],$shadow);
|
---|
[2] | 647 |
|
---|
| 648 |
|
---|
[284] | 649 | if( $aaoption !== 1 ) {
|
---|
| 650 | // Now print possible labels and add csim
|
---|
| 651 | $this->value->ApplyFont($img);
|
---|
| 652 | $margin = $img->GetFontHeight()/2 + $this->value->margin ;
|
---|
| 653 | for($i=0; $i < count($data); ++$i ) {
|
---|
| 654 | $la = $labeldata[$i][0];
|
---|
| 655 | $x = $labeldata[$i][1] + cos($la*M_PI/180)*($d+$margin)*$this->ilabelposadj;
|
---|
| 656 | $y = $labeldata[$i][2] - sin($la*M_PI/180)*($h+$margin)*$this->ilabelposadj;
|
---|
| 657 | if( $this->ilabelposadj >= 1.0 ) {
|
---|
| 658 | if( $la > 180 && $la < 360 ) $y += $z;
|
---|
| 659 | }
|
---|
| 660 | if( $this->labeltype == 0 ) {
|
---|
| 661 | if( $sum > 0 ) $l = 100*$data[$i]/$sum;
|
---|
| 662 | else $l = 0;
|
---|
| 663 | }
|
---|
| 664 | elseif( $this->labeltype == 1 ) {
|
---|
| 665 | $l = $data[$i];
|
---|
| 666 | }
|
---|
| 667 | else {
|
---|
| 668 | $l = $this->adjusted_data[$i];
|
---|
| 669 | }
|
---|
| 670 | if( isset($this->labels[$i]) && is_string($this->labels[$i]) ) {
|
---|
| 671 | $l=sprintf($this->labels[$i],$l);
|
---|
| 672 | }
|
---|
[2] | 673 |
|
---|
[284] | 674 | $this->StrokeLabels($l,$img,$labeldata[$i][0]*M_PI/180,$x,$y,$z);
|
---|
| 675 |
|
---|
| 676 | $this->Add3DSliceToCSIM($i,$labeldata[$i][1],$labeldata[$i][2],$h*2,$d*2,$z,
|
---|
| 677 | $originalangles[$i][0],$originalangles[$i][1]);
|
---|
| 678 | }
|
---|
| 679 | }
|
---|
[2] | 680 |
|
---|
[284] | 681 | //
|
---|
| 682 | // Finally add potential lines in pie
|
---|
| 683 | //
|
---|
| 684 |
|
---|
| 685 | if( $edgecolor=="" || $aaoption !== 0 ) return;
|
---|
| 686 |
|
---|
| 687 | $accsum = 0;
|
---|
| 688 | $a = $startangle;
|
---|
| 689 | $a = $this->NormAngle($a);
|
---|
| 690 |
|
---|
| 691 | $a *= M_PI/180.0;
|
---|
| 692 |
|
---|
| 693 | $idx=0;
|
---|
| 694 | $img->PushColor($edgecolor);
|
---|
| 695 | $img->SetLineWeight($edgeweight);
|
---|
| 696 |
|
---|
| 697 | $fulledge = true;
|
---|
| 698 | for($i=0; $i < count($data) && $fulledge; ++$i ) {
|
---|
| 699 | if( empty($this->explode_radius[$i]) ) {
|
---|
| 700 | $this->explode_radius[$i]=0;
|
---|
| 701 | }
|
---|
| 702 | if( $this->explode_radius[$i] > 0 ) {
|
---|
| 703 | $fulledge = false;
|
---|
| 704 | }
|
---|
| 705 | }
|
---|
| 706 |
|
---|
| 707 |
|
---|
| 708 | for($i=0; $i < count($data); ++$i, ++$idx ) {
|
---|
| 709 |
|
---|
| 710 | $da = $data[$i]/$sum * 2*M_PI;
|
---|
| 711 | $this->StrokeFullSliceFrame($img,$xc,$yc,$a,$a+$da,$d,$h,$z,$edgecolor,
|
---|
| 712 | $this->explode_radius[$i],$fulledge);
|
---|
| 713 | $a += $da;
|
---|
| 714 | }
|
---|
| 715 | $img->PopColor();
|
---|
[2] | 716 | }
|
---|
| 717 |
|
---|
| 718 | function StrokeFullSliceFrame($img,$xc,$yc,$sa,$ea,$w,$h,$z,$edgecolor,$exploderadius,$fulledge) {
|
---|
[284] | 719 | $step = 0.02;
|
---|
[2] | 720 |
|
---|
[284] | 721 | if( $exploderadius > 0 ) {
|
---|
| 722 | $la = ($sa+$ea)/2;
|
---|
| 723 | $xc += $exploderadius*cos($la);
|
---|
| 724 | $yc -= $exploderadius*sin($la) * ($h/$w) ;
|
---|
| 725 |
|
---|
| 726 | }
|
---|
[2] | 727 |
|
---|
[284] | 728 | $p = array($xc,$yc,$xc+$w*cos($sa),$yc-$h*sin($sa));
|
---|
[2] | 729 |
|
---|
[284] | 730 | for($a=$sa; $a < $ea; $a += $step ) {
|
---|
| 731 | $p[] = $xc + $w*cos($a);
|
---|
| 732 | $p[] = $yc - $h*sin($a);
|
---|
| 733 | }
|
---|
[2] | 734 |
|
---|
[284] | 735 | $p[] = $xc+$w*cos($ea);
|
---|
| 736 | $p[] = $yc-$h*sin($ea);
|
---|
| 737 | $p[] = $xc;
|
---|
| 738 | $p[] = $yc;
|
---|
[2] | 739 |
|
---|
[284] | 740 | $img->SetColor($edgecolor);
|
---|
| 741 | $img->Polygon($p);
|
---|
[2] | 742 |
|
---|
[284] | 743 | // Unfortunately we can't really draw the full edge around the whole of
|
---|
| 744 | // of the slice if any of the slices are exploded. The reason is that
|
---|
| 745 | // this algorithm is to simply. There are cases where the edges will
|
---|
| 746 | // "overwrite" other slices when they have been exploded.
|
---|
| 747 | // Doing the full, proper 3D hidden lines stiff is actually quite
|
---|
| 748 | // tricky. So for exploded pies we only draw the top edge. Not perfect
|
---|
| 749 | // but the "real" solution is much more complicated.
|
---|
| 750 | if( $fulledge && !( $sa > 0 && $sa < M_PI && $ea < M_PI) ) {
|
---|
[2] | 751 |
|
---|
[284] | 752 | if($sa < M_PI && $ea > M_PI) {
|
---|
| 753 | $sa = M_PI;
|
---|
| 754 | }
|
---|
[2] | 755 |
|
---|
[284] | 756 | if($sa < 2*M_PI && (($ea >= 2*M_PI) || ($ea > 0 && $ea < $sa ) ) ) {
|
---|
| 757 | $ea = 2*M_PI;
|
---|
| 758 | }
|
---|
| 759 |
|
---|
| 760 | if( $sa >= M_PI && $ea <= 2*M_PI ) {
|
---|
| 761 | $p = array($xc + $w*cos($sa),$yc - $h*sin($sa),
|
---|
| 762 | $xc + $w*cos($sa),$z + $yc - $h*sin($sa));
|
---|
| 763 |
|
---|
| 764 | for($a=$sa+$step; $a < $ea; $a += $step ) {
|
---|
| 765 | $p[] = $xc + $w*cos($a);
|
---|
| 766 | $p[] = $z + $yc - $h*sin($a);
|
---|
| 767 | }
|
---|
| 768 | $p[] = $xc + $w*cos($ea);
|
---|
| 769 | $p[] = $z + $yc - $h*sin($ea);
|
---|
| 770 | $p[] = $xc + $w*cos($ea);
|
---|
| 771 | $p[] = $yc - $h*sin($ea);
|
---|
| 772 | $img->SetColor($edgecolor);
|
---|
| 773 | $img->Polygon($p);
|
---|
| 774 | }
|
---|
| 775 | }
|
---|
[2] | 776 | }
|
---|
| 777 |
|
---|
| 778 | function Stroke($img,$aaoption=0) {
|
---|
[284] | 779 | $n = count($this->data);
|
---|
[2] | 780 |
|
---|
[284] | 781 | // If user hasn't set the colors use the theme array
|
---|
| 782 | if( $this->setslicecolors==null ) {
|
---|
| 783 | $colors = array_keys($img->rgb->rgb_table);
|
---|
| 784 | sort($colors);
|
---|
| 785 | $idx_a=$this->themearr[$this->theme];
|
---|
| 786 | $ca = array();
|
---|
| 787 | $m = count($idx_a);
|
---|
| 788 | for($i=0; $i < $m; ++$i) {
|
---|
| 789 | $ca[$i] = $colors[$idx_a[$i]];
|
---|
| 790 | }
|
---|
| 791 | $ca = array_reverse(array_slice($ca,0,$n));
|
---|
| 792 | }
|
---|
| 793 | else {
|
---|
| 794 | $ca = $this->setslicecolors;
|
---|
| 795 | }
|
---|
[2] | 796 |
|
---|
| 797 |
|
---|
[284] | 798 | if( $this->posx <= 1 && $this->posx > 0 ) {
|
---|
| 799 | $xc = round($this->posx*$img->width);
|
---|
| 800 | }
|
---|
| 801 | else {
|
---|
| 802 | $xc = $this->posx ;
|
---|
| 803 | }
|
---|
[2] | 804 |
|
---|
[284] | 805 | if( $this->posy <= 1 && $this->posy > 0 ) {
|
---|
| 806 | $yc = round($this->posy*$img->height);
|
---|
| 807 | }
|
---|
| 808 | else {
|
---|
| 809 | $yc = $this->posy ;
|
---|
| 810 | }
|
---|
[2] | 811 |
|
---|
[284] | 812 | if( $this->radius <= 1 ) {
|
---|
| 813 | $width = floor($this->radius*min($img->width,$img->height));
|
---|
| 814 | // Make sure that the pie doesn't overflow the image border
|
---|
| 815 | // The 0.9 factor is simply an extra margin to leave some space
|
---|
| 816 | // between the pie an the border of the image.
|
---|
| 817 | $width = min($width,min($xc*0.9,($yc*90/$this->angle-$width/4)*0.9));
|
---|
| 818 | }
|
---|
| 819 | else {
|
---|
| 820 | $width = $this->radius * ($aaoption === 1 ? 2 : 1 ) ;
|
---|
| 821 | }
|
---|
[2] | 822 |
|
---|
[284] | 823 | // Add a sanity check for width
|
---|
| 824 | if( $width < 1 ) {
|
---|
| 825 | JpGraphError::RaiseL(14007);//("Width for 3D Pie is 0. Specify a size > 0");
|
---|
| 826 | }
|
---|
[2] | 827 |
|
---|
[284] | 828 | // Establish a thickness. By default the thickness is a fifth of the
|
---|
| 829 | // pie slice width (=pie radius) but since the perspective depends
|
---|
| 830 | // on the inclination angle we use some heuristics to make the edge
|
---|
| 831 | // slightly thicker the less the angle.
|
---|
[2] | 832 |
|
---|
[284] | 833 | // Has user specified an absolute thickness? In that case use
|
---|
| 834 | // that instead
|
---|
[2] | 835 |
|
---|
[284] | 836 | if( $this->iThickness ) {
|
---|
| 837 | $thick = $this->iThickness;
|
---|
| 838 | $thick *= ($aaoption === 1 ? 2 : 1 );
|
---|
| 839 | }
|
---|
| 840 | else {
|
---|
| 841 | $thick = $width/12;
|
---|
| 842 | }
|
---|
| 843 | $a = $this->angle;
|
---|
| 844 |
|
---|
| 845 | if( $a <= 30 ) $thick *= 1.6;
|
---|
| 846 | elseif( $a <= 40 ) $thick *= 1.4;
|
---|
| 847 | elseif( $a <= 50 ) $thick *= 1.2;
|
---|
| 848 | elseif( $a <= 60 ) $thick *= 1.0;
|
---|
| 849 | elseif( $a <= 70 ) $thick *= 0.8;
|
---|
| 850 | elseif( $a <= 80 ) $thick *= 0.7;
|
---|
| 851 | else $thick *= 0.6;
|
---|
| 852 |
|
---|
| 853 | $thick = floor($thick);
|
---|
| 854 |
|
---|
| 855 | if( $this->explode_all ) {
|
---|
| 856 | for($i=0; $i < $n; ++$i)
|
---|
| 857 | $this->explode_radius[$i]=$this->explode_r;
|
---|
| 858 | }
|
---|
| 859 |
|
---|
| 860 | $this->Pie3D($aaoption,$img,$this->data, $ca, $xc, $yc, $width, $this->angle,
|
---|
| 861 | $thick, 0.65, $this->startangle, $this->edgecolor, $this->edgeweight);
|
---|
| 862 |
|
---|
| 863 | // Adjust title position
|
---|
| 864 | if( $aaoption != 1 ) {
|
---|
| 865 | $this->title->SetPos($xc,$yc-$this->title->GetFontHeight($img)-$width/2-$this->title->margin, "center","bottom");
|
---|
| 866 | $this->title->Stroke($img);
|
---|
| 867 | }
|
---|
[2] | 868 | }
|
---|
| 869 |
|
---|
[284] | 870 | //---------------
|
---|
| 871 | // PRIVATE METHODS
|
---|
[2] | 872 |
|
---|
| 873 | // Position the labels of each slice
|
---|
| 874 | function StrokeLabels($label,$img,$a,$xp,$yp,$z) {
|
---|
[284] | 875 | $this->value->halign="left";
|
---|
| 876 | $this->value->valign="top";
|
---|
[2] | 877 |
|
---|
[284] | 878 | // Position the axis title.
|
---|
| 879 | // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
|
---|
| 880 | // that intersects with the extension of the corresponding axis. The code looks a little
|
---|
| 881 | // bit messy but this is really the only way of having a reasonable position of the
|
---|
| 882 | // axis titles.
|
---|
| 883 | $this->value->ApplyFont($img);
|
---|
| 884 | $h=$img->GetTextHeight($label);
|
---|
| 885 | // For numeric values the format of the display value
|
---|
| 886 | // must be taken into account
|
---|
| 887 | if( is_numeric($label) ) {
|
---|
| 888 | if( $label >= 0 ) {
|
---|
| 889 | $w=$img->GetTextWidth(sprintf($this->value->format,$label));
|
---|
| 890 | }
|
---|
| 891 | else {
|
---|
| 892 | $w=$img->GetTextWidth(sprintf($this->value->negformat,$label));
|
---|
| 893 | }
|
---|
| 894 | }
|
---|
| 895 | else {
|
---|
| 896 | $w=$img->GetTextWidth($label);
|
---|
| 897 | }
|
---|
| 898 |
|
---|
| 899 | while( $a > 2*M_PI ) {
|
---|
| 900 | $a -= 2*M_PI;
|
---|
| 901 | }
|
---|
| 902 |
|
---|
| 903 | if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;
|
---|
| 904 | if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI;
|
---|
| 905 | if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;
|
---|
| 906 | if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);
|
---|
[2] | 907 |
|
---|
[284] | 908 | if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;
|
---|
| 909 | if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);
|
---|
| 910 | if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;
|
---|
| 911 | if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);
|
---|
| 912 | if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;
|
---|
[2] | 913 |
|
---|
[284] | 914 | $x = round($xp-$dx*$w);
|
---|
| 915 | $y = round($yp-$dy*$h);
|
---|
| 916 |
|
---|
| 917 | // Mark anchor point for debugging
|
---|
| 918 | /*
|
---|
| 919 | $img->SetColor('red');
|
---|
| 920 | $img->Line($xp-10,$yp,$xp+10,$yp);
|
---|
| 921 | $img->Line($xp,$yp-10,$xp,$yp+10);
|
---|
| 922 | */
|
---|
| 923 |
|
---|
| 924 | $oldmargin = $this->value->margin;
|
---|
| 925 | $this->value->margin=0;
|
---|
| 926 | $this->value->Stroke($img,$label,$x,$y);
|
---|
| 927 | $this->value->margin=$oldmargin;
|
---|
| 928 |
|
---|
| 929 | }
|
---|
[2] | 930 | } // Class
|
---|
| 931 |
|
---|
| 932 | /* EOF */
|
---|
| 933 | ?>
|
---|