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