Changeset 265 for trunk/client/modules/Elezioni/grafici/jpgraph.php
- Timestamp:
- Apr 13, 2019, 8:05:15 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/client/modules/Elezioni/grafici/jpgraph.php
r2 r265 1 1 <?php 2 2 //======================================================================= 3 // File: 4 // Description: 5 // Created: 6 // Ver: $Id: jpgraph.php 1091 2009-01-18 22:57:40Z ljp $3 // File: JPGRAPH.PHP 4 // Description: PHP Graph Plotting library. Base module. 5 // Created: 2001-01-08 6 // Ver: $Id: jpgraph.php 1924 2010-01-11 14:03:26Z ljp $ 7 7 // 8 // Copyright (c) A ditus Consulting. All rights reserved.8 // Copyright (c) Asial Corporation. All rights reserved. 9 9 //======================================================================== 10 10 … … 16 16 require_once('jpgraph_text.inc.php'); 17 17 require_once('jpgraph_legend.inc.php'); 18 require_once('jpgraph_theme.inc.php'); 19 require_once('gd_image.inc.php'); 18 20 19 21 // Version info 20 define('JPG_VERSION',' 2.3.5-dev');22 define('JPG_VERSION','4.2.6'); 21 23 22 24 // Minimum required PHP version 23 25 define('MIN_PHPVERSION','5.1.0'); 24 26 25 // Should the image be a truecolor image? 26 define('USE_TRUECOLOR',true); 27 28 //------------------------------------------------------------------------ 29 // Automatic settings of path for cache and font directory 30 // if they have not been previously specified 31 //------------------------------------------------------------------------ 32 if(USE_CACHE) { 33 if (!defined('CACHE_DIR')) { 34 if ( strstr( PHP_OS, 'WIN') ) { 35 if( empty($_SERVER['TEMP']) ) { 36 $t = new ErrMsgText(); 37 $msg = $t->Get(11,$file,$lineno); 38 die($msg); 39 } 40 else { 41 define('CACHE_DIR', $_SERVER['TEMP'] . '/'); 42 } 43 } else { 44 define('CACHE_DIR','/tmp/jpgraph_cache/'); 45 } 46 } 47 } 48 elseif( !defined('CACHE_DIR') ) { 49 define('CACHE_DIR', ''); 50 } 51 52 if (!defined('TTF_DIR')) { 53 if (strstr( PHP_OS, 'WIN') ) { 54 $sroot = getenv('SystemRoot'); 55 if( empty($sroot) ) { 56 $t = new ErrMsgText(); 57 $msg = $t->Get(12,$file,$lineno); 58 die($msg); 59 } 60 else { 61 define('TTF_DIR', $sroot.'/fonts/'); 62 } 63 } else { 64 define('TTF_DIR','/usr/share/fonts/truetype/'); 65 } 66 } 67 68 if (!defined('MBTTF_DIR')) { 69 if (strstr( PHP_OS, 'WIN') ) { 70 $sroot = getenv('SystemRoot'); 71 if( empty($sroot) ) { 72 $t = new ErrMsgText(); 73 $msg = $t->Get(12,$file,$lineno); 74 die($msg); 75 } 76 else { 77 define('TTF_DIR', $sroot.'/fonts/'); 78 } 79 } else { 80 define('MBTTF_DIR','/usr/share/fonts/ja/TrueType/'); 81 } 82 } 83 84 //------------------------------------------------------------------ 85 // Constants which are used as parameters for the method calls 86 //------------------------------------------------------------------ 87 27 // Special file name to indicate that we only want to calc 28 // the image map in the call to Graph::Stroke() used 29 // internally from the GetHTMLCSIM() method. 30 define('_CSIM_SPECIALFILE','_csim_special_'); 31 32 // HTTP GET argument that is used with image map 33 // to indicate to the script to just generate the image 34 // and not the full CSIM HTML page. 35 define('_CSIM_DISPLAY','_jpg_csimd'); 36 37 // Special filename for Graph::Stroke(). If this filename is given 38 // then the image will NOT be streamed to browser of file. Instead the 39 // Stroke call will return the handler for the created GD image. 40 define('_IMG_HANDLER','__handle'); 41 42 // Special filename for Graph::Stroke(). If this filename is given 43 // the image will be stroked to a file with a name based on the script name. 44 define('_IMG_AUTO','auto'); 88 45 89 46 // Tick density … … 93 50 define("TICKD_VERYSPARSE",4); 94 51 95 // Side for ticks and labels. 52 // Side for ticks and labels. 96 53 define("SIDE_LEFT",-1); 97 54 define("SIDE_RIGHT",1); … … 156 113 define("HORIZONTAL",0); 157 114 158 159 115 // Axis styles for scientific style axis 160 116 define('AXSTYLE_SIMPLE',1); … … 176 132 define('TITLEBKG_FILLSTYLE_SOLID',3); 177 133 134 // Styles for axis labels background 135 define('LABELBKG_NONE',0); 136 define('LABELBKG_XAXIS',1); 137 define('LABELBKG_YAXIS',2); 138 define('LABELBKG_XAXISFULL',3); 139 define('LABELBKG_YAXISFULL',4); 140 define('LABELBKG_XYFULL',5); 141 define('LABELBKG_XY',6); 142 143 178 144 // Style for background gradient fills 179 145 define('BGRAD_FRAME',1); … … 191 157 define('SKEW3D_RIGHT',3); 192 158 193 // Line styles194 define('LINESTYLE_SOLID',1);195 define('LINESTYLE_DOTTED',2);196 define('LINESTYLE_DASHED',3);197 define('LINESTYLE_LONGDASH',4);198 199 159 // For internal use only 200 160 define("_JPG_DEBUG",false); … … 202 162 define("_FORCE_IMGDIR",'/tmp/jpgimg/'); 203 163 204 require_once('gd_image.inc.php'); 205 206 function CheckPHPVersion($aMinVersion) 207 { 208 list($majorC, $minorC, $editC) = split('[/.-]', PHP_VERSION); 209 list($majorR, $minorR, $editR) = split('[/.-]', $aMinVersion); 210 211 if ($majorC != $majorR) return false; 164 165 // 166 // Automatic settings of path for cache and font directory 167 // if they have not been previously specified 168 // 169 if(USE_CACHE) { 170 if (!defined('CACHE_DIR')) { 171 if ( strstr( PHP_OS, 'WIN') ) { 172 if( empty($_SERVER['TEMP']) ) { 173 $t = new ErrMsgText(); 174 $msg = $t->Get(11,$file,$lineno); 175 die($msg); 176 } 177 else { 178 define('CACHE_DIR', $_SERVER['TEMP'] . '/'); 179 } 180 } else { 181 define('CACHE_DIR','/tmp/jpgraph_cache/'); 182 } 183 } 184 } 185 elseif( !defined('CACHE_DIR') ) { 186 define('CACHE_DIR', ''); 187 } 188 189 // 190 // Setup path for western/latin TTF fonts 191 // 192 if (!defined('TTF_DIR')) { 193 if (strstr( PHP_OS, 'WIN') ) { 194 $sroot = getenv('SystemRoot'); 195 if( empty($sroot) ) { 196 $t = new ErrMsgText(); 197 $msg = $t->Get(12,$file,$lineno); 198 die($msg); 199 } 200 else { 201 define('TTF_DIR', $sroot.'/fonts/'); 202 } 203 } else { 204 define('TTF_DIR','/usr/share/fonts/truetype/'); 205 } 206 } 207 208 // 209 // Setup path for MultiByte TTF fonts (japanese, chinese etc.) 210 // 211 if (!defined('MBTTF_DIR')) { 212 if (strstr( PHP_OS, 'WIN') ) { 213 $sroot = getenv('SystemRoot'); 214 if( empty($sroot) ) { 215 $t = new ErrMsgText(); 216 $msg = $t->Get(12,$file,$lineno); 217 die($msg); 218 } 219 else { 220 define('MBTTF_DIR', $sroot.'/fonts/'); 221 } 222 } else { 223 define('MBTTF_DIR','/usr/share/fonts/truetype/'); 224 } 225 } 226 227 // 228 // Check minimum PHP version 229 // 230 function CheckPHPVersion($aMinVersion) { 231 list($majorC, $minorC, $editC) = preg_split('/[\/.-]/', PHP_VERSION); 232 list($majorR, $minorR, $editR) = preg_split('/[\/.-]/', $aMinVersion); 233 212 234 if ($majorC < $majorR) return false; 213 // same major - check ninor 214 if ($minorC > $minorR) return true; 215 if ($minorC < $minorR) return false; 216 // and same minor 217 if ($editC >= $editR) return true; 235 236 if ($majorC == $majorR) { 237 if($minorC < $minorR) return false; 238 239 if($minorC == $minorR){ 240 if($editC < $editR) return false; 241 } 242 } 243 218 244 return true; 219 245 } … … 227 253 } 228 254 229 230 255 // 231 256 // Make GD sanity check … … 233 258 if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) { 234 259 JpGraphError::RaiseL(25001); 235 //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)");260 //("This PHP installation is not configured with the GD library. Please recompile PHP with GD support to run JpGraph. (Neither function imagetypes() nor imagecreatefromstring() does exist)"); 236 261 } 237 262 … … 242 267 // Respect current error level 243 268 if( $errno & error_reporting() ) { 244 JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); 269 JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); 245 270 } 246 271 } … … 251 276 252 277 // 253 //Check if there were any warnings, perhaps some wrong includes by the 254 //user 278 // Check if there were any warnings, perhaps some wrong includes by the user. In this 279 // case we raise it immediately since otherwise the image will not show and makes 280 // debugging difficult. This is controlled by the user setting CATCH_PHPERRMSG 255 281 // 256 if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && 257 !preg_match('/|Deprecated|/i', $GLOBALS['php_errormsg']) ) { 282 if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && !preg_match('/|Deprecated|/i', $GLOBALS['php_errormsg']) ) { 258 283 JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']); 259 284 } 260 285 261 262 286 // Useful mathematical function 263 287 function sign($a) {return $a >= 0 ? 1 : -1;} 264 288 289 // 265 290 // Utility function to generate an image name based on the filename we 266 291 // are running from and assuming we use auto detection of graphic format 267 292 // (top level), i.e it is safe to call this function 268 293 // from a script that uses JpGraph 294 // 269 295 function GenImgName() { 270 296 // Determine what format we should use when we save the images 271 297 $supported = imagetypes(); 272 if( $supported & IMG_PNG ) 298 if( $supported & IMG_PNG ) $img_format="png"; 273 299 elseif( $supported & IMG_GIF ) $img_format="gif"; 274 300 elseif( $supported & IMG_JPG ) $img_format="jpeg"; … … 277 303 278 304 279 if( !isset($_SERVER['PHP_SELF']) ) 280 JpGraphError::RaiseL(25005); 281 //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files."); 305 if( !isset($_SERVER['PHP_SELF']) ) { 306 JpGraphError::RaiseL(25005); 307 //(" Can't access PHP_SELF, PHP global variable. You can't run PHP from command line if you want to use the 'auto' naming of cache or image files."); 308 } 282 309 $fname = basename($_SERVER['PHP_SELF']); 283 310 if( !empty($_SERVER['QUERY_STRING']) ) { 284 285 311 $q = @$_SERVER['QUERY_STRING']; 312 $fname .= '_'.preg_replace("/\W/", "_", $q).'.'.$img_format; 286 313 } 287 314 else { 288 315 $fname = substr($fname,0,strlen($fname)-4).'.'.$img_format; 289 316 } 290 317 return $fname; 291 318 } 292 293 319 294 320 //=================================================== … … 299 325 //=================================================== 300 326 class JpgTimer { 301 private $start, $idx; 302 //--------------- 303 // CONSTRUCTOR 304 function JpgTimer() { 305 $this->idx=0; 306 } 307 308 //--------------- 309 // PUBLIC METHODS 327 private $start, $idx; 328 329 function __construct() { 330 $this->idx=0; 331 } 310 332 311 333 // Push a new timer start on stack 312 334 function Push() { 313 list($ms,$s)=explode(" ",microtime()); 314 $this->start[$this->idx++]=floor($ms*1000) + 1000*$s; 335 list($ms,$s)=explode(" ",microtime()); 336 $this->start[$this->idx++]=floor($ms*1000) + 1000*$s; 315 337 } 316 338 … … 318 340 // current time 319 341 function Pop() { 320 321 list($ms,$s)=explode(" ",microtime()); 322 323 324 342 assert($this->idx>0); 343 list($ms,$s)=explode(" ",microtime()); 344 $etime=floor($ms*1000) + (1000*$s); 345 $this->idx--; 346 return $etime-$this->start[$this->idx]; 325 347 } 326 348 } // Class 327 349 328 $gJpgBrandTiming = BRAND_TIMING;329 350 //=================================================== 330 351 // CLASS DateLocale … … 332 353 //=================================================== 333 354 class DateLocale { 334 355 335 356 public $iLocale = 'C'; // environmental locale be used by default 336 357 private $iDayAbb = null, $iShortDay = null, $iShortMonth = null, $iMonthName = null; 337 358 338 //--------------- 339 // CONSTRUCTOR 340 function DateLocale() { 341 settype($this->iDayAbb, 'array'); 342 settype($this->iShortDay, 'array'); 343 settype($this->iShortMonth, 'array'); 344 settype($this->iMonthName, 'array'); 345 346 347 $this->Set('C'); 348 } 349 350 //--------------- 351 // PUBLIC METHODS 359 function __construct() { 360 settype($this->iDayAbb, 'array'); 361 settype($this->iShortDay, 'array'); 362 settype($this->iShortMonth, 'array'); 363 settype($this->iMonthName, 'array'); 364 $this->Set('C'); 365 } 366 352 367 function Set($aLocale) { 353 if ( in_array($aLocale, array_keys($this->iDayAbb)) ){ 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 if ( ! $res ){374 375 //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region.");376 377 378 379 380 for ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 368 if ( in_array($aLocale, array_keys($this->iDayAbb)) ){ 369 $this->iLocale = $aLocale; 370 return TRUE; // already cached nothing else to do! 371 } 372 373 $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME 374 375 if (is_array($aLocale)) { 376 foreach ($aLocale as $loc) { 377 $res = @setlocale(LC_TIME, $loc); 378 if ( $res ) { 379 $aLocale = $loc; 380 break; 381 } 382 } 383 } 384 else { 385 $res = @setlocale(LC_TIME, $aLocale); 386 } 387 388 if ( ! $res ) { 389 JpGraphError::RaiseL(25007,$aLocale); 390 //("You are trying to use the locale ($aLocale) which your PHP installation does not support. Hint: Use '' to indicate the default locale for this geographic region."); 391 return FALSE; 392 } 393 394 $this->iLocale = $aLocale; 395 for( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ) { 396 $day = strftime('%a', strtotime("$ofs day")); 397 $day[0] = strtoupper($day[0]); 398 $this->iDayAbb[$aLocale][]= $day[0]; 399 $this->iShortDay[$aLocale][]= $day; 400 } 401 402 for($i=1; $i<=12; ++$i) { 403 list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01"))); 404 $this->iShortMonth[$aLocale][] = ucfirst($short); 405 $this->iMonthName [$aLocale][] = ucfirst($full); 406 } 407 408 setlocale(LC_TIME, $pLocale); 409 410 return TRUE; 396 411 } 397 412 398 413 399 414 function GetDayAbb() { 400 401 } 402 415 return $this->iDayAbb[$this->iLocale]; 416 } 417 403 418 function GetShortDay() { 404 419 return $this->iShortDay[$this->iLocale]; 405 420 } 406 421 407 422 function GetShortMonth() { 408 409 } 410 423 return $this->iShortMonth[$this->iLocale]; 424 } 425 411 426 function GetShortMonthName($aNbr) { 412 427 return $this->iShortMonth[$this->iLocale][$aNbr]; 413 428 } 414 429 415 430 function GetLongMonthName($aNbr) { 416 431 return $this->iMonthName[$this->iLocale][$aNbr]; 417 432 } 418 433 419 434 function GetMonth() { 420 435 return $this->iMonthName[$this->iLocale]; 421 436 } 422 437 } 423 438 439 // Global object handlers 424 440 $gDateLocale = new DateLocale(); 425 441 $gJpgDateLocale = new DateLocale(); … … 432 448 public $iLeftMargin = 3, $iRightMargin = 3, $iBottomMargin = 3 ; 433 449 public $left,$center,$right; 434 435 function Footer() { 436 $this->left = new Text(); 437 $this->left->ParagraphAlign('left'); 438 $this->center = new Text(); 439 $this->center->ParagraphAlign('center'); 440 $this->right = new Text(); 441 $this->right->ParagraphAlign('right'); 450 private $iTimer=null, $itimerpoststring=''; 451 452 function __construct() { 453 $this->left = new Text(); 454 $this->left->ParagraphAlign('left'); 455 $this->center = new Text(); 456 $this->center->ParagraphAlign('center'); 457 $this->right = new Text(); 458 $this->right->ParagraphAlign('right'); 459 } 460 461 function SetTimer($aTimer,$aTimerPostString='') { 462 $this->iTimer = $aTimer; 463 $this->itimerpoststring = $aTimerPostString; 442 464 } 443 465 444 466 function SetMargin($aLeft=3,$aRight=3,$aBottom=3) { 445 446 447 467 $this->iLeftMargin = $aLeft; 468 $this->iRightMargin = $aRight; 469 $this->iBottomMargin = $aBottom; 448 470 } 449 471 450 472 function Stroke($aImg) { 451 $y = $aImg->height - $this->iBottomMargin; 452 $x = $this->iLeftMargin; 453 $this->left->Align('left','bottom'); 454 $this->left->Stroke($aImg,$x,$y); 455 456 $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2; 457 $this->center->Align('center','bottom'); 458 $this->center->Stroke($aImg,$x,$y); 459 460 $x = $aImg->width - $this->iRightMargin; 461 $this->right->Align('right','bottom'); 462 $this->right->Stroke($aImg,$x,$y); 473 $y = $aImg->height - $this->iBottomMargin; 474 $x = $this->iLeftMargin; 475 $this->left->Align('left','bottom'); 476 $this->left->Stroke($aImg,$x,$y); 477 478 $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2; 479 $this->center->Align('center','bottom'); 480 $this->center->Stroke($aImg,$x,$y); 481 482 $x = $aImg->width - $this->iRightMargin; 483 $this->right->Align('right','bottom'); 484 if( $this->iTimer != null ) { 485 $this->right->Set( $this->right->t . sprintf('%.3f',$this->iTimer->Pop()/1000.0) . $this->itimerpoststring ); 486 } 487 $this->right->Stroke($aImg,$x,$y); 463 488 } 464 489 } … … 470 495 //=================================================== 471 496 class Graph { 472 public $cache=null; 473 public $img=null; 474 public $plots=array(); 475 public $y2plots=array(); 497 public $cache=null; // Cache object (singleton) 498 public $img=null; // Img object (singleton) 499 public $plots=array(); // Array of all plot object in the graph (for Y 1 axis) 500 public $y2plots=array(); // Array of all plot object in the graph (for Y 2 axis) 476 501 public $ynplots=array(); 477 public $xscale=null; 502 public $xscale=null; // X Scale object (could be instance of LinearScale or LogScale 478 503 public $yscale=null,$y2scale=null, $ynscale=array(); 479 public $iIcons = array(); // Array of Icons to add to480 public $cache_name; 481 public $xgrid=null; 482 public $ygrid=null,$y2grid=null; 483 public $doframe =true,$frame_color=array(0,0,0), $frame_weight=1;// Frame around graph484 public $boxed=false, $box_color= array(0,0,0), $box_weight=1;// Box around plot area485 public $doshadow=false,$shadow_width=4,$shadow_color= array(102,102,102);// Shadow for graph486 public $xaxis=null; 487 public $yaxis=null, $y2axis=null, $ynaxis=array(); 488 public $margin_color =array(200,200,200);// Margin color of graph489 public $plotarea_color=array(255,255,255); 490 public $title,$subtitle,$subsubtitle; 491 public $axtype="linlin"; 492 public $xtick_factor,$ytick_factor; 493 public $texts=null, $y2texts=null; 504 public $iIcons = array(); // Array of Icons to add to 505 public $cache_name; // File name to be used for the current graph in the cache directory 506 public $xgrid=null; // X Grid object (linear or logarithmic) 507 public $ygrid=null,$y2grid=null; //dito for Y 508 public $doframe,$frame_color, $frame_weight; // Frame around graph 509 public $boxed=false, $box_color='black', $box_weight=1; // Box around plot area 510 public $doshadow=false,$shadow_width=4,$shadow_color='gray@0.5'; // Shadow for graph 511 public $xaxis=null; // X-axis (instane of Axis class) 512 public $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class) 513 public $margin_color; // Margin color of graph 514 public $plotarea_color=array(255,255,255); // Plot area color 515 public $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object 516 public $axtype="linlin"; // Type of axis 517 public $xtick_factor,$ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width 518 public $texts=null, $y2texts=null; // Text object to ge shown in the graph 494 519 public $lines=null, $y2lines=null; 495 520 public $bands=null, $y2bands=null; 496 public $text_scale_off=0, $text_scale_abscenteroff=-1; 497 public $background_image= "",$background_image_type=-1,$background_image_format="png";521 public $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale in fractions and for centering bars 522 public $background_image='',$background_image_type=-1,$background_image_format="png"; 498 523 public $background_image_bright=0,$background_image_contr=0,$background_image_sat=0; 499 524 public $background_image_xpos=0,$background_image_ypos=0; … … 501 526 public $inline; 502 527 public $showcsim=0,$csimcolor="red";//debug stuff, draw the csim boundaris on the image if <>0 503 public $grid_depth=DEPTH_BACK; 528 public $grid_depth=DEPTH_BACK; // Draw grid under all plots as default 504 529 public $iAxisStyle = AXSTYLE_SIMPLE; 505 530 public $iCSIMdisplay=false,$iHasStroked = false; … … 511 536 public $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN; 512 537 public $bkg_gradfrom='navy', $bkg_gradto='silver'; 538 public $plot_gradtype=-1,$plot_gradstyle=BGRAD_MARGIN; 539 public $plot_gradfrom='silver', $plot_gradto='navy'; 540 513 541 public $titlebackground = false; 514 542 public $titlebackground_color = 'lightblue', 515 516 $titlebackground_framecolor = 'blue',517 $titlebackground_framestyle = 2,518 $titlebackground_frameweight = 1,519 $titlebackground_bevelheight = 3;543 $titlebackground_style = 1, 544 $titlebackground_framecolor, 545 $titlebackground_framestyle, 546 $titlebackground_frameweight, 547 $titlebackground_bevelheight; 520 548 public $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; 521 549 public $titlebkg_scolor1='black',$titlebkg_scolor2='white'; 522 public $framebevel = false, $framebeveldepth = 2;523 public $framebevelborder = false, $framebevelbordercolor='black';524 public $framebevelcolor1 ='white@0.4', $framebevelcolor2='black@0.4';550 public $framebevel, $framebeveldepth; 551 public $framebevelborder, $framebevelbordercolor; 552 public $framebevelcolor1, $framebevelcolor2; 525 553 public $background_image_mix=100; 526 554 public $background_cflag = ''; … … 528 556 public $background_cflag_mix = 100; 529 557 public $iImgTrans=false, 530 531 532 533 558 $iImgTransHorizon = 100,$iImgTransSkewDist=150, 559 $iImgTransDirection = 1, $iImgTransMinSize = true, 560 $iImgTransFillColor='white',$iImgTransHighQ=false, 561 $iImgTransBorder=false,$iImgTransHorizonPos=0.5; 534 562 public $legend; 563 public $graph_theme; 535 564 protected $iYAxisDeltaPos=50; 536 565 protected $iIconDepth=DEPTH_BACK; 537 566 protected $iAxisLblBgType = 0, 538 539 567 $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black', 568 $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black'; 540 569 protected $iTables=NULL; 541 570 542 //--------------- 543 // CONSTRUCTOR 544 545 // aWIdth Width in pixels of image 546 // aHeight Height in pixels of image 547 // aCachedName Name for image file in cache directory 548 // aTimeOut Timeout in minutes for image in cache 549 // aInline If true the image is streamed back in the call to Stroke() 550 // If false the image is just created in the cache 551 function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) { 552 GLOBAL $gJpgBrandTiming; 553 // If timing is used create a new timing object 554 if( $gJpgBrandTiming ) { 555 global $tim; 556 $tim = new JpgTimer(); 557 $tim->Push(); 558 } 559 560 if( !is_numeric($aWidth) || !is_numeric($aHeight) ) { 561 JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric'); 562 } 563 564 // Automatically generate the image file name based on the name of the script that 565 // generates the graph 566 if( $aCachedName=="auto" ) 567 $aCachedName=GenImgName(); 568 569 // Should the image be streamed back to the browser or only to the cache? 570 $this->inline=$aInline; 571 572 $this->img = new RotImage($aWidth,$aHeight); 573 574 $this->cache = new ImgStreamCache($this->img); 575 $this->cache->SetTimeOut($aTimeOut); 576 577 $this->title = new Text(); 578 $this->title->ParagraphAlign('center'); 579 $this->title->SetFont(FF_FONT2,FS_BOLD); 580 $this->title->SetMargin(3); 581 $this->title->SetAlign('center'); 582 583 $this->subtitle = new Text(); 584 $this->subtitle->ParagraphAlign('center'); 585 $this->subtitle->SetMargin(2); 586 $this->subtitle->SetAlign('center'); 587 588 $this->subsubtitle = new Text(); 589 $this->subsubtitle->ParagraphAlign('center'); 590 $this->subsubtitle->SetMargin(2); 591 $this->subsubtitle->SetAlign('center'); 592 593 $this->legend = new Legend(); 594 $this->footer = new Footer(); 595 596 // Window doesn't like '?' in the file name so replace it with an '_' 597 $aCachedName = str_replace("?","_",$aCachedName); 598 599 // If the cached version exist just read it directly from the 600 // cache, stream it back to browser and exit 601 if( $aCachedName!="" && READ_CACHE && $aInline ) 602 if( $this->cache->GetAndStream($aCachedName) ) { 603 exit(); 604 } 605 606 $this->cache_name = $aCachedName; 607 $this->SetTickDensity(); // Normal density 608 609 $this->tabtitle = new GraphTabTitle(); 610 } 611 //--------------- 612 // PUBLIC METHODS 613 571 protected $isRunningClear = false; 572 protected $inputValues; 573 protected $isAfterSetScale = false; 574 575 // aWIdth Width in pixels of image 576 // aHeight Height in pixels of image 577 // aCachedName Name for image file in cache directory 578 // aTimeOut Timeout in minutes for image in cache 579 // aInline If true the image is streamed back in the call to Stroke() 580 // If false the image is just created in the cache 581 function __construct($aWidth=300,$aHeight=200,$aCachedName='',$aTimeout=0,$aInline=true) { 582 583 if( !is_numeric($aWidth) || !is_numeric($aHeight) ) { 584 JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric'); 585 } 586 587 // Initialize frame and margin 588 $this->InitializeFrameAndMargin(); 589 590 // Automatically generate the image file name based on the name of the script that 591 // generates the graph 592 if( $aCachedName == 'auto' ) { 593 $aCachedName=GenImgName(); 594 } 595 596 // Should the image be streamed back to the browser or only to the cache? 597 $this->inline=$aInline; 598 599 $this->img = new RotImage($aWidth,$aHeight); 600 $this->cache = new ImgStreamCache(); 601 602 // Window doesn't like '?' in the file name so replace it with an '_' 603 $aCachedName = str_replace("?","_",$aCachedName); 604 $this->SetupCache($aCachedName, $aTimeout); 605 606 $this->title = new Text(); 607 $this->title->ParagraphAlign('center'); 608 $this->title->SetFont(FF_DEFAULT,FS_NORMAL); //FF_FONT2, FS_BOLD 609 $this->title->SetMargin(5); 610 $this->title->SetAlign('center'); 611 612 $this->subtitle = new Text(); 613 $this->subtitle->ParagraphAlign('center'); 614 $this->subtitle->SetMargin(3); 615 $this->subtitle->SetAlign('center'); 616 617 $this->subsubtitle = new Text(); 618 $this->subsubtitle->ParagraphAlign('center'); 619 $this->subsubtitle->SetMargin(3); 620 $this->subsubtitle->SetAlign('center'); 621 622 $this->legend = new Legend(); 623 $this->footer = new Footer(); 624 625 // If the cached version exist just read it directly from the 626 // cache, stream it back to browser and exit 627 if( $aCachedName!='' && READ_CACHE && $aInline ) { 628 if( $this->cache->GetAndStream($this->img,$aCachedName) ) { 629 exit(); 630 } 631 } 632 633 $this->SetTickDensity(); // Normal density 634 635 $this->tabtitle = new GraphTabTitle(); 636 637 if (!$this->isRunningClear) { 638 $this->inputValues = array(); 639 $this->inputValues['aWidth'] = $aWidth; 640 $this->inputValues['aHeight'] = $aHeight; 641 $this->inputValues['aCachedName'] = $aCachedName; 642 $this->inputValues['aTimeout'] = $aTimeout; 643 $this->inputValues['aInline'] = $aInline; 644 645 $theme_class = DEFAULT_THEME_CLASS; 646 if (class_exists($theme_class)) { 647 $this->graph_theme = new $theme_class(); 648 } 649 } 650 } 651 652 function InitializeFrameAndMargin() { 653 $this->doframe=true; 654 $this->frame_color='black'; 655 $this->frame_weight=1; 656 657 $this->titlebackground_framecolor = 'blue'; 658 $this->titlebackground_framestyle = 2; 659 $this->titlebackground_frameweight = 1; 660 $this->titlebackground_bevelheight = 3; 661 $this->titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID; 662 $this->titlebkg_scolor1='black'; 663 $this->titlebkg_scolor2='white'; 664 $this->framebevel = false; 665 $this->framebeveldepth = 2; 666 $this->framebevelborder = false; 667 $this->framebevelbordercolor='black'; 668 $this->framebevelcolor1='white@0.4'; 669 $this->framebevelcolor2='black@0.4'; 670 671 $this->margin_color = array(250,250,250); 672 } 673 674 function SetupCache($aFilename,$aTimeout=60) { 675 $this->cache_name = $aFilename; 676 $this->cache->SetTimeOut($aTimeout); 677 } 678 614 679 // Enable final image perspective transformation 615 680 function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) { 616 617 618 619 620 621 622 623 624 681 $this->iImgTrans = true; 682 $this->iImgTransHorizon = $aHorizon; 683 $this->iImgTransSkewDist= $aSkewDist; 684 $this->iImgTransDirection = $aDir; 685 $this->iImgTransMinSize = $aMinSize; 686 $this->iImgTransFillColor=$aFillColor; 687 $this->iImgTransHighQ=$aQuality; 688 $this->iImgTransBorder=$aBorder; 689 $this->iImgTransHorizonPos=$aHorizonPos; 625 690 } 626 691 627 692 function SetUserFont($aNormal,$aBold='',$aItalic='',$aBoldIt='') { 628 693 $this->img->ttf->SetUserFont($aNormal,$aBold,$aItalic,$aBoldIt); 629 694 } 630 695 631 696 function SetUserFont1($aNormal,$aBold='',$aItalic='',$aBoldIt='') { 632 697 $this->img->ttf->SetUserFont1($aNormal,$aBold,$aItalic,$aBoldIt); 633 698 } 634 699 635 700 function SetUserFont2($aNormal,$aBold='',$aItalic='',$aBoldIt='') { 636 701 $this->img->ttf->SetUserFont2($aNormal,$aBold,$aItalic,$aBoldIt); 637 702 } 638 703 639 704 function SetUserFont3($aNormal,$aBold='',$aItalic='',$aBoldIt='') { 640 705 $this->img->ttf->SetUserFont3($aNormal,$aBold,$aItalic,$aBoldIt); 641 706 } 642 707 643 708 // Set Image format and optional quality 644 709 function SetImgFormat($aFormat,$aQuality=75) { 645 710 $this->img->SetImgFormat($aFormat,$aQuality); 646 711 } 647 712 648 713 // Should the grid be in front or back of the plot? 649 714 function SetGridDepth($aDepth) { 650 715 $this->grid_depth=$aDepth; 651 716 } 652 717 653 718 function SetIconDepth($aDepth) { 654 655 } 656 719 $this->iIconDepth=$aDepth; 720 } 721 657 722 // Specify graph angle 0-360 degrees. 658 723 function SetAngle($aAngle) { 659 724 $this->img->SetAngle($aAngle); 660 725 } 661 726 662 727 function SetAlphaBlending($aFlg=true) { 663 728 $this->img->SetAlphaBlending($aFlg); 664 729 } 665 730 666 731 // Shortcut to image margin 667 732 function SetMargin($lm,$rm,$tm,$bm) { 668 733 $this->img->SetMargin($lm,$rm,$tm,$bm); 669 734 } 670 735 671 736 function SetY2OrderBack($aBack=true) { 672 673 } 674 675 // Rotate the graph 90 degrees and set the margin 737 $this->y2orderback = $aBack; 738 } 739 740 // Rotate the graph 90 degrees and set the margin 676 741 // when we have done a 90 degree rotation 677 742 function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) { 678 $lm = $lm ==0 ? floor(0.2 * $this->img->width) : $lm ; 679 $rm = $rm ==0 ? floor(0.1 * $this->img->width) : $rm ; 680 $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ; 681 $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ; 682 683 $adj = ($this->img->height - $this->img->width)/2; 684 $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj); 685 $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); 686 $this->SetAngle(90); 687 if( empty($this->yaxis) || empty($this->xaxis) ) { 688 JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()'); 689 } 690 $this->xaxis->SetLabelAlign('right','center'); 691 $this->yaxis->SetLabelAlign('center','bottom'); 692 } 693 743 $adj = ($this->img->height - $this->img->width)/2; 744 $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj); 745 $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2)); 746 $this->SetAngle(90); 747 if( empty($this->yaxis) || empty($this->xaxis) ) { 748 JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()'); 749 } 750 $this->xaxis->SetLabelAlign('right','center'); 751 $this->yaxis->SetLabelAlign('center','bottom'); 752 } 753 694 754 function SetClipping($aFlg=true) { 695 755 $this->iDoClipping = $aFlg ; 696 756 } 697 757 698 758 // Add a plot object to the graph 699 759 function Add($aPlot) { 700 if( $aPlot == null ) 701 JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); 702 if( is_array($aPlot) && count($aPlot) > 0 ) 703 $cl = $aPlot[0]; 704 else 705 $cl = $aPlot; 706 707 if( $cl instanceof Text ) 708 $this->AddText($aPlot); 709 elseif( $cl instanceof PlotLine ) 710 $this->AddLine($aPlot); 711 elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) 712 $this->AddBand($aPlot); 713 elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) 714 $this->AddIcon($aPlot); 715 elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) ) 716 $this->AddTable($aPlot); 717 else 718 $this->plots[] = $aPlot; 760 if( $aPlot == null ) { 761 JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph."); 762 } 763 if( is_array($aPlot) && count($aPlot) > 0 ) { 764 $cl = $aPlot[0]; 765 } 766 else { 767 $cl = $aPlot; 768 } 769 770 if( $cl instanceof Text ) $this->AddText($aPlot); 771 elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) $this->AddLine($aPlot); 772 elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) $this->AddBand($aPlot); 773 elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) ) $this->AddIcon($aPlot); 774 elseif( class_exists('GTextTable',false) && ($cl instanceof GTextTable) ) $this->AddTable($aPlot); 775 else { 776 if( is_array($aPlot) ) { 777 $this->plots = array_merge($this->plots,$aPlot); 778 } 779 else { 780 $this->plots[] = $aPlot; 781 } 782 } 783 784 if ($this->graph_theme) { 785 $this->graph_theme->SetupPlot($aPlot); 786 } 719 787 } 720 788 721 789 function AddTable($aTable) { 722 if( is_array($aTable) ) { 723 for($i=0; $i < count($aTable); ++$i ) 724 $this->iTables[]=$aTable[$i]; 725 } 726 else { 727 $this->iTables[] = $aTable ; 728 } 790 if( is_array($aTable) ) { 791 for($i=0; $i < count($aTable); ++$i ) { 792 $this->iTables[]=$aTable[$i]; 793 } 794 } 795 else { 796 $this->iTables[] = $aTable ; 797 } 729 798 } 730 799 731 800 function AddIcon($aIcon) { 732 if( is_array($aIcon) ) { 733 for($i=0; $i < count($aIcon); ++$i ) 734 $this->iIcons[]=$aIcon[$i]; 735 } 736 else { 737 $this->iIcons[] = $aIcon ; 738 } 801 if( is_array($aIcon) ) { 802 for($i=0; $i < count($aIcon); ++$i ) { 803 $this->iIcons[]=$aIcon[$i]; 804 } 805 } 806 else { 807 $this->iIcons[] = $aIcon ; 808 } 739 809 } 740 810 741 811 // Add plot to second Y-scale 742 812 function AddY2($aPlot) { 743 if( $aPlot == null ) 744 JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph."); 745 746 if( is_array($aPlot) && count($aPlot) > 0 ) 747 $cl = $aPlot[0]; 748 else 749 $cl = $aPlot; 750 751 if( $cl instanceof Text ) 752 $this->AddText($aPlot,true); 753 elseif( $cl instanceof PlotLine ) 754 $this->AddLine($aPlot,true); 755 elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) 756 $this->AddBand($aPlot,true); 757 else 758 $this->y2plots[] = $aPlot; 759 } 760 813 if( $aPlot == null ) { 814 JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph."); 815 } 816 817 if( is_array($aPlot) && count($aPlot) > 0 ) { 818 $cl = $aPlot[0]; 819 } 820 else { 821 $cl = $aPlot; 822 } 823 824 if( $cl instanceof Text ) { 825 $this->AddText($aPlot,true); 826 } 827 elseif( class_exists('PlotLine',false) && ($cl instanceof PlotLine) ) { 828 $this->AddLine($aPlot,true); 829 } 830 elseif( class_exists('PlotBand',false) && ($cl instanceof PlotBand) ) { 831 $this->AddBand($aPlot,true); 832 } 833 else { 834 $this->y2plots[] = $aPlot; 835 } 836 837 if ($this->graph_theme) { 838 $this->graph_theme->SetupPlot($aPlot); 839 } 840 } 841 761 842 // Add plot to the extra Y-axises 762 843 function AddY($aN,$aPlot) { 763 844 764 if( $aPlot == null ) 765 JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph."); 766 767 if( is_array($aPlot) && count($aPlot) > 0 ) 768 $cl = $aPlot[0]; 769 else 770 $cl = $aPlot; 771 772 if( ($cl instanceof Text) || ($cl instanceof PlotLine) || 773 (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) ) 774 JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis'); 775 else 776 $this->ynplots[$aN][] = $aPlot; 845 if( $aPlot == null ) { 846 JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph."); 847 } 848 849 if( is_array($aPlot) && count($aPlot) > 0 ) { 850 $cl = $aPlot[0]; 851 } 852 else { 853 $cl = $aPlot; 854 } 855 856 if( ($cl instanceof Text) || 857 (class_exists('PlotLine',false) && ($cl instanceof PlotLine)) || 858 (class_exists('PlotBand',false) && ($cl instanceof PlotBand)) ) { 859 JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis'); 860 } 861 else { 862 $this->ynplots[$aN][] = $aPlot; 863 } 864 865 if ($this->graph_theme) { 866 $this->graph_theme->SetupPlot($aPlot); 867 } 777 868 } 778 869 779 870 // Add text object to the graph 780 871 function AddText($aTxt,$aToY2=false) { 781 if( $aTxt == null ) 782 JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph."); 783 if( $aToY2 ) { 784 if( is_array($aTxt) ) { 785 for($i=0; $i < count($aTxt); ++$i ) 786 $this->y2texts[]=$aTxt[$i]; 787 } 788 else 789 $this->y2texts[] = $aTxt; 790 } 791 else { 792 if( is_array($aTxt) ) { 793 for($i=0; $i < count($aTxt); ++$i ) 794 $this->texts[]=$aTxt[$i]; 795 } 796 else 797 $this->texts[] = $aTxt; 798 } 799 } 800 872 if( $aTxt == null ) { 873 JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph."); 874 } 875 if( $aToY2 ) { 876 if( is_array($aTxt) ) { 877 for($i=0; $i < count($aTxt); ++$i ) { 878 $this->y2texts[]=$aTxt[$i]; 879 } 880 } 881 else { 882 $this->y2texts[] = $aTxt; 883 } 884 } 885 else { 886 if( is_array($aTxt) ) { 887 for($i=0; $i < count($aTxt); ++$i ) { 888 $this->texts[]=$aTxt[$i]; 889 } 890 } 891 else { 892 $this->texts[] = $aTxt; 893 } 894 } 895 } 896 801 897 // Add a line object (class PlotLine) to the graph 802 898 function AddLine($aLine,$aToY2=false) { 803 if( $aLine == null ) 804 JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph."); 805 806 if( $aToY2 ) { 807 if( is_array($aLine) ) { 808 for($i=0; $i < count($aLine); ++$i ) 809 $this->y2lines[]=$aLine[$i]; 810 } 811 else 812 $this->y2lines[] = $aLine; 813 } 814 else { 815 if( is_array($aLine) ) { 816 for($i=0; $i<count($aLine); ++$i ) 817 $this->lines[]=$aLine[$i]; 818 } 819 else 820 $this->lines[] = $aLine; 821 } 899 if( $aLine == null ) { 900 JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph."); 901 } 902 903 if( $aToY2 ) { 904 if( is_array($aLine) ) { 905 for($i=0; $i < count($aLine); ++$i ) { 906 //$this->y2lines[]=$aLine[$i]; 907 $this->y2plots[]=$aLine[$i]; 908 } 909 } 910 else { 911 //$this->y2lines[] = $aLine; 912 $this->y2plots[]=$aLine; 913 } 914 } 915 else { 916 if( is_array($aLine) ) { 917 for($i=0; $i<count($aLine); ++$i ) { 918 //$this->lines[]=$aLine[$i]; 919 $this->plots[]=$aLine[$i]; 920 } 921 } 922 else { 923 //$this->lines[] = $aLine; 924 $this->plots[] = $aLine; 925 } 926 } 822 927 } 823 928 824 929 // Add vertical or horizontal band 825 930 function AddBand($aBand,$aToY2=false) { 826 if( $aBand == null ) 827 JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph."); 828 829 if( $aToY2 ) { 830 if( is_array($aBand) ) { 831 for($i=0; $i < count($aBand); ++$i ) 832 $this->y2bands[] = $aBand[$i]; 833 } 834 else 835 $this->y2bands[] = $aBand; 836 } 837 else { 838 if( is_array($aBand) ) { 839 for($i=0; $i < count($aBand); ++$i ) 840 $this->bands[] = $aBand[$i]; 841 } 842 else 843 $this->bands[] = $aBand; 844 } 931 if( $aBand == null ) { 932 JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph."); 933 } 934 935 if( $aToY2 ) { 936 if( is_array($aBand) ) { 937 for($i=0; $i < count($aBand); ++$i ) { 938 $this->y2bands[] = $aBand[$i]; 939 } 940 } 941 else { 942 $this->y2bands[] = $aBand; 943 } 944 } 945 else { 946 if( is_array($aBand) ) { 947 for($i=0; $i < count($aBand); ++$i ) { 948 $this->bands[] = $aBand[$i]; 949 } 950 } 951 else { 952 $this->bands[] = $aBand; 953 } 954 } 955 } 956 957 function SetPlotGradient($aFrom='navy',$aTo='silver',$aGradType=2) { 958 $this->plot_gradtype=$aGradType; 959 $this->plot_gradfrom = $aFrom; 960 $this->plot_gradto = $aTo; 845 961 } 846 962 847 963 function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) { 848 849 850 851 852 } 853 964 $this->bkg_gradtype=$aGradType; 965 $this->bkg_gradstyle=$aStyle; 966 $this->bkg_gradfrom = $aFrom; 967 $this->bkg_gradto = $aTo; 968 } 969 854 970 // Set a country flag in the background 855 971 function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { 856 857 858 972 $this->background_cflag = $aName; 973 $this->background_cflag_type = $aBgType; 974 $this->background_cflag_mix = $aMix; 859 975 } 860 976 861 977 // Alias for the above method 862 978 function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) { 863 864 865 979 $this->background_cflag = $aName; 980 $this->background_cflag_type = $aBgType; 981 $this->background_cflag_mix = $aMix; 866 982 } 867 983 868 984 869 985 // Specify a background image 870 function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat="auto") { 871 872 if( !USE_TRUECOLOR ) { 873 JpGraphError::RaiseL(25017);//("You are using GD 2.x and are trying to use a background images on a non truecolor image. To use background images with GD 2.x you <b>must</b> enable truecolor by setting the USE_TRUECOLOR constant to TRUE. Due to a bug in GD 2.0.1 using any truetype fonts with truecolor images will result in very poor quality fonts."); 874 } 875 876 // Get extension to determine image type 877 if( $aImgFormat == "auto" ) { 878 $e = explode('.',$aFileName); 879 if( !$e ) { 880 JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); 881 } 882 883 $valid_formats = array('png', 'jpg', 'gif'); 884 $aImgFormat = strtolower($e[count($e)-1]); 885 if ($aImgFormat == 'jpeg') { 886 $aImgFormat = 'jpg'; 887 } 888 elseif (!in_array($aImgFormat, $valid_formats) ) { 889 JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName); 890 } 891 } 892 893 $this->background_image = $aFileName; 894 $this->background_image_type=$aBgType; 895 $this->background_image_format=$aImgFormat; 986 function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat='auto') { 987 988 // Get extension to determine image type 989 if( $aImgFormat == 'auto' ) { 990 $e = explode('.',$aFileName); 991 if( !$e ) { 992 JpGraphError::RaiseL(25018,$aFileName);//('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type'); 993 } 994 995 $valid_formats = array('png', 'jpg', 'gif'); 996 $aImgFormat = strtolower($e[count($e)-1]); 997 if ($aImgFormat == 'jpeg') { 998 $aImgFormat = 'jpg'; 999 } 1000 elseif (!in_array($aImgFormat, $valid_formats) ) { 1001 JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName); 1002 } 1003 } 1004 1005 $this->background_image = $aFileName; 1006 $this->background_image_type=$aBgType; 1007 $this->background_image_format=$aImgFormat; 896 1008 } 897 1009 898 1010 function SetBackgroundImageMix($aMix) { 899 900 } 901 1011 $this->background_image_mix = $aMix ; 1012 } 1013 902 1014 // Adjust background image position 903 1015 function SetBackgroundImagePos($aXpos,$aYpos) { 904 905 906 } 907 1016 $this->background_image_xpos = $aXpos ; 1017 $this->background_image_ypos = $aYpos ; 1018 } 1019 908 1020 // Specify axis style (boxed or single) 909 1021 function SetAxisStyle($aStyle) { 910 1022 $this->iAxisStyle = $aStyle ; 911 1023 } 912 1024 913 1025 // Set a frame around the plot area 914 1026 function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) { 915 916 917 918 } 919 1027 $this->boxed = $aDrawPlotFrame; 1028 $this->box_weight = $aPlotFrameWeight; 1029 $this->box_color = $aPlotFrameColor; 1030 } 1031 920 1032 // Specify color for the plotarea (not the margins) 921 1033 function SetColor($aColor) { 922 923 } 924 1034 $this->plotarea_color=$aColor; 1035 } 1036 925 1037 // Specify color for the margins (all areas outside the plotarea) 926 1038 function SetMarginColor($aColor) { 927 928 } 929 1039 $this->margin_color=$aColor; 1040 } 1041 930 1042 // Set a frame around the entire image 931 1043 function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) { 932 933 934 1044 $this->doframe = $aDrawImgFrame; 1045 $this->frame_color = $aImgFrameColor; 1046 $this->frame_weight = $aImgFrameWeight; 935 1047 } 936 1048 937 1049 function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) { 938 939 940 941 942 943 944 945 1050 $this->framebevel = $aFlg ; 1051 $this->framebeveldepth = $aDepth ; 1052 $this->framebevelborder = $aBorder ; 1053 $this->framebevelbordercolor = $aBorderColor ; 1054 $this->framebevelcolor1 = $aColor1 ; 1055 $this->framebevelcolor2 = $aColor2 ; 1056 1057 $this->doshadow = false ; 946 1058 } 947 1059 948 1060 // Set the shadow around the whole image 949 function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor= array(102,102,102)) {950 951 952 953 954 1061 function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor='darkgray') { 1062 $this->doshadow = $aShowShadow; 1063 $this->shadow_color = $aShadowColor; 1064 $this->shadow_width = $aShadowWidth; 1065 $this->footer->iBottomMargin += $aShadowWidth; 1066 $this->footer->iRightMargin += $aShadowWidth; 955 1067 } 956 1068 … … 958 1070 // you must also specify the tick distance with a call to Ticks::Set() 959 1071 function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) { 960 $this->axtype = $aAxisType; 961 962 if( $aYMax < $aYMin || $aXMax < $aXMin ) 963 JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.'); 964 965 $yt=substr($aAxisType,-3,3); 966 if( $yt=="lin" ) 967 $this->yscale = new LinearScale($aYMin,$aYMax); 968 elseif( $yt == "int" ) { 969 $this->yscale = new LinearScale($aYMin,$aYMax); 970 $this->yscale->SetIntScale(); 971 } 972 elseif( $yt=="log" ) 973 $this->yscale = new LogScale($aYMin,$aYMax); 974 else 975 JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)"); 976 977 $xt=substr($aAxisType,0,3); 978 if( $xt == "lin" || $xt == "tex" ) { 979 $this->xscale = new LinearScale($aXMin,$aXMax,"x"); 980 $this->xscale->textscale = ($xt == "tex"); 981 } 982 elseif( $xt == "int" ) { 983 $this->xscale = new LinearScale($aXMin,$aXMax,"x"); 984 $this->xscale->SetIntScale(); 985 } 986 elseif( $xt == "dat" ) { 987 $this->xscale = new DateScale($aXMin,$aXMax,"x"); 988 } 989 elseif( $xt == "log" ) 990 $this->xscale = new LogScale($aXMin,$aXMax,"x"); 991 else 992 JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)"); 993 994 $this->xaxis = new Axis($this->img,$this->xscale); 995 $this->yaxis = new Axis($this->img,$this->yscale); 996 $this->xgrid = new Grid($this->xaxis); 997 $this->ygrid = new Grid($this->yaxis); 998 $this->ygrid->Show(); 999 } 1000 1072 $this->axtype = $aAxisType; 1073 1074 if( $aYMax < $aYMin || $aXMax < $aXMin ) { 1075 JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.'); 1076 } 1077 1078 $yt=substr($aAxisType,-3,3); 1079 if( $yt == 'lin' ) { 1080 $this->yscale = new LinearScale($aYMin,$aYMax); 1081 } 1082 elseif( $yt == 'int' ) { 1083 $this->yscale = new LinearScale($aYMin,$aYMax); 1084 $this->yscale->SetIntScale(); 1085 } 1086 elseif( $yt == 'log' ) { 1087 $this->yscale = new LogScale($aYMin,$aYMax); 1088 } 1089 else { 1090 JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)"); 1091 } 1092 1093 $xt=substr($aAxisType,0,3); 1094 if( $xt == 'lin' || $xt == 'tex' ) { 1095 $this->xscale = new LinearScale($aXMin,$aXMax,'x'); 1096 $this->xscale->textscale = ($xt == 'tex'); 1097 } 1098 elseif( $xt == 'int' ) { 1099 $this->xscale = new LinearScale($aXMin,$aXMax,'x'); 1100 $this->xscale->SetIntScale(); 1101 } 1102 elseif( $xt == 'dat' ) { 1103 $this->xscale = new DateScale($aXMin,$aXMax,'x'); 1104 } 1105 elseif( $xt == 'log' ) { 1106 $this->xscale = new LogScale($aXMin,$aXMax,'x'); 1107 } 1108 else { 1109 JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)"); 1110 } 1111 1112 $this->xaxis = new Axis($this->img,$this->xscale); 1113 $this->yaxis = new Axis($this->img,$this->yscale); 1114 $this->xgrid = new Grid($this->xaxis); 1115 $this->ygrid = new Grid($this->yaxis); 1116 $this->ygrid->Show(); 1117 1118 1119 if (!$this->isRunningClear) { 1120 $this->inputValues['aAxisType'] = $aAxisType; 1121 $this->inputValues['aYMin'] = $aYMin; 1122 $this->inputValues['aYMax'] = $aYMax; 1123 $this->inputValues['aXMin'] = $aXMin; 1124 $this->inputValues['aXMax'] = $aXMax; 1125 1126 if ($this->graph_theme) { 1127 $this->graph_theme->ApplyGraph($this); 1128 } 1129 } 1130 1131 $this->isAfterSetScale = true; 1132 } 1133 1001 1134 // Specify secondary Y scale 1002 function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) { 1003 if( $aAxisType=="lin" ) 1004 $this->y2scale = new LinearScale($aY2Min,$aY2Max); 1005 elseif( $aAxisType == "int" ) { 1006 $this->y2scale = new LinearScale($aY2Min,$aY2Max); 1007 $this->y2scale->SetIntScale(); 1008 } 1009 elseif( $aAxisType=="log" ) { 1010 $this->y2scale = new LogScale($aY2Min,$aY2Max); 1011 } 1012 else JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)"); 1013 1014 $this->y2axis = new Axis($this->img,$this->y2scale); 1015 $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); 1016 $this->y2axis->SetLabelSide(SIDE_RIGHT); 1017 $this->y2axis->SetPos('max'); 1018 $this->y2axis->SetTitleSide(SIDE_RIGHT); 1019 1020 // Deafult position is the max x-value 1021 $this->y2grid = new Grid($this->y2axis); 1135 function SetY2Scale($aAxisType='lin',$aY2Min=1,$aY2Max=1) { 1136 if( $aAxisType == 'lin' ) { 1137 $this->y2scale = new LinearScale($aY2Min,$aY2Max); 1138 } 1139 elseif( $aAxisType == 'int' ) { 1140 $this->y2scale = new LinearScale($aY2Min,$aY2Max); 1141 $this->y2scale->SetIntScale(); 1142 } 1143 elseif( $aAxisType == 'log' ) { 1144 $this->y2scale = new LogScale($aY2Min,$aY2Max); 1145 } 1146 else { 1147 JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)"); 1148 } 1149 1150 $this->y2axis = new Axis($this->img,$this->y2scale); 1151 $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); 1152 $this->y2axis->SetLabelSide(SIDE_RIGHT); 1153 $this->y2axis->SetPos('max'); 1154 $this->y2axis->SetTitleSide(SIDE_RIGHT); 1155 1156 // Deafult position is the max x-value 1157 $this->y2grid = new Grid($this->y2axis); 1158 1159 if ($this->graph_theme) { 1160 $this->graph_theme->ApplyGraph($this); 1161 } 1022 1162 } 1023 1163 1024 1164 // Set the delta position (in pixels) between the multiple Y-axis 1025 1165 function SetYDeltaDist($aDist) { 1026 1166 $this->iYAxisDeltaPos = $aDist; 1027 1167 } 1028 1168 … … 1030 1170 function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) { 1031 1171 1032 if( $aAxisType=="lin" ) 1033 $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); 1034 elseif( $aAxisType == "int" ) { 1035 $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); 1036 $this->ynscale[$aN]->SetIntScale(); 1037 } 1038 elseif( $aAxisType=="log" ) { 1039 $this->ynscale[$aN] = new LogScale($aYMin,$aYMax); 1040 } 1041 else JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)"); 1042 1043 $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]); 1044 $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); 1045 $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); 1172 if( $aAxisType == 'lin' ) { 1173 $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); 1174 } 1175 elseif( $aAxisType == 'int' ) { 1176 $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax); 1177 $this->ynscale[$aN]->SetIntScale(); 1178 } 1179 elseif( $aAxisType == 'log' ) { 1180 $this->ynscale[$aN] = new LogScale($aYMin,$aYMax); 1181 } 1182 else { 1183 JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)"); 1184 } 1185 1186 $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]); 1187 $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); 1188 $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); 1189 1190 if ($this->graph_theme) { 1191 $this->graph_theme->ApplyGraph($this); 1192 } 1046 1193 } 1047 1194 1048 1195 // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse' 1049 // The dividing factor have been determined heuristically according to my aesthetic 1196 // The dividing factor have been determined heuristically according to my aesthetic 1050 1197 // sense (or lack off) y.m.m.v ! 1051 1198 function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) { 1052 1053 $this->ytick_factor=25; 1054 1055 1056 $this->ytick_factor=12; 1057 1058 1059 $this->ytick_factor=25; 1060 1061 1062 $this->ytick_factor=40; 1063 1064 1065 $this->ytick_factor=100; 1066 break; 1067 1068 1069 1070 1071 1072 $this->xtick_factor=15; 1073 1074 1075 $this->xtick_factor=30; 1076 1077 1078 $this->xtick_factor=45; 1079 1080 1081 $this->xtick_factor=60; 1082 break; 1083 1084 1085 } 1086 } 1087 1088 1089 // Get a string of all image map areas 1199 $this->xtick_factor=30; 1200 $this->ytick_factor=25; 1201 switch( $aYDensity ) { 1202 case TICKD_DENSE: 1203 $this->ytick_factor=12; 1204 break; 1205 case TICKD_NORMAL: 1206 $this->ytick_factor=25; 1207 break; 1208 case TICKD_SPARSE: 1209 $this->ytick_factor=40; 1210 break; 1211 case TICKD_VERYSPARSE: 1212 $this->ytick_factor=100; 1213 break; 1214 default: 1215 JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy"); 1216 } 1217 switch( $aXDensity ) { 1218 case TICKD_DENSE: 1219 $this->xtick_factor=15; 1220 break; 1221 case TICKD_NORMAL: 1222 $this->xtick_factor=30; 1223 break; 1224 case TICKD_SPARSE: 1225 $this->xtick_factor=45; 1226 break; 1227 case TICKD_VERYSPARSE: 1228 $this->xtick_factor=60; 1229 break; 1230 default: 1231 JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx"); 1232 } 1233 } 1234 1235 1236 // Get a string of all image map areas 1090 1237 function GetCSIMareas() { 1091 if( !$this->iHasStroked ) 1092 $this->Stroke(_CSIM_SPECIALFILE); 1093 1094 $csim = $this->title->GetCSIMAreas(); 1095 $csim .= $this->subtitle->GetCSIMAreas(); 1096 $csim .= $this->subsubtitle->GetCSIMAreas(); 1097 $csim .= $this->legend->GetCSIMAreas(); 1098 1099 if( $this->y2axis != NULL ) { 1100 $csim .= $this->y2axis->title->GetCSIMAreas(); 1101 } 1102 1103 if( $this->texts != null ) { 1104 $n = count($this->texts); 1105 for($i=0; $i < $n; ++$i ) { 1106 $csim .= $this->texts[$i]->GetCSIMAreas(); 1107 } 1108 } 1109 1110 if( $this->y2texts != null && $this->y2scale != null ) { 1111 $n = count($this->y2texts); 1112 for($i=0; $i < $n; ++$i ) { 1113 $csim .= $this->y2texts[$i]->GetCSIMAreas(); 1114 } 1115 } 1116 1117 if( $this->yaxis != null && $this->xaxis != null ) { 1118 $csim .= $this->yaxis->title->GetCSIMAreas(); 1119 $csim .= $this->xaxis->title->GetCSIMAreas(); 1120 } 1121 1122 $n = count($this->plots); 1123 for( $i=0; $i < $n; ++$i ) 1124 $csim .= $this->plots[$i]->GetCSIMareas(); 1125 1126 $n = count($this->y2plots); 1127 for( $i=0; $i < $n; ++$i ) 1128 $csim .= $this->y2plots[$i]->GetCSIMareas(); 1129 1130 $n = count($this->ynaxis); 1131 for( $i=0; $i < $n; ++$i ) { 1132 $m = count($this->ynplots[$i]); 1133 for($j=0; $j < $m; ++$j ) { 1134 $csim .= $this->ynplots[$i][$j]->GetCSIMareas(); 1135 } 1136 } 1137 1138 $n = count($this->iTables); 1139 for( $i=0; $i < $n; ++$i ) { 1140 $csim .= $this->iTables[$i]->GetCSIMareas(); 1141 } 1142 1143 return $csim; 1144 } 1145 1238 if( !$this->iHasStroked ) { 1239 $this->Stroke(_CSIM_SPECIALFILE); 1240 } 1241 1242 $csim = $this->title->GetCSIMAreas(); 1243 $csim .= $this->subtitle->GetCSIMAreas(); 1244 $csim .= $this->subsubtitle->GetCSIMAreas(); 1245 $csim .= $this->legend->GetCSIMAreas(); 1246 1247 if( $this->y2axis != NULL ) { 1248 $csim .= $this->y2axis->title->GetCSIMAreas(); 1249 } 1250 1251 if( $this->texts != null ) { 1252 $n = count($this->texts); 1253 for($i=0; $i < $n; ++$i ) { 1254 $csim .= $this->texts[$i]->GetCSIMAreas(); 1255 } 1256 } 1257 1258 if( $this->y2texts != null && $this->y2scale != null ) { 1259 $n = count($this->y2texts); 1260 for($i=0; $i < $n; ++$i ) { 1261 $csim .= $this->y2texts[$i]->GetCSIMAreas(); 1262 } 1263 } 1264 1265 if( $this->yaxis != null && $this->xaxis != null ) { 1266 $csim .= $this->yaxis->title->GetCSIMAreas(); 1267 $csim .= $this->xaxis->title->GetCSIMAreas(); 1268 } 1269 1270 $n = count($this->plots); 1271 for( $i=0; $i < $n; ++$i ) { 1272 $csim .= $this->plots[$i]->GetCSIMareas(); 1273 } 1274 1275 $n = count($this->y2plots); 1276 for( $i=0; $i < $n; ++$i ) { 1277 $csim .= $this->y2plots[$i]->GetCSIMareas(); 1278 } 1279 1280 $n = count($this->ynaxis); 1281 for( $i=0; $i < $n; ++$i ) { 1282 $m = count($this->ynplots[$i]); 1283 for($j=0; $j < $m; ++$j ) { 1284 $csim .= $this->ynplots[$i][$j]->GetCSIMareas(); 1285 } 1286 } 1287 1288 if($this->iTables != null) { 1289 $n = count($this->iTables); 1290 for ($i = 0; $i < $n; ++$i) { 1291 $csim .= $this->iTables[$i]->GetCSIMareas(); 1292 } 1293 } 1294 1295 return $csim; 1296 } 1297 1146 1298 // Get a complete <MAP>..</MAP> tag for the final image map 1147 1299 function GetHTMLImageMap($aMapName) { 1148 1149 1150 $im .= "</map>"; 1151 1300 $im = "<map name=\"$aMapName\" id=\"$aMapName\" >\n"; 1301 $im .= $this->GetCSIMareas(); 1302 $im .= "</map>"; 1303 return $im; 1152 1304 } 1153 1305 1154 1306 function CheckCSIMCache($aCacheName,$aTimeOut=60) { 1155 global $_SERVER; 1156 1157 if( $aCacheName=='auto' ) 1158 $aCacheName=basename($_SERVER['PHP_SELF']); 1159 1160 $urlarg = $this->GetURLArguments(); 1161 $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg; 1162 $this->csimcachetimeout = $aTimeOut; 1163 1164 // First determine if we need to check for a cached version 1165 // This differs from the standard cache in the sense that the 1166 // image and CSIM map HTML file is written relative to the directory 1167 // the script executes in and not the specified cache directory. 1168 // The reason for this is that the cache directory is not necessarily 1169 // accessible from the HTTP server. 1170 if( $this->csimcachename != '' ) { 1171 $dir = dirname($this->csimcachename); 1172 $base = basename($this->csimcachename); 1173 $base = strtok($base,'.'); 1174 $suffix = strtok('.'); 1175 $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; 1176 $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format; 1177 1178 $timedout=false; 1179 // Does it exist at all ? 1180 1181 if( file_exists($basecsim) && file_exists($baseimg) ) { 1182 // Check that it hasn't timed out 1183 $diff=time()-filemtime($basecsim); 1184 if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) { 1185 $timedout=true; 1186 @unlink($basecsim); 1187 @unlink($baseimg); 1188 } 1189 else { 1190 if ($fh = @fopen($basecsim, "r")) { 1191 fpassthru($fh); 1192 return true; 1193 } 1194 else 1195 JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading."); 1196 } 1197 } 1198 } 1199 return false; 1307 global $_SERVER; 1308 1309 if( $aCacheName=='auto' ) { 1310 $aCacheName=basename($_SERVER['PHP_SELF']); 1311 } 1312 1313 $urlarg = $this->GetURLArguments(); 1314 $this->csimcachename = CSIMCACHE_DIR.$aCacheName.$urlarg; 1315 $this->csimcachetimeout = $aTimeOut; 1316 1317 // First determine if we need to check for a cached version 1318 // This differs from the standard cache in the sense that the 1319 // image and CSIM map HTML file is written relative to the directory 1320 // the script executes in and not the specified cache directory. 1321 // The reason for this is that the cache directory is not necessarily 1322 // accessible from the HTTP server. 1323 if( $this->csimcachename != '' ) { 1324 $dir = dirname($this->csimcachename); 1325 $base = basename($this->csimcachename); 1326 $base = strtok($base,'.'); 1327 $suffix = strtok('.'); 1328 $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; 1329 $baseimg = $dir.'/'.$base.'?'.$urlarg.'.'.$this->img->img_format; 1330 1331 $timedout=false; 1332 // Does it exist at all ? 1333 1334 if( file_exists($basecsim) && file_exists($baseimg) ) { 1335 // Check that it hasn't timed out 1336 $diff=time()-filemtime($basecsim); 1337 if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) { 1338 $timedout=true; 1339 @unlink($basecsim); 1340 @unlink($baseimg); 1341 } 1342 else { 1343 if ($fh = @fopen($basecsim, "r")) { 1344 fpassthru($fh); 1345 return true; 1346 } 1347 else { 1348 JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading."); 1349 } 1350 } 1351 } 1352 } 1353 return false; 1200 1354 } 1201 1355 1202 1356 // Build the argument string to be used with the csim images 1203 function GetURLArguments() { 1204 1205 // This is a JPGRAPH internal defined that prevents 1206 // us from recursively coming here again 1207 $urlarg = _CSIM_DISPLAY.'=1'; 1208 1209 // Now reconstruct any user URL argument 1210 reset($_GET); 1211 while( list($key,$value) = each($_GET) ) { 1212 if( is_array($value) ) { 1213 foreach ( $value as $k => $v ) { 1214 $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); 1215 } 1216 } 1217 else { 1218 $urlarg .= '&'.$key.'='.urlencode($value); 1219 } 1220 } 1221 1222 // It's not ideal to convert POST argument to GET arguments 1223 // but there is little else we can do. One idea for the 1224 // future might be recreate the POST header in case. 1225 reset($_POST); 1226 while( list($key,$value) = each($_POST) ) { 1227 if( is_array($value) ) { 1228 foreach ( $value as $k => $v ) { 1229 $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); 1230 } 1231 } 1232 else { 1233 $urlarg .= '&'.$key.'='.urlencode($value); 1234 } 1235 } 1236 1237 return $urlarg; 1357 static function GetURLArguments($aAddRecursiveBlocker=false) { 1358 1359 if( $aAddRecursiveBlocker ) { 1360 // This is a JPGRAPH internal defined that prevents 1361 // us from recursively coming here again 1362 $urlarg = _CSIM_DISPLAY.'=1'; 1363 } 1364 1365 // Now reconstruct any user URL argument 1366 reset($_GET); 1367 foreach ($_GET as $key => $value) { 1368 if( is_array($value) ) { 1369 foreach ( $value as $k => $v ) { 1370 $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); 1371 } 1372 } 1373 else { 1374 $urlarg .= '&'.$key.'='.urlencode($value); 1375 } 1376 } 1377 1378 // It's not ideal to convert POST argument to GET arguments 1379 // but there is little else we can do. One idea for the 1380 // future might be recreate the POST header in case. 1381 reset($_POST); 1382 foreach ($_POST as $key => $value) { 1383 if( is_array($value) ) { 1384 foreach ( $value as $k => $v ) { 1385 $urlarg .= '&'.$key.'%5B'.$k.'%5D='.urlencode($v); 1386 } 1387 } 1388 else { 1389 $urlarg .= '&'.$key.'='.urlencode($value); 1390 } 1391 } 1392 1393 return $urlarg; 1238 1394 } 1239 1395 1240 1396 function SetCSIMImgAlt($aAlt) { 1241 1397 $this->iCSIMImgAlt = $aAlt; 1242 1398 } 1243 1399 1244 1400 function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) { 1245 if( $aCSIMName=='' ) { 1246 // create a random map name 1247 srand ((double) microtime() * 1000000); 1248 $r = rand(0,100000); 1249 $aCSIMName='__mapname'.$r.'__'; 1250 } 1251 1252 if( $aScriptName=='auto' ) 1253 $aScriptName=basename($_SERVER['PHP_SELF']); 1254 1255 $urlarg = $this->GetURLArguments(); 1256 1257 if( empty($_GET[_CSIM_DISPLAY]) ) { 1258 // First determine if we need to check for a cached version 1259 // This differs from the standard cache in the sense that the 1260 // image and CSIM map HTML file is written relative to the directory 1261 // the script executes in and not the specified cache directory. 1262 // The reason for this is that the cache directory is not necessarily 1263 // accessible from the HTTP server. 1264 if( $this->csimcachename != '' ) { 1265 $dir = dirname($this->csimcachename); 1266 $base = basename($this->csimcachename); 1267 $base = strtok($base,'.'); 1268 $suffix = strtok('.'); 1269 $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; 1270 $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format; 1271 1272 // Check that apache can write to directory specified 1273 1274 if( file_exists($dir) && !is_writeable($dir) ) { 1275 JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.'); 1276 } 1277 1278 // Make sure directory exists 1279 $this->cache->MakeDirs($dir); 1280 1281 // Write the image file 1282 $this->Stroke(CSIMCACHE_DIR.$baseimg); 1283 1284 // Construct wrapper HTML and write to file and send it back to browser 1285 1286 // In the src URL we must replace the '?' with its encoding to prevent the arguments 1287 // to be converted to real arguments. 1288 $tmp = str_replace('?','%3f',$baseimg); 1289 $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n". 1290 '<img src="'.CSIMCACHE_HTTP_DIR.$tmp.'" ismap="ismap" usemap="#'.$aCSIMName.'" border="'.$aBorder.'" width="'.$this->img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n"; 1291 1292 if($fh = @fopen($basecsim,'w') ) { 1293 fwrite($fh,$htmlwrap); 1294 fclose($fh); 1295 echo $htmlwrap; 1296 } 1297 else 1298 JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions."); 1299 } 1300 else { 1301 1302 if( $aScriptName=='' ) { 1303 JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().'); 1304 } 1305 echo $this->GetHTMLImageMap($aCSIMName); 1306 echo "<img src=\"".$aScriptName.'?'.$urlarg."\" ismap=\"ismap\" usemap=\"#".$aCSIMName.'" border="'.$aBorder.'" width="'.$this->img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n"; 1307 } 1308 } 1309 else { 1310 $this->Stroke(); 1311 } 1401 if( $aCSIMName=='' ) { 1402 // create a random map name 1403 srand ((double) microtime() * 1000000); 1404 $r = rand(0,100000); 1405 $aCSIMName='__mapname'.$r.'__'; 1406 } 1407 1408 if( $aScriptName=='auto' ) { 1409 $aScriptName=basename($_SERVER['PHP_SELF']); 1410 } 1411 1412 $urlarg = $this->GetURLArguments(true); 1413 1414 if( empty($_GET[_CSIM_DISPLAY]) ) { 1415 // First determine if we need to check for a cached version 1416 // This differs from the standard cache in the sense that the 1417 // image and CSIM map HTML file is written relative to the directory 1418 // the script executes in and not the specified cache directory. 1419 // The reason for this is that the cache directory is not necessarily 1420 // accessible from the HTTP server. 1421 if( $this->csimcachename != '' ) { 1422 $dir = dirname($this->csimcachename); 1423 $base = basename($this->csimcachename); 1424 $base = strtok($base,'.'); 1425 $suffix = strtok('.'); 1426 $basecsim = $dir.'/'.$base.'?'.$urlarg.'_csim_.html'; 1427 $baseimg = $base.'?'.$urlarg.'.'.$this->img->img_format; 1428 1429 // Check that apache can write to directory specified 1430 1431 if( file_exists($dir) && !is_writeable($dir) ) { 1432 JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.'); 1433 } 1434 1435 // Make sure directory exists 1436 $this->cache->MakeDirs($dir); 1437 1438 // Write the image file 1439 $this->Stroke(CSIMCACHE_DIR.$baseimg); 1440 1441 // Construct wrapper HTML and write to file and send it back to browser 1442 1443 // In the src URL we must replace the '?' with its encoding to prevent the arguments 1444 // to be converted to real arguments. 1445 $tmp = str_replace('?','%3f',$baseimg); 1446 $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n". 1447 '<img src="'.CSIMCACHE_HTTP_DIR.$tmp.'" ismap="ismap" usemap="#'.$aCSIMName.' width="'.$this->img->width.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n"; 1448 1449 if($fh = @fopen($basecsim,'w') ) { 1450 fwrite($fh,$htmlwrap); 1451 fclose($fh); 1452 echo $htmlwrap; 1453 } 1454 else { 1455 JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions."); 1456 } 1457 } 1458 else { 1459 1460 if( $aScriptName=='' ) { 1461 JpGraphError::RaiseL(25030);//('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().'); 1462 } 1463 echo $this->GetHTMLImageMap($aCSIMName) . $this->GetCSIMImgHTML($aCSIMName, $aScriptName, $aBorder); 1464 } 1465 } 1466 else { 1467 $this->Stroke(); 1468 } 1469 } 1470 1471 function StrokeCSIMImage() { 1472 if( @$_GET[_CSIM_DISPLAY] == 1 ) { 1473 $this->Stroke(); 1474 } 1475 } 1476 1477 function GetCSIMImgHTML($aCSIMName, $aScriptName='auto', $aBorder=0 ) { 1478 if( $aScriptName=='auto' ) { 1479 $aScriptName=basename($_SERVER['PHP_SELF']); 1480 } 1481 $urlarg = $this->GetURLArguments(true); 1482 return "<img src=\"".$aScriptName.'?'.$urlarg."\" ismap=\"ismap\" usemap=\"#".$aCSIMName.'" height="'.$this->img->height."\" alt=\"".$this->iCSIMImgAlt."\" />\n"; 1312 1483 } 1313 1484 1314 1485 function GetTextsYMinMax($aY2=false) { 1315 if( $aY2 ) 1316 $txts = $this->y2texts; 1317 else 1318 $txts = $this->texts; 1319 $n = count($txts); 1320 $min=null; 1321 $max=null; 1322 for( $i=0; $i < $n; ++$i ) { 1323 if( $txts[$i]->iScalePosY !== null && 1324 $txts[$i]->iScalePosX !== null ) { 1325 if( $min === null ) { 1326 $min = $max = $txts[$i]->iScalePosY ; 1327 } 1328 else { 1329 $min = min($min,$txts[$i]->iScalePosY); 1330 $max = max($max,$txts[$i]->iScalePosY); 1331 } 1332 } 1333 } 1334 if( $min !== null ) { 1335 return array($min,$max); 1336 } 1337 else 1338 return null; 1486 if( $aY2 ) { 1487 $txts = $this->y2texts; 1488 } 1489 else { 1490 $txts = $this->texts; 1491 } 1492 $n = is_array($txts) ? count($txts) : 0; 1493 $min=null; 1494 $max=null; 1495 for( $i=0; $i < $n; ++$i ) { 1496 if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) { 1497 if( $min === null ) { 1498 $min = $max = $txts[$i]->iScalePosY ; 1499 } 1500 else { 1501 $min = min($min,$txts[$i]->iScalePosY); 1502 $max = max($max,$txts[$i]->iScalePosY); 1503 } 1504 } 1505 } 1506 if( $min !== null ) { 1507 return array($min,$max); 1508 } 1509 else { 1510 return null; 1511 } 1339 1512 } 1340 1513 1341 1514 function GetTextsXMinMax($aY2=false) { 1342 if( $aY2 ) 1343 $txts = $this->y2texts; 1344 else 1345 $txts = $this->texts; 1346 $n = count($txts); 1347 $min=null; 1348 $max=null; 1349 for( $i=0; $i < $n; ++$i ) { 1350 if( $txts[$i]->iScalePosY !== null && 1351 $txts[$i]->iScalePosX !== null ) { 1352 if( $min === null ) { 1353 $min = $max = $txts[$i]->iScalePosX ; 1354 } 1355 else { 1356 $min = min($min,$txts[$i]->iScalePosX); 1357 $max = max($max,$txts[$i]->iScalePosX); 1358 } 1359 } 1360 } 1361 if( $min !== null ) { 1362 return array($min,$max); 1363 } 1364 else 1365 return null; 1515 if( $aY2 ) { 1516 $txts = $this->y2texts; 1517 } 1518 else { 1519 $txts = $this->texts; 1520 } 1521 $n = is_array($txts) ? count($txts) : 0; 1522 $min=null; 1523 $max=null; 1524 for( $i=0; $i < $n; ++$i ) { 1525 if( $txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null ) { 1526 if( $min === null ) { 1527 $min = $max = $txts[$i]->iScalePosX ; 1528 } 1529 else { 1530 $min = min($min,$txts[$i]->iScalePosX); 1531 $max = max($max,$txts[$i]->iScalePosX); 1532 } 1533 } 1534 } 1535 if( $min !== null ) { 1536 return array($min,$max); 1537 } 1538 else { 1539 return null; 1540 } 1366 1541 } 1367 1542 1368 1543 function GetXMinMax() { 1369 list($min,$ymin) = $this->plots[0]->Min(); 1370 list($max,$ymax) = $this->plots[0]->Max(); 1371 foreach( $this->plots as $p ) { 1372 list($xmin,$ymin) = $p->Min(); 1373 list($xmax,$ymax) = $p->Max(); 1374 $min = Min($xmin,$min); 1375 $max = Max($xmax,$max); 1376 } 1377 1378 if( $this->y2axis != null ) { 1379 foreach( $this->y2plots as $p ) { 1380 list($xmin,$ymin) = $p->Min(); 1381 list($xmax,$ymax) = $p->Max(); 1382 $min = Min($xmin,$min); 1383 $max = Max($xmax,$max); 1384 } 1385 } 1386 1387 $n = count($this->ynaxis); 1388 for( $i=0; $i < $n; ++$i ) { 1389 if( $this->ynaxis[$i] != null) { 1390 foreach( $this->ynplots[$i] as $p ) { 1391 list($xmin,$ymin) = $p->Min(); 1392 list($xmax,$ymax) = $p->Max(); 1393 $min = Min($xmin,$min); 1394 $max = Max($xmax,$max); 1395 } 1396 } 1397 } 1398 return array($min,$max); 1544 1545 list($min,$ymin) = $this->plots[0]->Min(); 1546 list($max,$ymax) = $this->plots[0]->Max(); 1547 1548 $i=0; 1549 // Some plots, e.g. PlotLine should not affect the scale 1550 // and will return (null,null). We should ignore those 1551 // values. 1552 while( ($min===null || $max === null) && ($i < count($this->plots)-1) ) { 1553 ++$i; 1554 list($min,$ymin) = $this->plots[$i]->Min(); 1555 list($max,$ymax) = $this->plots[$i]->Max(); 1556 } 1557 1558 foreach( $this->plots as $p ) { 1559 list($xmin,$ymin) = $p->Min(); 1560 list($xmax,$ymax) = $p->Max(); 1561 1562 if( $xmin !== null && $xmax !== null ) { 1563 $min = Min($xmin,$min); 1564 $max = Max($xmax,$max); 1565 } 1566 } 1567 1568 if( $this->y2axis != null ) { 1569 foreach( $this->y2plots as $p ) { 1570 list($xmin,$ymin) = $p->Min(); 1571 list($xmax,$ymax) = $p->Max(); 1572 if( $xmin !== null && $xmax !== null ) { 1573 $min = Min($xmin, $min); 1574 $max = Max($xmax, $max); 1575 } 1576 } 1577 } 1578 1579 $n = count($this->ynaxis); 1580 for( $i=0; $i < $n; ++$i ) { 1581 if( $this->ynaxis[$i] != null) { 1582 foreach( $this->ynplots[$i] as $p ) { 1583 list($xmin,$ymin) = $p->Min(); 1584 list($xmax,$ymax) = $p->Max(); 1585 if( $xmin !== null && $xmax !== null ) { 1586 $min = Min($xmin, $min); 1587 $max = Max($xmax, $max); 1588 } 1589 } 1590 } 1591 } 1592 return array($min,$max); 1399 1593 } 1400 1594 1401 1595 function AdjustMarginsForTitles() { 1402 $totrequired = 1403 ($this->title->t != '' ? 1404 $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) + 1405 ($this->subtitle->t != '' ? 1406 $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) + 1407 ($this->subsubtitle->t != '' ? 1408 $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ; 1409 1410 1411 $btotrequired = 0; 1412 if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) { 1413 // Minimum bottom margin 1414 if( $this->xaxis->title->t != '' ) { 1415 if( $this->img->a == 90 ) 1416 $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 5 ; 1417 else 1418 $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 5 ; 1419 } 1420 else 1421 $btotrequired = 0; 1422 1423 if( $this->img->a == 90 ) { 1424 $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style, 1425 $this->yaxis->font_size); 1426 $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle); 1427 } 1428 else { 1429 $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style, 1430 $this->xaxis->font_size); 1431 $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle); 1432 } 1433 1434 $btotrequired += $lh + 5; 1435 } 1436 1437 if( $this->img->a == 90 ) { 1438 // DO Nothing. It gets too messy to do this properly for 90 deg... 1439 } 1440 else{ 1441 if( $this->img->top_margin < $totrequired ) { 1442 $this->SetMargin($this->img->left_margin,$this->img->right_margin, 1443 $totrequired,$this->img->bottom_margin); 1444 } 1445 if( $this->img->bottom_margin < $btotrequired ) { 1446 $this->SetMargin($this->img->left_margin,$this->img->right_margin, 1447 $this->img->top_margin,$btotrequired); 1448 } 1449 } 1450 } 1596 $totrequired = 1597 ($this->title->t != '' 1598 ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * SUPERSAMPLING_SCALE 1599 : 0 ) + 1600 ($this->subtitle->t != '' 1601 ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * SUPERSAMPLING_SCALE 1602 : 0 ) + 1603 ($this->subsubtitle->t != '' 1604 ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * SUPERSAMPLING_SCALE 1605 : 0 ) ; 1606 1607 $btotrequired = 0; 1608 if($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels ) { 1609 // Minimum bottom margin 1610 if( $this->xaxis->title->t != '' ) { 1611 if( $this->img->a == 90 ) { 1612 $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7 ; 1613 } 1614 else { 1615 $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7 ; 1616 } 1617 } 1618 else { 1619 $btotrequired = 0; 1620 } 1621 1622 if( $this->img->a == 90 ) { 1623 $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style, 1624 $this->yaxis->font_size); 1625 $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle); 1626 } 1627 else { 1628 $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style, 1629 $this->xaxis->font_size); 1630 $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle); 1631 } 1632 1633 $btotrequired += $lh + 6; 1634 } 1635 1636 if( $this->img->a == 90 ) { 1637 // DO Nothing. It gets too messy to do this properly for 90 deg... 1638 } 1639 else{ 1640 // need more top margin 1641 if( $this->img->top_margin < $totrequired ) { 1642 $this->SetMargin( 1643 $this->img->raw_left_margin, 1644 $this->img->raw_right_margin, 1645 $totrequired / SUPERSAMPLING_SCALE, 1646 $this->img->raw_bottom_margin 1647 ); 1648 } 1649 1650 // need more bottom margin 1651 if( $this->img->bottom_margin < $btotrequired ) { 1652 $this->SetMargin( 1653 $this->img->raw_left_margin, 1654 $this->img->raw_right_margin, 1655 $this->img->raw_top_margin, 1656 $btotrequired / SUPERSAMPLING_SCALE 1657 ); 1658 } 1659 } 1660 } 1661 1662 function StrokeStore($aStrokeFileName) { 1663 // Get the handler to prevent the library from sending the 1664 // image to the browser 1665 $ih = $this->Stroke(_IMG_HANDLER); 1666 1667 // Stroke it to a file 1668 $this->img->Stream($aStrokeFileName); 1669 1670 // Send it back to browser 1671 $this->img->Headers(); 1672 $this->img->Stream(); 1673 } 1674 1675 function doAutoscaleXAxis() { 1676 //Check if we should autoscale x-axis 1677 if( !$this->xscale->IsSpecified() ) { 1678 if( substr($this->axtype,0,4) == "text" ) { 1679 $max=0; 1680 $n = count($this->plots); 1681 for($i=0; $i < $n; ++$i ) { 1682 $p = $this->plots[$i]; 1683 // We need some unfortunate sub class knowledge here in order 1684 // to increase number of data points in case it is a line plot 1685 // which has the barcenter set. If not it could mean that the 1686 // last point of the data is outside the scale since the barcenter 1687 // settings means that we will shift the entire plot half a tick step 1688 // to the right in oder to align with the center of the bars. 1689 if( class_exists('BarPlot',false) ) { 1690 $cl = strtolower(get_class($p)); 1691 if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) || empty($p->barcenter) ) { 1692 $max=max($max,$p->numpoints-1); 1693 } 1694 else { 1695 $max=max($max,$p->numpoints); 1696 } 1697 } 1698 else { 1699 if( empty($p->barcenter) ) { 1700 $max=max($max,$p->numpoints-1); 1701 } 1702 else { 1703 $max=max($max,$p->numpoints); 1704 } 1705 } 1706 } 1707 $min=0; 1708 if( $this->y2axis != null ) { 1709 foreach( $this->y2plots as $p ) { 1710 $max=max($max,$p->numpoints-1); 1711 } 1712 } 1713 $n = count($this->ynaxis); 1714 for( $i=0; $i < $n; ++$i ) { 1715 if( $this->ynaxis[$i] != null) { 1716 foreach( $this->ynplots[$i] as $p ) { 1717 $max=max($max,$p->numpoints-1); 1718 } 1719 } 1720 } 1721 1722 $this->xscale->Update($this->img,$min,$max); 1723 $this->xscale->ticks->Set($this->xaxis->tick_step,1); 1724 $this->xscale->ticks->SupressMinorTickMarks(); 1725 } 1726 else { 1727 list($min,$max) = $this->GetXMinMax(); 1728 1729 $lres = $this->GetLinesXMinMax($this->lines); 1730 if( $lres ) { 1731 list($linmin,$linmax) = $lres ; 1732 $min = min($min,$linmin); 1733 $max = max($max,$linmax); 1734 } 1735 1736 $lres = $this->GetLinesXMinMax($this->y2lines); 1737 if( $lres ) { 1738 list($linmin,$linmax) = $lres ; 1739 $min = min($min,$linmin); 1740 $max = max($max,$linmax); 1741 } 1742 1743 $tres = $this->GetTextsXMinMax(); 1744 if( $tres ) { 1745 list($tmin,$tmax) = $tres ; 1746 $min = min($min,$tmin); 1747 $max = max($max,$tmax); 1748 } 1749 1750 $tres = $this->GetTextsXMinMax(true); 1751 if( $tres ) { 1752 list($tmin,$tmax) = $tres ; 1753 $min = min($min,$tmin); 1754 $max = max($max,$tmax); 1755 } 1756 1757 $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor)); 1758 } 1759 1760 //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale 1761 if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) { 1762 $this->yaxis->SetPos($this->xscale->GetMinVal()); 1763 } 1764 } 1765 elseif( $this->xscale->IsSpecified() && 1766 ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) { 1767 // The tick calculation will use the user suplied min/max values to determine 1768 // the ticks. If auto_ticks is false the exact user specifed min and max 1769 // values will be used for the scale. 1770 // If auto_ticks is true then the scale might be slightly adjusted 1771 // so that the min and max values falls on an even major step. 1772 $min = $this->xscale->scale[0]; 1773 $max = $this->xscale->scale[1]; 1774 $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor),false); 1775 1776 // Now make sure we show enough precision to accurate display the 1777 // labels. If this is not done then the user might end up with 1778 // a scale that might actually start with, say 13.5, butdue to rounding 1779 // the scale label will ony show 14. 1780 if( abs(floor($min)-$min) > 0 ) { 1781 1782 // If the user has set a format then we bail out 1783 if( $this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '' ) { 1784 $this->xscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1785 } 1786 } 1787 } 1788 1789 // Position the optional Y2 and Yn axis to the rightmost position of the x-axis 1790 if( $this->y2axis != null ) { 1791 if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) { 1792 $this->y2axis->SetPos($this->xscale->GetMaxVal()); 1793 } 1794 $this->y2axis->SetTitleSide(SIDE_RIGHT); 1795 } 1796 1797 $n = count($this->ynaxis); 1798 $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0; 1799 for( $i=0; $i < $n; ++$i ) { 1800 if( $this->ynaxis[$i] != null ) { 1801 if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) { 1802 $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal()); 1803 $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj); 1804 } 1805 $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT); 1806 } 1807 } 1808 } 1809 1810 1811 function doAutoScaleYnAxis() { 1812 1813 if( $this->y2scale != null) { 1814 if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) { 1815 list($min,$max) = $this->GetPlotsYMinMax($this->y2plots); 1816 1817 $lres = $this->GetLinesYMinMax($this->y2lines); 1818 if( is_array($lres) ) { 1819 list($linmin,$linmax) = $lres ; 1820 $min = min($min,$linmin); 1821 $max = max($max,$linmax); 1822 } 1823 $tres = $this->GetTextsYMinMax(true); 1824 if( is_array($tres) ) { 1825 list($tmin,$tmax) = $tres ; 1826 $min = min($min,$tmin); 1827 $max = max($max,$tmax); 1828 } 1829 $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); 1830 } 1831 elseif( $this->y2scale->IsSpecified() && ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) { 1832 // The tick calculation will use the user suplied min/max values to determine 1833 // the ticks. If auto_ticks is false the exact user specifed min and max 1834 // values will be used for the scale. 1835 // If auto_ticks is true then the scale might be slightly adjusted 1836 // so that the min and max values falls on an even major step. 1837 $min = $this->y2scale->scale[0]; 1838 $max = $this->y2scale->scale[1]; 1839 $this->y2scale->AutoScale($this->img,$min,$max, 1840 $this->img->plotheight/$this->ytick_factor, 1841 $this->y2scale->auto_ticks); 1842 1843 // Now make sure we show enough precision to accurate display the 1844 // labels. If this is not done then the user might end up with 1845 // a scale that might actually start with, say 13.5, butdue to rounding 1846 // the scale label will ony show 14. 1847 if( abs(floor($min)-$min) > 0 ) { 1848 // If the user has set a format then we bail out 1849 if( $this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '' ) { 1850 $this->y2scale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1851 } 1852 } 1853 1854 } 1855 } 1856 1857 1858 // 1859 // Autoscale the extra Y-axises 1860 // 1861 $n = count($this->ynaxis); 1862 for( $i=0; $i < $n; ++$i ) { 1863 if( $this->ynscale[$i] != null) { 1864 if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) { 1865 list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]); 1866 $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); 1867 } 1868 elseif( $this->ynscale[$i]->IsSpecified() && ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) { 1869 // The tick calculation will use the user suplied min/max values to determine 1870 // the ticks. If auto_ticks is false the exact user specifed min and max 1871 // values will be used for the scale. 1872 // If auto_ticks is true then the scale might be slightly adjusted 1873 // so that the min and max values falls on an even major step. 1874 $min = $this->ynscale[$i]->scale[0]; 1875 $max = $this->ynscale[$i]->scale[1]; 1876 $this->ynscale[$i]->AutoScale($this->img,$min,$max, 1877 $this->img->plotheight/$this->ytick_factor, 1878 $this->ynscale[$i]->auto_ticks); 1879 1880 // Now make sure we show enough precision to accurate display the 1881 // labels. If this is not done then the user might end up with 1882 // a scale that might actually start with, say 13.5, butdue to rounding 1883 // the scale label will ony show 14. 1884 if( abs(floor($min)-$min) > 0 ) { 1885 // If the user has set a format then we bail out 1886 if( $this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '' ) { 1887 $this->ynscale[$i]->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1888 } 1889 } 1890 } 1891 } 1892 } 1893 } 1894 1895 function doAutoScaleYAxis() { 1896 1897 //Check if we should autoscale y-axis 1898 if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { 1899 list($min,$max) = $this->GetPlotsYMinMax($this->plots); 1900 $lres = $this->GetLinesYMinMax($this->lines); 1901 if( is_array($lres) ) { 1902 list($linmin,$linmax) = $lres ; 1903 $min = min($min,$linmin); 1904 $max = max($max,$linmax); 1905 } 1906 $tres = $this->GetTextsYMinMax(); 1907 if( is_array($tres) ) { 1908 list($tmin,$tmax) = $tres ; 1909 $min = min($min,$tmin); 1910 $max = max($max,$tmax); 1911 } 1912 $this->yscale->AutoScale($this->img,$min,$max, 1913 $this->img->plotheight/$this->ytick_factor); 1914 } 1915 elseif( $this->yscale->IsSpecified() && ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { 1916 // The tick calculation will use the user suplied min/max values to determine 1917 // the ticks. If auto_ticks is false the exact user specifed min and max 1918 // values will be used for the scale. 1919 // If auto_ticks is true then the scale might be slightly adjusted 1920 // so that the min and max values falls on an even major step. 1921 $min = $this->yscale->scale[0]; 1922 $max = $this->yscale->scale[1]; 1923 $this->yscale->AutoScale($this->img,$min,$max, 1924 $this->img->plotheight/$this->ytick_factor, 1925 $this->yscale->auto_ticks); 1926 1927 // Now make sure we show enough precision to accurate display the 1928 // labels. If this is not done then the user might end up with 1929 // a scale that might actually start with, say 13.5, butdue to rounding 1930 // the scale label will ony show 14. 1931 if( abs(floor($min)-$min) > 0 ) { 1932 1933 // If the user has set a format then we bail out 1934 if( $this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '' ) { 1935 $this->yscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1936 } 1937 } 1938 } 1939 1940 } 1941 1942 function InitScaleConstants() { 1943 // Setup scale constants 1944 if( $this->yscale ) $this->yscale->InitConstants($this->img); 1945 if( $this->xscale ) $this->xscale->InitConstants($this->img); 1946 if( $this->y2scale ) $this->y2scale->InitConstants($this->img); 1947 1948 $n=count($this->ynscale); 1949 for($i=0; $i < $n; ++$i) { 1950 if( $this->ynscale[$i] ) { 1951 $this->ynscale[$i]->InitConstants($this->img); 1952 } 1953 } 1954 } 1955 1956 function doPrestrokeAdjustments() { 1957 1958 // Do any pre-stroke adjustment that is needed by the different plot types 1959 // (i.e bar plots want's to add an offset to the x-labels etc) 1960 for($i=0; $i < count($this->plots) ; ++$i ) { 1961 $this->plots[$i]->PreStrokeAdjust($this); 1962 $this->plots[$i]->DoLegend($this); 1963 } 1964 1965 // Any plots on the second Y scale? 1966 if( $this->y2scale != null ) { 1967 for($i=0; $i<count($this->y2plots) ; ++$i ) { 1968 $this->y2plots[$i]->PreStrokeAdjust($this); 1969 $this->y2plots[$i]->DoLegend($this); 1970 } 1971 } 1972 1973 // Any plots on the extra Y axises? 1974 $n = count($this->ynaxis); 1975 for($i=0; $i<$n ; ++$i ) { 1976 if( $this->ynplots == null || $this->ynplots[$i] == null) { 1977 JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i"); 1978 } 1979 $m = count($this->ynplots[$i]); 1980 for($j=0; $j < $m; ++$j ) { 1981 $this->ynplots[$i][$j]->PreStrokeAdjust($this); 1982 $this->ynplots[$i][$j]->DoLegend($this); 1983 } 1984 } 1985 } 1986 1987 function StrokeBands($aDepth,$aCSIM) { 1988 // Stroke bands 1989 if( $this->bands != null && !$aCSIM) { 1990 for($i=0; $i < count($this->bands); ++$i) { 1991 // Stroke all bands that asks to be in the background 1992 if( $this->bands[$i]->depth == $aDepth ) { 1993 $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); 1994 } 1995 } 1996 } 1997 1998 if( $this->y2bands != null && $this->y2scale != null && !$aCSIM ) { 1999 for($i=0; $i < count($this->y2bands); ++$i) { 2000 // Stroke all bands that asks to be in the foreground 2001 if( $this->y2bands[$i]->depth == $aDepth ) { 2002 $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); 2003 } 2004 } 2005 } 2006 } 2007 1451 2008 1452 2009 // Stroke the graph 1453 // $aStrokeFileName 2010 // $aStrokeFileName If != "" the image will be written to this file and NOT 1454 2011 // streamed back to the browser 1455 function Stroke($aStrokeFileName="") { 1456 1457 // Fist make a sanity check that user has specified a scale 1458 if( empty($this->yscale) ) { 1459 JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().'); 1460 } 1461 1462 // Start by adjusting the margin so that potential titles will fit. 1463 $this->AdjustMarginsForTitles(); 1464 1465 // Setup scale constants 1466 if( $this->yscale ) $this->yscale->InitConstants($this->img); 1467 if( $this->xscale ) $this->xscale->InitConstants($this->img); 1468 if( $this->y2scale ) $this->y2scale->InitConstants($this->img); 1469 1470 $n=count($this->ynscale); 1471 for($i=0; $i < $n; ++$i) { 1472 if( $this->ynscale[$i] ) $this->ynscale[$i]->InitConstants($this->img); 1473 } 1474 1475 // If the filename is the predefined value = '_csim_special_' 1476 // we assume that the call to stroke only needs to do enough 1477 // to correctly generate the CSIM maps. 1478 // We use this variable to skip things we don't strictly need 1479 // to do to generate the image map to improve performance 1480 // a best we can. Therefor you will see a lot of tests !$_csim in the 1481 // code below. 1482 $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); 1483 1484 // We need to know if we have stroked the plot in the 1485 // GetCSIMareas. Otherwise the CSIM hasn't been generated 1486 // and in the case of GetCSIM called before stroke to generate 1487 // CSIM without storing an image to disk GetCSIM must call Stroke. 1488 $this->iHasStroked = true; 1489 1490 // Do any pre-stroke adjustment that is needed by the different plot types 1491 // (i.e bar plots want's to add an offset to the x-labels etc) 1492 for($i=0; $i < count($this->plots) ; ++$i ) { 1493 $this->plots[$i]->PreStrokeAdjust($this); 1494 $this->plots[$i]->DoLegend($this); 1495 } 1496 1497 // Any plots on the second Y scale? 1498 if( $this->y2scale != null ) { 1499 for($i=0; $i<count($this->y2plots) ; ++$i ) { 1500 $this->y2plots[$i]->PreStrokeAdjust($this); 1501 $this->y2plots[$i]->DoLegend($this); 1502 } 1503 } 1504 1505 // Any plots on the extra Y axises? 1506 $n = count($this->ynaxis); 1507 for($i=0; $i<$n ; ++$i ) { 1508 if( $this->ynplots == null || $this->ynplots[$i] == null) { 1509 JpGraphError::RaiseL(25032,$i);//("No plots for Y-axis nbr:$i"); 1510 } 1511 $m = count($this->ynplots[$i]); 1512 for($j=0; $j < $m; ++$j ) { 1513 $this->ynplots[$i][$j]->PreStrokeAdjust($this); 1514 $this->ynplots[$i][$j]->DoLegend($this); 1515 } 1516 } 1517 1518 // Bail out if any of the Y-axis not been specified and 1519 // has no plots. (This means it is impossible to do autoscaling and 1520 // no other scale was given so we can't possible draw anything). If you use manual 1521 // scaling you also have to supply the tick steps as well. 1522 if( (!$this->yscale->IsSpecified() && count($this->plots)==0) || 1523 ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) { 1524 //$e = "n=".count($this->y2plots)."\n"; 1525 // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n"; 1526 // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n"; 1527 // $e .= "2. Specified a scale manually but have forgot to specify the tick steps"; 1528 JpGraphError::RaiseL(25026); 1529 } 1530 1531 // Bail out if no plots and no specified X-scale 1532 if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) 1533 JpGraphError::RaiseL(25034);//("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>"); 1534 1535 //Check if we should autoscale y-axis 1536 if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) { 1537 list($min,$max) = $this->GetPlotsYMinMax($this->plots); 1538 $lres = $this->GetLinesYMinMax($this->lines); 1539 if( is_array($lres) ) { 1540 list($linmin,$linmax) = $lres ; 1541 $min = min($min,$linmin); 1542 $max = max($max,$linmax); 1543 } 1544 $tres = $this->GetTextsYMinMax(); 1545 if( is_array($tres) ) { 1546 list($tmin,$tmax) = $tres ; 1547 $min = min($min,$tmin); 1548 $max = max($max,$tmax); 1549 } 1550 $this->yscale->AutoScale($this->img,$min,$max, 1551 $this->img->plotheight/$this->ytick_factor); 1552 } 1553 elseif( $this->yscale->IsSpecified() && 1554 ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) { 1555 // The tick calculation will use the user suplied min/max values to determine 1556 // the ticks. If auto_ticks is false the exact user specifed min and max 1557 // values will be used for the scale. 1558 // If auto_ticks is true then the scale might be slightly adjusted 1559 // so that the min and max values falls on an even major step. 1560 $min = $this->yscale->scale[0]; 1561 $max = $this->yscale->scale[1]; 1562 $this->yscale->AutoScale($this->img,$min,$max, 1563 $this->img->plotheight/$this->ytick_factor, 1564 $this->yscale->auto_ticks); 1565 1566 // Now make sure we show enough precision to accurate display the 1567 // labels. If this is not done then the user might end up with 1568 // a scale that might actually start with, say 13.5, butdue to rounding 1569 // the scale label will ony show 14. 1570 if( abs(floor($min)-$min) > 0 ) { 1571 1572 // If the user has set a format then we bail out 1573 if( $this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '' ) { 1574 $this->yscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1575 } 1576 } 1577 } 1578 1579 if( $this->y2scale != null) { 1580 if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) { 1581 list($min,$max) = $this->GetPlotsYMinMax($this->y2plots); 1582 1583 $lres = $this->GetLinesYMinMax($this->y2lines); 1584 if( is_array($lres) ) { 1585 list($linmin,$linmax) = $lres ; 1586 $min = min($min,$linmin); 1587 $max = max($max,$linmax); 1588 } 1589 $tres = $this->GetTextsYMinMax(true); 1590 if( is_array($tres) ) { 1591 list($tmin,$tmax) = $tres ; 1592 $min = min($min,$tmin); 1593 $max = max($max,$tmax); 1594 } 1595 $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); 1596 } 1597 elseif( $this->y2scale->IsSpecified() && 1598 ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) { 1599 // The tick calculation will use the user suplied min/max values to determine 1600 // the ticks. If auto_ticks is false the exact user specifed min and max 1601 // values will be used for the scale. 1602 // If auto_ticks is true then the scale might be slightly adjusted 1603 // so that the min and max values falls on an even major step. 1604 $min = $this->y2scale->scale[0]; 1605 $max = $this->y2scale->scale[1]; 1606 $this->y2scale->AutoScale($this->img,$min,$max, 1607 $this->img->plotheight/$this->ytick_factor, 1608 $this->y2scale->auto_ticks); 1609 1610 // Now make sure we show enough precision to accurate display the 1611 // labels. If this is not done then the user might end up with 1612 // a scale that might actually start with, say 13.5, butdue to rounding 1613 // the scale label will ony show 14. 1614 if( abs(floor($min)-$min) > 0 ) { 1615 1616 // If the user has set a format then we bail out 1617 if( $this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '' ) { 1618 $this->y2scale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1619 } 1620 } 1621 1622 } 1623 } 1624 1625 // 1626 // Autoscale the extra Y-axises 1627 // 1628 $n = count($this->ynaxis); 1629 for( $i=0; $i < $n; ++$i ) { 1630 if( $this->ynscale[$i] != null) { 1631 if( !$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i])>0 ) { 1632 list($min,$max) = $this->GetPlotsYMinMax($this->ynplots[$i]); 1633 $this->ynscale[$i]->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor); 1634 } 1635 elseif( $this->ynscale[$i]->IsSpecified() && 1636 ( $this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified()) ) { 1637 // The tick calculation will use the user suplied min/max values to determine 1638 // the ticks. If auto_ticks is false the exact user specifed min and max 1639 // values will be used for the scale. 1640 // If auto_ticks is true then the scale might be slightly adjusted 1641 // so that the min and max values falls on an even major step. 1642 $min = $this->ynscale[$i]->scale[0]; 1643 $max = $this->ynscale[$i]->scale[1]; 1644 $this->ynscale[$i]->AutoScale($this->img,$min,$max, 1645 $this->img->plotheight/$this->ytick_factor, 1646 $this->ynscale[$i]->auto_ticks); 1647 1648 // Now make sure we show enough precision to accurate display the 1649 // labels. If this is not done then the user might end up with 1650 // a scale that might actually start with, say 13.5, butdue to rounding 1651 // the scale label will ony show 14. 1652 if( abs(floor($min)-$min) > 0 ) { 1653 1654 // If the user has set a format then we bail out 1655 if( $this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '' ) { 1656 $this->ynscale[$i]->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1657 } 1658 } 1659 1660 } 1661 } 1662 } 1663 1664 //Check if we should autoscale x-axis 1665 if( !$this->xscale->IsSpecified() ) { 1666 if( substr($this->axtype,0,4) == "text" ) { 1667 $max=0; 1668 $n = count($this->plots); 1669 for($i=0; $i < $n; ++$i ) { 1670 $p = $this->plots[$i]; 1671 // We need some unfortunate sub class knowledge here in order 1672 // to increase number of data points in case it is a line plot 1673 // which has the barcenter set. If not it could mean that the 1674 // last point of the data is outside the scale since the barcenter 1675 // settings means that we will shift the entire plot half a tick step 1676 // to the right in oder to align with the center of the bars. 1677 if( class_exists('BarPlot',false) ) { 1678 $cl = strtolower(get_class($p)); 1679 if( (class_exists('BarPlot',false) && ($p instanceof BarPlot)) || 1680 empty($p->barcenter) ) 1681 $max=max($max,$p->numpoints-1); 1682 else { 1683 $max=max($max,$p->numpoints); 1684 } 1685 } 1686 else { 1687 if( empty($p->barcenter) ) { 1688 $max=max($max,$p->numpoints-1); 1689 } 1690 else { 1691 $max=max($max,$p->numpoints); 1692 } 1693 } 1694 } 1695 $min=0; 1696 if( $this->y2axis != null ) { 1697 foreach( $this->y2plots as $p ) { 1698 $max=max($max,$p->numpoints-1); 1699 } 1700 } 1701 $n = count($this->ynaxis); 1702 for( $i=0; $i < $n; ++$i ) { 1703 if( $this->ynaxis[$i] != null) { 1704 foreach( $this->ynplots[$i] as $p ) { 1705 $max=max($max,$p->numpoints-1); 1706 } 1707 } 1708 } 1709 1710 $this->xscale->Update($this->img,$min,$max); 1711 $this->xscale->ticks->Set($this->xaxis->tick_step,1); 1712 $this->xscale->ticks->SupressMinorTickMarks(); 1713 } 1714 else { 1715 list($min,$max) = $this->GetXMinMax(); 1716 1717 $lres = $this->GetLinesXMinMax($this->lines); 1718 if( $lres ) { 1719 list($linmin,$linmax) = $lres ; 1720 $min = min($min,$linmin); 1721 $max = max($max,$linmax); 1722 } 1723 1724 $lres = $this->GetLinesXMinMax($this->y2lines); 1725 if( $lres ) { 1726 list($linmin,$linmax) = $lres ; 1727 $min = min($min,$linmin); 1728 $max = max($max,$linmax); 1729 } 1730 1731 $tres = $this->GetTextsXMinMax(); 1732 if( $tres ) { 1733 list($tmin,$tmax) = $tres ; 1734 $min = min($min,$tmin); 1735 $max = max($max,$tmax); 1736 } 1737 1738 $tres = $this->GetTextsXMinMax(true); 1739 if( $tres ) { 1740 list($tmin,$tmax) = $tres ; 1741 $min = min($min,$tmin); 1742 $max = max($max,$tmax); 1743 } 1744 1745 $this->xscale->AutoScale($this->img,$min,$max,round($this->img->plotwidth/$this->xtick_factor)); 1746 } 1747 1748 //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale 1749 if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) ) 1750 $this->yaxis->SetPos($this->xscale->GetMinVal()); 1751 if( $this->y2axis != null ) { 1752 if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) 1753 $this->y2axis->SetPos($this->xscale->GetMaxVal()); 1754 $this->y2axis->SetTitleSide(SIDE_RIGHT); 1755 } 1756 $n = count($this->ynaxis); 1757 $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0; 1758 for( $i=0; $i < $n; ++$i ) { 1759 if( $this->ynaxis[$i] != null ) { 1760 if( !is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos) ) { 1761 $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal()); 1762 $this->ynaxis[$i]->SetPosAbsDelta($i*$this->iYAxisDeltaPos + $nY2adj); 1763 } 1764 $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT); 1765 } 1766 } 1767 1768 } 1769 elseif( $this->xscale->IsSpecified() && 1770 ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) { 1771 // The tick calculation will use the user suplied min/max values to determine 1772 // the ticks. If auto_ticks is false the exact user specifed min and max 1773 // values will be used for the scale. 1774 // If auto_ticks is true then the scale might be slightly adjusted 1775 // so that the min and max values falls on an even major step. 1776 $min = $this->xscale->scale[0]; 1777 $max = $this->xscale->scale[1]; 1778 $this->xscale->AutoScale($this->img,$min,$max, 1779 round($this->img->plotwidth/$this->xtick_factor), 1780 false); 1781 1782 // Now make sure we show enough precision to accurate display the 1783 // labels. If this is not done then the user might end up with 1784 // a scale that might actually start with, say 13.5, butdue to rounding 1785 // the scale label will ony show 14. 1786 if( abs(floor($min)-$min) > 0 ) { 1787 1788 // If the user has set a format then we bail out 1789 if( $this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '' ) { 1790 $this->xscale->ticks->precision = abs( floor(log10( abs(floor($min)-$min))) )+1; 1791 } 1792 } 1793 1794 1795 if( $this->y2axis != null ) { 1796 if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) ) 1797 $this->y2axis->SetPos($this->xscale->GetMaxVal()); 1798 $this->y2axis->SetTitleSide(SIDE_RIGHT); 1799 } 1800 1801 } 1802 1803 // If we have a negative values and x-axis position is at 0 1804 // we need to supress the first and possible the last tick since 1805 // they will be drawn on top of the y-axis (and possible y2 axis) 1806 // The test below might seem strange the reasone being that if 1807 // the user hasn't specified a value for position this will not 1808 // be set until we do the stroke for the axis so as of now it 1809 // is undefined. 1810 // For X-text scale we ignore all this since the tick are usually 1811 // much further in and not close to the Y-axis. Hence the test 1812 // for 'text' 1813 1814 if( ($this->yaxis->pos==$this->xscale->GetMinVal() || 1815 (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) && 1816 !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && 1817 substr($this->axtype,0,4) != 'text' && $this->xaxis->pos!="min" ) { 1818 1819 //$this->yscale->ticks->SupressZeroLabel(false); 1820 $this->xscale->ticks->SupressFirst(); 1821 if( $this->y2axis != null ) { 1822 $this->xscale->ticks->SupressLast(); 1823 } 1824 } 1825 elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) { 1826 $this->xscale->ticks->SupressLast(); 1827 } 1828 1829 1830 if( !$_csim ) { 1831 $this->StrokePlotArea(); 1832 if( $this->iIconDepth == DEPTH_BACK ) { 1833 $this->StrokeIcons(); 1834 } 1835 } 1836 $this->StrokeAxis(false); 1837 1838 // Stroke bands 1839 if( $this->bands != null && !$_csim) 1840 for($i=0; $i < count($this->bands); ++$i) { 1841 // Stroke all bands that asks to be in the background 1842 if( $this->bands[$i]->depth == DEPTH_BACK ) 1843 $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); 1844 } 1845 1846 if( $this->y2bands != null && $this->y2scale != null && !$_csim ) 1847 for($i=0; $i < count($this->y2bands); ++$i) { 1848 // Stroke all bands that asks to be in the foreground 1849 if( $this->y2bands[$i]->depth == DEPTH_BACK ) 1850 $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); 1851 } 1852 1853 1854 if( $this->grid_depth == DEPTH_BACK && !$_csim) { 1855 $this->ygrid->Stroke(); 1856 $this->xgrid->Stroke(); 1857 } 1858 1859 // Stroke Y2-axis 1860 if( $this->y2axis != null && !$_csim) { 1861 $this->y2axis->Stroke($this->xscale); 1862 $this->y2grid->Stroke(); 1863 } 1864 1865 // Stroke yn-axis 1866 $n = count($this->ynaxis); 1867 for( $i=0; $i < $n; ++$i ) { 1868 $this->ynaxis[$i]->Stroke($this->xscale); 1869 } 1870 1871 $oldoff=$this->xscale->off; 1872 if(substr($this->axtype,0,4)=="text") { 1873 if( $this->text_scale_abscenteroff > -1 ) { 1874 // For a text scale the scale factor is the number of pixel per step. 1875 // Hence we can use the scale factor as a substitute for number of pixels 1876 // per major scale step and use that in order to adjust the offset so that 1877 // an object of width "abscenteroff" becomes centered. 1878 $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2); 1879 } 1880 else { 1881 $this->xscale->off += 1882 ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step); 1883 } 1884 } 1885 1886 if( $this->iDoClipping ) { 1887 $oldimage = $this->img->CloneCanvasH(); 1888 } 1889 1890 if( ! $this->y2orderback ) { 1891 // Stroke all plots for Y1 axis 1892 for($i=0; $i < count($this->plots); ++$i) { 1893 $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); 1894 $this->plots[$i]->StrokeMargin($this->img); 1895 } 1896 } 1897 1898 // Stroke all plots for Y2 axis 1899 if( $this->y2scale != null ) 1900 for($i=0; $i< count($this->y2plots); ++$i ) { 1901 $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale); 1902 } 1903 1904 if( $this->y2orderback ) { 1905 // Stroke all plots for Y1 axis 1906 for($i=0; $i < count($this->plots); ++$i) { 1907 $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); 1908 $this->plots[$i]->StrokeMargin($this->img); 1909 } 1910 } 1911 1912 $n = count($this->ynaxis); 1913 for( $i=0; $i < $n; ++$i ) { 1914 $m = count($this->ynplots[$i]); 1915 for( $j=0; $j < $m; ++$j ) { 1916 $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]); 1917 $this->ynplots[$i][$j]->StrokeMargin($this->img); 1918 } 1919 } 1920 1921 if( $this->iIconDepth == DEPTH_FRONT) { 1922 $this->StrokeIcons(); 1923 } 1924 1925 if( $this->iDoClipping ) { 1926 // Clipping only supports graphs at 0 and 90 degrees 1927 if( $this->img->a == 0 ) { 1928 $this->img->CopyCanvasH($oldimage,$this->img->img, 1929 $this->img->left_margin,$this->img->top_margin, 1930 $this->img->left_margin,$this->img->top_margin, 1931 $this->img->plotwidth+1,$this->img->plotheight); 1932 } 1933 elseif( $this->img->a == 90 ) { 1934 $adj = ($this->img->height - $this->img->width)/2; 1935 $this->img->CopyCanvasH($oldimage,$this->img->img, 1936 $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, 1937 $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, 1938 $this->img->plotheight+1,$this->img->plotwidth); 1939 } 1940 else { 1941 JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.'); 1942 } 1943 $this->img->Destroy(); 1944 $this->img->SetCanvasH($oldimage); 1945 } 1946 1947 $this->xscale->off=$oldoff; 1948 1949 if( $this->grid_depth == DEPTH_FRONT && !$_csim ) { 1950 $this->ygrid->Stroke(); 1951 $this->xgrid->Stroke(); 1952 } 1953 1954 // Stroke bands 1955 if( $this->bands!= null ) 1956 for($i=0; $i < count($this->bands); ++$i) { 1957 // Stroke all bands that asks to be in the foreground 1958 if( $this->bands[$i]->depth == DEPTH_FRONT ) 1959 $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale); 1960 } 1961 1962 if( $this->y2bands!= null && $this->y2scale != null ) 1963 for($i=0; $i < count($this->y2bands); ++$i) { 1964 // Stroke all bands that asks to be in the foreground 1965 if( $this->y2bands[$i]->depth == DEPTH_FRONT ) 1966 $this->y2bands[$i]->Stroke($this->img,$this->xscale,$this->y2scale); 1967 } 1968 1969 1970 // Stroke any lines added 1971 if( $this->lines != null ) { 1972 for($i=0; $i < count($this->lines); ++$i) { 1973 $this->lines[$i]->Stroke($this->img,$this->xscale,$this->yscale); 1974 $this->lines[$i]->DoLegend($this); 1975 } 1976 } 1977 1978 if( $this->y2lines != null && $this->y2scale != null ) { 1979 for($i=0; $i < count($this->y2lines); ++$i) { 1980 $this->y2lines[$i]->Stroke($this->img,$this->xscale,$this->y2scale); 1981 $this->y2lines[$i]->DoLegend($this); 1982 } 1983 } 1984 1985 // Finally draw the axis again since some plots may have nagged 1986 // the axis in the edges. 1987 if( !$_csim ) { 1988 $this->StrokeAxis(); 1989 } 1990 1991 if( $this->y2scale != null && !$_csim ) 1992 $this->y2axis->Stroke($this->xscale,false); 1993 1994 if( !$_csim ) { 1995 $this->StrokePlotBox(); 1996 } 1997 1998 // The titles and legends never gets rotated so make sure 1999 // that the angle is 0 before stroking them 2000 $aa = $this->img->SetAngle(0); 2001 $this->StrokeTitles(); 2002 $this->footer->Stroke($this->img); 2003 $this->legend->Stroke($this->img); 2004 $this->img->SetAngle($aa); 2005 $this->StrokeTexts(); 2006 $this->StrokeTables(); 2007 2008 if( !$_csim ) { 2009 2010 $this->img->SetAngle($aa); 2011 2012 // Draw an outline around the image map 2013 if(_JPG_DEBUG) { 2014 $this->DisplayClientSideaImageMapAreas(); 2015 } 2016 2017 // Should we do any final image transformation 2018 if( $this->iImgTrans ) { 2019 if( !class_exists('ImgTrans',false) ) { 2020 require_once('jpgraph_imgtrans.php'); 2021 //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); 2022 } 2023 2024 $tform = new ImgTrans($this->img->img); 2025 $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, 2026 $this->iImgTransDirection,$this->iImgTransHighQ, 2027 $this->iImgTransMinSize,$this->iImgTransFillColor, 2028 $this->iImgTransBorder); 2029 } 2030 2031 // If the filename is given as the special "__handle" 2032 // then the image handler is returned and the image is NOT 2033 // streamed back 2034 if( $aStrokeFileName == _IMG_HANDLER ) { 2035 return $this->img->img; 2036 } 2037 else { 2038 // Finally stream the generated picture 2039 $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); 2040 } 2041 } 2012 function Stroke($aStrokeFileName='') { 2013 // Fist make a sanity check that user has specified a scale 2014 if( empty($this->yscale) ) { 2015 JpGraphError::RaiseL(25031);//('You must specify what scale to use with a call to Graph::SetScale().'); 2016 } 2017 2018 // Start by adjusting the margin so that potential titles will fit. 2019 $this->AdjustMarginsForTitles(); 2020 2021 // Give the plot a chance to do any scale adjuments the individual plots 2022 // wants to do. Right now this is only used by the contour plot to set scale 2023 // limits 2024 for($i=0; $i < count($this->plots) ; ++$i ) { 2025 $this->plots[$i]->PreScaleSetup($this); 2026 } 2027 2028 // Init scale constants that are used to calculate the transformation from 2029 // world to pixel coordinates 2030 $this->InitScaleConstants(); 2031 2032 // If the filename is the predefined value = '_csim_special_' 2033 // we assume that the call to stroke only needs to do enough 2034 // to correctly generate the CSIM maps. 2035 // We use this variable to skip things we don't strictly need 2036 // to do to generate the image map to improve performance 2037 // a best we can. Therefor you will see a lot of tests !$_csim in the 2038 // code below. 2039 $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE); 2040 2041 // If we are called the second time (perhaps the user has called GetHTMLImageMap() 2042 // himself then the legends have alsready been populated once in order to get the 2043 // CSIM coordinats. Since we do not want the legends to be populated a second time 2044 // we clear the legends 2045 $this->legend->Clear(); 2046 2047 // We need to know if we have stroked the plot in the 2048 // GetCSIMareas. Otherwise the CSIM hasn't been generated 2049 // and in the case of GetCSIM called before stroke to generate 2050 // CSIM without storing an image to disk GetCSIM must call Stroke. 2051 $this->iHasStroked = true; 2052 2053 // Setup pre-stroked adjustments and Legends 2054 $this->doPrestrokeAdjustments(); 2055 2056 if ($this->graph_theme) { 2057 $this->graph_theme->PreStrokeApply($this); 2058 } 2059 2060 // Bail out if any of the Y-axis not been specified and 2061 // has no plots. (This means it is impossible to do autoscaling and 2062 // no other scale was given so we can't possible draw anything). If you use manual 2063 // scaling you also have to supply the tick steps as well. 2064 if( (!$this->yscale->IsSpecified() && count($this->plots)==0) || 2065 ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) { 2066 //$e = "n=".count($this->y2plots)."\n"; 2067 // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n"; 2068 // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n"; 2069 // $e .= "2. Specified a scale manually but have forgot to specify the tick steps"; 2070 JpGraphError::RaiseL(25026); 2071 } 2072 2073 // Bail out if no plots and no specified X-scale 2074 if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) ) { 2075 JpGraphError::RaiseL(25034);//("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>"); 2076 } 2077 2078 // Autoscale the normal Y-axis 2079 $this->doAutoScaleYAxis(); 2080 2081 // Autoscale all additiopnal y-axis 2082 $this->doAutoScaleYnAxis(); 2083 2084 // Autoscale the regular x-axis and position the y-axis properly 2085 $this->doAutoScaleXAxis(); 2086 2087 // If we have a negative values and x-axis position is at 0 2088 // we need to supress the first and possible the last tick since 2089 // they will be drawn on top of the y-axis (and possible y2 axis) 2090 // The test below might seem strange the reasone being that if 2091 // the user hasn't specified a value for position this will not 2092 // be set until we do the stroke for the axis so as of now it 2093 // is undefined. 2094 // For X-text scale we ignore all this since the tick are usually 2095 // much further in and not close to the Y-axis. Hence the test 2096 // for 'text' 2097 if( ($this->yaxis->pos==$this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) && 2098 !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 && 2099 substr($this->axtype,0,4) != 'text' && $this->xaxis->pos != 'min' ) { 2100 2101 //$this->yscale->ticks->SupressZeroLabel(false); 2102 $this->xscale->ticks->SupressFirst(); 2103 if( $this->y2axis != null ) { 2104 $this->xscale->ticks->SupressLast(); 2105 } 2106 } 2107 elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) { 2108 $this->xscale->ticks->SupressLast(); 2109 } 2110 2111 if( !$_csim ) { 2112 $this->StrokePlotArea(); 2113 if( $this->iIconDepth == DEPTH_BACK ) { 2114 $this->StrokeIcons(); 2115 } 2116 } 2117 $this->StrokeAxis(false); 2118 2119 // Stroke colored bands 2120 $this->StrokeBands(DEPTH_BACK,$_csim); 2121 2122 if( $this->grid_depth == DEPTH_BACK && !$_csim) { 2123 $this->ygrid->Stroke(); 2124 $this->xgrid->Stroke(); 2125 } 2126 2127 // Stroke Y2-axis 2128 if( $this->y2axis != null && !$_csim) { 2129 $this->y2axis->Stroke($this->xscale); 2130 $this->y2grid->Stroke(); 2131 } 2132 2133 // Stroke yn-axis 2134 $n = count($this->ynaxis); 2135 for( $i=0; $i < $n; ++$i ) { 2136 $this->ynaxis[$i]->Stroke($this->xscale); 2137 } 2138 2139 $oldoff=$this->xscale->off; 2140 if( substr($this->axtype,0,4) == 'text' ) { 2141 if( $this->text_scale_abscenteroff > -1 ) { 2142 // For a text scale the scale factor is the number of pixel per step. 2143 // Hence we can use the scale factor as a substitute for number of pixels 2144 // per major scale step and use that in order to adjust the offset so that 2145 // an object of width "abscenteroff" becomes centered. 2146 $this->xscale->off += round($this->xscale->scale_factor/2)-round($this->text_scale_abscenteroff/2); 2147 } 2148 else { 2149 $this->xscale->off += ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step); 2150 } 2151 } 2152 2153 if( $this->iDoClipping ) { 2154 $oldimage = $this->img->CloneCanvasH(); 2155 } 2156 2157 if( ! $this->y2orderback ) { 2158 // Stroke all plots for Y1 axis 2159 for($i=0; $i < count($this->plots); ++$i) { 2160 $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); 2161 $this->plots[$i]->StrokeMargin($this->img); 2162 } 2163 } 2164 2165 // Stroke all plots for Y2 axis 2166 if( $this->y2scale != null ) { 2167 for($i=0; $i< count($this->y2plots); ++$i ) { 2168 $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale); 2169 } 2170 } 2171 2172 if( $this->y2orderback ) { 2173 // Stroke all plots for Y1 axis 2174 for($i=0; $i < count($this->plots); ++$i) { 2175 $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale); 2176 $this->plots[$i]->StrokeMargin($this->img); 2177 } 2178 } 2179 2180 $n = count($this->ynaxis); 2181 for( $i=0; $i < $n; ++$i ) { 2182 $m = count($this->ynplots[$i]); 2183 for( $j=0; $j < $m; ++$j ) { 2184 $this->ynplots[$i][$j]->Stroke($this->img,$this->xscale,$this->ynscale[$i]); 2185 $this->ynplots[$i][$j]->StrokeMargin($this->img); 2186 } 2187 } 2188 2189 if( $this->iIconDepth == DEPTH_FRONT) { 2190 $this->StrokeIcons(); 2191 } 2192 2193 if( $this->iDoClipping ) { 2194 // Clipping only supports graphs at 0 and 90 degrees 2195 if( $this->img->a == 0 ) { 2196 $this->img->CopyCanvasH($oldimage,$this->img->img, 2197 $this->img->left_margin,$this->img->top_margin, 2198 $this->img->left_margin,$this->img->top_margin, 2199 $this->img->plotwidth+1,$this->img->plotheight); 2200 } 2201 elseif( $this->img->a == 90 ) { 2202 $adj = ($this->img->height - $this->img->width)/2; 2203 $this->img->CopyCanvasH($oldimage,$this->img->img, 2204 $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, 2205 $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, 2206 $this->img->plotheight+1,$this->img->plotwidth); 2207 } 2208 else { 2209 JpGraphError::RaiseL(25035,$this->img->a);//('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.'); 2210 } 2211 $this->img->Destroy(); 2212 $this->img->SetCanvasH($oldimage); 2213 } 2214 2215 $this->xscale->off=$oldoff; 2216 2217 if( $this->grid_depth == DEPTH_FRONT && !$_csim ) { 2218 $this->ygrid->Stroke(); 2219 $this->xgrid->Stroke(); 2220 } 2221 2222 // Stroke colored bands 2223 $this->StrokeBands(DEPTH_FRONT,$_csim); 2224 2225 // Finally draw the axis again since some plots may have nagged 2226 // the axis in the edges. 2227 if( !$_csim ) { 2228 $this->StrokeAxis(); 2229 } 2230 2231 if( $this->y2scale != null && !$_csim ) { 2232 $this->y2axis->Stroke($this->xscale,false); 2233 } 2234 2235 if( !$_csim ) { 2236 $this->StrokePlotBox(); 2237 } 2238 2239 // The titles and legends never gets rotated so make sure 2240 // that the angle is 0 before stroking them 2241 $aa = $this->img->SetAngle(0); 2242 $this->StrokeTitles(); 2243 $this->footer->Stroke($this->img); 2244 $this->legend->Stroke($this->img); 2245 $this->img->SetAngle($aa); 2246 $this->StrokeTexts(); 2247 $this->StrokeTables(); 2248 2249 if( !$_csim ) { 2250 2251 $this->img->SetAngle($aa); 2252 2253 // Draw an outline around the image map 2254 if(_JPG_DEBUG) { 2255 $this->DisplayClientSideaImageMapAreas(); 2256 } 2257 2258 // Should we do any final image transformation 2259 if( $this->iImgTrans ) { 2260 if( !class_exists('ImgTrans',false) ) { 2261 require_once('jpgraph_imgtrans.php'); 2262 //JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.'); 2263 } 2264 2265 $tform = new ImgTrans($this->img->img); 2266 $this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist, 2267 $this->iImgTransDirection,$this->iImgTransHighQ, 2268 $this->iImgTransMinSize,$this->iImgTransFillColor, 2269 $this->iImgTransBorder); 2270 } 2271 2272 // If the filename is given as the special "__handle" 2273 // then the image handler is returned and the image is NOT 2274 // streamed back 2275 if( $aStrokeFileName == _IMG_HANDLER ) { 2276 return $this->img->img; 2277 } 2278 else { 2279 // Finally stream the generated picture 2280 $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName); 2281 } 2282 } 2042 2283 } 2043 2284 2044 2285 function SetAxisLabelBackground($aType,$aXFColor='lightgray',$aXColor='black',$aYFColor='lightgray',$aYColor='black') { 2045 $this->iAxisLblBgType = $aType; 2046 $this->iXAxisLblBgFillColor = $aXFColor; 2047 $this->iXAxisLblBgColor = $aXColor; 2048 $this->iYAxisLblBgFillColor = $aYFColor; 2049 $this->iYAxisLblBgColor = $aYColor; 2050 } 2051 2052 //--------------- 2053 // PRIVATE METHODS 2286 $this->iAxisLblBgType = $aType; 2287 $this->iXAxisLblBgFillColor = $aXFColor; 2288 $this->iXAxisLblBgColor = $aXColor; 2289 $this->iYAxisLblBgFillColor = $aYFColor; 2290 $this->iYAxisLblBgColor = $aYColor; 2291 } 2054 2292 2055 2293 function StrokeAxisLabelBackground() { 2056 // Types 2057 // 0 = No background 2058 // 1 = Only X-labels, length of axis 2059 // 2 = Only Y-labels, length of axis 2060 // 3 = As 1 but extends to width of graph 2061 // 4 = As 2 but extends to height of graph 2062 // 5 = Combination of 3 & 4 2063 // 6 = Combination of 1 & 2 2064 2065 $t = $this->iAxisLblBgType ; 2066 if( $t < 1 ) return; 2067 // Stroke optional X-axis label background color 2068 if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) { 2069 $this->img->PushColor($this->iXAxisLblBgFillColor); 2070 if( $t == 1 || $t == 6 ) { 2071 $xl = $this->img->left_margin; 2072 $yu = $this->img->height - $this->img->bottom_margin + 1; 2073 $xr = $this->img->width - $this->img->right_margin ; 2074 $yl = $this->img->height-1-$this->frame_weight; 2075 } 2076 else { // t==3 || t==5 2077 $xl = $this->frame_weight; 2078 $yu = $this->img->height - $this->img->bottom_margin + 1; 2079 $xr = $this->img->width - 1 - $this->frame_weight; 2080 $yl = $this->img->height-1-$this->frame_weight; 2081 } 2082 2083 $this->img->FilledRectangle($xl,$yu,$xr,$yl); 2084 $this->img->PopColor(); 2085 2086 // Check if we should add the vertical lines at left and right edge 2087 if( $this->iXAxisLblBgColor !== '' ) { 2088 // Hardcode to one pixel wide 2089 $this->img->SetLineWeight(1); 2090 $this->img->PushColor($this->iXAxisLblBgColor); 2091 if( $t == 1 || $t == 6 ) { 2092 $this->img->Line($xl,$yu,$xl,$yl); 2093 $this->img->Line($xr,$yu,$xr,$yl); 2094 } 2095 else { 2096 $xl = $this->img->width - $this->img->right_margin ; 2097 $this->img->Line($xl,$yu-1,$xr,$yu-1); 2098 } 2099 $this->img->PopColor(); 2100 } 2101 } 2102 2103 if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) { 2104 $this->img->PushColor($this->iYAxisLblBgFillColor); 2105 if( $t == 2 || $t == 6 ) { 2106 $xl = $this->frame_weight; 2107 $yu = $this->frame_weight+$this->img->top_margin; 2108 $xr = $this->img->left_margin - 1; 2109 $yl = $this->img->height - $this->img->bottom_margin + 1; 2110 } 2111 else { 2112 $xl = $this->frame_weight; 2113 $yu = $this->frame_weight; 2114 $xr = $this->img->left_margin - 1; 2115 $yl = $this->img->height-1-$this->frame_weight; 2116 } 2117 2118 $this->img->FilledRectangle($xl,$yu,$xr,$yl); 2119 $this->img->PopColor(); 2120 2121 // Check if we should add the vertical lines at left and right edge 2122 if( $this->iXAxisLblBgColor !== '' ) { 2123 $this->img->PushColor($this->iXAxisLblBgColor); 2124 if( $t == 2 || $t == 6 ) { 2125 $this->img->Line($xl,$yu-1,$xr,$yu-1); 2126 $this->img->Line($xl,$yl-1,$xr,$yl-1); 2127 } 2128 else { 2129 $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin); 2130 } 2131 $this->img->PopColor(); 2132 } 2133 2134 } 2294 // Types 2295 // 0 = No background 2296 // 1 = Only X-labels, length of axis 2297 // 2 = Only Y-labels, length of axis 2298 // 3 = As 1 but extends to width of graph 2299 // 4 = As 2 but extends to height of graph 2300 // 5 = Combination of 3 & 4 2301 // 6 = Combination of 1 & 2 2302 2303 $t = $this->iAxisLblBgType ; 2304 if( $t < 1 ) return; 2305 2306 // Stroke optional X-axis label background color 2307 if( $t == 1 || $t == 3 || $t == 5 || $t == 6 ) { 2308 $this->img->PushColor($this->iXAxisLblBgFillColor); 2309 if( $t == 1 || $t == 6 ) { 2310 $xl = $this->img->left_margin; 2311 $yu = $this->img->height - $this->img->bottom_margin + 1; 2312 $xr = $this->img->width - $this->img->right_margin ; 2313 $yl = $this->img->height-1-$this->frame_weight; 2314 } 2315 else { // t==3 || t==5 2316 $xl = $this->frame_weight; 2317 $yu = $this->img->height - $this->img->bottom_margin + 1; 2318 $xr = $this->img->width - 1 - $this->frame_weight; 2319 $yl = $this->img->height-1-$this->frame_weight; 2320 } 2321 2322 $this->img->FilledRectangle($xl,$yu,$xr,$yl); 2323 $this->img->PopColor(); 2324 2325 // Check if we should add the vertical lines at left and right edge 2326 if( $this->iXAxisLblBgColor !== '' ) { 2327 // Hardcode to one pixel wide 2328 $this->img->SetLineWeight(1); 2329 $this->img->PushColor($this->iXAxisLblBgColor); 2330 if( $t == 1 || $t == 6 ) { 2331 $this->img->Line($xl,$yu,$xl,$yl); 2332 $this->img->Line($xr,$yu,$xr,$yl); 2333 } 2334 else { 2335 $xl = $this->img->width - $this->img->right_margin ; 2336 $this->img->Line($xl,$yu-1,$xr,$yu-1); 2337 } 2338 $this->img->PopColor(); 2339 } 2340 } 2341 2342 if( $t == 2 || $t == 4 || $t == 5 || $t == 6 ) { 2343 $this->img->PushColor($this->iYAxisLblBgFillColor); 2344 if( $t == 2 || $t == 6 ) { 2345 $xl = $this->frame_weight; 2346 $yu = $this->frame_weight+$this->img->top_margin; 2347 $xr = $this->img->left_margin - 1; 2348 $yl = $this->img->height - $this->img->bottom_margin + 1; 2349 } 2350 else { 2351 $xl = $this->frame_weight; 2352 $yu = $this->frame_weight; 2353 $xr = $this->img->left_margin - 1; 2354 $yl = $this->img->height-1-$this->frame_weight; 2355 } 2356 2357 $this->img->FilledRectangle($xl,$yu,$xr,$yl); 2358 $this->img->PopColor(); 2359 2360 // Check if we should add the vertical lines at left and right edge 2361 if( $this->iXAxisLblBgColor !== '' ) { 2362 $this->img->PushColor($this->iXAxisLblBgColor); 2363 if( $t == 2 || $t == 6 ) { 2364 $this->img->Line($xl,$yu-1,$xr,$yu-1); 2365 $this->img->Line($xl,$yl-1,$xr,$yl-1); 2366 } 2367 else { 2368 $this->img->Line($xr+1,$yu,$xr+1,$this->img->top_margin); 2369 } 2370 $this->img->PopColor(); 2371 } 2372 2373 } 2135 2374 } 2136 2375 2137 2376 function StrokeAxis($aStrokeLabels=true) { 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 $bottompos = SIDE_DOWN; 2155 2156 2157 2158 2159 $toppos = FALSE; 2160 2161 2162 2163 2164 2165 2166 $bottompos = SIDE_DOWN; 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 $this->xscale->ticks->SupressFirst(false); 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 // No title for the top X-axis 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 // No title for the right side 2209 2210 2211 2212 2213 2214 $this->yaxis->Stroke($this->xscale,$aStrokeLabels); 2215 2216 2217 2218 $this->yaxis->Stroke($this->xscale,$aStrokeLabels); 2219 2377 2378 if( $aStrokeLabels ) { 2379 $this->StrokeAxisLabelBackground(); 2380 } 2381 2382 // Stroke axis 2383 if( $this->iAxisStyle != AXSTYLE_SIMPLE ) { 2384 switch( $this->iAxisStyle ) { 2385 case AXSTYLE_BOXIN : 2386 $toppos = SIDE_DOWN; 2387 $bottompos = SIDE_UP; 2388 $leftpos = SIDE_RIGHT; 2389 $rightpos = SIDE_LEFT; 2390 break; 2391 case AXSTYLE_BOXOUT : 2392 $toppos = SIDE_UP; 2393 $bottompos = SIDE_DOWN; 2394 $leftpos = SIDE_LEFT; 2395 $rightpos = SIDE_RIGHT; 2396 break; 2397 case AXSTYLE_YBOXIN: 2398 $toppos = FALSE; 2399 $bottompos = SIDE_UP; 2400 $leftpos = SIDE_RIGHT; 2401 $rightpos = SIDE_LEFT; 2402 break; 2403 case AXSTYLE_YBOXOUT: 2404 $toppos = FALSE; 2405 $bottompos = SIDE_DOWN; 2406 $leftpos = SIDE_LEFT; 2407 $rightpos = SIDE_RIGHT; 2408 break; 2409 default: 2410 JpGRaphError::RaiseL(25036,$this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle); 2411 break; 2412 } 2413 2414 // By default we hide the first label so it doesn't cross the 2415 // Y-axis in case the positon hasn't been set by the user. 2416 // However, if we use a box we always want the first value 2417 // displayed so we make sure it will be displayed. 2418 $this->xscale->ticks->SupressFirst(false); 2419 2420 // Now draw the bottom X-axis 2421 $this->xaxis->SetPos('min'); 2422 $this->xaxis->SetLabelSide(SIDE_DOWN); 2423 $this->xaxis->scale->ticks->SetSide($bottompos); 2424 $this->xaxis->Stroke($this->yscale,$aStrokeLabels); 2425 2426 if( $toppos !== FALSE ) { 2427 // We also want a top X-axis 2428 $this->xaxis = $this->xaxis; 2429 $this->xaxis->SetPos('max'); 2430 $this->xaxis->SetLabelSide(SIDE_UP); 2431 // No title for the top X-axis 2432 if( $aStrokeLabels ) { 2433 $this->xaxis->title->Set(''); 2434 } 2435 $this->xaxis->scale->ticks->SetSide($toppos); 2436 $this->xaxis->Stroke($this->yscale,$aStrokeLabels); 2437 } 2438 2439 // Stroke the left Y-axis 2440 $this->yaxis->SetPos('min'); 2441 $this->yaxis->SetLabelSide(SIDE_LEFT); 2442 $this->yaxis->scale->ticks->SetSide($leftpos); 2443 $this->yaxis->Stroke($this->xscale,$aStrokeLabels); 2444 2445 // Stroke the right Y-axis 2446 $this->yaxis->SetPos('max'); 2447 // No title for the right side 2448 if( $aStrokeLabels ) { 2449 $this->yaxis->title->Set(''); 2450 } 2451 $this->yaxis->SetLabelSide(SIDE_RIGHT); 2452 $this->yaxis->scale->ticks->SetSide($rightpos); 2453 $this->yaxis->Stroke($this->xscale,$aStrokeLabels); 2454 } 2455 else { 2456 $this->xaxis->Stroke($this->yscale,$aStrokeLabels); 2457 $this->yaxis->Stroke($this->xscale,$aStrokeLabels); 2458 } 2220 2459 } 2221 2460 … … 2223 2462 // Private helper function for backgound image 2224 2463 static function LoadBkgImage($aImgFormat='',$aFile='',$aImgStr='') { 2225 if( $aImgStr != '' ) { 2226 return Image::CreateFromString($aImgStr); 2227 } 2228 2229 // Remove case sensitivity and setup appropriate function to create image 2230 // Get file extension. This should be the LAST '.' separated part of the filename 2231 $e = explode('.',$aFile); 2232 $ext = strtolower($e[count($e)-1]); 2233 if ($ext == "jpeg") { 2234 $ext = "jpg"; 2235 } 2236 2237 if( trim($ext) == '' ) 2238 $ext = 'png'; // Assume PNG if no extension specified 2239 2240 if( $aImgFormat == '' ) 2241 $imgtag = $ext; 2242 else 2243 $imgtag = $aImgFormat; 2244 2245 $supported = imagetypes(); 2246 if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) || 2247 ( $ext == 'gif' && !($supported & IMG_GIF) ) || 2248 ( $ext == 'png' && !($supported & IMG_PNG) ) || 2249 ( $ext == 'bmp' && !($supported & IMG_WBMP) ) || 2250 ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) { 2251 2252 JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. '); 2253 } 2254 2255 2256 if( $imgtag == "jpg" || $imgtag == "jpeg") 2257 { 2258 $f = "imagecreatefromjpeg"; 2259 $imgtag = "jpg"; 2260 } 2261 else 2262 { 2263 $f = "imagecreatefrom".$imgtag; 2264 } 2265 2266 // Compare specified image type and file extension 2267 if( $imgtag != $ext ) { 2268 //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'"; 2269 JpGraphError::RaiseL(25038, $aImgFormat, $aFile); 2270 } 2271 2272 $img = @$f($aFile); 2273 if( !$img ) { 2274 JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'"); 2275 } 2276 return $img; 2277 } 2464 if( $aImgStr != '' ) { 2465 return Image::CreateFromString($aImgStr); 2466 } 2467 2468 // Remove case sensitivity and setup appropriate function to create image 2469 // Get file extension. This should be the LAST '.' separated part of the filename 2470 $e = explode('.',$aFile); 2471 $ext = strtolower($e[count($e)-1]); 2472 if ($ext == "jpeg") { 2473 $ext = "jpg"; 2474 } 2475 2476 if( trim($ext) == '' ) { 2477 $ext = 'png'; // Assume PNG if no extension specified 2478 } 2479 2480 if( $aImgFormat == '' ) { 2481 $imgtag = $ext; 2482 } 2483 else { 2484 $imgtag = $aImgFormat; 2485 } 2486 2487 $supported = imagetypes(); 2488 if( ( $ext == 'jpg' && !($supported & IMG_JPG) ) || 2489 ( $ext == 'gif' && !($supported & IMG_GIF) ) || 2490 ( $ext == 'png' && !($supported & IMG_PNG) ) || 2491 ( $ext == 'bmp' && !($supported & IMG_WBMP) ) || 2492 ( $ext == 'xpm' && !($supported & IMG_XPM) ) ) { 2493 2494 JpGraphError::RaiseL(25037,$aFile);//('The image format of your background image ('.$aFile.') is not supported in your system configuration. '); 2495 } 2496 2497 2498 if( $imgtag == "jpg" || $imgtag == "jpeg") { 2499 $f = "imagecreatefromjpeg"; 2500 $imgtag = "jpg"; 2501 } 2502 else { 2503 $f = "imagecreatefrom".$imgtag; 2504 } 2505 2506 // Compare specified image type and file extension 2507 if( $imgtag != $ext ) { 2508 //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'"; 2509 JpGraphError::RaiseL(25038, $aImgFormat, $aFile); 2510 } 2511 2512 $img = @$f($aFile); 2513 if( !$img ) { 2514 JpGraphError::RaiseL(25039,$aFile);//(" Can't read background image: '".$aFile."'"); 2515 } 2516 return $img; 2517 } 2518 2519 function StrokePlotGrad() { 2520 if( $this->plot_gradtype < 0 ) 2521 return; 2522 2523 $grad = new Gradient($this->img); 2524 $xl = $this->img->left_margin; 2525 $yt = $this->img->top_margin; 2526 $xr = $xl + $this->img->plotwidth+1 ; 2527 $yb = $yt + $this->img->plotheight ; 2528 $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->plot_gradfrom,$this->plot_gradto,$this->plot_gradtype); 2529 2530 } 2278 2531 2279 2532 function StrokeBackgroundGrad() { 2280 if( $this->bkg_gradtype < 0 ) 2281 return; 2282 $grad = new Gradient($this->img); 2283 if( $this->bkg_gradstyle == BGRAD_PLOT ) { 2284 $xl = $this->img->left_margin; 2285 $yt = $this->img->top_margin; 2286 $xr = $xl + $this->img->plotwidth+1 ; 2287 $yb = $yt + $this->img->plotheight ; 2288 $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); 2289 } 2290 else { 2291 $xl = 0; 2292 $yt = 0; 2293 $xr = $xl + $this->img->width - 1; 2294 $yb = $yt + $this->img->height ; 2295 if( $this->doshadow ) { 2296 $xr -= $this->shadow_width; 2297 $yb -= $this->shadow_width; 2298 } 2299 if( $this->doframe ) { 2300 $yt += $this->frame_weight; 2301 $yb -= $this->frame_weight; 2302 $xl += $this->frame_weight; 2303 $xr -= $this->frame_weight; 2304 } 2305 $aa = $this->img->SetAngle(0); 2306 $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); 2307 $aa = $this->img->SetAngle($aa); 2308 } 2533 if( $this->bkg_gradtype < 0 ) 2534 return; 2535 2536 $grad = new Gradient($this->img); 2537 if( $this->bkg_gradstyle == BGRAD_PLOT ) { 2538 $xl = $this->img->left_margin; 2539 $yt = $this->img->top_margin; 2540 $xr = $xl + $this->img->plotwidth+1 ; 2541 $yb = $yt + $this->img->plotheight ; 2542 $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); 2543 } 2544 else { 2545 $xl = 0; 2546 $yt = 0; 2547 $xr = $xl + $this->img->width - 1; 2548 $yb = $yt + $this->img->height - 1 ; 2549 if( $this->doshadow ) { 2550 $xr -= $this->shadow_width; 2551 $yb -= $this->shadow_width; 2552 } 2553 if( $this->doframe ) { 2554 $yt += $this->frame_weight; 2555 $yb -= $this->frame_weight; 2556 $xl += $this->frame_weight; 2557 $xr -= $this->frame_weight; 2558 } 2559 $aa = $this->img->SetAngle(0); 2560 $grad->FilledRectangle($xl,$yt,$xr,$yb,$this->bkg_gradfrom,$this->bkg_gradto,$this->bkg_gradtype); 2561 $aa = $this->img->SetAngle($aa); 2562 } 2309 2563 } 2310 2564 2311 2565 function StrokeFrameBackground() { 2312 if( $this->background_image != "" && $this->background_cflag != "" ) { 2313 JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.'); 2314 } 2315 if( $this->background_image != "" ) { 2316 $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image); 2317 } 2318 elseif( $this->background_cflag != "" ) { 2319 if( ! class_exists('FlagImages',false) ) { 2320 JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.'); 2321 } 2322 $fobj = new FlagImages(FLAGSIZE4); 2323 $dummy=''; 2324 $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy); 2325 $this->background_image_mix = $this->background_cflag_mix; 2326 $this->background_image_type = $this->background_cflag_type; 2327 } 2328 else { 2329 return ; 2330 } 2331 2332 $bw = ImageSX($bkgimg); 2333 $bh = ImageSY($bkgimg); 2334 2335 // No matter what the angle is we always stroke the image and frame 2336 // assuming it is 0 degree 2337 $aa = $this->img->SetAngle(0); 2338 2339 switch( $this->background_image_type ) { 2340 case BGIMG_FILLPLOT: // Resize to just fill the plotarea 2341 $this->FillMarginArea(); 2342 $this->StrokeFrame(); 2343 // Special case to hande 90 degree rotated graph corectly 2344 if( $aa == 90 ) { 2345 $this->img->SetAngle(90); 2346 $this->FillPlotArea(); 2347 $aa = $this->img->SetAngle(0); 2348 $adj = ($this->img->height - $this->img->width)/2; 2349 $this->img->CopyMerge($bkgimg, 2350 $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, 2351 0,0, 2352 $this->img->plotheight+1,$this->img->plotwidth, 2353 $bw,$bh,$this->background_image_mix); 2354 2355 } 2356 else { 2357 $this->FillPlotArea(); 2358 $this->img->CopyMerge($bkgimg, 2359 $this->img->left_margin,$this->img->top_margin, 2360 0,0,$this->img->plotwidth+1,$this->img->plotheight, 2361 $bw,$bh,$this->background_image_mix); 2362 } 2363 break; 2364 case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit 2365 $hadj=0; $vadj=0; 2366 if( $this->doshadow ) { 2367 $hadj = $this->shadow_width; 2368 $vadj = $this->shadow_width; 2369 } 2370 $this->FillMarginArea(); 2371 $this->FillPlotArea(); 2372 $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj, 2373 $bw,$bh,$this->background_image_mix); 2374 $this->StrokeFrame(); 2375 break; 2376 case BGIMG_COPY: // Just copy the image from left corner, no resizing 2377 $this->FillMarginArea(); 2378 $this->FillPlotArea(); 2379 $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh, 2380 $bw,$bh,$this->background_image_mix); 2381 $this->StrokeFrame(); 2382 break; 2383 case BGIMG_CENTER: // Center original image in the plot area 2384 $this->FillMarginArea(); 2385 $this->FillPlotArea(); 2386 $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2); 2387 $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2); 2388 $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh, 2389 $bw,$bh,$this->background_image_mix); 2390 $this->StrokeFrame(); 2391 break; 2392 case BGIMG_FREE: // Just copy the image to the specified location 2393 $this->img->CopyMerge($bkgimg, 2394 $this->background_image_xpos,$this->background_image_ypos, 2395 0,0,$bw,$bh,$bw,$bh,$this->background_image_mix); 2396 $this->StrokeFrame(); // New 2397 break; 2398 default: 2399 JpGraphError::RaiseL(25042);//(" Unknown background image layout"); 2400 } 2401 $this->img->SetAngle($aa); 2566 if( $this->background_image != '' && $this->background_cflag != '' ) { 2567 JpGraphError::RaiseL(25040);//('It is not possible to specify both a background image and a background country flag.'); 2568 } 2569 if( $this->background_image != '' ) { 2570 $bkgimg = $this->LoadBkgImage($this->background_image_format,$this->background_image); 2571 } 2572 elseif( $this->background_cflag != '' ) { 2573 if( ! class_exists('FlagImages',false) ) { 2574 JpGraphError::RaiseL(25041);//('In order to use Country flags as backgrounds you must include the "jpgraph_flags.php" file.'); 2575 } 2576 $fobj = new FlagImages(FLAGSIZE4); 2577 $dummy=''; 2578 $bkgimg = $fobj->GetImgByName($this->background_cflag,$dummy); 2579 $this->background_image_mix = $this->background_cflag_mix; 2580 $this->background_image_type = $this->background_cflag_type; 2581 } 2582 else { 2583 return ; 2584 } 2585 2586 $bw = ImageSX($bkgimg); 2587 $bh = ImageSY($bkgimg); 2588 2589 // No matter what the angle is we always stroke the image and frame 2590 // assuming it is 0 degree 2591 $aa = $this->img->SetAngle(0); 2592 2593 switch( $this->background_image_type ) { 2594 case BGIMG_FILLPLOT: // Resize to just fill the plotarea 2595 $this->FillMarginArea(); 2596 $this->StrokeFrame(); 2597 // Special case to hande 90 degree rotated graph corectly 2598 if( $aa == 90 ) { 2599 $this->img->SetAngle(90); 2600 $this->FillPlotArea(); 2601 $aa = $this->img->SetAngle(0); 2602 $adj = ($this->img->height - $this->img->width)/2; 2603 $this->img->CopyMerge($bkgimg, 2604 $this->img->bottom_margin-$adj,$this->img->left_margin+$adj, 2605 0,0, 2606 $this->img->plotheight+1,$this->img->plotwidth, 2607 $bw,$bh,$this->background_image_mix); 2608 } 2609 else { 2610 $this->FillPlotArea(); 2611 $this->img->CopyMerge($bkgimg, 2612 $this->img->left_margin,$this->img->top_margin+1, 2613 0,0,$this->img->plotwidth+1,$this->img->plotheight, 2614 $bw,$bh,$this->background_image_mix); 2615 } 2616 break; 2617 case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit 2618 $hadj=0; $vadj=0; 2619 if( $this->doshadow ) { 2620 $hadj = $this->shadow_width; 2621 $vadj = $this->shadow_width; 2622 } 2623 $this->FillMarginArea(); 2624 $this->FillPlotArea(); 2625 $this->img->CopyMerge($bkgimg,0,0,0,0,$this->img->width-$hadj,$this->img->height-$vadj, 2626 $bw,$bh,$this->background_image_mix); 2627 $this->StrokeFrame(); 2628 break; 2629 case BGIMG_COPY: // Just copy the image from left corner, no resizing 2630 $this->FillMarginArea(); 2631 $this->FillPlotArea(); 2632 $this->img->CopyMerge($bkgimg,0,0,0,0,$bw,$bh, 2633 $bw,$bh,$this->background_image_mix); 2634 $this->StrokeFrame(); 2635 break; 2636 case BGIMG_CENTER: // Center original image in the plot area 2637 $this->FillMarginArea(); 2638 $this->FillPlotArea(); 2639 $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2); 2640 $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2); 2641 $this->img->CopyMerge($bkgimg,$centerx,$centery,0,0,$bw,$bh, 2642 $bw,$bh,$this->background_image_mix); 2643 $this->StrokeFrame(); 2644 break; 2645 case BGIMG_FREE: // Just copy the image to the specified location 2646 $this->img->CopyMerge($bkgimg, 2647 $this->background_image_xpos,$this->background_image_ypos, 2648 0,0,$bw,$bh,$bw,$bh,$this->background_image_mix); 2649 $this->StrokeFrame(); // New 2650 break; 2651 default: 2652 JpGraphError::RaiseL(25042);//(" Unknown background image layout"); 2653 } 2654 $this->img->SetAngle($aa); 2402 2655 } 2403 2656 … … 2405 2658 // Draw a frame around the image 2406 2659 function StrokeFrame() { 2407 if( !$this->doframe ) return; 2408 2409 if( $this->background_image_type <= 1 && 2410 ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) { 2411 $c = $this->margin_color; 2412 } 2413 else { 2414 $c = false; 2415 } 2416 2417 if( $this->doshadow ) { 2418 $this->img->SetColor($this->frame_color); 2419 $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height, 2420 $c,$this->shadow_width,$this->shadow_color); 2421 } 2422 elseif( $this->framebevel ) { 2423 if( $c ) { 2424 $this->img->SetColor($this->margin_color); 2425 $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); 2426 } 2427 $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, 2428 $this->framebeveldepth, 2429 $this->framebevelcolor1,$this->framebevelcolor2); 2430 if( $this->framebevelborder ) { 2431 $this->img->SetColor($this->framebevelbordercolor); 2432 $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); 2433 } 2434 } 2435 else { 2436 $this->img->SetLineWeight($this->frame_weight); 2437 if( $c ) { 2438 $this->img->SetColor($this->margin_color); 2439 $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); 2440 } 2441 $this->img->SetColor($this->frame_color); 2442 $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); 2443 } 2660 if( !$this->doframe ) return; 2661 2662 if( $this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT)) ) { 2663 $c = $this->margin_color; 2664 } 2665 else { 2666 $c = false; 2667 } 2668 2669 if( $this->doshadow ) { 2670 $this->img->SetColor($this->frame_color); 2671 $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height, 2672 $c,$this->shadow_width,$this->shadow_color); 2673 } 2674 elseif( $this->framebevel ) { 2675 if( $c ) { 2676 $this->img->SetColor($this->margin_color); 2677 $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); 2678 } 2679 $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, 2680 $this->framebeveldepth, 2681 $this->framebevelcolor1,$this->framebevelcolor2); 2682 if( $this->framebevelborder ) { 2683 $this->img->SetColor($this->framebevelbordercolor); 2684 $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); 2685 } 2686 } 2687 else { 2688 $this->img->SetLineWeight($this->frame_weight); 2689 if( $c ) { 2690 $this->img->SetColor($this->margin_color); 2691 $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1); 2692 } 2693 $this->img->SetColor($this->frame_color); 2694 $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); 2695 } 2444 2696 } 2445 2697 2446 2698 function FillMarginArea() { 2447 2448 2449 2450 2451 2452 2453 2454 // $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); 2455 2456 $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); 2457 $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); 2458 2459 2460 2461 $this->img->height-1-$hadj); 2462 2463 2464 2465 $this->img->height-$this->img->bottom_margin-1); 2699 $hadj=0; $vadj=0; 2700 if( $this->doshadow ) { 2701 $hadj = $this->shadow_width; 2702 $vadj = $this->shadow_width; 2703 } 2704 2705 $this->img->SetColor($this->margin_color); 2706 $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->height-1-$vadj); 2707 2708 $this->img->FilledRectangle(0,0,$this->img->width-1-$hadj,$this->img->top_margin); 2709 $this->img->FilledRectangle(0,$this->img->top_margin,$this->img->left_margin,$this->img->height-1-$hadj); 2710 $this->img->FilledRectangle($this->img->left_margin+1, 2711 $this->img->height-$this->img->bottom_margin, 2712 $this->img->width-1-$hadj, 2713 $this->img->height-1-$hadj); 2714 $this->img->FilledRectangle($this->img->width-$this->img->right_margin, 2715 $this->img->top_margin+1, 2716 $this->img->width-1-$hadj, 2717 $this->img->height-$this->img->bottom_margin-1); 2466 2718 } 2467 2719 2468 2720 function FillPlotArea() { 2469 2470 2471 2472 2473 $this->img->height-$this->img->bottom_margin); 2474 2475 } 2476 2721 $this->img->PushColor($this->plotarea_color); 2722 $this->img->FilledRectangle($this->img->left_margin, 2723 $this->img->top_margin, 2724 $this->img->width-$this->img->right_margin, 2725 $this->img->height-$this->img->bottom_margin); 2726 $this->img->PopColor(); 2727 } 2728 2477 2729 // Stroke the plot area with either a solid color or a background image 2478 2730 function StrokePlotArea() { 2479 2480 2481 2482 // means it has no way of compensating for the adjusted plotarea in case of a 2483 2484 2485 2486 2487 2488 if( $this->background_image != "" || $this->background_cflag != "") {2489 2490 2491 2492 2493 2494 2495 $this->StrokeBackgroundGrad(); 2496 if( $this->bkg_gradtype < 0 || 2497 ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) { 2498 $this->FillPlotArea(); 2499 } 2500 } 2501 } 2731 // Note: To be consistent we really should take a possible shadow 2732 // into account. However, that causes some problem for the LinearScale class 2733 // since in the current design it does not have any links to class Graph which 2734 // means it has no way of compensating for the adjusted plotarea in case of a 2735 // shadow. So, until I redesign LinearScale we can't compensate for this. 2736 // So just set the two adjustment parameters to zero for now. 2737 $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ; 2738 $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ; 2739 2740 if( $this->background_image != '' || $this->background_cflag != '' ) { 2741 $this->StrokeFrameBackground(); 2742 } 2743 else { 2744 $aa = $this->img->SetAngle(0); 2745 $this->StrokeFrame(); 2746 $aa = $this->img->SetAngle($aa); 2747 $this->StrokeBackgroundGrad(); 2748 if( $this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN) ) { 2749 $this->FillPlotArea(); 2750 } 2751 $this->StrokePlotGrad(); 2752 } 2753 } 2502 2754 2503 2755 function StrokeIcons() { 2504 2505 2506 2507 2508 } 2509 2756 $n = count($this->iIcons); 2757 for( $i=0; $i < $n; ++$i ) { 2758 $this->iIcons[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); 2759 } 2760 } 2761 2510 2762 function StrokePlotBox() { 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 } 2523 } 2763 // Should we draw a box around the plot area? 2764 if( $this->boxed ) { 2765 $this->img->SetLineWeight(1); 2766 $this->img->SetLineStyle('solid'); 2767 $this->img->SetColor($this->box_color); 2768 for($i=0; $i < $this->box_weight; ++$i ) { 2769 $this->img->Rectangle( 2770 $this->img->left_margin-$i,$this->img->top_margin-$i, 2771 $this->img->width-$this->img->right_margin+$i, 2772 $this->img->height-$this->img->bottom_margin+$i); 2773 } 2774 } 2775 } 2524 2776 2525 2777 function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') { 2526 2527 2528 2778 $this->titlebkg_fillstyle = $aStyle; 2779 $this->titlebkg_scolor1 = $aColor1; 2780 $this->titlebkg_scolor2 = $aColor2; 2529 2781 } 2530 2782 2531 2783 function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) { 2532 2533 2534 2535 2536 2537 $this->titlebackground_frameweight = $aFrameWeight; 2538 2784 $this->titlebackground = $aEnable; 2785 $this->titlebackground_color = $aBackColor; 2786 $this->titlebackground_style = $aStyle; 2787 $this->titlebackground_framecolor = $aFrameColor; 2788 $this->titlebackground_framestyle = $aFrameStyle; 2789 $this->titlebackground_frameweight = $aFrameWeight; 2790 $this->titlebackground_bevelheight = $aBevelHeight ; 2539 2791 } 2540 2792 … … 2542 2794 function StrokeTitles() { 2543 2795 2544 $margin=3; 2545 2546 if( $this->titlebackground ) { 2547 2548 // Find out height 2549 $this->title->margin += 2 ; 2550 $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin; 2551 if( $this->subtitle->t != "" && !$this->subtitle->hide ) { 2552 $h += $this->subtitle->GetTextHeight($this->img)+$margin+ 2553 $this->subtitle->margin; 2554 $h += 2; 2555 } 2556 if( $this->subsubtitle->t != "" && !$this->subsubtitle->hide ) { 2557 $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+ 2558 $this->subsubtitle->margin; 2559 $h += 2; 2560 } 2561 $this->img->PushColor($this->titlebackground_color); 2562 if( $this->titlebackground_style === TITLEBKG_STYLE1 ) { 2563 // Inside the frame 2564 if( $this->framebevel ) { 2565 $x1 = $y1 = $this->framebeveldepth + 1 ; 2566 $x2 = $this->img->width - $this->framebeveldepth - 2 ; 2567 $this->title->margin += $this->framebeveldepth + 1 ; 2568 $h += $y1 ; 2569 $h += 2; 2570 } 2571 else { 2572 $x1 = $y1 = $this->frame_weight; 2573 $x2 = $this->img->width - 2*$x1; 2574 } 2575 } 2576 elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) { 2577 // Cover the frame as well 2578 $x1 = $y1 = 0; 2579 $x2 = $this->img->width - 1 ; 2580 } 2581 elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) { 2582 // Cover the frame as well (the difference is that 2583 // for style==3 a bevel frame border is on top 2584 // of the title background) 2585 $x1 = $y1 = 0; 2586 $x2 = $this->img->width - 1 ; 2587 $h += $this->framebeveldepth ; 2588 $this->title->margin += $this->framebeveldepth ; 2589 } 2590 else { 2591 JpGraphError::RaiseL(25043);//('Unknown title background style.'); 2592 } 2593 2594 if( $this->titlebackground_framestyle === 3 ) { 2595 $h += $this->titlebackground_bevelheight*2 + 1 ; 2596 $this->title->margin += $this->titlebackground_bevelheight ; 2597 } 2598 2599 if( $this->doshadow ) { 2600 $x2 -= $this->shadow_width ; 2601 } 2602 2603 $indent=0; 2604 if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { 2605 $ind = $this->titlebackground_bevelheight; 2606 } 2607 2608 if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) { 2609 $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind, 2610 $this->titlebkg_scolor1, 2611 $this->titlebkg_scolor2); 2612 } 2613 elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) { 2614 $this->img->FilledRectangle2($x1+$ind,$y1+$ind,$x2-$ind,$h-$ind, 2615 $this->titlebkg_scolor1, 2616 $this->titlebkg_scolor2,2); 2617 } 2618 else { 2619 // Solid fill 2620 $this->img->FilledRectangle($x1,$y1,$x2,$h); 2621 } 2622 $this->img->PopColor(); 2623 2624 $this->img->PushColor($this->titlebackground_framecolor); 2625 $this->img->SetLineWeight($this->titlebackground_frameweight); 2626 if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) { 2627 // Frame background 2628 $this->img->Rectangle($x1,$y1,$x2,$h); 2629 } 2630 elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) { 2631 // Bottom line only 2632 $this->img->Line($x1,$h,$x2,$h); 2633 } 2634 elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { 2635 $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight); 2636 } 2637 $this->img->PopColor(); 2638 2639 // This is clumsy. But we neeed to stroke the whole graph frame if it is 2640 // set to bevel to get the bevel shading on top of the text background 2641 if( $this->framebevel && $this->doframe && 2642 $this->titlebackground_style === 3 ) { 2643 $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, 2644 $this->framebeveldepth, 2645 $this->framebevelcolor1,$this->framebevelcolor2); 2646 if( $this->framebevelborder ) { 2647 $this->img->SetColor($this->framebevelbordercolor); 2648 $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); 2649 } 2650 } 2651 } 2652 2653 // Stroke title 2654 $y = $this->title->margin; 2655 if( $this->title->halign == 'center' ) 2656 $this->title->Center(0,$this->img->width,$y); 2657 elseif( $this->title->halign == 'left' ) { 2658 $this->title->SetPos($this->title->margin+2,$y); 2659 } 2660 elseif( $this->title->halign == 'right' ) { 2661 $indent = 0; 2662 if( $this->doshadow ) 2663 $indent = $this->shadow_width+2; 2664 $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right'); 2665 } 2666 $this->title->Stroke($this->img); 2667 2668 // ... and subtitle 2669 $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin; 2670 if( $this->subtitle->halign == 'center' ) 2671 $this->subtitle->Center(0,$this->img->width,$y); 2672 elseif( $this->subtitle->halign == 'left' ) { 2673 $this->subtitle->SetPos($this->subtitle->margin+2,$y); 2674 } 2675 elseif( $this->subtitle->halign == 'right' ) { 2676 $indent = 0; 2677 if( $this->doshadow ) 2678 $indent = $this->shadow_width+2; 2679 $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); 2680 } 2681 $this->subtitle->Stroke($this->img); 2682 2683 // ... and subsubtitle 2684 $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin; 2685 if( $this->subsubtitle->halign == 'center' ) 2686 $this->subsubtitle->Center(0,$this->img->width,$y); 2687 elseif( $this->subsubtitle->halign == 'left' ) { 2688 $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); 2689 } 2690 elseif( $this->subsubtitle->halign == 'right' ) { 2691 $indent = 0; 2692 if( $this->doshadow ) 2693 $indent = $this->shadow_width+2; 2694 $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right'); 2695 } 2696 $this->subsubtitle->Stroke($this->img); 2697 2698 // ... and fancy title 2699 $this->tabtitle->Stroke($this->img); 2796 $margin=3; 2797 2798 if( $this->titlebackground ) { 2799 // Find out height 2800 $this->title->margin += 2 ; 2801 $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin; 2802 if( $this->subtitle->t != '' && !$this->subtitle->hide ) { 2803 $h += $this->subtitle->GetTextHeight($this->img)+$margin+ 2804 $this->subtitle->margin; 2805 $h += 2; 2806 } 2807 if( $this->subsubtitle->t != '' && !$this->subsubtitle->hide ) { 2808 $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+ 2809 $this->subsubtitle->margin; 2810 $h += 2; 2811 } 2812 $this->img->PushColor($this->titlebackground_color); 2813 if( $this->titlebackground_style === TITLEBKG_STYLE1 ) { 2814 // Inside the frame 2815 if( $this->framebevel ) { 2816 $x1 = $y1 = $this->framebeveldepth + 1 ; 2817 $x2 = $this->img->width - $this->framebeveldepth - 2 ; 2818 $this->title->margin += $this->framebeveldepth + 1 ; 2819 $h += $y1 ; 2820 $h += 2; 2821 } 2822 else { 2823 $x1 = $y1 = $this->frame_weight; 2824 $x2 = $this->img->width - $this->frame_weight-1; 2825 } 2826 } 2827 elseif( $this->titlebackground_style === TITLEBKG_STYLE2 ) { 2828 // Cover the frame as well 2829 $x1 = $y1 = 0; 2830 $x2 = $this->img->width - 1 ; 2831 } 2832 elseif( $this->titlebackground_style === TITLEBKG_STYLE3 ) { 2833 // Cover the frame as well (the difference is that 2834 // for style==3 a bevel frame border is on top 2835 // of the title background) 2836 $x1 = $y1 = 0; 2837 $x2 = $this->img->width - 1 ; 2838 $h += $this->framebeveldepth ; 2839 $this->title->margin += $this->framebeveldepth ; 2840 } 2841 else { 2842 JpGraphError::RaiseL(25043);//('Unknown title background style.'); 2843 } 2844 2845 if( $this->titlebackground_framestyle === 3 ) { 2846 $h += $this->titlebackground_bevelheight*2 + 1 ; 2847 $this->title->margin += $this->titlebackground_bevelheight ; 2848 } 2849 2850 if( $this->doshadow ) { 2851 $x2 -= $this->shadow_width ; 2852 } 2853 2854 $indent=0; 2855 if( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { 2856 $indent = $this->titlebackground_bevelheight; 2857 } 2858 2859 if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) { 2860 $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent, 2861 $this->titlebkg_scolor1, 2862 $this->titlebkg_scolor2); 2863 } 2864 elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) { 2865 $this->img->FilledRectangle2($x1+$indent,$y1+$indent,$x2-$indent,$h-$indent, 2866 $this->titlebkg_scolor1, 2867 $this->titlebkg_scolor2,2); 2868 } 2869 else { 2870 // Solid fill 2871 $this->img->FilledRectangle($x1,$y1,$x2,$h); 2872 } 2873 $this->img->PopColor(); 2874 2875 $this->img->PushColor($this->titlebackground_framecolor); 2876 $this->img->SetLineWeight($this->titlebackground_frameweight); 2877 if( $this->titlebackground_framestyle == TITLEBKG_FRAME_FULL ) { 2878 // Frame background 2879 $this->img->Rectangle($x1,$y1,$x2,$h); 2880 } 2881 elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM ) { 2882 // Bottom line only 2883 $this->img->Line($x1,$h,$x2,$h); 2884 } 2885 elseif( $this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL ) { 2886 $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight); 2887 } 2888 $this->img->PopColor(); 2889 2890 // This is clumsy. But we neeed to stroke the whole graph frame if it is 2891 // set to bevel to get the bevel shading on top of the text background 2892 if( $this->framebevel && $this->doframe && $this->titlebackground_style === 3 ) { 2893 $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2, 2894 $this->framebeveldepth, 2895 $this->framebevelcolor1,$this->framebevelcolor2); 2896 if( $this->framebevelborder ) { 2897 $this->img->SetColor($this->framebevelbordercolor); 2898 $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1); 2899 } 2900 } 2901 } 2902 2903 // Stroke title 2904 $y = $this->title->margin; 2905 if( $this->title->halign == 'center' ) { 2906 $this->title->Center(0,$this->img->width,$y); 2907 } 2908 elseif( $this->title->halign == 'left' ) { 2909 $this->title->SetPos($this->title->margin+2,$y); 2910 } 2911 elseif( $this->title->halign == 'right' ) { 2912 $indent = 0; 2913 if( $this->doshadow ) { 2914 $indent = $this->shadow_width+2; 2915 } 2916 $this->title->SetPos($this->img->width-$this->title->margin-$indent,$y,'right'); 2917 } 2918 $this->title->Stroke($this->img); 2919 2920 // ... and subtitle 2921 $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin; 2922 if( $this->subtitle->halign == 'center' ) { 2923 $this->subtitle->Center(0,$this->img->width,$y); 2924 } 2925 elseif( $this->subtitle->halign == 'left' ) { 2926 $this->subtitle->SetPos($this->subtitle->margin+2,$y); 2927 } 2928 elseif( $this->subtitle->halign == 'right' ) { 2929 $indent = 0; 2930 if( $this->doshadow ) 2931 $indent = $this->shadow_width+2; 2932 $this->subtitle->SetPos($this->img->width-$this->subtitle->margin-$indent,$y,'right'); 2933 } 2934 $this->subtitle->Stroke($this->img); 2935 2936 // ... and subsubtitle 2937 $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin; 2938 if( $this->subsubtitle->halign == 'center' ) { 2939 $this->subsubtitle->Center(0,$this->img->width,$y); 2940 } 2941 elseif( $this->subsubtitle->halign == 'left' ) { 2942 $this->subsubtitle->SetPos($this->subsubtitle->margin+2,$y); 2943 } 2944 elseif( $this->subsubtitle->halign == 'right' ) { 2945 $indent = 0; 2946 if( $this->doshadow ) 2947 $indent = $this->shadow_width+2; 2948 $this->subsubtitle->SetPos($this->img->width-$this->subsubtitle->margin-$indent,$y,'right'); 2949 } 2950 $this->subsubtitle->Stroke($this->img); 2951 2952 // ... and fancy title 2953 $this->tabtitle->Stroke($this->img); 2700 2954 2701 2955 } 2702 2956 2703 2957 function StrokeTexts() { 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2958 // Stroke any user added text objects 2959 if( $this->texts != null ) { 2960 for($i=0; $i < count($this->texts); ++$i) { 2961 $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); 2962 } 2963 } 2964 2965 if( $this->y2texts != null && $this->y2scale != null ) { 2966 for($i=0; $i < count($this->y2texts); ++$i) { 2967 $this->y2texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->y2scale); 2968 } 2969 } 2716 2970 2717 2971 } 2718 2972 2719 2973 function StrokeTables() { 2720 2721 2722 2723 2724 2725 2974 if( $this->iTables != null ) { 2975 $n = count($this->iTables); 2976 for( $i=0; $i < $n; ++$i ) { 2977 $this->iTables[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale); 2978 } 2979 } 2726 2980 } 2727 2981 2728 2982 function DisplayClientSideaImageMapAreas() { 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 if ($coords[1][$i]=="poly") {2740 2741 2742 2743 2744 2745 2746 } else if ($coords[1][$i]=="rect") {2747 2748 2749 2750 2751 2752 $this->img->LineTo($pts[0],$pts[1]); 2753 2754 2755 2983 // Debug stuff - display the outline of the image map areas 2984 $csim=''; 2985 foreach ($this->plots as $p) { 2986 $csim.= $p->GetCSIMareas(); 2987 } 2988 $csim .= $this->legend->GetCSIMareas(); 2989 if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) { 2990 $this->img->SetColor($this->csimcolor); 2991 $n = count($coords[0]); 2992 for ($i=0; $i < $n; $i++) { 2993 if ( $coords[1][$i] == 'poly' ) { 2994 preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts); 2995 $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]); 2996 $m = count($pts[0]); 2997 for ($j=0; $j < $m; $j++) { 2998 $this->img->LineTo($pts[1][$j],$pts[2][$j]); 2999 } 3000 } elseif ( $coords[1][$i] == 'rect' ) { 3001 $pts = preg_split('/,/', $coords[2][$i]); 3002 $this->img->SetStartPoint($pts[0],$pts[1]); 3003 $this->img->LineTo($pts[2],$pts[1]); 3004 $this->img->LineTo($pts[2],$pts[3]); 3005 $this->img->LineTo($pts[0],$pts[3]); 3006 $this->img->LineTo($pts[0],$pts[1]); 3007 } 3008 } 3009 } 2756 3010 } 2757 3011 2758 3012 // Text scale offset in world coordinates 2759 3013 function SetTextScaleOff($aOff) { 2760 2761 3014 $this->text_scale_off = $aOff; 3015 $this->xscale->text_scale_off = $aOff; 2762 3016 } 2763 3017 2764 3018 // Text width of bar to be centered in absolute pixels 2765 3019 function SetTextScaleAbsCenterOff($aOff) { 2766 3020 $this->text_scale_abscenteroff = $aOff; 2767 3021 } 2768 3022 2769 3023 // Get Y min and max values for added lines 2770 3024 function GetLinesYMinMax( $aLines ) { 2771 $n = count($aLines);2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 3025 $n = is_array($aLines) ? count($aLines) : 0; 3026 if( $n == 0 ) return false; 3027 $min = $aLines[0]->scaleposition ; 3028 $max = $min ; 3029 $flg = false; 3030 for( $i=0; $i < $n; ++$i ) { 3031 if( $aLines[$i]->direction == HORIZONTAL ) { 3032 $flg = true ; 3033 $v = $aLines[$i]->scaleposition ; 3034 if( $min > $v ) $min = $v ; 3035 if( $max < $v ) $max = $v ; 3036 } 3037 } 3038 return $flg ? array($min,$max) : false ; 2785 3039 } 2786 3040 2787 3041 // Get X min and max values for added lines 2788 3042 function GetLinesXMinMax( $aLines ) { 2789 $n = count($aLines);2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 3043 $n = is_array($aLines) ? count($aLines) : 0; 3044 if( $n == 0 ) return false ; 3045 $min = $aLines[0]->scaleposition ; 3046 $max = $min ; 3047 $flg = false; 3048 for( $i=0; $i < $n; ++$i ) { 3049 if( $aLines[$i]->direction == VERTICAL ) { 3050 $flg = true ; 3051 $v = $aLines[$i]->scaleposition ; 3052 if( $min > $v ) $min = $v ; 3053 if( $max < $v ) $max = $v ; 3054 } 3055 } 3056 return $flg ? array($min,$max) : false ; 2803 3057 } 2804 3058 2805 3059 // Get min and max values for all included plots 2806 3060 function GetPlotsYMinMax($aPlots) { 2807 $n = count($aPlots); 2808 $i=0; 2809 do { 2810 list($xmax,$max) = $aPlots[$i]->Max(); 2811 } while( ++$i < $n && !is_numeric($max) ); 2812 2813 $i=0; 2814 do { 2815 list($xmin,$min) = $aPlots[$i]->Min(); 2816 } while( ++$i < $n && !is_numeric($min) ); 2817 2818 if( !is_numeric($min) || !is_numeric($max) ) { 2819 JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).'); 2820 } 2821 2822 for($i=0; $i < $n; ++$i ) { 2823 list($xmax,$ymax)=$aPlots[$i]->Max(); 2824 list($xmin,$ymin)=$aPlots[$i]->Min(); 2825 if (is_numeric($ymax)) $max=max($max,$ymax); 2826 if (is_numeric($ymin)) $min=min($min,$ymin); 2827 } 2828 if( $min == '' ) $min = 0; 2829 if( $max == '' ) $max = 0; 2830 if( $min == 0 && $max == 0 ) { 2831 // Special case if all values are 0 2832 $min=0;$max=1; 2833 } 2834 return array($min,$max); 3061 $n = count($aPlots); 3062 $i=0; 3063 do { 3064 list($xmax,$max) = $aPlots[$i]->Max(); 3065 } while( ++$i < $n && !is_numeric($max) ); 3066 3067 $i=0; 3068 do { 3069 list($xmin,$min) = $aPlots[$i]->Min(); 3070 } while( ++$i < $n && !is_numeric($min) ); 3071 3072 if( !is_numeric($min) || !is_numeric($max) ) { 3073 JpGraphError::RaiseL(25044);//('Cannot use autoscaling since it is impossible to determine a valid min/max value of the Y-axis (only null values).'); 3074 } 3075 3076 for($i=0; $i < $n; ++$i ) { 3077 list($xmax,$ymax)=$aPlots[$i]->Max(); 3078 list($xmin,$ymin)=$aPlots[$i]->Min(); 3079 if (is_numeric($ymax)) $max=max($max,$ymax); 3080 if (is_numeric($ymin)) $min=min($min,$ymin); 3081 } 3082 if( $min == '' ) $min = 0; 3083 if( $max == '' ) $max = 0; 3084 if( $min == 0 && $max == 0 ) { 3085 // Special case if all values are 0 3086 $min=0;$max=1; 3087 } 3088 return array($min,$max); 3089 } 3090 3091 function hasLinePlotAndBarPlot() { 3092 $has_line = false; 3093 $has_bar = false; 3094 3095 foreach ($this->plots as $plot) { 3096 if ($plot instanceof LinePlot) { 3097 $has_line = true; 3098 } 3099 if ($plot instanceof BarPlot) { 3100 $has_bar = true; 3101 } 3102 } 3103 3104 if ($has_line && $has_bar) { 3105 return true; 3106 } 3107 3108 return false; 3109 } 3110 3111 function SetTheme($graph_theme) { 3112 3113 if (!($this instanceof PieGraph)) { 3114 if (!$this->isAfterSetScale) { 3115 JpGraphError::RaiseL(25133);//('Use Graph::SetTheme() after Graph::SetScale().'); 3116 } 3117 } 3118 3119 if ($this->graph_theme) { 3120 $this->ClearTheme(); 3121 } 3122 $this->graph_theme = $graph_theme; 3123 $this->graph_theme->ApplyGraph($this); 3124 } 3125 3126 function ClearTheme() { 3127 $this->graph_theme = null; 3128 3129 $this->isRunningClear = true; 3130 3131 $this->__construct( 3132 $this->inputValues['aWidth'], 3133 $this->inputValues['aHeight'], 3134 $this->inputValues['aCachedName'], 3135 $this->inputValues['aTimeout'], 3136 $this->inputValues['aInline'] 3137 ); 3138 3139 if (!($this instanceof PieGraph)) { 3140 if ($this->isAfterSetScale) { 3141 $this->SetScale( 3142 $this->inputValues['aAxisType'], 3143 $this->inputValues['aYMin'], 3144 $this->inputValues['aYMax'], 3145 $this->inputValues['aXMin'], 3146 $this->inputValues['aXMax'] 3147 ); 3148 } 3149 } 3150 3151 $this->isRunningClear = false; 3152 } 3153 3154 function SetSupersampling($do = false, $scale = 2) { 3155 if ($do) { 3156 define('SUPERSAMPLING_SCALE', $scale); 3157 // $this->img->scale = $scale; 3158 } else { 3159 define('SUPERSAMPLING_SCALE', 1); 3160 //$this->img->scale = 0; 3161 } 2835 3162 } 2836 3163 … … 2842 3169 //=================================================== 2843 3170 class LineProperty { 2844 public $iWeight=1, $iColor="black",$iStyle="solid",$iShow=true; 2845 2846 //--------------- 2847 // PUBLIC METHODS 3171 public $iWeight=1, $iColor='black', $iStyle='solid', $iShow=false; 3172 3173 function __construct($aWeight=1,$aColor='black',$aStyle='solid') { 3174 $this->iWeight = $aWeight; 3175 $this->iColor = $aColor; 3176 $this->iStyle = $aStyle; 3177 } 3178 2848 3179 function SetColor($aColor) { 2849 2850 } 2851 3180 $this->iColor = $aColor; 3181 } 3182 2852 3183 function SetWeight($aWeight) { 2853 2854 } 2855 3184 $this->iWeight = $aWeight; 3185 } 3186 2856 3187 function SetStyle($aStyle) { 2857 2858 } 2859 3188 $this->iStyle = $aStyle; 3189 } 3190 2860 3191 function Show($aShow=true) { 2861 2862 } 2863 3192 $this->iShow=$aShow; 3193 } 3194 2864 3195 function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) { 2865 2866 2867 2868 2869 2870 $aImg->SetLineStyle($this->iStyle); 2871 2872 2873 2874 2875 2876 3196 if( $this->iShow ) { 3197 $aImg->PushColor($this->iColor); 3198 $oldls = $aImg->line_style; 3199 $oldlw = $aImg->line_weight; 3200 $aImg->SetLineWeight($this->iWeight); 3201 $aImg->SetLineStyle($this->iStyle); 3202 $aImg->StyleLine($aX1,$aY1,$aX2,$aY2); 3203 $aImg->PopColor($this->iColor); 3204 $aImg->line_style = $oldls; 3205 $aImg->line_weight = $oldlw; 3206 3207 } 2877 3208 } 2878 3209 } 2879 3210 3211 //=================================================== 3212 // CLASS GraphTabTitle 3213 // Description: Draw "tab" titles on top of graphs 3214 //=================================================== 2880 3215 class GraphTabTitle extends Text{ 2881 3216 private $corner = 6 , $posx = 7, $posy = 4; 2882 3217 private $fillcolor='lightyellow',$bordercolor='black'; 2883 3218 private $align = 'left', $width=TABTITLE_WIDTHFIT; 2884 function GraphTabTitle() {2885 2886 2887 2888 3219 function __construct() { 3220 $this->t = ''; 3221 $this->font_style = FS_BOLD; 3222 $this->hide = true; 3223 $this->color = 'darkred'; 2889 3224 } 2890 3225 2891 3226 function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') { 2892 2893 2894 3227 $this->color = $aTxtColor; 3228 $this->fillcolor = $aFillColor; 3229 $this->bordercolor = $aBorderColor; 2895 3230 } 2896 3231 2897 3232 function SetFillColor($aFillColor) { 2898 3233 $this->fillcolor = $aFillColor; 2899 3234 } 2900 3235 2901 3236 function SetTabAlign($aAlign) { 2902 2903 } 2904 3237 $this->align = $aAlign; 3238 } 3239 2905 3240 function SetWidth($aWidth) { 2906 3241 $this->width = $aWidth ; 2907 3242 } 2908 3243 2909 3244 function Set($t) { 2910 2911 3245 $this->t = $t; 3246 $this->hide = false; 2912 3247 } 2913 3248 2914 3249 function SetCorner($aD) { 2915 3250 $this->corner = $aD ; 2916 3251 } 2917 3252 2918 3253 function Stroke($aImg,$aDummy1=null,$aDummy2=null) { 2919 if( $this->hide ) 2920 return; 2921 $this->boxed = false; 2922 $w = $this->GetWidth($aImg) + 2*$this->posx; 2923 $h = $this->GetTextHeight($aImg) + 2*$this->posy; 2924 2925 $x = $aImg->left_margin; 2926 $y = $aImg->top_margin; 2927 2928 if( $this->width === TABTITLE_WIDTHFIT ) { 2929 if( $this->align == 'left' ) { 2930 $p = array($x, $y, 2931 $x, $y-$h+$this->corner, 2932 $x + $this->corner,$y-$h, 2933 $x + $w - $this->corner, $y-$h, 2934 $x + $w, $y-$h+$this->corner, 2935 $x + $w, $y); 2936 } 2937 elseif( $this->align == 'center' ) { 2938 $x += round($aImg->plotwidth/2) - round($w/2); 2939 $p = array($x, $y, 2940 $x, $y-$h+$this->corner, 2941 $x + $this->corner, $y-$h, 2942 $x + $w - $this->corner, $y-$h, 2943 $x + $w, $y-$h+$this->corner, 2944 $x + $w, $y); 2945 } 2946 else { 2947 $x += $aImg->plotwidth -$w; 2948 $p = array($x, $y, 2949 $x, $y-$h+$this->corner, 2950 $x + $this->corner,$y-$h, 2951 $x + $w - $this->corner, $y-$h, 2952 $x + $w, $y-$h+$this->corner, 2953 $x + $w, $y); 2954 } 2955 } 2956 else { 2957 if( $this->width === TABTITLE_WIDTHFULL ) 2958 $w = $aImg->plotwidth ; 2959 else 2960 $w = $this->width ; 2961 2962 // Make the tab fit the width of the plot area 2963 $p = array($x, $y, 2964 $x, $y-$h+$this->corner, 2965 $x + $this->corner,$y-$h, 2966 $x + $w - $this->corner, $y-$h, 2967 $x + $w, $y-$h+$this->corner, 2968 $x + $w, $y); 2969 2970 } 2971 if( $this->halign == 'left' ) { 2972 $aImg->SetTextAlign('left','bottom'); 2973 $x += $this->posx; 2974 $y -= $this->posy; 2975 } 2976 elseif( $this->halign == 'center' ) { 2977 $aImg->SetTextAlign('center','bottom'); 2978 $x += $w/2; 2979 $y -= $this->posy; 2980 } 2981 else { 2982 $aImg->SetTextAlign('right','bottom'); 2983 $x += $w - $this->posx; 2984 $y -= $this->posy; 2985 } 2986 2987 $aImg->SetColor($this->fillcolor); 2988 $aImg->FilledPolygon($p); 2989 2990 $aImg->SetColor($this->bordercolor); 2991 $aImg->Polygon($p,true); 2992 2993 $aImg->SetColor($this->color); 2994 $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); 2995 $aImg->StrokeText($x,$y,$this->t,0,'center'); 3254 if( $this->hide ) 3255 return; 3256 $this->boxed = false; 3257 $w = $this->GetWidth($aImg) + 2*$this->posx; 3258 $h = $this->GetTextHeight($aImg) + 2*$this->posy; 3259 3260 $x = $aImg->left_margin; 3261 $y = $aImg->top_margin; 3262 3263 if( $this->width === TABTITLE_WIDTHFIT ) { 3264 if( $this->align == 'left' ) { 3265 $p = array($x, $y, 3266 $x, $y-$h+$this->corner, 3267 $x + $this->corner,$y-$h, 3268 $x + $w - $this->corner, $y-$h, 3269 $x + $w, $y-$h+$this->corner, 3270 $x + $w, $y); 3271 } 3272 elseif( $this->align == 'center' ) { 3273 $x += round($aImg->plotwidth/2) - round($w/2); 3274 $p = array($x, $y, 3275 $x, $y-$h+$this->corner, 3276 $x + $this->corner, $y-$h, 3277 $x + $w - $this->corner, $y-$h, 3278 $x + $w, $y-$h+$this->corner, 3279 $x + $w, $y); 3280 } 3281 else { 3282 $x += $aImg->plotwidth -$w; 3283 $p = array($x, $y, 3284 $x, $y-$h+$this->corner, 3285 $x + $this->corner,$y-$h, 3286 $x + $w - $this->corner, $y-$h, 3287 $x + $w, $y-$h+$this->corner, 3288 $x + $w, $y); 3289 } 3290 } 3291 else { 3292 if( $this->width === TABTITLE_WIDTHFULL ) { 3293 $w = $aImg->plotwidth ; 3294 } 3295 else { 3296 $w = $this->width ; 3297 } 3298 3299 // Make the tab fit the width of the plot area 3300 $p = array($x, $y, 3301 $x, $y-$h+$this->corner, 3302 $x + $this->corner,$y-$h, 3303 $x + $w - $this->corner, $y-$h, 3304 $x + $w, $y-$h+$this->corner, 3305 $x + $w, $y); 3306 3307 } 3308 if( $this->halign == 'left' ) { 3309 $aImg->SetTextAlign('left','bottom'); 3310 $x += $this->posx; 3311 $y -= $this->posy; 3312 } 3313 elseif( $this->halign == 'center' ) { 3314 $aImg->SetTextAlign('center','bottom'); 3315 $x += $w/2; 3316 $y -= $this->posy; 3317 } 3318 else { 3319 $aImg->SetTextAlign('right','bottom'); 3320 $x += $w - $this->posx; 3321 $y -= $this->posy; 3322 } 3323 3324 $aImg->SetColor($this->fillcolor); 3325 $aImg->FilledPolygon($p); 3326 3327 $aImg->SetColor($this->bordercolor); 3328 $aImg->Polygon($p,true); 3329 3330 $aImg->SetColor($this->color); 3331 $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); 3332 $aImg->StrokeText($x,$y,$this->t,0,'center'); 2996 3333 } 2997 3334 … … 3003 3340 //=================================================== 3004 3341 class SuperScriptText extends Text { 3005 private $iSuper= "";3006 private $sfont_family= "",$sfont_style="",$sfont_size=8;3342 private $iSuper=''; 3343 private $sfont_family='',$sfont_style='',$sfont_size=8; 3007 3344 private $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65; 3008 3345 private $iSDir=0; 3009 3346 private $iSimple=false; 3010 3347 3011 function SuperScriptText($aTxt="",$aSuper="",$aXAbsPos=0,$aYAbsPos=0) {3012 parent::Text($aTxt,$aXAbsPos,$aYAbsPos);3013 3348 function __construct($aTxt='',$aSuper='',$aXAbsPos=0,$aYAbsPos=0) { 3349 parent::__construct($aTxt,$aXAbsPos,$aYAbsPos); 3350 $this->iSuper = $aSuper; 3014 3351 } 3015 3352 3016 3353 function FromReal($aVal,$aPrecision=2) { 3017 // Convert a floating point number to scientific notation 3018 $neg=1.0; 3019 if( $aVal < 0 ) { 3020 $neg = -1.0; 3021 $aVal = -$aVal; 3022 } 3023 3024 $l = floor(log10($aVal)); 3025 $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision)); 3026 $a *= $neg; 3027 if( $this->iSimple && ($a == 1 || $a==-1) ) $a = ''; 3028 3029 if( $a != '' ) 3030 $this->t = $a.' * 10'; 3031 else { 3032 if( $neg == 1 ) 3033 $this->t = '10'; 3034 else 3035 $this->t = '-10'; 3036 } 3037 $this->iSuper = $l; 3038 } 3039 3040 function Set($aTxt,$aSuper="") { 3041 $this->t = $aTxt; 3042 $this->iSuper = $aSuper; 3354 // Convert a floating point number to scientific notation 3355 $neg=1.0; 3356 if( $aVal < 0 ) { 3357 $neg = -1.0; 3358 $aVal = -$aVal; 3359 } 3360 3361 $l = floor(log10($aVal)); 3362 $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision)); 3363 $a *= $neg; 3364 if( $this->iSimple && ($a == 1 || $a==-1) ) $a = ''; 3365 3366 if( $a != '' ) { 3367 $this->t = $a.' * 10'; 3368 } 3369 else { 3370 if( $neg == 1 ) { 3371 $this->t = '10'; 3372 } 3373 else { 3374 $this->t = '-10'; 3375 } 3376 } 3377 $this->iSuper = $l; 3378 } 3379 3380 function Set($aTxt,$aSuper='') { 3381 $this->t = $aTxt; 3382 $this->iSuper = $aSuper; 3043 3383 } 3044 3384 3045 3385 function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) { 3046 3047 3048 3386 $this->sfont_family = $aFontFam; 3387 $this->sfont_style = $aFontStyle; 3388 $this->sfont_size = $aFontSize; 3049 3389 } 3050 3390 3051 3391 // Total width of text 3052 3392 function GetWidth($aImg) { 3053 3054 3055 3056 3057 3058 3059 } 3060 3393 $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); 3394 $w = $aImg->GetTextWidth($this->t); 3395 $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); 3396 $w += $aImg->GetTextWidth($this->iSuper); 3397 $w += $this->iSuperMargin; 3398 return $w; 3399 } 3400 3061 3401 // Hight of font (approximate the height of the text) 3062 3402 function GetFontHeight($aImg) { 3063 $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); 3064 3065 3066 3067 3403 $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); 3404 $h = $aImg->GetFontHeight(); 3405 $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); 3406 $h += $aImg->GetFontHeight(); 3407 return $h; 3068 3408 } 3069 3409 3070 3410 // Hight of text 3071 3411 function GetTextHeight($aImg) { 3072 3073 3074 3075 3076 3412 $aImg->SetFont($this->font_family,$this->font_style,$this->font_size); 3413 $h = $aImg->GetTextHeight($this->t); 3414 $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size); 3415 $h += $aImg->GetTextHeight($this->iSuper); 3416 return $h; 3077 3417 } 3078 3418 3079 3419 function Stroke($aImg,$ax=-1,$ay=-1) { 3080 3420 3081 3421 // To position the super script correctly we need different 3082 // cases to handle the alignmewnt specified since that will 3083 // determine how we can interpret the x,y coordinates 3084 3085 $w = parent::GetWidth($aImg); 3086 $h = parent::GetTextHeight($aImg); 3087 switch( $this->valign ) { 3088 case 'top': 3089 $sy = $this->y; 3090 break; 3091 case 'center': 3092 $sy = $this->y - $h/2; 3093 break; 3094 case 'bottom': 3095 $sy = $this->y - $h; 3096 break; 3097 default: 3098 JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text'); 3099 break; 3100 } 3101 3102 switch( $this->halign ) { 3103 case 'left': 3104 $sx = $this->x + $w; 3105 break; 3106 case 'center': 3107 $sx = $this->x + $w/2; 3108 break; 3109 case 'right': 3110 $sx = $this->x; 3111 break; 3112 default: 3113 JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text'); 3114 break; 3115 } 3116 3117 $sx += $this->iSuperMargin; 3118 $sy += $this->iVertOverlap; 3119 3120 // Should we automatically determine the font or 3121 // has the user specified it explicetly? 3122 if( $this->sfont_family == "" ) { 3123 if( $this->font_family <= FF_FONT2 ) { 3124 if( $this->font_family == FF_FONT0 ) { 3125 $sff = FF_FONT0; 3126 } 3127 elseif( $this->font_family == FF_FONT1 ) { 3128 if( $this->font_style == FS_NORMAL ) 3129 $sff = FF_FONT0; 3130 else 3131 $sff = FF_FONT1; 3132 } 3133 else { 3134 $sff = FF_FONT1; 3135 } 3136 $sfs = $this->font_style; 3137 $sfz = $this->font_size; 3138 } 3139 else { 3140 // TTF fonts 3141 $sff = $this->font_family; 3142 $sfs = $this->font_style; 3143 $sfz = floor($this->font_size*$this->iSuperScale); 3144 if( $sfz < 8 ) $sfz = 8; 3145 } 3146 $this->sfont_family = $sff; 3147 $this->sfont_style = $sfs; 3148 $this->sfont_size = $sfz; 3149 } 3150 else { 3151 $sff = $this->sfont_family; 3152 $sfs = $this->sfont_style; 3153 $sfz = $this->sfont_size; 3154 } 3155 3156 parent::Stroke($aImg,$ax,$ay); 3157 3158 3159 // For the builtin fonts we need to reduce the margins 3160 // since the bounding bx reported for the builtin fonts 3161 // are much larger than for the TTF fonts. 3162 if( $sff <= FF_FONT2 ) { 3163 $sx -= 2; 3164 $sy += 3; 3165 } 3166 3167 $aImg->SetTextAlign('left','bottom'); 3168 $aImg->SetFont($sff,$sfs,$sfz); 3169 $aImg->PushColor($this->color); 3170 $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left'); 3171 $aImg->PopColor(); 3422 // cases to handle the alignmewnt specified since that will 3423 // determine how we can interpret the x,y coordinates 3424 3425 $w = parent::GetWidth($aImg); 3426 $h = parent::GetTextHeight($aImg); 3427 switch( $this->valign ) { 3428 case 'top': 3429 $sy = $this->y; 3430 break; 3431 case 'center': 3432 $sy = $this->y - $h/2; 3433 break; 3434 case 'bottom': 3435 $sy = $this->y - $h; 3436 break; 3437 default: 3438 JpGraphError::RaiseL(25052);//('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text'); 3439 break; 3440 } 3441 3442 switch( $this->halign ) { 3443 case 'left': 3444 $sx = $this->x + $w; 3445 break; 3446 case 'center': 3447 $sx = $this->x + $w/2; 3448 break; 3449 case 'right': 3450 $sx = $this->x; 3451 break; 3452 default: 3453 JpGraphError::RaiseL(25053);//('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text'); 3454 break; 3455 } 3456 3457 $sx += $this->iSuperMargin; 3458 $sy += $this->iVertOverlap; 3459 3460 // Should we automatically determine the font or 3461 // has the user specified it explicetly? 3462 if( $this->sfont_family == '' ) { 3463 if( $this->font_family <= FF_FONT2 ) { 3464 if( $this->font_family == FF_FONT0 ) { 3465 $sff = FF_FONT0; 3466 } 3467 elseif( $this->font_family == FF_FONT1 ) { 3468 if( $this->font_style == FS_NORMAL ) { 3469 $sff = FF_FONT0; 3470 } 3471 else { 3472 $sff = FF_FONT1; 3473 } 3474 } 3475 else { 3476 $sff = FF_FONT1; 3477 } 3478 $sfs = $this->font_style; 3479 $sfz = $this->font_size; 3480 } 3481 else { 3482 // TTF fonts 3483 $sff = $this->font_family; 3484 $sfs = $this->font_style; 3485 $sfz = floor($this->font_size*$this->iSuperScale); 3486 if( $sfz < 8 ) $sfz = 8; 3487 } 3488 $this->sfont_family = $sff; 3489 $this->sfont_style = $sfs; 3490 $this->sfont_size = $sfz; 3491 } 3492 else { 3493 $sff = $this->sfont_family; 3494 $sfs = $this->sfont_style; 3495 $sfz = $this->sfont_size; 3496 } 3497 3498 parent::Stroke($aImg,$ax,$ay); 3499 3500 // For the builtin fonts we need to reduce the margins 3501 // since the bounding bx reported for the builtin fonts 3502 // are much larger than for the TTF fonts. 3503 if( $sff <= FF_FONT2 ) { 3504 $sx -= 2; 3505 $sy += 3; 3506 } 3507 3508 $aImg->SetTextAlign('left','bottom'); 3509 $aImg->SetFont($sff,$sfs,$sfz); 3510 $aImg->PushColor($this->color); 3511 $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left'); 3512 $aImg->PopColor(); 3172 3513 } 3173 3514 } … … 3181 3522 protected $img; 3182 3523 protected $scale; 3183 protected $ grid_color='#DDDDDD',$grid_mincolor='#DDDDDD';3184 protected $ type="solid";3185 protected $show=false, $showMinor=false,$ weight=1;3524 protected $majorcolor='#CCCCCC',$minorcolor='#DDDDDD'; 3525 protected $majortype='solid',$minortype='solid'; 3526 protected $show=false, $showMinor=false,$majorweight=1,$minorweight=1; 3186 3527 protected $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF'); 3187 //--------------- 3188 // CONSTRUCTOR 3189 function Grid($aAxis) { 3190 $this->scale = $aAxis->scale; 3191 $this->img = $aAxis->img; 3192 } 3193 //--------------- 3194 // PUBLIC METHODS 3528 3529 function __construct($aAxis) { 3530 $this->scale = $aAxis->scale; 3531 $this->img = $aAxis->img; 3532 } 3533 3195 3534 function SetColor($aMajColor,$aMinColor=false) { 3196 $this->grid_color=$aMajColor; 3197 if( $aMinColor === false ) 3198 $aMinColor = $aMajColor ; 3199 $this->grid_mincolor = $aMinColor; 3200 } 3201 3202 function SetWeight($aWeight) { 3203 $this->weight=$aWeight; 3204 } 3205 3535 $this->majorcolor=$aMajColor; 3536 if( $aMinColor === false ) { 3537 $aMinColor = $aMajColor ; 3538 } 3539 $this->minorcolor = $aMinColor; 3540 } 3541 3542 function SetWeight($aMajorWeight,$aMinorWeight=1) { 3543 $this->majorweight=$aMajorWeight; 3544 $this->minorweight=$aMinorWeight; 3545 } 3546 3206 3547 // Specify if grid should be dashed, dotted or solid 3207 function SetLineStyle($aType) { 3208 $this->type = $aType; 3209 } 3210 3548 function SetLineStyle($aMajorType,$aMinorType='solid') { 3549 $this->majortype = $aMajorType; 3550 $this->minortype = $aMinorType; 3551 } 3552 3553 function SetStyle($aMajorType,$aMinorType='solid') { 3554 $this->SetLineStyle($aMajorType,$aMinorType); 3555 } 3556 3211 3557 // Decide if both major and minor grid should be displayed 3212 3558 function Show($aShowMajor=true,$aShowMinor=false) { 3213 3214 3215 } 3216 3559 $this->show=$aShowMajor; 3560 $this->showMinor=$aShowMinor; 3561 } 3562 3217 3563 function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') { 3218 3219 3220 } 3221 3564 $this->fill = $aFlg; 3565 $this->fillcolor = array( $aColor1, $aColor2 ); 3566 } 3567 3222 3568 // Display the grid 3223 3569 function Stroke() { 3224 if( $this->showMinor && !$this->scale->textscale ) { 3225 $tmp = $this->grid_color; 3226 $this->grid_color = $this->grid_mincolor; 3227 $this->DoStroke($this->scale->ticks->ticks_pos); 3228 3229 $this->grid_color = $tmp; 3230 $this->DoStroke($this->scale->ticks->maj_ticks_pos); 3231 } 3232 else { 3233 $this->DoStroke($this->scale->ticks->maj_ticks_pos); 3234 } 3235 } 3236 3237 //-------------- 3238 // Private methods 3570 if( $this->showMinor && !$this->scale->textscale ) { 3571 $this->DoStroke($this->scale->ticks->ticks_pos,$this->minortype,$this->minorcolor,$this->minorweight); 3572 $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight); 3573 } 3574 else { 3575 $this->DoStroke($this->scale->ticks->maj_ticks_pos,$this->majortype,$this->majorcolor,$this->majorweight); 3576 } 3577 } 3578 3579 //-------------- 3580 // Private methods 3239 3581 // Draw the grid 3240 function DoStroke($aTicksPos) { 3241 if( !$this->show ) 3242 return; 3243 $nbrgrids = count($aTicksPos); 3244 3245 if( $this->scale->type=="y" ) { 3246 $xl=$this->img->left_margin; 3247 $xr=$this->img->width-$this->img->right_margin; 3248 3249 if( $this->fill ) { 3250 // Draw filled areas 3251 $y2 = $aTicksPos[0]; 3252 $i=1; 3253 while( $i < $nbrgrids ) { 3254 $y1 = $y2; 3255 $y2 = $aTicksPos[$i++]; 3256 $this->img->SetColor($this->fillcolor[$i & 1]); 3257 $this->img->FilledRectangle($xl,$y1,$xr,$y2); 3258 } 3259 } 3260 3261 $this->img->SetColor($this->grid_color); 3262 $this->img->SetLineWeight($this->weight); 3263 3264 // Draw grid lines 3265 switch( $this->type ) { 3266 case "solid": $style = LINESTYLE_SOLID; break; 3267 case "dotted": $style = LINESTYLE_DOTTED; break; 3268 case "dashed": $style = LINESTYLE_DASHED; break; 3269 case "longdashed": $style = LINESTYLE_LONGDASH; break; 3270 default: 3271 $style = LINESTYLE_SOLID; break; 3272 } 3273 3274 for($i=0; $i < $nbrgrids; ++$i) { 3275 $y=$aTicksPos[$i]; 3276 $this->img->StyleLine($xl,$y,$xr,$y,$style); 3277 } 3278 } 3279 elseif( $this->scale->type=="x" ) { 3280 $yu=$this->img->top_margin; 3281 $yl=$this->img->height-$this->img->bottom_margin; 3282 $limit=$this->img->width-$this->img->right_margin; 3283 3284 if( $this->fill ) { 3285 // Draw filled areas 3286 $x2 = $aTicksPos[0]; 3287 $i=1; 3288 while( $i < $nbrgrids ) { 3289 $x1 = $x2; 3290 $x2 = min($aTicksPos[$i++],$limit) ; 3291 $this->img->SetColor($this->fillcolor[$i & 1]); 3292 $this->img->FilledRectangle($x1,$yu,$x2,$yl); 3293 } 3294 } 3295 3296 $this->img->SetColor($this->grid_color); 3297 $this->img->SetLineWeight($this->weight); 3298 3299 // We must also test for limit since we might have 3300 // an offset and the number of ticks is calculated with 3301 // assumption offset==0 so we might end up drawing one 3302 // to many gridlines 3303 $i=0; 3304 $x=$aTicksPos[$i]; 3305 while( $i<count($aTicksPos) && ($x=$aTicksPos[$i]) <= $limit ) { 3306 if( $this->type == "solid" ) 3307 $this->img->Line($x,$yl,$x,$yu); 3308 elseif( $this->type == "dotted" ) 3309 $this->img->DashedLine($x,$yl,$x,$yu,1,6); 3310 elseif( $this->type == "dashed" ) 3311 $this->img->DashedLine($x,$yl,$x,$yu,2,4); 3312 elseif( $this->type == "longdashed" ) 3313 $this->img->DashedLine($x,$yl,$x,$yu,8,6); 3314 ++$i; 3315 } 3316 } 3317 else { 3318 JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']'); 3319 } 3320 return true; 3582 function DoStroke($aTicksPos,$aType,$aColor,$aWeight) { 3583 if( !$this->show ) return; 3584 $nbrgrids = count($aTicksPos); 3585 3586 if( $this->scale->type == 'y' ) { 3587 $xl=$this->img->left_margin; 3588 $xr=$this->img->width-$this->img->right_margin; 3589 3590 if( $this->fill ) { 3591 // Draw filled areas 3592 $y2 = !empty($aTicksPos) ? $aTicksPos[0] : null; 3593 $i=1; 3594 while( $i < $nbrgrids ) { 3595 $y1 = $y2; 3596 $y2 = $aTicksPos[$i++]; 3597 $this->img->SetColor($this->fillcolor[$i & 1]); 3598 $this->img->FilledRectangle($xl,$y1,$xr,$y2); 3599 } 3600 } 3601 3602 $this->img->SetColor($aColor); 3603 $this->img->SetLineWeight($aWeight); 3604 3605 // Draw grid lines 3606 switch( $aType ) { 3607 case 'solid': $style = LINESTYLE_SOLID; break; 3608 case 'dotted': $style = LINESTYLE_DOTTED; break; 3609 case 'dashed': $style = LINESTYLE_DASHED; break; 3610 case 'longdashed': $style = LINESTYLE_LONGDASH; break; 3611 default: 3612 $style = LINESTYLE_SOLID; break; 3613 } 3614 3615 for($i=0; $i < $nbrgrids; ++$i) { 3616 $y=$aTicksPos[$i]; 3617 $this->img->StyleLine($xl,$y,$xr,$y,$style,true); 3618 } 3619 } 3620 elseif( $this->scale->type == 'x' ) { 3621 $yu=$this->img->top_margin; 3622 $yl=$this->img->height-$this->img->bottom_margin; 3623 $limit=$this->img->width-$this->img->right_margin; 3624 3625 if( $this->fill ) { 3626 // Draw filled areas 3627 $x2 = $aTicksPos[0]; 3628 $i=1; 3629 while( $i < $nbrgrids ) { 3630 $x1 = $x2; 3631 $x2 = min($aTicksPos[$i++],$limit) ; 3632 $this->img->SetColor($this->fillcolor[$i & 1]); 3633 $this->img->FilledRectangle($x1,$yu,$x2,$yl); 3634 } 3635 } 3636 3637 $this->img->SetColor($aColor); 3638 $this->img->SetLineWeight($aWeight); 3639 3640 // We must also test for limit since we might have 3641 // an offset and the number of ticks is calculated with 3642 // assumption offset==0 so we might end up drawing one 3643 // to many gridlines 3644 $i=0; 3645 $x=$aTicksPos[$i]; 3646 while( $i<count($aTicksPos) && ($x=$aTicksPos[$i]) <= $limit ) { 3647 if ( $aType == 'solid' ) $this->img->Line($x,$yl,$x,$yu); 3648 elseif( $aType == 'dotted' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,1,6); 3649 elseif( $aType == 'dashed' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,2,4); 3650 elseif( $aType == 'longdashed' ) $this->img->DashedLineForGrid($x,$yl,$x,$yu,8,6); 3651 ++$i; 3652 } 3653 } 3654 else { 3655 JpGraphError::RaiseL(25054,$this->scale->type);//('Internal error: Unknown grid axis ['.$this->scale->type.']'); 3656 } 3657 return true; 3321 3658 } 3322 3659 } // Class … … 3328 3665 // several occasion must know wheter it's an X or Y axis. 3329 3666 // This was a design decision to make the code easier to 3330 // follow. 3667 // follow. 3331 3668 //=================================================== 3332 3669 class AxisPrototype { 3333 public $scale=null; 3670 public $scale=null; 3334 3671 public $img=null; 3335 3672 public $hide=false,$hide_labels=false; 3336 3673 public $title=null; 3337 public $font_family=FF_ FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0;3674 public $font_family=FF_DEFAULT,$font_style=FS_NORMAL,$font_size=8,$label_angle=0; 3338 3675 public $tick_step=1; 3339 3676 public $pos = false; … … 3348 3685 protected $labelPos=0; // Which side of the axis should the labels be? 3349 3686 protected $title_adjust,$title_margin,$title_side=SIDE_LEFT; 3350 protected $tick_label_margin= 7;3687 protected $tick_label_margin=5; 3351 3688 protected $label_halign = '',$label_valign = '', $label_para_align='left'; 3352 3689 protected $hide_line=false; 3353 3690 protected $iDeltaAbsPos=0; 3354 3691 3355 //--------------- 3356 // CONSTRUCTOR 3357 function Axis($img,$aScale,$color=array(0,0,0)) { 3358 $this->img = $img; 3359 $this->scale = $aScale; 3360 $this->color = $color; 3361 $this->title=new Text(""); 3362 3363 if( $aScale->type=="y" ) { 3364 $this->title_margin = 25; 3365 $this->title_adjust="middle"; 3366 $this->title->SetOrientation(90); 3367 $this->tick_label_margin=7; 3368 $this->labelPos=SIDE_LEFT; 3369 } 3370 else { 3371 $this->title_margin = 5; 3372 $this->title_adjust="high"; 3373 $this->title->SetOrientation(0); 3374 $this->tick_label_margin=7; 3375 $this->labelPos=SIDE_DOWN; 3376 $this->title_side=SIDE_DOWN; 3377 } 3378 } 3379 //--------------- 3380 // PUBLIC METHODS 3381 3692 function __construct($img,$aScale,$color = array(0,0,0)) { 3693 $this->img = $img; 3694 $this->scale = $aScale; 3695 $this->color = $color; 3696 $this->title=new Text(''); 3697 3698 if( $aScale->type == 'y' ) { 3699 $this->title_margin = 25; 3700 $this->title_adjust = 'middle'; 3701 $this->title->SetOrientation(90); 3702 $this->tick_label_margin=7; 3703 $this->labelPos=SIDE_LEFT; 3704 } 3705 else { 3706 $this->title_margin = 5; 3707 $this->title_adjust = 'high'; 3708 $this->title->SetOrientation(0); 3709 $this->tick_label_margin=5; 3710 $this->labelPos=SIDE_DOWN; 3711 $this->title_side=SIDE_DOWN; 3712 } 3713 } 3714 3382 3715 function SetLabelFormat($aFormStr) { 3383 3716 $this->scale->ticks->SetLabelFormat($aFormStr); 3384 3717 } 3385 3718 3386 3719 function SetLabelFormatString($aFormStr,$aDate=false) { 3387 3388 } 3389 3720 $this->scale->ticks->SetLabelFormat($aFormStr,$aDate); 3721 } 3722 3390 3723 function SetLabelFormatCallback($aFuncName) { 3391 3392 } 3393 3394 function SetLabelAlign($aHAlign,$aVAlign= "top",$aParagraphAlign='left') {3395 3396 3397 3398 } 3724 $this->scale->ticks->SetFormatCallback($aFuncName); 3725 } 3726 3727 function SetLabelAlign($aHAlign,$aVAlign='top',$aParagraphAlign='left') { 3728 $this->label_halign = $aHAlign; 3729 $this->label_valign = $aVAlign; 3730 $this->label_para_align = $aParagraphAlign; 3731 } 3399 3732 3400 3733 // Don't display the first label 3401 3734 function HideFirstTickLabel($aShow=false) { 3402 3735 $this->show_first_label=$aShow; 3403 3736 } 3404 3737 3405 3738 function HideLastTickLabel($aShow=false) { 3406 3739 $this->show_last_label=$aShow; 3407 3740 } 3408 3741 3409 3742 // Manually specify the major and (optional) minor tick position and labels 3410 3743 function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { 3411 3744 $this->scale->ticks->SetTickPositions($aMajPos,$aMinPos,$aLabels); 3412 3745 } 3413 3746 3414 3747 // Manually specify major tick positions and optional labels 3415 3748 function SetMajTickPositions($aMajPos,$aLabels=NULL) { 3416 3749 $this->scale->ticks->SetTickPositions($aMajPos,NULL,$aLabels); 3417 3750 } 3418 3751 3419 3752 // Hide minor or major tick marks 3420 3753 function HideTicks($aHideMinor=true,$aHideMajor=true) { 3421 3422 3754 $this->scale->ticks->SupressMinorTickMarks($aHideMinor); 3755 $this->scale->ticks->SupressTickMarks($aHideMajor); 3423 3756 } 3424 3757 3425 3758 // Hide zero label 3426 3759 function HideZeroLabel($aFlag=true) { 3427 3428 } 3429 3760 $this->scale->ticks->SupressZeroLabel(); 3761 } 3762 3430 3763 function HideFirstLastLabel() { 3431 // The two first calls to ticks method will supress 3432 3433 3434 3435 3436 3437 3438 $this->show_first_label= false;3439 3440 } 3441 3764 // The two first calls to ticks method will supress 3765 // automatically generated scale values. However, that 3766 // will not affect manually specified value, e.g text-scales. 3767 // therefor we also make a kludge here to supress manually 3768 // specified scale labels. 3769 $this->scale->ticks->SupressLast(); 3770 $this->scale->ticks->SupressFirst(); 3771 $this->show_first_label = false; 3772 $this->show_last_label = false; 3773 } 3774 3442 3775 // Hide the axis 3443 3776 function Hide($aHide=true) { 3444 3777 $this->hide=$aHide; 3445 3778 } 3446 3779 3447 3780 // Hide the actual axis-line, but still print the labels 3448 3781 function HideLine($aHide=true) { 3449 3782 $this->hide_line = $aHide; 3450 3783 } 3451 3784 3452 3785 function HideLabels($aHide=true) { 3453 $this->hide_labels = $aHide; 3454 } 3455 3786 $this->hide_labels = $aHide; 3787 } 3456 3788 3457 3789 // Weight of axis 3458 3790 function SetWeight($aWeight) { 3459 3791 $this->weight = $aWeight; 3460 3792 } 3461 3793 3462 3794 // Axis color 3463 3795 function SetColor($aColor,$aLabelColor=false) { 3464 3465 3466 3467 } 3468 3796 $this->color = $aColor; 3797 if( !$aLabelColor ) $this->label_color = $aColor; 3798 else $this->label_color = $aLabelColor; 3799 } 3800 3469 3801 // Title on axis 3470 function SetTitle($aTitle,$aAdjustAlign= "high") {3471 3472 3473 } 3474 3802 function SetTitle($aTitle,$aAdjustAlign='high') { 3803 $this->title->Set($aTitle); 3804 $this->title_adjust=$aAdjustAlign; 3805 } 3806 3475 3807 // Specify distance from the axis 3476 3808 function SetTitleMargin($aMargin) { 3477 3478 } 3479 3809 $this->title_margin=$aMargin; 3810 } 3811 3480 3812 // Which side of the axis should the axis title be? 3481 3813 function SetTitleSide($aSideOfAxis) { 3482 $this->title_side = $aSideOfAxis; 3483 } 3484 3485 // Utility function to set the direction for tick marks 3486 function SetTickDirection($aDir) { 3487 // Will be deprecated from 1.7 3488 if( ERR_DEPRECATED ) 3489 JpGraphError::RaiseL(25055);//('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead'); 3490 $this->scale->ticks->SetSide($aDir); 3491 } 3492 3814 $this->title_side = $aSideOfAxis; 3815 } 3816 3493 3817 function SetTickSide($aDir) { 3494 $this->scale->ticks->SetSide($aDir); 3495 } 3496 3818 $this->scale->ticks->SetSide($aDir); 3819 } 3820 3821 function SetTickSize($aMajSize,$aMinSize=3) { 3822 $this->scale->ticks->SetSize($aMajSize,$aMinSize=3); 3823 } 3824 3497 3825 // Specify text labels for the ticks. One label for each data point 3498 3826 function SetTickLabels($aLabelArray,$aLabelColorArray=null) { 3499 $this->ticks_label = $aLabelArray; 3500 $this->ticks_label_colors = $aLabelColorArray; 3501 } 3502 3503 // How far from the axis should the labels be drawn 3504 function SetTickLabelMargin($aMargin) { 3505 if( ERR_DEPRECATED ) 3506 JpGraphError::RaiseL(25056);//('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.'); 3507 $this->tick_label_margin=$aMargin; 3827 $this->ticks_label = $aLabelArray; 3828 $this->ticks_label_colors = $aLabelColorArray; 3508 3829 } 3509 3830 3510 3831 function SetLabelMargin($aMargin) { 3511 3512 } 3513 3832 $this->tick_label_margin=$aMargin; 3833 } 3834 3514 3835 // Specify that every $step of the ticks should be displayed starting 3515 3836 // at $start 3516 // DEPRECATED FUNCTION: USE SetTextTickInterval() INSTEAD3517 function SetTextTicks($step,$start=0) {3518 JpGraphError::RaiseL(25057);//(" SetTextTicks() is deprecated. Use SetTextTickInterval() instead.");3519 }3520 3521 // Specify that every $step of the ticks should be displayed starting3522 // at $start3523 3837 function SetTextTickInterval($aStep,$aStart=0) { 3524 3525 3526 } 3527 3528 // Specify that every $step tick mark should have a label 3838 $this->scale->ticks->SetTextLabelStart($aStart); 3839 $this->tick_step=$aStep; 3840 } 3841 3842 // Specify that every $step tick mark should have a label 3529 3843 // should be displayed starting 3530 3844 function SetTextLabelInterval($aStep) { 3531 if( $aStep < 1 ) 3532 JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1."); 3533 $this->label_step=$aStep; 3534 } 3535 3536 // Which side of the axis should the labels be on? 3537 function SetLabelPos($aSidePos) { 3538 // This will be deprecated from 1.7 3539 if( ERR_DEPRECATED ) 3540 JpGraphError::RaiseL(25059);//('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.'); 3541 $this->labelPos=$aSidePos; 3542 } 3543 3845 if( $aStep < 1 ) { 3846 JpGraphError::RaiseL(25058);//(" Text label interval must be specified >= 1."); 3847 } 3848 $this->label_step=$aStep; 3849 } 3850 3544 3851 function SetLabelSide($aSidePos) { 3545 3852 $this->labelPos=$aSidePos; 3546 3853 } 3547 3854 3548 3855 // Set the font 3549 3856 function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) { 3550 3551 3552 3857 $this->font_family = $aFamily; 3858 $this->font_style = $aStyle; 3859 $this->font_size = $aSize; 3553 3860 } 3554 3861 3555 3862 // Position for axis line on the "other" scale 3556 3863 function SetPos($aPosOnOtherScale) { 3557 3558 } 3559 3560 // Set the position of the axis to be X-pixels delta to the right 3864 $this->pos=$aPosOnOtherScale; 3865 } 3866 3867 // Set the position of the axis to be X-pixels delta to the right 3561 3868 // of the max X-position (used to position the multiple Y-axis) 3562 3869 function SetPosAbsDelta($aDelta) { 3563 $this->iDeltaAbsPos=$aDelta;3564 } 3565 3870 $this->iDeltaAbsPos=$aDelta; 3871 } 3872 3566 3873 // Specify the angle for the tick labels 3567 3874 function SetLabelAngle($aAngle) { 3568 3569 } 3875 $this->label_angle = $aAngle; 3876 } 3570 3877 3571 3878 } // Class … … 3578 3885 // several occasion must know wheter it's an X or Y axis. 3579 3886 // This was a design decision to make the code easier to 3580 // follow. 3887 // follow. 3581 3888 //=================================================== 3582 3889 class Axis extends AxisPrototype { 3583 3890 3584 function Axis($img,$aScale,$color=array(0,0,0)) {3585 parent::Axis($img,$aScale,$color);3586 } 3587 3891 function __construct($img,$aScale,$color='black') { 3892 parent::__construct($img,$aScale,$color); 3893 } 3894 3588 3895 // Stroke the axis. 3589 function Stroke($aOtherAxisScale,$aStrokeLabels=true) { 3590 if( $this->hide ) return; 3591 if( is_numeric($this->pos) ) { 3592 $pos=$aOtherAxisScale->Translate($this->pos); 3593 } 3594 else { // Default to minimum of other scale if pos not set 3595 if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos=="min" ) { 3596 $pos = $aOtherAxisScale->scale_abs[0]; 3597 } 3598 elseif($this->pos == "max") { 3599 $pos = $aOtherAxisScale->scale_abs[1]; 3600 } 3601 else { // If negative set x-axis at 0 3602 $this->pos=0; 3603 $pos=$aOtherAxisScale->Translate(0); 3604 } 3605 } 3606 $pos += $this->iDeltaAbsPos; 3607 $this->img->SetLineWeight($this->weight); 3608 $this->img->SetColor($this->color); 3609 $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); 3610 if( $this->scale->type == "x" ) { 3611 if( !$this->hide_line ) 3612 $this->img->FilledRectangle($this->img->left_margin,$pos, 3613 $this->img->width-$this->img->right_margin,$pos+$this->weight-1); 3614 if( $this->title_side == SIDE_DOWN ) { 3615 $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; 3616 $yalign = 'top'; 3617 } 3618 else { 3619 $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin; 3620 $yalign = 'bottom'; 3621 } 3622 3623 if( $this->title_adjust=='high' ) 3624 $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign); 3625 elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' ) 3626 $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign); 3627 elseif($this->title_adjust=='low') 3628 $this->title->SetPos($this->img->left_margin,$y,'left',$yalign); 3629 else { 3630 JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); 3631 } 3632 } 3633 elseif( $this->scale->type == "y" ) { 3634 // Add line weight to the height of the axis since 3635 // the x-axis could have a width>1 and we want the axis to fit nicely together. 3636 if( !$this->hide_line ) 3637 $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin, 3638 $pos,$this->img->height-$this->img->bottom_margin+$this->weight-1); 3639 $x=$pos ; 3640 if( $this->title_side == SIDE_LEFT ) { 3641 $x -= $this->title_margin; 3642 $x -= $this->title->margin; 3643 $halign="right"; 3644 } 3645 else { 3646 $x += $this->title_margin; 3647 $x += $this->title->margin; 3648 $halign="left"; 3649 } 3650 // If the user has manually specified an hor. align 3651 // then we override the automatic settings with this 3652 // specifed setting. Since default is 'left' we compare 3653 // with that. (This means a manually set 'left' align 3654 // will have no effect.) 3655 if( $this->title->halign != 'left' ) 3656 $halign = $this->title->halign; 3657 if( $this->title_adjust=="high" ) 3658 $this->title->SetPos($x,$this->img->top_margin,$halign,"top"); 3659 elseif($this->title_adjust=="middle" || $this->title_adjust=="center") 3660 $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center"); 3661 elseif($this->title_adjust=="low") 3662 $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,"bottom"); 3663 else 3664 JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')'); 3665 3666 } 3667 $this->scale->ticks->Stroke($this->img,$this->scale,$pos); 3668 if( $aStrokeLabels ) { 3669 if( !$this->hide_labels ) 3670 $this->StrokeLabels($pos); 3671 $this->title->Stroke($this->img); 3672 } 3673 } 3674 3675 //--------------- 3676 // PRIVATE METHODS 3896 function Stroke($aOtherAxisScale,$aStrokeLabels=true) { 3897 if( $this->hide ) 3898 return; 3899 if( is_numeric($this->pos) ) { 3900 $pos=$aOtherAxisScale->Translate($this->pos); 3901 } 3902 else { // Default to minimum of other scale if pos not set 3903 if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos == 'min' ) { 3904 $pos = $aOtherAxisScale->scale_abs[0]; 3905 } 3906 elseif($this->pos == "max") { 3907 $pos = $aOtherAxisScale->scale_abs[1]; 3908 } 3909 else { // If negative set x-axis at 0 3910 $this->pos=0; 3911 $pos=$aOtherAxisScale->Translate(0); 3912 } 3913 } 3914 3915 $pos += $this->iDeltaAbsPos; 3916 $this->img->SetLineWeight($this->weight); 3917 $this->img->SetColor($this->color); 3918 $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); 3919 3920 if( $this->scale->type == "x" ) { 3921 if( !$this->hide_line ) { 3922 // Stroke X-axis 3923 $this->img->FilledRectangle( 3924 $this->img->left_margin, 3925 $pos, 3926 $this->img->width - $this->img->right_margin, 3927 $pos + $this->weight-1 3928 ); 3929 } 3930 if( $this->title_side == SIDE_DOWN ) { 3931 $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; 3932 $yalign = 'top'; 3933 } 3934 else { 3935 $y = $pos - $this->img->GetFontHeight() - $this->title_margin - $this->title->margin; 3936 $yalign = 'bottom'; 3937 } 3938 3939 if( $this->title_adjust=='high' ) { 3940 $this->title->SetPos($this->img->width-$this->img->right_margin,$y,'right',$yalign); 3941 } 3942 elseif( $this->title_adjust=='middle' || $this->title_adjust=='center' ) { 3943 $this->title->SetPos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,'center',$yalign); 3944 } 3945 elseif($this->title_adjust=='low') { 3946 $this->title->SetPos($this->img->left_margin,$y,'left',$yalign); 3947 } 3948 else { 3949 JpGraphError::RaiseL(25060,$this->title_adjust);//('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); 3950 } 3951 } 3952 elseif( $this->scale->type == "y" ) { 3953 // Add line weight to the height of the axis since 3954 // the x-axis could have a width>1 and we want the axis to fit nicely together. 3955 if( !$this->hide_line ) { 3956 // Stroke Y-axis 3957 $this->img->FilledRectangle( 3958 $pos - $this->weight + 1, 3959 $this->img->top_margin, 3960 $pos, 3961 $this->img->height - $this->img->bottom_margin + $this->weight - 1 3962 ); 3963 } 3964 3965 $x=$pos ; 3966 if( $this->title_side == SIDE_LEFT ) { 3967 $x -= $this->title_margin; 3968 $x -= $this->title->margin; 3969 $halign = 'right'; 3970 } 3971 else { 3972 $x += $this->title_margin; 3973 $x += $this->title->margin; 3974 $halign = 'left'; 3975 } 3976 // If the user has manually specified an hor. align 3977 // then we override the automatic settings with this 3978 // specifed setting. Since default is 'left' we compare 3979 // with that. (This means a manually set 'left' align 3980 // will have no effect.) 3981 if( $this->title->halign != 'left' ) { 3982 $halign = $this->title->halign; 3983 } 3984 if( $this->title_adjust == 'high' ) { 3985 $this->title->SetPos($x,$this->img->top_margin,$halign,'top'); 3986 } 3987 elseif($this->title_adjust=='middle' || $this->title_adjust=='center') { 3988 $this->title->SetPos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center"); 3989 } 3990 elseif($this->title_adjust=='low') { 3991 $this->title->SetPos($x,$this->img->height-$this->img->bottom_margin,$halign,'bottom'); 3992 } 3993 else { 3994 JpGraphError::RaiseL(25061,$this->title_adjust);//('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')'); 3995 } 3996 } 3997 $this->scale->ticks->Stroke($this->img,$this->scale,$pos); 3998 if( $aStrokeLabels ) { 3999 if( !$this->hide_labels ) { 4000 $this->StrokeLabels($pos); 4001 } 4002 $this->title->Stroke($this->img); 4003 } 4004 } 4005 4006 //--------------- 4007 // PRIVATE METHODS 3677 4008 // Draw all the tick labels on major tick marks 3678 4009 function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) { 3679 4010 3680 $this->img->SetColor($this->label_color); 3681 $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); 3682 $yoff=$this->img->GetFontHeight()/2; 3683 3684 // Only draw labels at major tick marks 3685 $nbr = count($this->scale->ticks->maj_ticks_label); 3686 3687 // We have the option to not-display the very first mark 3688 // (Usefull when the first label might interfere with another 3689 // axis.) 3690 $i = $this->show_first_label ? 0 : 1 ; 3691 if( !$this->show_last_label ) --$nbr; 3692 // Now run through all labels making sure we don't overshoot the end 3693 // of the scale. 3694 $ncolor=0; 3695 if( isset($this->ticks_label_colors) ) 3696 $ncolor=count($this->ticks_label_colors); 3697 while( $i<$nbr ) { 3698 // $tpos holds the absolute text position for the label 3699 $tpos=$this->scale->ticks->maj_ticklabels_pos[$i]; 3700 3701 // Note. the $limit is only used for the x axis since we 3702 // might otherwise overshoot if the scale has been centered 3703 // This is due to us "loosing" the last tick mark if we center. 3704 if( $this->scale->type=="x" && $tpos > $this->img->width-$this->img->right_margin+1 ) { 3705 return; 3706 } 3707 // we only draw every $label_step label 3708 if( ($i % $this->label_step)==0 ) { 3709 3710 // Set specific label color if specified 3711 if( $ncolor > 0 ) 3712 $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); 3713 3714 // If the label has been specified use that and in other case 3715 // just label the mark with the actual scale value 3716 $m=$this->scale->ticks->GetMajor(); 3717 3718 // ticks_label has an entry for each data point and is the array 3719 // that holds the labels set by the user. If the user hasn't 3720 // specified any values we use whats in the automatically asigned 3721 // labels in the maj_ticks_label 3722 if( isset($this->ticks_label[$i*$m]) ) 3723 $label=$this->ticks_label[$i*$m]; 3724 else { 3725 if( $aAbsLabel ) 3726 $label=abs($this->scale->ticks->maj_ticks_label[$i]); 3727 else 3728 $label=$this->scale->ticks->maj_ticks_label[$i]; 3729 if( $this->scale->textscale && $this->scale->ticks->label_formfunc == '' ) { 3730 ++$label; 3731 } 3732 } 3733 3734 if( $this->scale->type == "x" ) { 3735 if( $this->labelPos == SIDE_DOWN ) { 3736 if( $this->label_angle==0 || $this->label_angle==90 ) { 3737 if( $this->label_halign=='' && $this->label_valign=='') 3738 $this->img->SetTextAlign('center','top'); 3739 else 3740 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 3741 3742 } 3743 else { 3744 if( $this->label_halign=='' && $this->label_valign=='') 3745 $this->img->SetTextAlign("right","top"); 3746 else 3747 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 3748 } 3749 $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin+1,$label, 3750 $this->label_angle,$this->label_para_align); 3751 } 3752 else { 3753 if( $this->label_angle==0 || $this->label_angle==90 ) { 3754 if( $this->label_halign=='' && $this->label_valign=='') 3755 $this->img->SetTextAlign("center","bottom"); 3756 else 3757 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 3758 } 3759 else { 3760 if( $this->label_halign=='' && $this->label_valign=='') 3761 $this->img->SetTextAlign("right","bottom"); 3762 else 3763 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 3764 } 3765 $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label, 3766 $this->label_angle,$this->label_para_align); 3767 } 3768 } 3769 else { 3770 // scale->type == "y" 3771 //if( $this->label_angle!=0 ) 3772 //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis"); 3773 if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis 3774 if( $this->label_halign=='' && $this->label_valign=='') 3775 $this->img->SetTextAlign("right","center"); 3776 else 3777 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 3778 $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); 3779 } 3780 else { // To the right of the y-axis 3781 if( $this->label_halign=='' && $this->label_valign=='') 3782 $this->img->SetTextAlign("left","center"); 3783 else 3784 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 3785 $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); 3786 } 3787 } 3788 } 3789 ++$i; 3790 } 3791 } 4011 if( is_array($this->label_color) && count($this->label_color) > 3 ) { 4012 $this->ticks_label_colors = $this->label_color; 4013 $this->img->SetColor($this->label_color[0]); 4014 } 4015 else { 4016 $this->img->SetColor($this->label_color); 4017 } 4018 $this->img->SetFont($this->font_family,$this->font_style,$this->font_size); 4019 $yoff=$this->img->GetFontHeight()/2; 4020 4021 // Only draw labels at major tick marks 4022 $nbr = count($this->scale->ticks->maj_ticks_label); 4023 4024 // We have the option to not-display the very first mark 4025 // (Usefull when the first label might interfere with another 4026 // axis.) 4027 $i = $this->show_first_label ? 0 : 1 ; 4028 if( !$this->show_last_label ) { 4029 --$nbr; 4030 } 4031 // Now run through all labels making sure we don't overshoot the end 4032 // of the scale. 4033 $ncolor=0; 4034 if( isset($this->ticks_label_colors) ) { 4035 $ncolor=count($this->ticks_label_colors); 4036 } 4037 while( $i < $nbr ) { 4038 // $tpos holds the absolute text position for the label 4039 $tpos=$this->scale->ticks->maj_ticklabels_pos[$i]; 4040 4041 // Note. the $limit is only used for the x axis since we 4042 // might otherwise overshoot if the scale has been centered 4043 // This is due to us "loosing" the last tick mark if we center. 4044 if( $this->scale->type == 'x' && $tpos > $this->img->width-$this->img->right_margin+1 ) { 4045 return; 4046 } 4047 // we only draw every $label_step label 4048 if( ($i % $this->label_step)==0 ) { 4049 4050 // Set specific label color if specified 4051 if( $ncolor > 0 ) { 4052 $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]); 4053 } 4054 4055 // If the label has been specified use that and in other case 4056 // just label the mark with the actual scale value 4057 $m=$this->scale->ticks->GetMajor(); 4058 4059 // ticks_label has an entry for each data point and is the array 4060 // that holds the labels set by the user. If the user hasn't 4061 // specified any values we use whats in the automatically asigned 4062 // labels in the maj_ticks_label 4063 if( isset($this->ticks_label[$i*$m]) ) { 4064 $label=$this->ticks_label[$i*$m]; 4065 } 4066 else { 4067 if( $aAbsLabel ) { 4068 $label=abs($this->scale->ticks->maj_ticks_label[$i]); 4069 } 4070 else { 4071 $label=$this->scale->ticks->maj_ticks_label[$i]; 4072 } 4073 4074 // We number the scale from 1 and not from 0 so increase by one 4075 if( $this->scale->textscale && 4076 $this->scale->ticks->label_formfunc == '' && 4077 ! $this->scale->ticks->HaveManualLabels() ) { 4078 4079 ++$label; 4080 4081 } 4082 } 4083 4084 if( $this->scale->type == "x" ) { 4085 if( $this->labelPos == SIDE_DOWN ) { 4086 if( $this->label_angle==0 || $this->label_angle==90 ) { 4087 if( $this->label_halign=='' && $this->label_valign=='') { 4088 $this->img->SetTextAlign('center','top'); 4089 } 4090 else { 4091 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 4092 } 4093 4094 } 4095 else { 4096 if( $this->label_halign=='' && $this->label_valign=='') { 4097 $this->img->SetTextAlign("right","top"); 4098 } 4099 else { 4100 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 4101 } 4102 } 4103 $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label, 4104 $this->label_angle,$this->label_para_align); 4105 } 4106 else { 4107 if( $this->label_angle==0 || $this->label_angle==90 ) { 4108 if( $this->label_halign=='' && $this->label_valign=='') { 4109 $this->img->SetTextAlign("center","bottom"); 4110 } 4111 else { 4112 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 4113 } 4114 } 4115 else { 4116 if( $this->label_halign=='' && $this->label_valign=='') { 4117 $this->img->SetTextAlign("right","bottom"); 4118 } 4119 else { 4120 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 4121 } 4122 } 4123 $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin-1,$label, 4124 $this->label_angle,$this->label_para_align); 4125 } 4126 } 4127 else { 4128 // scale->type == "y" 4129 //if( $this->label_angle!=0 ) 4130 //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis"); 4131 if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis 4132 if( $this->label_halign=='' && $this->label_valign=='') { 4133 $this->img->SetTextAlign("right","center"); 4134 } 4135 else { 4136 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 4137 } 4138 $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); 4139 } 4140 else { // To the right of the y-axis 4141 if( $this->label_halign=='' && $this->label_valign=='') { 4142 $this->img->SetTextAlign("left","center"); 4143 } 4144 else { 4145 $this->img->SetTextAlign($this->label_halign,$this->label_valign); 4146 } 4147 $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align); 4148 } 4149 } 4150 } 4151 ++$i; 4152 } 4153 } 3792 4154 3793 4155 } … … 3805 4167 public $direction=1; // Should ticks be in(=1) the plot area or outside (=-1) 3806 4168 public $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false; 3807 public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), 3808 4169 public $maj_ticks_pos = array(), $maj_ticklabels_pos = array(), 4170 $ticks_pos = array(), $maj_ticks_label = array(); 3809 4171 public $precision; 3810 4172 … … 3813 4175 protected $is_set=false; 3814 4176 protected $supress_zerolabel=false,$supress_first=false; 3815 protected $mincolor= "",$majcolor="";4177 protected $mincolor='',$majcolor=''; 3816 4178 protected $weight=1; 3817 4179 protected $label_usedateformat=FALSE; 3818 4180 3819 //--------------- 3820 // CONSTRUCTOR 3821 function Ticks($aScale) { 3822 $this->scale=$aScale; 3823 $this->precision = -1; 3824 } 3825 3826 //--------------- 3827 // PUBLIC METHODS 4181 function __construct($aScale) { 4182 $this->scale=$aScale; 4183 $this->precision = -1; 4184 } 4185 3828 4186 // Set format string for automatic labels 3829 4187 function SetLabelFormat($aFormatString,$aDate=FALSE) { 3830 3831 3832 } 3833 4188 $this->label_formatstr=$aFormatString; 4189 $this->label_usedateformat=$aDate; 4190 } 4191 3834 4192 function SetLabelDateFormat($aFormatString) { 3835 3836 } 3837 4193 $this->label_dateformatstr=$aFormatString; 4194 } 4195 3838 4196 function SetFormatCallback($aCallbackFuncName) { 3839 3840 } 3841 4197 $this->label_formfunc = $aCallbackFuncName; 4198 } 4199 3842 4200 // Don't display the first zero label 3843 4201 function SupressZeroLabel($aFlag=true) { 3844 3845 } 3846 4202 $this->supress_zerolabel=$aFlag; 4203 } 4204 3847 4205 // Don't display minor tick marks 3848 4206 function SupressMinorTickMarks($aHide=true) { 3849 3850 } 3851 4207 $this->supress_minor_tickmarks=$aHide; 4208 } 4209 3852 4210 // Don't display major tick marks 3853 4211 function SupressTickMarks($aHide=true) { 3854 3855 } 3856 4212 $this->supress_tickmarks=$aHide; 4213 } 4214 3857 4215 // Hide the first tick mark 3858 4216 function SupressFirst($aHide=true) { 3859 3860 } 3861 4217 $this->supress_first=$aHide; 4218 } 4219 3862 4220 // Hide the last tick mark 3863 4221 function SupressLast($aHide=true) { 3864 4222 $this->supress_last=$aHide; 3865 4223 } 3866 4224 3867 4225 // Size (in pixels) of minor tick marks 3868 4226 function GetMinTickAbsSize() { 3869 3870 } 3871 4227 return $this->minor_abs_size; 4228 } 4229 3872 4230 // Size (in pixels) of major tick marks 3873 4231 function GetMajTickAbsSize() { 3874 return $this->major_abs_size; 3875 } 3876 4232 return $this->major_abs_size; 4233 } 4234 3877 4235 function SetSize($aMajSize,$aMinSize=3) { 3878 $this->major_abs_size = $aMajSize; 3879 $this->minor_abs_size = $aMinSize; 4236 $this->major_abs_size = $aMajSize; 4237 $this->minor_abs_size = $aMinSize; 3880 4238 } 3881 4239 3882 4240 // Have the ticks been specified 3883 4241 function IsSpecified() { 3884 return $this->is_set; 3885 } 3886 3887 // Specify number of decimals in automatic labels 3888 // Deprecated from 1.4. Use SetFormatString() instead 3889 function SetPrecision($aPrecision) { 3890 if( ERR_DEPRECATED ) 3891 JpGraphError::RaiseL(25063);//('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead'); 3892 $this->precision=$aPrecision; 4242 return $this->is_set; 3893 4243 } 3894 4244 3895 4245 function SetSide($aSide) { 3896 3897 } 3898 4246 $this->direction=$aSide; 4247 } 4248 3899 4249 // Which side of the axis should the ticks be on 3900 4250 function SetDirection($aSide=SIDE_RIGHT) { 3901 3902 } 3903 4251 $this->direction=$aSide; 4252 } 4253 3904 4254 // Set colors for major and minor tick marks 3905 function SetMarkColor($aMajorColor,$aMinorColor="") { 3906 $this->SetColor($aMajorColor,$aMinorColor); 3907 } 3908 3909 function SetColor($aMajorColor,$aMinorColor="") { 3910 $this->majcolor=$aMajorColor; 3911 3912 // If not specified use same as major 3913 if( $aMinorColor=="" ) 3914 $this->mincolor=$aMajorColor; 3915 else 3916 $this->mincolor=$aMinorColor; 3917 } 3918 4255 function SetMarkColor($aMajorColor,$aMinorColor='') { 4256 $this->SetColor($aMajorColor,$aMinorColor); 4257 } 4258 4259 function SetColor($aMajorColor,$aMinorColor='') { 4260 $this->majcolor=$aMajorColor; 4261 4262 // If not specified use same as major 4263 if( $aMinorColor == '' ) { 4264 $this->mincolor=$aMajorColor; 4265 } 4266 else { 4267 $this->mincolor=$aMinorColor; 4268 } 4269 } 4270 3919 4271 function SetWeight($aWeight) { 3920 3921 } 3922 4272 $this->weight=$aWeight; 4273 } 4274 3923 4275 } // Class 3924 4276 … … 3936 4288 private $iAdjustForDST = false; // If a date falls within the DST period add one hour to the diaplyed time 3937 4289 3938 //--------------- 3939 // CONSTRUCTOR 3940 function LinearTicks() { 3941 $this->precision = -1; 3942 } 3943 3944 //--------------- 3945 // PUBLIC METHODS 3946 3947 4290 function __construct() { 4291 $this->precision = -1; 4292 } 4293 3948 4294 // Return major step size in world coordinates 3949 4295 function GetMajor() { 3950 3951 } 3952 4296 return $this->major_step; 4297 } 4298 3953 4299 // Return minor step size in world coordinates 3954 4300 function GetMinor() { 3955 3956 } 3957 4301 return $this->minor_step; 4302 } 4303 3958 4304 // Set Minor and Major ticks (in world coordinates) 3959 4305 function Set($aMajStep,$aMinStep=false) { 3960 if( $aMinStep==false ) 3961 $aMinStep=$aMajStep; 3962 3963 if( $aMajStep <= 0 || $aMinStep <= 0 ) { 3964 JpGraphError::RaiseL(25064); 3965 //(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); 3966 } 3967 3968 $this->major_step=$aMajStep; 3969 $this->minor_step=$aMinStep; 3970 $this->is_set = true; 4306 if( $aMinStep==false ) { 4307 $aMinStep=$aMajStep; 4308 } 4309 4310 if( $aMajStep <= 0 || $aMinStep <= 0 ) { 4311 JpGraphError::RaiseL(25064); 4312 //(" Minor or major step size is 0. Check that you haven't got an accidental SetTextTicks(0) in your code. If this is not the case you might have stumbled upon a bug in JpGraph. Please report this and if possible include the data that caused the problem."); 4313 } 4314 4315 $this->major_step=$aMajStep; 4316 $this->minor_step=$aMinStep; 4317 $this->is_set = true; 3971 4318 } 3972 4319 3973 4320 function SetMajTickPositions($aMajPos,$aLabels=NULL) { 3974 4321 $this->SetTickPositions($aMajPos,NULL,$aLabels); 3975 4322 } 3976 4323 3977 4324 function SetTickPositions($aMajPos,$aMinPos=NULL,$aLabels=NULL) { 3978 3979 3980 3981 3982 3983 3984 3985 return; 3986 } 3987 $this->iManualTickPos = $aMajPos;3988 $this->iManualMinTickPos = $aMinPos;3989 $this->iManualTickLabels = $aLabels; 3990 } 3991 3992 // Specify all the tick positions manually and possible also the exact labels3993 function _doManualTickPos($aScale) {3994 $n=count($this->iManualTickPos); 3995 $m=count($this->iManualMinTickPos); 3996 $doLbl=count($this->iManualTickLabels) > 0; 3997 3998 $this->maj_ticks_pos = array();3999 $this->maj_ticklabels_pos = array();4000 $this->ticks_pos = array(); 4001 4002 // Now loop through the supplied positions and translate them to screen coordinates 4003 // and store them in the maj_label_positions 4004 $minScale = $aScale->scale[0]; 4005 $maxScale = $aScale->scale[1]; 4006 $j=0; 4007 for($i=0; $i < $n ; ++$i ) { 4008 // First make sure that the first tick is not lower than the lower scale value 4009 if( !isset($this->iManualTickPos[$i]) || 4010 $this->iManualTickPos[$i] < $minScale || $this->iManualTickPos[$i] > $maxScale) {4011 continue; 4012 } 4013 4014 4015 $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]); 4016 $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j]; 4017 4018 // Set the minor tick marks the same as major if not specified 4019 if( $m <= 0 ) { 4020 $this->ticks_pos[$j] = $this->maj_ticks_pos[$j]; 4021 } 4022 4023 if( $doLbl ) { 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 if( empty($this->iManualMinTickPos[$i]) || 4041 $this->iManualMinTickPos[$i] < $minScale || $this->iManualMinTickPos[$i] > $maxScale) 4042 continue; 4043 4044 4045 4325 if( !is_array($aMajPos) || ($aMinPos!==NULL && !is_array($aMinPos)) ) { 4326 JpGraphError::RaiseL(25065);//('Tick positions must be specifued as an array()'); 4327 return; 4328 } 4329 $n=count($aMajPos); 4330 if( is_array($aLabels) && (count($aLabels) != $n) ) { 4331 JpGraphError::RaiseL(25066);//('When manually specifying tick positions and labels the number of labels must be the same as the number of specified ticks.'); 4332 } 4333 $this->iManualTickPos = $aMajPos; 4334 $this->iManualMinTickPos = $aMinPos; 4335 $this->iManualTickLabels = $aLabels; 4336 } 4337 4338 function HaveManualLabels() { 4339 return is_array($this->iManualTickLabels) ? count($this->iManualTickLabels) > 0 : false; 4340 } 4341 4342 // Specify all the tick positions manually and possible also the exact labels 4343 function _doManualTickPos($aScale) { 4344 $n=count($this->iManualTickPos); 4345 $m= is_array($this->iManualMinTickPos) ? count($this->iManualMinTickPos) : 0; 4346 $doLbl= is_array($this->iManualTickLabels) ? count($this->iManualTickLabels) > 0 : false; 4347 4348 $this->maj_ticks_pos = array(); 4349 $this->maj_ticklabels_pos = array(); 4350 $this->ticks_pos = array(); 4351 4352 // Now loop through the supplied positions and translate them to screen coordinates 4353 // and store them in the maj_label_positions 4354 $minScale = $aScale->scale[0]; 4355 $maxScale = $aScale->scale[1]; 4356 $j=0; 4357 for($i=0; $i < $n ; ++$i ) { 4358 // First make sure that the first tick is not lower than the lower scale value 4359 if( !isset($this->iManualTickPos[$i]) || $this->iManualTickPos[$i] < $minScale || $this->iManualTickPos[$i] > $maxScale) { 4360 continue; 4361 } 4362 4363 $this->maj_ticks_pos[$j] = $aScale->Translate($this->iManualTickPos[$i]); 4364 $this->maj_ticklabels_pos[$j] = $this->maj_ticks_pos[$j]; 4365 4366 // Set the minor tick marks the same as major if not specified 4367 if( $m <= 0 ) { 4368 $this->ticks_pos[$j] = $this->maj_ticks_pos[$j]; 4369 } 4370 if( $doLbl ) { 4371 $this->maj_ticks_label[$j] = $this->iManualTickLabels[$i]; 4372 } 4373 else { 4374 $this->maj_ticks_label[$j]=$this->_doLabelFormat($this->iManualTickPos[$i],$i,$n); 4375 } 4376 ++$j; 4377 } 4378 4379 // Some sanity check 4380 if( count($this->maj_ticks_pos) < 2 ) { 4381 JpGraphError::RaiseL(25067);//('Your manually specified scale and ticks is not correct. The scale seems to be too small to hold any of the specified tickl marks.'); 4382 } 4383 4384 // Setup the minor tick marks 4385 $j=0; 4386 for($i=0; $i < $m; ++$i ) { 4387 if( empty($this->iManualMinTickPos[$i]) || $this->iManualMinTickPos[$i] < $minScale || $this->iManualMinTickPos[$i] > $maxScale) { 4388 continue; 4389 } 4390 $this->ticks_pos[$j] = $aScale->Translate($this->iManualMinTickPos[$i]); 4391 ++$j; 4392 } 4046 4393 } 4047 4394 4048 4395 function _doAutoTickPos($aScale) { 4049 $maj_step_abs = $aScale->scale_factor*$this->major_step; 4050 $min_step_abs = $aScale->scale_factor*$this->minor_step; 4051 4052 if( $min_step_abs==0 || $maj_step_abs==0 ) { 4053 JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')"); 4054 } 4055 // We need to make this an int since comparing it below 4056 // with the result from round() can give wrong result, such that 4057 // (40 < 40) == TRUE !!! 4058 $limit = (int)$aScale->scale_abs[1]; 4059 4060 if( $aScale->textscale ) { 4061 // This can only be true for a X-scale (horizontal) 4062 // Define ticks for a text scale. This is slightly different from a 4063 // normal linear type of scale since the position might be adjusted 4064 // and the labels start at on 4065 $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset; 4066 $start_abs=$aScale->scale_factor*$this->text_label_start; 4067 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; 4068 4069 $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs; 4070 for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) { 4071 // Apply format to label 4072 $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks); 4073 $label+=$this->major_step; 4074 4075 // The x-position of the tick marks can be different from the labels. 4076 // Note that we record the tick position (not the label) so that the grid 4077 // happen upon tick marks and not labels. 4078 $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs; 4079 $this->maj_ticks_pos[$i]=$xtick; 4080 $this->maj_ticklabels_pos[$i] = round($x); 4081 $x += $maj_step_abs; 4082 } 4083 } 4084 else { 4085 $label = $aScale->GetMinVal(); 4086 $abs_pos = $aScale->scale_abs[0]; 4087 $j=0; $i=0; 4088 $step = round($maj_step_abs/$min_step_abs); 4089 if( $aScale->type == "x" ) { 4090 // For a normal linear type of scale the major ticks will always be multiples 4091 // of the minor ticks. In order to avoid any rounding issues the major ticks are 4092 // defined as every "step" minor ticks and not calculated separately 4093 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; 4094 while( round($abs_pos) <= $limit ) { 4095 $this->ticks_pos[] = round($abs_pos); 4096 $this->ticks_label[] = $label; 4097 if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) { 4098 $this->maj_ticks_pos[$j] = round($abs_pos); 4099 $this->maj_ticklabels_pos[$j] = round($abs_pos); 4100 $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); 4101 ++$j; 4102 } 4103 ++$i; 4104 $abs_pos += $min_step_abs; 4105 $label+=$this->minor_step; 4106 } 4107 } 4108 elseif( $aScale->type == "y" ) { 4109 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1; 4110 while( round($abs_pos) >= $limit ) { 4111 $this->ticks_pos[$i] = round($abs_pos); 4112 $this->ticks_label[$i]=$label; 4113 if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) { 4114 $this->maj_ticks_pos[$j] = round($abs_pos); 4115 $this->maj_ticklabels_pos[$j] = round($abs_pos); 4116 $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); 4117 ++$j; 4118 } 4119 ++$i; 4120 $abs_pos += $min_step_abs; 4121 $label += $this->minor_step; 4122 } 4123 } 4124 } 4396 $maj_step_abs = $aScale->scale_factor*$this->major_step; 4397 $min_step_abs = $aScale->scale_factor*$this->minor_step; 4398 4399 if( $min_step_abs==0 || $maj_step_abs==0 ) { 4400 JpGraphError::RaiseL(25068);//("A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. It could also be that no input data value is numeric (perhaps only '-' or 'x')"); 4401 } 4402 // We need to make this an int since comparing it below 4403 // with the result from round() can give wrong result, such that 4404 // (40 < 40) == TRUE !!! 4405 $limit = (int)$aScale->scale_abs[1]; 4406 4407 if( $aScale->textscale ) { 4408 // This can only be true for a X-scale (horizontal) 4409 // Define ticks for a text scale. This is slightly different from a 4410 // normal linear type of scale since the position might be adjusted 4411 // and the labels start at on 4412 $label = (float)$aScale->GetMinVal()+$this->text_label_start+$this->label_offset; 4413 $start_abs=$aScale->scale_factor*$this->text_label_start; 4414 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; 4415 4416 $x = $aScale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs; 4417 for( $i=0; $label <= $aScale->GetMaxVal()+$this->label_offset; ++$i ) { 4418 // Apply format to label 4419 $this->maj_ticks_label[$i]=$this->_doLabelFormat($label,$i,$nbrmajticks); 4420 $label+=$this->major_step; 4421 4422 // The x-position of the tick marks can be different from the labels. 4423 // Note that we record the tick position (not the label) so that the grid 4424 // happen upon tick marks and not labels. 4425 $xtick=$aScale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs; 4426 $this->maj_ticks_pos[$i]=$xtick; 4427 $this->maj_ticklabels_pos[$i] = round($x); 4428 $x += $maj_step_abs; 4429 } 4430 } 4431 else { 4432 $label = $aScale->GetMinVal(); 4433 $abs_pos = $aScale->scale_abs[0]; 4434 $j=0; $i=0; 4435 $step = round($maj_step_abs/$min_step_abs); 4436 if( $aScale->type == "x" ) { 4437 // For a normal linear type of scale the major ticks will always be multiples 4438 // of the minor ticks. In order to avoid any rounding issues the major ticks are 4439 // defined as every "step" minor ticks and not calculated separately 4440 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; 4441 while( round($abs_pos) <= $limit ) { 4442 $this->ticks_pos[] = round($abs_pos); 4443 $this->ticks_label[] = $label; 4444 if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks ) { 4445 $this->maj_ticks_pos[$j] = round($abs_pos); 4446 $this->maj_ticklabels_pos[$j] = round($abs_pos); 4447 $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); 4448 ++$j; 4449 } 4450 ++$i; 4451 $abs_pos += $min_step_abs; 4452 $label+=$this->minor_step; 4453 } 4454 } 4455 elseif( $aScale->type == "y" ) { 4456 //@todo s=2:20,12 s=1:50,6 $this->major_step:$nbr 4457 // abs_point,limit s=1:270,80 s=2:540,160 4458 // $this->major_step = 50; 4459 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal())/$this->major_step)+1; 4460 // $step = 5; 4461 while( round($abs_pos) >= $limit ) { 4462 $this->ticks_pos[$i] = round($abs_pos); 4463 $this->ticks_label[$i]=$label; 4464 if( $step== 0 || $i % $step == 0 && $j < $nbrmajticks) { 4465 $this->maj_ticks_pos[$j] = round($abs_pos); 4466 $this->maj_ticklabels_pos[$j] = round($abs_pos); 4467 $this->maj_ticks_label[$j]=$this->_doLabelFormat($label,$j,$nbrmajticks); 4468 ++$j; 4469 } 4470 ++$i; 4471 $abs_pos += $min_step_abs; 4472 $label += $this->minor_step; 4473 } 4474 } 4475 } 4125 4476 } 4126 4477 4127 4478 function AdjustForDST($aFlg=true) { 4128 4479 $this->iAdjustForDST = $aFlg; 4129 4480 } 4130 4481 … … 4132 4483 function _doLabelFormat($aVal,$aIdx,$aNbrTicks) { 4133 4484 4134 // If precision hasn't been specified set it to a sensible value 4135 if( $this->precision==-1 ) { 4136 $t = log10($this->minor_step); 4137 if( $t > 0 ) 4138 $precision = 0; 4139 else 4140 $precision = -floor($t); 4141 } 4142 else 4143 $precision = $this->precision; 4144 4145 if( $this->label_formfunc != '' ) { 4146 $f=$this->label_formfunc; 4147 $l = call_user_func($f,$aVal); 4148 } 4149 elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) { 4150 if( $this->label_usedateformat ) { 4151 // Adjust the value to take daylight savings into account 4152 if (date("I",$aVal)==1 && $this->iAdjustForDST ) // DST 4153 $aVal+=3600; 4154 4155 $l = date($this->label_formatstr,$aVal); 4156 if( $this->label_formatstr == 'W' ) { 4157 // If we use week formatting then add a single 'w' in front of the 4158 // week number to differentiate it from dates 4159 $l = 'w'.$l; 4160 } 4161 } 4162 else { 4163 if( $this->label_dateformatstr !== '' ) { 4164 // Adjust the value to take daylight savings into account 4165 if (date("I",$aVal)==1 && $this->iAdjustForDST ) // DST 4166 $aVal+=3600; 4167 4168 $l = date($this->label_dateformatstr,$aVal); 4169 if( $this->label_formatstr == 'W' ) { 4170 // If we use week formatting then add a single 'w' in front of the 4171 // week number to differentiate it from dates 4172 $l = 'w'.$l; 4173 } 4174 } 4175 else 4176 $l = sprintf($this->label_formatstr,$aVal); 4177 } 4178 } 4179 else { 4180 $l = sprintf('%01.'.$precision.'f',round($aVal,$precision)); 4181 } 4182 4183 if( ($this->supress_zerolabel && $l==0) || ($this->supress_first && $aIdx==0) || 4184 ($this->supress_last && $aIdx==$aNbrTicks-1) ) { 4185 $l=''; 4186 } 4187 return $l; 4485 // If precision hasn't been specified set it to a sensible value 4486 if( $this->precision==-1 ) { 4487 $t = log10($this->minor_step); 4488 if( $t > 0 || $t === 0.0) { 4489 $precision = 0; 4490 } 4491 else { 4492 $precision = -floor($t); 4493 } 4494 } 4495 else { 4496 $precision = $this->precision; 4497 } 4498 4499 if( $this->label_formfunc != '' ) { 4500 $f=$this->label_formfunc; 4501 if( $this->label_formatstr == '' ) { 4502 $l = call_user_func($f,$aVal); 4503 } 4504 else { 4505 $l = sprintf($this->label_formatstr, call_user_func($f,$aVal)); 4506 } 4507 } 4508 elseif( $this->label_formatstr != '' || $this->label_dateformatstr != '' ) { 4509 if( $this->label_usedateformat ) { 4510 // Adjust the value to take daylight savings into account 4511 if (date("I",$aVal)==1 && $this->iAdjustForDST ) { 4512 // DST 4513 $aVal+=3600; 4514 } 4515 4516 $l = date($this->label_formatstr,$aVal); 4517 if( $this->label_formatstr == 'W' ) { 4518 // If we use week formatting then add a single 'w' in front of the 4519 // week number to differentiate it from dates 4520 $l = 'w'.$l; 4521 } 4522 } 4523 else { 4524 if( $this->label_dateformatstr !== '' ) { 4525 // Adjust the value to take daylight savings into account 4526 if (date("I",$aVal)==1 && $this->iAdjustForDST ) { 4527 // DST 4528 $aVal+=3600; 4529 } 4530 4531 $l = date($this->label_dateformatstr,$aVal); 4532 if( $this->label_formatstr == 'W' ) { 4533 // If we use week formatting then add a single 'w' in front of the 4534 // week number to differentiate it from dates 4535 $l = 'w'.$l; 4536 } 4537 } 4538 else { 4539 $l = sprintf($this->label_formatstr,$aVal); 4540 } 4541 } 4542 } 4543 else { 4544 $l = sprintf('%01.'.$precision.'f',round($aVal,$precision)); 4545 } 4546 4547 if( ($this->supress_zerolabel && $l==0) || ($this->supress_first && $aIdx==0) || ($this->supress_last && $aIdx==$aNbrTicks-1) ) { 4548 $l=''; 4549 } 4550 return $l; 4188 4551 } 4189 4552 4190 4553 // Stroke ticks on either X or Y axis 4191 4554 function _StrokeTicks($aImg,$aScale,$aPos) { 4192 $hor = $aScale->type == 'x'; 4193 $aImg->SetLineWeight($this->weight); 4194 4195 // We need to make this an int since comparing it below 4196 // with the result from round() can give wrong result, such that 4197 // (40 < 40) == TRUE !!! 4198 $limit = (int)$aScale->scale_abs[1]; 4199 4200 // A text scale doesn't have any minor ticks 4201 if( !$aScale->textscale ) { 4202 // Stroke minor ticks 4203 $yu = $aPos - $this->direction*$this->GetMinTickAbsSize(); 4204 $xr = $aPos + $this->direction*$this->GetMinTickAbsSize(); 4205 $n = count($this->ticks_pos); 4206 for($i=0; $i < $n; ++$i ) { 4207 if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { 4208 if( $this->mincolor!="" ) $aImg->PushColor($this->mincolor); 4209 if( $hor ) { 4210 //if( $this->ticks_pos[$i] <= $limit ) 4211 $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu); 4212 } 4213 else { 4214 //if( $this->ticks_pos[$i] >= $limit ) 4215 $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]); 4216 } 4217 if( $this->mincolor!="" ) $aImg->PopColor(); 4218 } 4219 } 4220 } 4221 4222 // Stroke major ticks 4223 $yu = $aPos - $this->direction*$this->GetMajTickAbsSize(); 4224 $xr = $aPos + $this->direction*$this->GetMajTickAbsSize(); 4225 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; 4226 $n = count($this->maj_ticks_pos); 4227 for($i=0; $i < $n ; ++$i ) { 4228 if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) { 4229 if( $this->majcolor!="" ) $aImg->PushColor($this->majcolor); 4230 if( $hor ) { 4231 //if( $this->maj_ticks_pos[$i] <= $limit ) 4232 $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu); 4233 } 4234 else { 4235 //if( $this->maj_ticks_pos[$i] >= $limit ) 4236 $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]); 4237 } 4238 if( $this->majcolor!="" ) $aImg->PopColor(); 4239 } 4240 } 4241 4555 $hor = $aScale->type == 'x'; 4556 $aImg->SetLineWeight($this->weight); 4557 4558 // We need to make this an int since comparing it below 4559 // with the result from round() can give wrong result, such that 4560 // (40 < 40) == TRUE !!! 4561 $limit = (int)$aScale->scale_abs[1]; 4562 4563 // A text scale doesn't have any minor ticks 4564 if( !$aScale->textscale ) { 4565 // Stroke minor ticks 4566 $yu = $aPos - $this->direction*$this->GetMinTickAbsSize(); 4567 $xr = $aPos + $this->direction*$this->GetMinTickAbsSize(); 4568 $n = count($this->ticks_pos); 4569 for($i=0; $i < $n; ++$i ) { 4570 if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) { 4571 if( $this->mincolor != '') { 4572 $aImg->PushColor($this->mincolor); 4573 } 4574 if( $hor ) { 4575 //if( $this->ticks_pos[$i] <= $limit ) 4576 $aImg->Line($this->ticks_pos[$i],$aPos,$this->ticks_pos[$i],$yu); 4577 } 4578 else { 4579 //if( $this->ticks_pos[$i] >= $limit ) 4580 $aImg->Line($aPos,$this->ticks_pos[$i],$xr,$this->ticks_pos[$i]); 4581 } 4582 if( $this->mincolor != '' ) { 4583 $aImg->PopColor(); 4584 } 4585 } 4586 } 4587 } 4588 4589 // Stroke major ticks 4590 $yu = $aPos - $this->direction*$this->GetMajTickAbsSize(); 4591 $xr = $aPos + $this->direction*$this->GetMajTickAbsSize(); 4592 $nbrmajticks=round(($aScale->GetMaxVal()-$aScale->GetMinVal()-$this->text_label_start )/$this->major_step)+1; 4593 $n = count($this->maj_ticks_pos); 4594 for($i=0; $i < $n ; ++$i ) { 4595 if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) && !$this->supress_tickmarks) { 4596 if( $this->majcolor != '') { 4597 $aImg->PushColor($this->majcolor); 4598 } 4599 if( $hor ) { 4600 //if( $this->maj_ticks_pos[$i] <= $limit ) 4601 $aImg->Line($this->maj_ticks_pos[$i],$aPos,$this->maj_ticks_pos[$i],$yu); 4602 } 4603 else { 4604 //if( $this->maj_ticks_pos[$i] >= $limit ) 4605 $aImg->Line($aPos,$this->maj_ticks_pos[$i],$xr,$this->maj_ticks_pos[$i]); 4606 } 4607 if( $this->majcolor != '') { 4608 $aImg->PopColor(); 4609 } 4610 } 4611 } 4612 4242 4613 } 4243 4614 4244 4615 // Draw linear ticks 4245 4616 function Stroke($aImg,$aScale,$aPos) { 4246 if( $this->iManualTickPos != NULL ) 4247 $this->_doManualTickPos($aScale); 4248 else 4249 $this->_doAutoTickPos($aScale); 4250 $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' ); 4251 } 4252 4253 //--------------- 4254 // PRIVATE METHODS 4617 if( $this->iManualTickPos != NULL ) { 4618 $this->_doManualTickPos($aScale); 4619 } 4620 else { 4621 $this->_doAutoTickPos($aScale); 4622 } 4623 $this->_StrokeTicks($aImg,$aScale,$aPos, $aScale->type == 'x' ); 4624 } 4625 4626 //--------------- 4627 // PRIVATE METHODS 4255 4628 // Spoecify the offset of the displayed tick mark with the tick "space" 4256 // Legal values for $o is [0,1] used to adjust where the tick marks and label 4629 // Legal values for $o is [0,1] used to adjust where the tick marks and label 4257 4630 // should be positioned within the major tick-size 4258 4631 // $lo specifies the label offset and $to specifies the tick offset … … 4260 4633 // tick but have the labels displayed halfway under the bars. 4261 4634 function SetXLabelOffset($aLabelOff,$aTickOff=-1) { 4262 $this->xlabel_offset=$aLabelOff; 4263 if( $aTickOff==-1 ) // Same as label offset 4264 $this->xtick_offset=$aLabelOff; 4265 else 4266 $this->xtick_offset=$aTickOff; 4267 if( $aLabelOff>0 ) 4268 $this->SupressLast(); // The last tick wont fit 4635 $this->xlabel_offset=$aLabelOff; 4636 if( $aTickOff==-1 ) { 4637 // Same as label offset 4638 $this->xtick_offset=$aLabelOff; 4639 } 4640 else { 4641 $this->xtick_offset=$aTickOff; 4642 } 4643 if( $aLabelOff>0 ) { 4644 $this->SupressLast(); // The last tick wont fit 4645 } 4269 4646 } 4270 4647 4271 4648 // Which tick label should we start with? 4272 4649 function SetTextLabelStart($aTextLabelOff) { 4273 4274 } 4275 4650 $this->text_label_start=$aTextLabelOff; 4651 } 4652 4276 4653 } // Class 4277 4654 4278 4655 //=================================================== 4279 4656 // CLASS LinearScale 4280 // Description: Handle linear scaling between screen and world 4657 // Description: Handle linear scaling between screen and world 4281 4658 //=================================================== 4282 4659 class LinearScale { … … 4297 4674 public $auto_ticks=false; // When using manual scale should the ticks be automatically set? 4298 4675 public $world_abs_size; // Plot area size in pixels (Needed public in jpgraph_radar.php) 4299 public $world_size; // Plot area size in world coordinates4300 4676 public $intscale=false; // Restrict autoscale to integers 4301 4677 protected $autoscale_min=false; // Forced minimum value, auto determine max 4302 4678 protected $autoscale_max=false; // Forced maximum value, auto determine min 4303 4679 private $gracetop=0,$gracebottom=0; 4304 //--------------- 4305 // CONSTRUCTOR 4306 function LinearScale($aMin=0,$aMax=0,$aType="y") { 4307 assert($aType=="x" || $aType=="y" ); 4308 assert($aMin<=$aMax); 4309 4310 $this->type=$aType; 4311 $this->scale=array($aMin,$aMax); 4312 $this->world_size=$aMax-$aMin; 4313 $this->ticks = new LinearTicks(); 4314 } 4315 4316 //--------------- 4317 // PUBLIC METHODS 4680 4681 private $_world_size; // Plot area size in world coordinates 4682 4683 function __construct($aMin=0,$aMax=0,$aType='y') { 4684 assert($aType=='x' || $aType=='y' ); 4685 assert($aMin<=$aMax); 4686 4687 $this->type=$aType; 4688 $this->scale=array($aMin,$aMax); 4689 $this->world_size=$aMax-$aMin; 4690 $this->ticks = new LinearTicks(); 4691 } 4692 4318 4693 // Check if scale is set or if we should autoscale 4319 4694 // We should do this is either scale or ticks has not been set 4320 4695 function IsSpecified() { 4321 if( $this->GetMinVal()==$this->GetMaxVal() ) {// Scale not set4322 4323 4324 4325 } 4326 4327 // Set the minimum data value when the autoscaling is used. 4696 if( $this->GetMinVal()==$this->GetMaxVal() ) { // Scale not set 4697 return false; 4698 } 4699 return true; 4700 } 4701 4702 // Set the minimum data value when the autoscaling is used. 4328 4703 // Usefull if you want a fix minimum (like 0) but have an 4329 4704 // automatic maximum 4330 4705 function SetAutoMin($aMin) { 4331 4332 } 4333 4334 // Set the minimum data value when the autoscaling is used. 4706 $this->autoscale_min=$aMin; 4707 } 4708 4709 // Set the minimum data value when the autoscaling is used. 4335 4710 // Usefull if you want a fix minimum (like 0) but have an 4336 4711 // automatic maximum 4337 4712 function SetAutoMax($aMax) { 4338 4713 $this->autoscale_max=$aMax; 4339 4714 } 4340 4715 … … 4342 4717 // still be set automatically? 4343 4718 function SetAutoTicks($aFlag=true) { 4344 4719 $this->auto_ticks = $aFlag; 4345 4720 } 4346 4721 4347 4722 // Specify scale "grace" value (top and bottom) 4348 4723 function SetGrace($aGraceTop,$aGraceBottom=0) { 4349 if( $aGraceTop<0 || $aGraceBottom < 0 ) 4350 JpGraphError::RaiseL(25069);//(" Grace must be larger then 0"); 4351 $this->gracetop=$aGraceTop; 4352 $this->gracebottom=$aGraceBottom; 4353 } 4354 4724 if( $aGraceTop<0 || $aGraceBottom < 0 ) { 4725 JpGraphError::RaiseL(25069);//(" Grace must be larger then 0"); 4726 } 4727 $this->gracetop=$aGraceTop; 4728 $this->gracebottom=$aGraceBottom; 4729 } 4730 4355 4731 // Get the minimum value in the scale 4356 4732 function GetMinVal() { 4357 4358 } 4359 4733 return $this->scale[0]; 4734 } 4735 4360 4736 // get maximum value for scale 4361 4737 function GetMaxVal() { 4362 4363 } 4364 4365 // Specify a new min/max value for sclae 4738 return $this->scale[1]; 4739 } 4740 4741 // Specify a new min/max value for sclae 4366 4742 function Update($aImg,$aMin,$aMax) { 4367 $this->scale=array($aMin,$aMax); 4368 $this->world_size=$aMax-$aMin; 4369 $this->InitConstants($aImg); 4370 } 4371 4743 $this->scale=array($aMin,$aMax); 4744 $this->world_size=$aMax-$aMin; 4745 $this->InitConstants($aImg); 4746 } 4747 4372 4748 // Translate between world and screen 4373 4749 function Translate($aCoord) { 4374 if( !is_numeric($aCoord) ) { 4375 if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) 4376 JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); 4377 return 0; 4378 } 4379 else { 4380 return $this->off+($aCoord - $this->scale[0]) * $this->scale_factor; 4381 } 4382 } 4383 4750 if( !is_numeric($aCoord) ) { 4751 if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) { 4752 JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); 4753 } 4754 return 0; 4755 } 4756 else { 4757 return round($this->off+($aCoord - $this->scale[0]) * $this->scale_factor); 4758 } 4759 } 4760 4384 4761 // Relative translate (don't include offset) usefull when we just want 4385 4762 // to know the relative position (in pixels) on the axis 4386 4763 function RelTranslate($aCoord) { 4387 if( !is_numeric($aCoord) ) { 4388 if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) 4389 JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); 4390 return 0; 4391 } 4392 else { 4393 return ($aCoord - $this->scale[0]) * $this->scale_factor; 4394 } 4395 } 4396 4764 if( !is_numeric($aCoord) ) { 4765 if( $aCoord != '' && $aCoord != '-' && $aCoord != 'x' ) { 4766 JpGraphError::RaiseL(25070);//('Your data contains non-numeric values.'); 4767 } 4768 return 0; 4769 } 4770 else { 4771 return ($aCoord - $this->scale[0]) * $this->scale_factor; 4772 } 4773 } 4774 4397 4775 // Restrict autoscaling to only use integers 4398 4776 function SetIntScale($aIntScale=true) { 4399 4400 } 4401 4777 $this->intscale=$aIntScale; 4778 } 4779 4402 4780 // Calculate an integer autoscale 4403 4781 function IntAutoScale($img,$min,$max,$maxsteps,$majend=true) { 4404 // Make sure limits are integers 4405 $min=floor($min); 4406 $max=ceil($max); 4407 if( abs($min-$max)==0 ) { 4408 --$min; ++$max; 4409 } 4410 $maxsteps = floor($maxsteps); 4411 4412 $gracetop=round(($this->gracetop/100.0)*abs($max-$min)); 4413 $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min)); 4414 if( is_numeric($this->autoscale_min) ) { 4415 $min = ceil($this->autoscale_min); 4416 if( $min >= $max ) { 4417 JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); 4418 } 4419 } 4420 4421 if( is_numeric($this->autoscale_max) ) { 4422 $max = ceil($this->autoscale_max); 4423 if( $min >= $max ) { 4424 JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); 4425 } 4426 } 4427 4428 if( abs($min-$max ) == 0 ) { 4429 ++$max; 4430 --$min; 4431 } 4432 4433 $min -= $gracebottom; 4434 $max += $gracetop; 4435 4436 // First get tickmarks as multiples of 1, 10, ... 4437 if( $majend ) { 4438 list($num1steps,$adj1min,$adj1max,$maj1step) = 4439 $this->IntCalcTicks($maxsteps,$min,$max,1); 4440 } 4441 else { 4442 $adj1min = $min; 4443 $adj1max = $max; 4444 list($num1steps,$maj1step) = 4445 $this->IntCalcTicksFreeze($maxsteps,$min,$max,1); 4446 } 4447 4448 if( abs($min-$max) > 2 ) { 4449 // Then get tick marks as 2:s 2, 20, ... 4450 if( $majend ) { 4451 list($num2steps,$adj2min,$adj2max,$maj2step) = 4452 $this->IntCalcTicks($maxsteps,$min,$max,5); 4453 } 4454 else { 4455 $adj2min = $min; 4456 $adj2max = $max; 4457 list($num2steps,$maj2step) = 4458 $this->IntCalcTicksFreeze($maxsteps,$min,$max,5); 4459 } 4460 } 4461 else { 4462 $num2steps = 10000; // Dummy high value so we don't choose this 4463 } 4464 4465 if( abs($min-$max) > 5 ) { 4466 // Then get tickmarks as 5:s 5, 50, 500, ... 4467 if( $majend ) { 4468 list($num5steps,$adj5min,$adj5max,$maj5step) = 4469 $this->IntCalcTicks($maxsteps,$min,$max,2); 4470 } 4471 else { 4472 $adj5min = $min; 4473 $adj5max = $max; 4474 list($num5steps,$maj5step) = 4475 $this->IntCalcTicksFreeze($maxsteps,$min,$max,2); 4476 } 4477 } 4478 else { 4479 $num5steps = 10000; // Dummy high value so we don't choose this 4480 } 4481 4482 // Check to see whichof 1:s, 2:s or 5:s fit better with 4483 // the requested number of major ticks 4484 $match1=abs($num1steps-$maxsteps); 4485 $match2=abs($num2steps-$maxsteps); 4486 if( !empty($maj5step) && $maj5step > 1 ) 4487 $match5=abs($num5steps-$maxsteps); 4488 else 4489 $match5=10000; // Dummy high value 4490 4491 // Compare these three values and see which is the closest match 4492 // We use a 0.6 weight to gravitate towards multiple of 5:s 4493 if( $match1 < $match2 ) { 4494 if( $match1 < $match5 ) 4495 $r=1; 4496 else 4497 $r=3; 4498 } 4499 else { 4500 if( $match2 < $match5 ) 4501 $r=2; 4502 else 4503 $r=3; 4504 } 4505 // Minsteps are always the same as maxsteps for integer scale 4506 switch( $r ) { 4507 case 1: 4508 $this->ticks->Set($maj1step,$maj1step); 4509 $this->Update($img,$adj1min,$adj1max); 4510 break; 4511 case 2: 4512 $this->ticks->Set($maj2step,$maj2step); 4513 $this->Update($img,$adj2min,$adj2max); 4514 break; 4515 case 3: 4516 $this->ticks->Set($maj5step,$maj5step); 4517 $this->Update($img,$adj5min,$adj5max); 4518 break; 4519 default: 4520 JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)'); 4521 } 4522 } 4523 4524 4782 // Make sure limits are integers 4783 $min=floor($min); 4784 $max=ceil($max); 4785 if( abs($min-$max)==0 ) { 4786 --$min; ++$max; 4787 } 4788 $maxsteps = floor($maxsteps); 4789 4790 $gracetop=round(($this->gracetop/100.0)*abs($max-$min)); 4791 $gracebottom=round(($this->gracebottom/100.0)*abs($max-$min)); 4792 if( is_numeric($this->autoscale_min) ) { 4793 $min = ceil($this->autoscale_min); 4794 if( $min >= $max ) { 4795 JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); 4796 } 4797 } 4798 4799 if( is_numeric($this->autoscale_max) ) { 4800 $max = ceil($this->autoscale_max); 4801 if( $min >= $max ) { 4802 JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); 4803 } 4804 } 4805 4806 if( abs($min-$max ) == 0 ) { 4807 ++$max; 4808 --$min; 4809 } 4810 4811 $min -= $gracebottom; 4812 $max += $gracetop; 4813 4814 // First get tickmarks as multiples of 1, 10, ... 4815 if( $majend ) { 4816 list($num1steps,$adj1min,$adj1max,$maj1step) = $this->IntCalcTicks($maxsteps,$min,$max,1); 4817 } 4818 else { 4819 $adj1min = $min; 4820 $adj1max = $max; 4821 list($num1steps,$maj1step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,1); 4822 } 4823 4824 if( abs($min-$max) > 2 ) { 4825 // Then get tick marks as 2:s 2, 20, ... 4826 if( $majend ) { 4827 list($num2steps,$adj2min,$adj2max,$maj2step) = $this->IntCalcTicks($maxsteps,$min,$max,5); 4828 } 4829 else { 4830 $adj2min = $min; 4831 $adj2max = $max; 4832 list($num2steps,$maj2step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,5); 4833 } 4834 } 4835 else { 4836 $num2steps = 10000; // Dummy high value so we don't choose this 4837 } 4838 4839 if( abs($min-$max) > 5 ) { 4840 // Then get tickmarks as 5:s 5, 50, 500, ... 4841 if( $majend ) { 4842 list($num5steps,$adj5min,$adj5max,$maj5step) = $this->IntCalcTicks($maxsteps,$min,$max,2); 4843 } 4844 else { 4845 $adj5min = $min; 4846 $adj5max = $max; 4847 list($num5steps,$maj5step) = $this->IntCalcTicksFreeze($maxsteps,$min,$max,2); 4848 } 4849 } 4850 else { 4851 $num5steps = 10000; // Dummy high value so we don't choose this 4852 } 4853 4854 // Check to see whichof 1:s, 2:s or 5:s fit better with 4855 // the requested number of major ticks 4856 $match1=abs($num1steps-$maxsteps); 4857 $match2=abs($num2steps-$maxsteps); 4858 if( !empty($maj5step) && $maj5step > 1 ) { 4859 $match5=abs($num5steps-$maxsteps); 4860 } 4861 else { 4862 $match5=10000; // Dummy high value 4863 } 4864 4865 // Compare these three values and see which is the closest match 4866 // We use a 0.6 weight to gravitate towards multiple of 5:s 4867 if( $match1 < $match2 ) { 4868 if( $match1 < $match5 ) $r=1; 4869 else $r=3; 4870 } 4871 else { 4872 if( $match2 < $match5 ) $r=2; 4873 else $r=3; 4874 } 4875 // Minsteps are always the same as maxsteps for integer scale 4876 switch( $r ) { 4877 case 1: 4878 $this->ticks->Set($maj1step,$maj1step); 4879 $this->Update($img,$adj1min,$adj1max); 4880 break; 4881 case 2: 4882 $this->ticks->Set($maj2step,$maj2step); 4883 $this->Update($img,$adj2min,$adj2max); 4884 break; 4885 case 3: 4886 $this->ticks->Set($maj5step,$maj5step); 4887 $this->Update($img,$adj5min,$adj5max); 4888 break; 4889 default: 4890 JpGraphError::RaiseL(25073,$r);//('Internal error. Integer scale algorithm comparison out of bound (r=$r)'); 4891 } 4892 } 4893 4894 4525 4895 // Calculate autoscale. Used if user hasn't given a scale and ticks 4526 4896 // $maxsteps is the maximum number of major tickmarks allowed. 4527 4897 function AutoScale($img,$min,$max,$maxsteps,$majend=true) { 4528 if( $this->intscale ) { 4529 $this->IntAutoScale($img,$min,$max,$maxsteps,$majend); 4530 return; 4531 } 4532 if( abs($min-$max) < 0.00001 ) { 4533 // We need some difference to be able to autoscale 4534 // make it 5% above and 5% below value 4535 if( $min==0 && $max==0 ) { // Special case 4536 $min=-1; $max=1; 4537 } 4538 else { 4539 $delta = (abs($max)+abs($min))*0.005; 4540 $min -= $delta; 4541 $max += $delta; 4542 } 4543 } 4544 4545 $gracetop=($this->gracetop/100.0)*abs($max-$min); 4546 $gracebottom=($this->gracebottom/100.0)*abs($max-$min); 4547 if( is_numeric($this->autoscale_min) ) { 4548 $min = $this->autoscale_min; 4549 if( $min >= $max ) { 4550 JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); 4551 } 4552 if( abs($min-$max ) < 0.00001 ) 4553 $max *= 1.2; 4554 } 4555 4556 if( is_numeric($this->autoscale_max) ) { 4557 $max = $this->autoscale_max; 4558 if( $min >= $max ) { 4559 JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); 4560 } 4561 if( abs($min-$max ) < 0.00001 ) 4562 $min *= 0.8; 4563 } 4564 4565 $min -= $gracebottom; 4566 $max += $gracetop; 4567 4568 4569 // First get tickmarks as multiples of 0.1, 1, 10, ... 4570 if( $majend ) { 4571 list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = 4572 $this->CalcTicks($maxsteps,$min,$max,1,2); 4573 } 4574 else { 4575 $adj1min=$min; 4576 $adj1max=$max; 4577 list($num1steps,$min1step,$maj1step) = 4578 $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false); 4579 } 4580 4581 // Then get tick marks as 2:s 0.2, 2, 20, ... 4582 if( $majend ) { 4583 list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = 4584 $this->CalcTicks($maxsteps,$min,$max,5,2); 4585 } 4586 else { 4587 $adj2min=$min; 4588 $adj2max=$max; 4589 list($num2steps,$min2step,$maj2step) = 4590 $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false); 4591 } 4592 4593 // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ... 4594 if( $majend ) { 4595 list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = 4596 $this->CalcTicks($maxsteps,$min,$max,2,5); 4597 } 4598 else { 4599 $adj5min=$min; 4600 $adj5max=$max; 4601 list($num5steps,$min5step,$maj5step) = 4602 $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false); 4603 } 4604 4605 // Check to see whichof 1:s, 2:s or 5:s fit better with 4606 // the requested number of major ticks 4607 $match1=abs($num1steps-$maxsteps); 4608 $match2=abs($num2steps-$maxsteps); 4609 $match5=abs($num5steps-$maxsteps); 4610 // Compare these three values and see which is the closest match 4611 // We use a 0.8 weight to gravitate towards multiple of 5:s 4612 $r=$this->MatchMin3($match1,$match2,$match5,0.8); 4613 switch( $r ) { 4614 case 1: 4615 $this->Update($img,$adj1min,$adj1max); 4616 $this->ticks->Set($maj1step,$min1step); 4617 break; 4618 case 2: 4619 $this->Update($img,$adj2min,$adj2max); 4620 $this->ticks->Set($maj2step,$min2step); 4621 break; 4622 case 3: 4623 $this->Update($img,$adj5min,$adj5max); 4624 $this->ticks->Set($maj5step,$min5step); 4625 break; 4626 } 4627 } 4628 4629 //--------------- 4630 // PRIVATE METHODS 4898 4899 if( !is_numeric($min) || !is_numeric($max) ) { 4900 JpGraphError::Raise(25044); 4901 } 4902 4903 if( $this->intscale ) { 4904 $this->IntAutoScale($img,$min,$max,$maxsteps,$majend); 4905 return; 4906 } 4907 if( abs($min-$max) < 0.00001 ) { 4908 // We need some difference to be able to autoscale 4909 // make it 5% above and 5% below value 4910 if( $min==0 && $max==0 ) { // Special case 4911 $min=-1; $max=1; 4912 } 4913 else { 4914 $delta = (abs($max)+abs($min))*0.005; 4915 $min -= $delta; 4916 $max += $delta; 4917 } 4918 } 4919 4920 $gracetop=($this->gracetop/100.0)*abs($max-$min); 4921 $gracebottom=($this->gracebottom/100.0)*abs($max-$min); 4922 if( is_numeric($this->autoscale_min) ) { 4923 $min = $this->autoscale_min; 4924 if( $min >= $max ) { 4925 JpGraphError::RaiseL(25071);//('You have specified a min value with SetAutoMin() which is larger than the maximum value used for the scale. This is not possible.'); 4926 } 4927 if( abs($min-$max ) < 0.001 ) { 4928 $max *= 1.2; 4929 } 4930 } 4931 4932 if( is_numeric($this->autoscale_max) ) { 4933 $max = $this->autoscale_max; 4934 if( $min >= $max ) { 4935 JpGraphError::RaiseL(25072);//('You have specified a max value with SetAutoMax() which is smaller than the miminum value used for the scale. This is not possible.'); 4936 } 4937 if( abs($min-$max ) < 0.001 ) { 4938 $min *= 0.8; 4939 } 4940 } 4941 4942 $min -= $gracebottom; 4943 $max += $gracetop; 4944 4945 // First get tickmarks as multiples of 0.1, 1, 10, ... 4946 if( $majend ) { 4947 list($num1steps,$adj1min,$adj1max,$min1step,$maj1step) = $this->CalcTicks($maxsteps,$min,$max,1,2); 4948 } 4949 else { 4950 $adj1min=$min; 4951 $adj1max=$max; 4952 list($num1steps,$min1step,$maj1step) = $this->CalcTicksFreeze($maxsteps,$min,$max,1,2,false); 4953 } 4954 4955 // Then get tick marks as 2:s 0.2, 2, 20, ... 4956 if( $majend ) { 4957 list($num2steps,$adj2min,$adj2max,$min2step,$maj2step) = $this->CalcTicks($maxsteps,$min,$max,5,2); 4958 } 4959 else { 4960 $adj2min=$min; 4961 $adj2max=$max; 4962 list($num2steps,$min2step,$maj2step) = $this->CalcTicksFreeze($maxsteps,$min,$max,5,2,false); 4963 } 4964 4965 // Then get tickmarks as 5:s 0.05, 0.5, 5, 50, ... 4966 if( $majend ) { 4967 list($num5steps,$adj5min,$adj5max,$min5step,$maj5step) = $this->CalcTicks($maxsteps,$min,$max,2,5); 4968 } 4969 else { 4970 $adj5min=$min; 4971 $adj5max=$max; 4972 list($num5steps,$min5step,$maj5step) = $this->CalcTicksFreeze($maxsteps,$min,$max,2,5,false); 4973 } 4974 4975 // Check to see whichof 1:s, 2:s or 5:s fit better with 4976 // the requested number of major ticks 4977 $match1=abs($num1steps-$maxsteps); 4978 $match2=abs($num2steps-$maxsteps); 4979 $match5=abs($num5steps-$maxsteps); 4980 4981 // Compare these three values and see which is the closest match 4982 // We use a 0.8 weight to gravitate towards multiple of 5:s 4983 $r=$this->MatchMin3($match1,$match2,$match5,0.8); 4984 switch( $r ) { 4985 case 1: 4986 $this->Update($img,$adj1min,$adj1max); 4987 $this->ticks->Set($maj1step,$min1step); 4988 break; 4989 case 2: 4990 $this->Update($img,$adj2min,$adj2max); 4991 $this->ticks->Set($maj2step,$min2step); 4992 break; 4993 case 3: 4994 $this->Update($img,$adj5min,$adj5max); 4995 $this->ticks->Set($maj5step,$min5step); 4996 break; 4997 } 4998 } 4999 5000 //--------------- 5001 // PRIVATE METHODS 4631 5002 4632 5003 // This method recalculates all constants that are depending on the … … 4635 5006 // that image. Should really be installed as an observer of that image. 4636 5007 function InitConstants($img) { 4637 if( $this->type=="x" ) { 4638 $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin; 4639 $this->off=$img->left_margin; 4640 $this->scale_factor = 0; 4641 if( $this->world_size > 0 ) 4642 $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); 4643 } 4644 else { // y scale 4645 $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; 4646 $this->off=$img->top_margin+$this->world_abs_size; 4647 $this->scale_factor = 0; 4648 if( $this->world_size > 0 ) 4649 $this->scale_factor=-$this->world_abs_size/($this->world_size*1.0); 4650 } 4651 $size = $this->world_size * $this->scale_factor; 4652 $this->scale_abs=array($this->off,$this->off + $size); 4653 } 4654 5008 if( $this->type=='x' ) { 5009 $this->world_abs_size=$img->width - $img->left_margin - $img->right_margin; 5010 $this->off=$img->left_margin; 5011 $this->scale_factor = 0; 5012 if( $this->world_size > 0 ) { 5013 $this->scale_factor=$this->world_abs_size/($this->world_size*0.999999); 5014 } 5015 } 5016 else { // y scale 5017 $this->world_abs_size=$img->height - $img->top_margin - $img->bottom_margin; 5018 $this->off=$img->top_margin+$this->world_abs_size; 5019 $this->scale_factor = 0; 5020 if( $this->world_size > 0 ) { 5021 $this->scale_factor=-$this->world_abs_size/($this->world_size*0.999999); 5022 } 5023 } 5024 $size = $this->world_size * $this->scale_factor; 5025 $this->scale_abs=array($this->off,$this->off + $size); 5026 } 5027 4655 5028 // Initialize the conversion constants for this scale 4656 5029 // This tries to pre-calculate as much as possible to speed up the 4657 5030 // actual conversion (with Translate()) later on 4658 // $start 4659 // 4660 // $len =absolute length in pixels of scale5031 // $start =scale start in absolute pixels (for x-scale this is an y-position 5032 // and for an y-scale this is an x-position 5033 // $len =absolute length in pixels of scale 4661 5034 function SetConstants($aStart,$aLen) { 4662 $this->world_abs_size=$aLen; 4663 $this->off=$aStart; 4664 4665 if( $this->world_size<=0 ) { 4666 // This should never ever happen !! 4667 JpGraphError::RaiseL(25074); 4668 //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale] <br> Please report Bug #01 to jpgraph@aditus.nu and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); 4669 4670 } 4671 4672 // scale_factor = number of pixels per world unit 4673 $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); 4674 4675 // scale_abs = start and end points of scale in absolute pixels 4676 $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor); 4677 } 4678 4679 5035 $this->world_abs_size=$aLen; 5036 $this->off=$aStart; 5037 5038 if( $this->world_size<=0 ) { 5039 // This should never ever happen !! 5040 JpGraphError::RaiseL(25074); 5041 //("You have unfortunately stumbled upon a bug in JpGraph. It seems like the scale range is ".$this->world_size." [for ".$this->type." scale] <br> Please report Bug #01 to info@jpgraph.net and include the script that gave this error. This problem could potentially be caused by trying to use \"illegal\" values in the input data arrays (like trying to send in strings or only NULL values) which causes the autoscaling to fail."); 5042 } 5043 5044 // scale_factor = number of pixels per world unit 5045 $this->scale_factor=$this->world_abs_size/($this->world_size*1.0); 5046 5047 // scale_abs = start and end points of scale in absolute pixels 5048 $this->scale_abs=array($this->off,$this->off+$this->world_size*$this->scale_factor); 5049 } 5050 5051 4680 5052 // Calculate number of ticks steps with a specific division 4681 5053 // $a is the divisor of 10**x to generate the first maj tick intervall … … 4684 5056 // $a=2, $b=5 give major ticks with multiple of 5:s ...,0.5,5,50,... 4685 5057 // We return a vector of 4686 // 5058 // [$numsteps,$adjmin,$adjmax,$minstep,$majstep] 4687 5059 // If $majend==true then the first and last marks on the axis will be major 4688 5060 // labeled tick marks otherwise it will be adjusted to the closest min tick mark 4689 5061 function CalcTicks($maxsteps,$min,$max,$a,$b,$majend=true) { 4690 $diff=$max-$min; 4691 if( $diff==0 ) 4692 $ld=0; 4693 else 4694 $ld=floor(log10($diff)); 4695 4696 // Gravitate min towards zero if we are close 4697 if( $min>0 && $min < pow(10,$ld) ) $min=0; 4698 4699 //$majstep=pow(10,$ld-1)/$a; 4700 $majstep=pow(10,$ld)/$a; 4701 $minstep=$majstep/$b; 4702 4703 $adjmax=ceil($max/$minstep)*$minstep; 4704 $adjmin=floor($min/$minstep)*$minstep; 4705 $adjdiff = $adjmax-$adjmin; 4706 $numsteps=$adjdiff/$majstep; 4707 4708 while( $numsteps>$maxsteps ) { 4709 $majstep=pow(10,$ld)/$a; 4710 $numsteps=$adjdiff/$majstep; 4711 ++$ld; 4712 } 4713 4714 $minstep=$majstep/$b; 4715 $adjmin=floor($min/$minstep)*$minstep; 4716 $adjdiff = $adjmax-$adjmin; 4717 if( $majend ) { 4718 $adjmin = floor($min/$majstep)*$majstep; 4719 $adjdiff = $adjmax-$adjmin; 4720 $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; 4721 } 4722 else 4723 $adjmax=ceil($max/$minstep)*$minstep; 4724 4725 return array($numsteps,$adjmin,$adjmax,$minstep,$majstep); 5062 $diff=$max-$min; 5063 if( $diff==0 ) { 5064 $ld=0; 5065 } 5066 else { 5067 $ld=floor(log10($diff)); 5068 } 5069 5070 // Gravitate min towards zero if we are close 5071 if( $min>0 && $min < pow(10,$ld) ) $min=0; 5072 5073 //$majstep=pow(10,$ld-1)/$a; 5074 $majstep=pow(10,$ld)/$a; 5075 $minstep=$majstep/$b; 5076 5077 $adjmax=ceil($max/$minstep)*$minstep; 5078 $adjmin=floor($min/$minstep)*$minstep; 5079 $adjdiff = $adjmax-$adjmin; 5080 $numsteps=$adjdiff/$majstep; 5081 5082 while( $numsteps>$maxsteps ) { 5083 $majstep=pow(10,$ld)/$a; 5084 $numsteps=$adjdiff/$majstep; 5085 ++$ld; 5086 } 5087 5088 $minstep=$majstep/$b; 5089 $adjmin=floor($min/$minstep)*$minstep; 5090 $adjdiff = $adjmax-$adjmin; 5091 if( $majend ) { 5092 $adjmin = floor($min/$majstep)*$majstep; 5093 $adjdiff = $adjmax-$adjmin; 5094 $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; 5095 } 5096 else { 5097 $adjmax=ceil($max/$minstep)*$minstep; 5098 } 5099 5100 return array($numsteps,$adjmin,$adjmax,$minstep,$majstep); 4726 5101 } 4727 5102 4728 5103 function CalcTicksFreeze($maxsteps,$min,$max,$a,$b) { 4729 // Same as CalcTicks but don't adjust min/max values 4730 $diff=$max-$min; 4731 if( $diff==0 ) 4732 $ld=0; 4733 else 4734 $ld=floor(log10($diff)); 4735 4736 //$majstep=pow(10,$ld-1)/$a; 4737 $majstep=pow(10,$ld)/$a; 4738 $minstep=$majstep/$b; 4739 $numsteps=floor($diff/$majstep); 4740 4741 while( $numsteps > $maxsteps ) { 4742 $majstep=pow(10,$ld)/$a; 4743 $numsteps=floor($diff/$majstep); 4744 ++$ld; 4745 } 4746 $minstep=$majstep/$b; 4747 return array($numsteps,$minstep,$majstep); 4748 } 4749 4750 5104 // Same as CalcTicks but don't adjust min/max values 5105 $diff=$max-$min; 5106 if( $diff==0 ) { 5107 $ld=0; 5108 } 5109 else { 5110 $ld=floor(log10($diff)); 5111 } 5112 5113 //$majstep=pow(10,$ld-1)/$a; 5114 $majstep=pow(10,$ld)/$a; 5115 $minstep=$majstep/$b; 5116 $numsteps=floor($diff/$majstep); 5117 5118 while( $numsteps > $maxsteps ) { 5119 $majstep=pow(10,$ld)/$a; 5120 $numsteps=floor($diff/$majstep); 5121 ++$ld; 5122 } 5123 $minstep=$majstep/$b; 5124 return array($numsteps,$minstep,$majstep); 5125 } 5126 5127 4751 5128 function IntCalcTicks($maxsteps,$min,$max,$a,$majend=true) { 4752 $diff=$max-$min; 4753 if( $diff==0 ) 4754 JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); 4755 else 4756 $ld=floor(log10($diff)); 4757 4758 // Gravitate min towards zero if we are close 4759 if( $min>0 && $min < pow(10,$ld) ) $min=0; 4760 4761 if( $ld == 0 ) $ld=1; 4762 4763 if( $a == 1 ) 4764 $majstep = 1; 4765 else 4766 $majstep=pow(10,$ld)/$a; 4767 $adjmax=ceil($max/$majstep)*$majstep; 4768 4769 $adjmin=floor($min/$majstep)*$majstep; 4770 $adjdiff = $adjmax-$adjmin; 4771 $numsteps=$adjdiff/$majstep; 4772 while( $numsteps>$maxsteps ) { 4773 $majstep=pow(10,$ld)/$a; 4774 $numsteps=$adjdiff/$majstep; 4775 ++$ld; 4776 } 4777 4778 $adjmin=floor($min/$majstep)*$majstep; 4779 $adjdiff = $adjmax-$adjmin; 4780 if( $majend ) { 4781 $adjmin = floor($min/$majstep)*$majstep; 4782 $adjdiff = $adjmax-$adjmin; 4783 $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; 4784 } 4785 else 4786 $adjmax=ceil($max/$majstep)*$majstep; 4787 4788 return array($numsteps,$adjmin,$adjmax,$majstep); 5129 $diff=$max-$min; 5130 if( $diff==0 ) { 5131 JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); 5132 } 5133 else { 5134 $ld=floor(log10($diff)); 5135 } 5136 5137 // Gravitate min towards zero if we are close 5138 if( $min>0 && $min < pow(10,$ld) ) { 5139 $min=0; 5140 } 5141 if( $ld == 0 ) { 5142 $ld=1; 5143 } 5144 if( $a == 1 ) { 5145 $majstep = 1; 5146 } 5147 else { 5148 $majstep=pow(10,$ld)/$a; 5149 } 5150 $adjmax=ceil($max/$majstep)*$majstep; 5151 5152 $adjmin=floor($min/$majstep)*$majstep; 5153 $adjdiff = $adjmax-$adjmin; 5154 $numsteps=$adjdiff/$majstep; 5155 while( $numsteps>$maxsteps ) { 5156 $majstep=pow(10,$ld)/$a; 5157 $numsteps=$adjdiff/$majstep; 5158 ++$ld; 5159 } 5160 5161 $adjmin=floor($min/$majstep)*$majstep; 5162 $adjdiff = $adjmax-$adjmin; 5163 if( $majend ) { 5164 $adjmin = floor($min/$majstep)*$majstep; 5165 $adjdiff = $adjmax-$adjmin; 5166 $adjmax = ceil($adjdiff/$majstep)*$majstep+$adjmin; 5167 } 5168 else { 5169 $adjmax=ceil($max/$majstep)*$majstep; 5170 } 5171 5172 return array($numsteps,$adjmin,$adjmax,$majstep); 4789 5173 } 4790 5174 4791 5175 4792 5176 function IntCalcTicksFreeze($maxsteps,$min,$max,$a) { 4793 // Same as IntCalcTick but don't change min/max values 4794 $diff=$max-$min; 4795 if( $diff==0 ) 4796 JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); 4797 else 4798 $ld=floor(log10($diff)); 4799 4800 if( $ld == 0 ) $ld=1; 4801 4802 if( $a == 1 ) 4803 $majstep = 1; 4804 else 4805 $majstep=pow(10,$ld)/$a; 4806 4807 $numsteps=floor($diff/$majstep); 4808 while( $numsteps > $maxsteps ) { 4809 $majstep=pow(10,$ld)/$a; 4810 $numsteps=floor($diff/$majstep); 4811 ++$ld; 4812 } 4813 4814 return array($numsteps,$majstep); 4815 } 4816 4817 4818 5177 // Same as IntCalcTick but don't change min/max values 5178 $diff=$max-$min; 5179 if( $diff==0 ) { 5180 JpGraphError::RaiseL(25075);//('Can\'t automatically determine ticks since min==max.'); 5181 } 5182 else { 5183 $ld=floor(log10($diff)); 5184 } 5185 if( $ld == 0 ) { 5186 $ld=1; 5187 } 5188 if( $a == 1 ) { 5189 $majstep = 1; 5190 } 5191 else { 5192 $majstep=pow(10,$ld)/$a; 5193 } 5194 5195 $numsteps=floor($diff/$majstep); 5196 while( $numsteps > $maxsteps ) { 5197 $majstep=pow(10,$ld)/$a; 5198 $numsteps=floor($diff/$majstep); 5199 ++$ld; 5200 } 5201 5202 return array($numsteps,$majstep); 5203 } 5204 4819 5205 // Determine the minimum of three values witha weight for last value 4820 5206 function MatchMin3($a,$b,$c,$weight) { 4821 if( $a < $b ) { 4822 if( $a < ($c*$weight) ) 4823 return 1; // $a smallest 4824 else 4825 return 3; // $c smallest 4826 } 4827 elseif( $b < ($c*$weight) ) 4828 return 2; // $b smallest 4829 return 3; // $c smallest 5207 if( $a < $b ) { 5208 if( $a < ($c*$weight) ) { 5209 return 1; // $a smallest 5210 } 5211 else { 5212 return 3; // $c smallest 5213 } 5214 } 5215 elseif( $b < ($c*$weight) ) { 5216 return 2; // $b smallest 5217 } 5218 return 3; // $c smallest 5219 } 5220 5221 function __get($name) { 5222 $variable_name = '_' . $name; 5223 5224 if (isset($this->$variable_name)) { 5225 return $this->$variable_name * SUPERSAMPLING_SCALE; 5226 } else { 5227 JpGraphError::RaiseL('25132', $name); 5228 } 5229 } 5230 5231 function __set($name, $value) { 5232 $this->{'_'.$name} = $value; 4830 5233 } 4831 5234 } // Class … … 4839 5242 public $margin=5; 4840 5243 public $show=false; 4841 public $valign= "",$halign="center";4842 public $format= "%.1f",$negformat="";4843 private $ff=FF_ FONT1,$fs=FS_NORMAL,$fsize=10;5244 public $valign='',$halign='center'; 5245 public $format='%.1f',$negformat=''; 5246 private $ff=FF_DEFAULT,$fs=FS_NORMAL,$fsize=8; 4844 5247 private $iFormCallback=''; 4845 5248 private $angle=0; 4846 private $color= "navy",$negcolor="";5249 private $color='navy',$negcolor=''; 4847 5250 private $iHideZero=false; 5251 public $txt=null; 5252 5253 function __construct() { 5254 $this->txt = new Text(); 5255 } 4848 5256 4849 5257 function Show($aFlag=true) { 4850 4851 } 4852 4853 function SetColor($aColor,$aNegcolor= "") {4854 4855 4856 } 4857 4858 function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize= 10) {4859 4860 4861 5258 $this->show=$aFlag; 5259 } 5260 5261 function SetColor($aColor,$aNegcolor='') { 5262 $this->color = $aColor; 5263 $this->negcolor = $aNegcolor; 5264 } 5265 5266 function SetFont($aFontFamily,$aFontStyle=FS_NORMAL,$aFontSize=8) { 5267 $this->ff=$aFontFamily; 5268 $this->fs=$aFontStyle; 5269 $this->fsize=$aFontSize; 4862 5270 } 4863 5271 4864 5272 function ApplyFont($aImg) { 4865 5273 $aImg->SetFont($this->ff,$this->fs,$this->fsize); 4866 5274 } 4867 5275 4868 5276 function SetMargin($aMargin) { 4869 5277 $this->margin = $aMargin; 4870 5278 } 4871 5279 4872 5280 function SetAngle($aAngle) { 4873 5281 $this->angle = $aAngle; 4874 5282 } 4875 5283 4876 5284 function SetAlign($aHAlign,$aVAlign='') { 4877 4878 4879 } 4880 4881 function SetFormat($aFormat,$aNegFormat= "") {4882 4883 5285 $this->halign = $aHAlign; 5286 $this->valign = $aVAlign; 5287 } 5288 5289 function SetFormat($aFormat,$aNegFormat='') { 5290 $this->format= $aFormat; 5291 $this->negformat= $aNegFormat; 4884 5292 } 4885 5293 4886 5294 function SetFormatCallback($aFunc) { 4887 5295 $this->iFormCallback = $aFunc; 4888 5296 } 4889 5297 4890 5298 function HideZero($aFlag=true) { 4891 5299 $this->iHideZero=$aFlag; 4892 5300 } 4893 5301 4894 5302 function Stroke($img,$aVal,$x,$y) { 4895 4896 if( $this->show ) 4897 { 4898 if( $this->negformat=="" ) $this->negformat=$this->format; 4899 if( $this->negcolor=="" ) $this->negcolor=$this->color; 4900 4901 if( $aVal===NULL || (is_string($aVal) && ($aVal=="" || $aVal=="-" || $aVal=="x" ) ) ) 4902 return; 4903 4904 if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) { 4905 return; 4906 } 4907 4908 // Since the value is used in different cirumstances we need to check what 4909 // kind of formatting we shall use. For example, to display values in a line 4910 // graph we simply display the formatted value, but in the case where the user 4911 // has already specified a text string we don't fo anything. 4912 if( $this->iFormCallback != '' ) { 4913 $f = $this->iFormCallback; 4914 $sval = call_user_func($f,$aVal); 4915 } 4916 elseif( is_numeric($aVal) ) { 4917 if( $aVal >= 0 ) 4918 $sval=sprintf($this->format,$aVal); 4919 else 4920 $sval=sprintf($this->negformat,$aVal); 4921 } 4922 else 4923 $sval=$aVal; 4924 4925 $y = $y-sign($aVal)*$this->margin; 4926 4927 $txt = new Text($sval,$x,$y); 4928 $txt->SetFont($this->ff,$this->fs,$this->fsize); 4929 if( $this->valign == "" ) { 4930 if( $aVal >= 0 ) 4931 $valign = "bottom"; 4932 else 4933 $valign = "top"; 4934 } 4935 else 4936 $valign = $this->valign; 4937 $txt->Align($this->halign,$valign); 4938 4939 $txt->SetOrientation($this->angle); 4940 if( $aVal > 0 ) 4941 $txt->SetColor($this->color); 4942 else 4943 $txt->SetColor($this->negcolor); 4944 $txt->Stroke($img); 4945 } 5303 5304 if( $this->show ) 5305 { 5306 if( $this->negformat=='' ) { 5307 $this->negformat=$this->format; 5308 } 5309 if( $this->negcolor=='' ) { 5310 $this->negcolor=$this->color; 5311 } 5312 5313 if( $aVal===NULL || (is_string($aVal) && ($aVal=='' || $aVal=='-' || $aVal=='x' ) ) ) { 5314 return; 5315 } 5316 5317 if( is_numeric($aVal) && $aVal==0 && $this->iHideZero ) { 5318 return; 5319 } 5320 5321 // Since the value is used in different cirumstances we need to check what 5322 // kind of formatting we shall use. For example, to display values in a line 5323 // graph we simply display the formatted value, but in the case where the user 5324 // has already specified a text string we don't fo anything. 5325 if( $this->iFormCallback != '' ) { 5326 $f = $this->iFormCallback; 5327 $sval = call_user_func($f,$aVal); 5328 } 5329 elseif( is_numeric($aVal) ) { 5330 if( $aVal >= 0 ) { 5331 $sval=sprintf($this->format,$aVal); 5332 } 5333 else { 5334 $sval=sprintf($this->negformat,$aVal); 5335 } 5336 } 5337 else { 5338 $sval=$aVal; 5339 } 5340 5341 $y = $y-sign($aVal)*$this->margin; 5342 5343 $this->txt->Set($sval); 5344 $this->txt->SetPos($x,$y); 5345 $this->txt->SetFont($this->ff,$this->fs,$this->fsize); 5346 if( $this->valign == '' ) { 5347 if( $aVal >= 0 ) { 5348 $valign = "bottom"; 5349 } 5350 else { 5351 $valign = "top"; 5352 } 5353 } 5354 else { 5355 $valign = $this->valign; 5356 } 5357 $this->txt->Align($this->halign,$valign); 5358 5359 $this->txt->SetOrientation($this->angle); 5360 if( $aVal > 0 ) { 5361 $this->txt->SetColor($this->color); 5362 } 5363 else { 5364 $this->txt->SetColor($this->negcolor); 5365 } 5366 $this->txt->Stroke($img); 5367 } 4946 5368 } 4947 5369 } … … 4956 5378 public $legend=''; 4957 5379 public $coords=array(); 4958 public $color= "black";5380 public $color='black'; 4959 5381 public $hidelegend=false; 4960 5382 public $line_weight=1; 4961 5383 public $csimtargets=array(),$csimwintargets=array(); // Array of targets for CSIM 4962 public $csimareas= ""; // Resultant CSIM area tags4963 public $csimalts=null; 5384 public $csimareas=''; // Resultant CSIM area tags 5385 public $csimalts=null; // ALT:s for corresponding target 4964 5386 public $legendcsimtarget='',$legendcsimwintarget=''; 4965 5387 public $legendcsimalt=''; 4966 protected $weight=1; 5388 protected $weight=1; 4967 5389 protected $center=false; 4968 //--------------- 4969 // CONSTRUCTOR 4970 function Plot($aDatay,$aDatax=false) { 4971 $this->numpoints = count($aDatay); 4972 if( $this->numpoints==0 ) 4973 JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point."); 4974 $this->coords[0]=$aDatay; 4975 if( is_array($aDatax) ) { 4976 $this->coords[1]=$aDatax; 4977 $n = count($aDatax); 4978 for($i=0; $i < $n; ++$i ) { 4979 if( !is_numeric($aDatax[$i]) ) { 4980 JpGraphError::RaiseL(25070); 4981 } 4982 } 4983 } 4984 $this->value = new DisplayValue(); 4985 } 4986 4987 //--------------- 4988 // PUBLIC METHODS 5390 5391 protected $inputValues; 5392 protected $isRunningClear = false; 5393 5394 function __construct($aDatay,$aDatax=false) { 5395 $this->numpoints = count($aDatay); 5396 if( $this->numpoints==0 ) { 5397 JpGraphError::RaiseL(25121);//("Empty input data array specified for plot. Must have at least one data point."); 5398 } 5399 5400 if (!$this->isRunningClear) { 5401 $this->inputValues = array(); 5402 $this->inputValues['aDatay'] = $aDatay; 5403 $this->inputValues['aDatax'] = $aDatax; 5404 } 5405 5406 $this->coords[0]=$aDatay; 5407 if( is_array($aDatax) ) { 5408 $this->coords[1]=$aDatax; 5409 $n = count($aDatax); 5410 for( $i=0; $i < $n; ++$i ) { 5411 if( !is_numeric($aDatax[$i]) ) { 5412 JpGraphError::RaiseL(25070); 5413 } 5414 } 5415 } 5416 $this->value = new DisplayValue(); 5417 } 4989 5418 4990 5419 // Stroke the plot … … 4992 5421 // the subclasses 4993 5422 function Stroke($aImg,$aXScale,$aYScale) { 4994 5423 JpGraphError::RaiseL(25122);//("JpGraph: Stroke() must be implemented by concrete subclass to class Plot"); 4995 5424 } 4996 5425 4997 5426 function HideLegend($f=true) { 4998 5427 $this->hidelegend = $f; 4999 5428 } 5000 5429 5001 5430 function DoLegend($graph) { 5002 5003 5431 if( !$this->hidelegend ) 5432 $this->Legend($graph); 5004 5433 } 5005 5434 5006 5435 function StrokeDataValue($img,$aVal,$x,$y) { 5007 5008 } 5009 5010 // Set href targets for CSIM 5436 $this->value->Stroke($img,$aVal,$x,$y); 5437 } 5438 5439 // Set href targets for CSIM 5011 5440 function SetCSIMTargets($aTargets,$aAlts='',$aWinTargets='') { 5012 5013 5014 $this->csimalts=$aAlts; 5015 } 5016 5441 $this->csimtargets=$aTargets; 5442 $this->csimwintargets=$aWinTargets; 5443 $this->csimalts=$aAlts; 5444 } 5445 5017 5446 // Get all created areas 5018 5447 function GetCSIMareas() { 5019 5020 } 5021 5448 return $this->csimareas; 5449 } 5450 5022 5451 // "Virtual" function which gets called before any scale 5023 5452 // or axis are stroked used to do any plot specific adjustment 5024 5453 function PreStrokeAdjust($aGraph) { 5025 if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) 5026 JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead."); 5027 return true; 5028 } 5029 5454 if( substr($aGraph->axtype,0,4) == "text" && (isset($this->coords[1])) ) { 5455 JpGraphError::RaiseL(25123);//("JpGraph: You can't use a text X-scale with specified X-coords. Use a \"int\" or \"lin\" scale instead."); 5456 } 5457 return true; 5458 } 5459 5460 // Virtual function to the the concrete plot class to make any changes to the graph 5461 // and scale before the stroke process begins 5462 function PreScaleSetup($aGraph) { 5463 // Empty 5464 } 5465 5030 5466 // Get minimum values in plot 5031 5467 function Min() { 5032 if( isset($this->coords[1]) ) 5033 5034 else 5035 $x=""; 5036 if( $x != "" && count($x) > 0 ) { 5037 $xm=min($x); 5038 } 5039 else 5040 $xm=0; 5041 $y=$this->coords[0]; 5042 $cnt = count($y);5043 if( $cnt > 0 ) { 5044 /* 5045 if( ! isset($y[0]) ) { 5046 JpGraphError('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)'); 5047 } 5048 $ym = $y[0]; 5049 */ 5050 $i=0; 5051 while( $i<$cnt && !is_numeric($ym=$y[$i]) ) 5052 $i++; 5053 while( $i < $cnt) { 5054 if( is_numeric($y[$i]) ) 5055 $ym=min($ym,$y[$i]);5056 ++$i; 5057 } 5058 } 5059 else 5060 $ym=""; 5061 5062 } 5063 5468 if( isset($this->coords[1]) ) { 5469 $x=$this->coords[1]; 5470 } 5471 else { 5472 $x=''; 5473 } 5474 if( $x != '' && count($x) > 0 ) { 5475 $xm=min($x); 5476 } 5477 else { 5478 $xm=0; 5479 } 5480 $y=$this->coords[0]; 5481 $cnt = count($y); 5482 if( $cnt > 0 ) { 5483 $i=0; 5484 while( $i<$cnt && !is_numeric($ym=$y[$i]) ) { 5485 $i++; 5486 } 5487 while( $i < $cnt) { 5488 if( is_numeric($y[$i]) ) { 5489 $ym=min($ym,$y[$i]); 5490 } 5491 ++$i; 5492 } 5493 } 5494 else { 5495 $ym=''; 5496 } 5497 return array($xm,$ym); 5498 } 5499 5064 5500 // Get maximum value in plot 5065 5501 function Max() { 5066 if( isset($this->coords[1]) ) 5067 $x=$this->coords[1]; 5068 else 5069 $x=""; 5070 5071 if( $x!="" && count($x) > 0 ) 5072 $xm=max($x); 5073 else { 5074 $xm = $this->numpoints-1; 5075 } 5076 $y=$this->coords[0]; 5077 if( count($y) > 0 ) { 5078 /* 5079 if( !isset($y[0]) ) { 5080 JpGraphError::Raise('The input data array must have consecutive values from position 0 and forward. The given y-array starts with empty values (NULL)'); 5081 // $y[0] = 0; 5082 // Change in 1.5.1 Don't treat this as an error any more. Just silently convert to 0 5083 // Change in 1.17 Treat his as an error again !! This is the right way to do !! 5084 } 5085 */ 5086 $cnt = count($y); 5087 $i=0; 5088 while( $i<$cnt && !is_numeric($ym=$y[$i]) ) 5089 $i++; 5090 while( $i < $cnt ) { 5091 if( is_numeric($y[$i]) ) 5092 $ym=max($ym,$y[$i]); 5093 ++$i; 5094 } 5095 } 5096 else 5097 $ym=""; 5098 return array($xm,$ym); 5099 } 5100 5502 if( isset($this->coords[1]) ) { 5503 $x=$this->coords[1]; 5504 } 5505 else { 5506 $x=''; 5507 } 5508 5509 if( $x!='' && count($x) > 0 ) { 5510 $xm=max($x); 5511 } 5512 else { 5513 $xm = $this->numpoints-1; 5514 } 5515 $y=$this->coords[0]; 5516 if( count($y) > 0 ) { 5517 $cnt = count($y); 5518 $i=0; 5519 while( $i<$cnt && !is_numeric($ym=$y[$i]) ) { 5520 $i++; 5521 } 5522 while( $i < $cnt ) { 5523 if( is_numeric($y[$i]) ) { 5524 $ym=max($ym,$y[$i]); 5525 } 5526 ++$i; 5527 } 5528 } 5529 else { 5530 $ym=''; 5531 } 5532 return array($xm,$ym); 5533 } 5534 5101 5535 function SetColor($aColor) { 5102 5103 } 5104 5536 $this->color=$aColor; 5537 } 5538 5105 5539 function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { 5106 5107 5108 5109 5540 $this->legend = $aLegend; 5541 $this->legendcsimtarget = $aCSIM; 5542 $this->legendcsimwintarget = $aCSIMWinTarget; 5543 $this->legendcsimalt = $aCSIMAlt; 5110 5544 } 5111 5545 5112 5546 function SetWeight($aWeight) { 5113 5114 } 5115 5547 $this->weight=$aWeight; 5548 } 5549 5116 5550 function SetLineWeight($aWeight=1) { 5117 5118 } 5119 5551 $this->line_weight=$aWeight; 5552 } 5553 5120 5554 function SetCenter($aCenter=true) { 5121 5122 } 5123 5555 $this->center = $aCenter; 5556 } 5557 5124 5558 // This method gets called by Graph class to plot anything that should go 5125 5559 // into the margin after the margin color has been set. 5126 5560 function StrokeMargin($aImg) { 5127 5561 return true; 5128 5562 } 5129 5563 5130 5564 // Framework function the chance for each plot class to set a legend 5131 5565 function Legend($aGraph) { 5132 if( $this->legend != "" ) 5133 $aGraph->legend->Add($this->legend,$this->color,"",0,$this->legendcsimtarget, 5134 $this->legendcsimalt,$this->legendcsimwintarget); 5135 } 5136 5566 if( $this->legend != '' ) { 5567 $aGraph->legend->Add($this->legend,$this->color,'',0,$this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); 5568 } 5569 } 5570 5571 function Clear() { 5572 $this->isRunningClear = true; 5573 $this->__construct($this->inputValues['aDatay'], $this->inputValues['aDatax']); 5574 $this->isRunningClear = false; 5575 } 5576 5137 5577 } // Class 5138 5578 5139 5579 5140 //=================================================== 5141 // CLASS PlotLine 5142 // Description: 5143 // Data container class to hold properties for a static 5144 // line that is drawn directly in the plot area. 5145 // Usefull to add static borders inside a plot to show 5146 // for example set-values 5147 //=================================================== 5148 class PlotLine { 5149 public $scaleposition, $direction=-1; 5150 protected $weight=1; 5151 protected $color="black"; 5152 private $legend='',$hidelegend=false, $legendcsimtarget='', $legendcsimalt='',$legendcsimwintarget=''; 5153 private $iLineStyle='solid'; 5154 5155 //--------------- 5156 // CONSTRUCTOR 5157 function PlotLine($aDir=HORIZONTAL,$aPos=0,$aColor="black",$aWeight=1) { 5158 $this->direction = $aDir; 5159 $this->color=$aColor; 5160 $this->weight=$aWeight; 5161 $this->scaleposition=$aPos; 5162 } 5163 5164 //--------------- 5165 // PUBLIC METHODS 5166 5167 function SetLegend($aLegend,$aCSIM='',$aCSIMAlt='',$aCSIMWinTarget='') { 5168 $this->legend = $aLegend; 5169 $this->legendcsimtarget = $aCSIM; 5170 $this->legendcsimwintarget = $aCSIMWinTarget; 5171 $this->legendcsimalt = $aCSIMAlt; 5172 } 5173 5174 function HideLegend($f=true) { 5175 $this->hidelegend = $f; 5176 } 5177 5178 function SetPosition($aScalePosition) { 5179 $this->scaleposition=$aScalePosition; 5180 } 5181 5182 function SetDirection($aDir) { 5183 $this->direction = $aDir; 5184 } 5185 5186 function SetColor($aColor) { 5187 $this->color=$aColor; 5188 } 5189 5190 function SetWeight($aWeight) { 5191 $this->weight=$aWeight; 5192 } 5193 5194 function SetLineStyle($aStyle) { 5195 $this->iLineStyle = $aStyle; 5196 } 5197 5198 //--------------- 5199 // PRIVATE METHODS 5200 5201 function DoLegend(&$graph) { 5202 if( !$this->hidelegend ) 5203 $this->Legend($graph); 5204 } 5205 5206 // Framework function the chance for each plot class to set a legend 5207 function Legend(&$aGraph) { 5208 if( $this->legend != "" ) { 5209 $dummyPlotMark = new PlotMark(); 5210 $lineStyle = 1; 5211 $aGraph->legend->Add($this->legend,$this->color,$dummyPlotMark,$lineStyle, 5212 $this->legendcsimtarget,$this->legendcsimalt,$this->legendcsimwintarget); 5213 } 5214 } 5215 5216 function PreStrokeAdjust($aGraph) { 5217 // Nothing to do 5218 } 5219 5220 function Stroke($aImg,$aXScale,$aYScale) { 5221 $aImg->SetColor($this->color); 5222 $aImg->SetLineWeight($this->weight); 5223 $oldStyle = $aImg->SetLineStyle($this->iLineStyle); 5224 if( $this->direction == VERTICAL ) { 5225 $ymin_abs=$aYScale->Translate($aYScale->GetMinVal()); 5226 $ymax_abs=$aYScale->Translate($aYScale->GetMaxVal()); 5227 $xpos_abs=$aXScale->Translate($this->scaleposition); 5228 $aImg->StyleLine($xpos_abs, $ymin_abs, $xpos_abs, $ymax_abs); 5229 } 5230 elseif( $this->direction == HORIZONTAL ) { 5231 $xmin_abs=$aXScale->Translate($aXScale->GetMinVal()); 5232 $xmax_abs=$aXScale->Translate($aXScale->GetMaxVal()); 5233 $ypos_abs=$aYScale->Translate($this->scaleposition); 5234 $aImg->StyleLine($xmin_abs, $ypos_abs, $xmax_abs, $ypos_abs); 5235 } 5236 else { 5237 JpGraphError::RaiseL(25125);//(" Illegal direction for static line"); 5238 } 5239 $aImg->SetLineStyle($oldStyle); 5240 } 5580 // Provide a deterministic list of new colors whenever the getColor() method 5581 // is called. Used to automatically set colors of plots. 5582 class ColorFactory { 5583 5584 static private $iIdx = 0; 5585 static private $iColorList = array( 5586 'black', 5587 'blue', 5588 'orange', 5589 'darkgreen', 5590 'red', 5591 'AntiqueWhite3', 5592 'aquamarine3', 5593 'azure4', 5594 'brown', 5595 'cadetblue3', 5596 'chartreuse4', 5597 'chocolate', 5598 'darkblue', 5599 'darkgoldenrod3', 5600 'darkorchid3', 5601 'darksalmon', 5602 'darkseagreen4', 5603 'deepskyblue2', 5604 'dodgerblue4', 5605 'gold3', 5606 'hotpink', 5607 'lawngreen', 5608 'lightcoral', 5609 'lightpink3', 5610 'lightseagreen', 5611 'lightslateblue', 5612 'mediumpurple', 5613 'olivedrab', 5614 'orangered1', 5615 'peru', 5616 'slategray', 5617 'yellow4', 5618 'springgreen2'); 5619 static private $iNum = 33; 5620 5621 static function getColor() { 5622 if( ColorFactory::$iIdx >= ColorFactory::$iNum ) 5623 ColorFactory::$iIdx = 0; 5624 return ColorFactory::$iColorList[ColorFactory::$iIdx++]; 5625 } 5626 5241 5627 } 5242 5628
Note:
See TracChangeset
for help on using the changeset viewer.