PageRenderTime 92ms CodeModel.GetById 22ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 3ms

/code/ryzom/tools/server/admin/jpgraph/jpgraph.php

https://bitbucket.org/mattraykowski/ryzomcore_demoshard
PHP | 8563 lines | 6475 code | 998 blank | 1090 comment | 1307 complexity | cf2757885786d4194abb37ba5582567a MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2//=======================================================================
   3// File:	JPGRAPH.PHP
   4// Description:	PHP Graph Plotting library. Base module.
   5// Created: 	2001-01-08
   6// Author:	Johan Persson (johanp@aditus.nu)
   7// Ver:		$Id: jpgraph.php,v 1.1 2006/07/07 13:37:14 powles Exp $
   8//
   9// Copyright (c) Aditus Consulting. All rights reserved.
  10//========================================================================
  11
  12require_once('jpg-config.inc');
  13
  14// Version info
  15DEFINE('JPG_VERSION','1.20.3');
  16
  17// For internal use only
  18DEFINE("_JPG_DEBUG",false);
  19DEFINE("_FORCE_IMGTOFILE",false);
  20DEFINE("_FORCE_IMGDIR",'/tmp/jpgimg/');
  21
  22
  23//------------------------------------------------------------------------
  24// Automatic settings of path for cache and font directory
  25// if they have not been previously specified
  26//------------------------------------------------------------------------
  27if(USE_CACHE) {
  28    if (!defined('CACHE_DIR')) {
  29	if ( strstr( PHP_OS, 'WIN') ) {
  30	    if( empty($_SERVER['TEMP']) ) {
  31		$t = new ErrMsgText();
  32		$msg = $t->Get(11,$file,$lineno);
  33		die($msg);
  34	    }
  35	    else {
  36		DEFINE('CACHE_DIR', $_SERVER['TEMP'] . '/');
  37	    }
  38	} else {
  39	    DEFINE('CACHE_DIR','/tmp/jpgraph_cache/');
  40	}
  41    }
  42}
  43elseif( !defined('CACHE_DIR') ) {
  44    DEFINE('CACHE_DIR', '');
  45}
  46
  47if (!defined('TTF_DIR')) {
  48    if (strstr( PHP_OS, 'WIN') ) {
  49	$sroot = getenv('SystemRoot');
  50        if( empty($sroot) ) {
  51	    $t = new ErrMsgText();
  52	    $msg = $t->Get(12,$file,$lineno);
  53	    die($msg);
  54        }
  55	else {
  56	  DEFINE('TTF_DIR', $sroot.'/fonts/');
  57        }
  58    } else {
  59	DEFINE('TTF_DIR','/usr/X11R6/lib/X11/fonts/truetype/');
  60    }
  61}
  62
  63//------------------------------------------------------------------
  64// Constants which are used as parameters for the method calls
  65//------------------------------------------------------------------
  66
  67// TTF Font families
  68DEFINE("FF_COURIER",10);
  69DEFINE("FF_VERDANA",11);
  70DEFINE("FF_TIMES",12);
  71DEFINE("FF_COMIC",14);
  72DEFINE("FF_ARIAL",15);
  73DEFINE("FF_GEORGIA",16);
  74DEFINE("FF_TREBUCHE",17);
  75
  76// Gnome Vera font
  77// Available from http://www.gnome.org/fonts/
  78DEFINE("FF_VERA",19);
  79DEFINE("FF_VERAMONO",20);
  80DEFINE("FF_VERASERIF",21);
  81
  82// Chinese font
  83DEFINE("FF_SIMSUN",30);
  84DEFINE("FF_CHINESE",31);
  85DEFINE("FF_BIG5",31);
  86
  87// Japanese font
  88DEFINE("FF_MINCHO",40);
  89DEFINE("FF_PMINCHO",41);
  90DEFINE("FF_GOTHIC",42);
  91DEFINE("FF_PGOTHIC",43);
  92
  93// Limits for TTF fonts
  94DEFINE('_FF_FIRST',10);
  95DEFINE('_FF_LAST',43);
  96
  97// Older deprecated fonts 
  98DEFINE("FF_BOOK",91);    // Deprecated fonts from 1.9
  99DEFINE("FF_HANDWRT",92); // Deprecated fonts from 1.9
 100
 101// TTF Font styles
 102DEFINE("FS_NORMAL",9001);
 103DEFINE("FS_BOLD",9002);
 104DEFINE("FS_ITALIC",9003);
 105DEFINE("FS_BOLDIT",9004);
 106DEFINE("FS_BOLDITALIC",9004);
 107
 108//Definitions for internal font, new style
 109DEFINE("FF_FONT0",1);
 110DEFINE("FF_FONT1",2);
 111DEFINE("FF_FONT2",4);
 112
 113// Tick density
 114DEFINE("TICKD_DENSE",1);
 115DEFINE("TICKD_NORMAL",2);
 116DEFINE("TICKD_SPARSE",3);
 117DEFINE("TICKD_VERYSPARSE",4);
 118
 119// Side for ticks and labels. 
 120DEFINE("SIDE_LEFT",-1);
 121DEFINE("SIDE_RIGHT",1);
 122DEFINE("SIDE_DOWN",-1);
 123DEFINE("SIDE_BOTTOM",-1);
 124DEFINE("SIDE_UP",1);
 125DEFINE("SIDE_TOP",1);
 126
 127// Legend type stacked vertical or horizontal
 128DEFINE("LEGEND_VERT",0);
 129DEFINE("LEGEND_HOR",1);
 130
 131// Mark types for plot marks
 132DEFINE("MARK_SQUARE",1);
 133DEFINE("MARK_UTRIANGLE",2);
 134DEFINE("MARK_DTRIANGLE",3);
 135DEFINE("MARK_DIAMOND",4);
 136DEFINE("MARK_CIRCLE",5);
 137DEFINE("MARK_FILLEDCIRCLE",6);
 138DEFINE("MARK_CROSS",7);
 139DEFINE("MARK_STAR",8);
 140DEFINE("MARK_X",9);
 141DEFINE("MARK_LEFTTRIANGLE",10);
 142DEFINE("MARK_RIGHTTRIANGLE",11);
 143DEFINE("MARK_FLASH",12);
 144DEFINE("MARK_IMG",13);
 145DEFINE("MARK_FLAG1",14);
 146DEFINE("MARK_FLAG2",15);
 147DEFINE("MARK_FLAG3",16);
 148DEFINE("MARK_FLAG4",17);
 149
 150// Builtin images
 151DEFINE("MARK_IMG_PUSHPIN",50);
 152DEFINE("MARK_IMG_SPUSHPIN",50);
 153DEFINE("MARK_IMG_LPUSHPIN",51);
 154DEFINE("MARK_IMG_DIAMOND",52);
 155DEFINE("MARK_IMG_SQUARE",53);
 156DEFINE("MARK_IMG_STAR",54);
 157DEFINE("MARK_IMG_BALL",55);
 158DEFINE("MARK_IMG_SBALL",55);
 159DEFINE("MARK_IMG_MBALL",56);
 160DEFINE("MARK_IMG_LBALL",57);
 161DEFINE("MARK_IMG_BEVEL",58);
 162
 163// Inline defines
 164DEFINE("INLINE_YES",1);
 165DEFINE("INLINE_NO",0);
 166
 167// Format for background images
 168DEFINE("BGIMG_FILLPLOT",1);
 169DEFINE("BGIMG_FILLFRAME",2);
 170DEFINE("BGIMG_COPY",3);
 171DEFINE("BGIMG_CENTER",4);
 172
 173// Depth of objects
 174DEFINE("DEPTH_BACK",0);
 175DEFINE("DEPTH_FRONT",1);
 176
 177// Direction
 178DEFINE("VERTICAL",1);
 179DEFINE("HORIZONTAL",0);
 180
 181
 182// Axis styles for scientific style axis
 183DEFINE('AXSTYLE_SIMPLE',1);
 184DEFINE('AXSTYLE_BOXIN',2);
 185DEFINE('AXSTYLE_BOXOUT',3);
 186DEFINE('AXSTYLE_YBOXIN',4);
 187DEFINE('AXSTYLE_YBOXOUT',5);
 188
 189// Style for title backgrounds
 190DEFINE('TITLEBKG_STYLE1',1);
 191DEFINE('TITLEBKG_STYLE2',2);
 192DEFINE('TITLEBKG_STYLE3',3);
 193DEFINE('TITLEBKG_FRAME_NONE',0);
 194DEFINE('TITLEBKG_FRAME_FULL',1);
 195DEFINE('TITLEBKG_FRAME_BOTTOM',2);
 196DEFINE('TITLEBKG_FRAME_BEVEL',3);
 197DEFINE('TITLEBKG_FILLSTYLE_HSTRIPED',1);
 198DEFINE('TITLEBKG_FILLSTYLE_VSTRIPED',2);
 199DEFINE('TITLEBKG_FILLSTYLE_SOLID',3);
 200
 201// Style for background gradient fills
 202DEFINE('BGRAD_FRAME',1);
 203DEFINE('BGRAD_MARGIN',2);
 204DEFINE('BGRAD_PLOT',3);
 205
 206// Width of tab titles
 207DEFINE('TABTITLE_WIDTHFIT',0);
 208DEFINE('TABTITLE_WIDTHFULL',-1);
 209
 210// Defines for 3D skew directions
 211DEFINE('SKEW3D_UP',0);
 212DEFINE('SKEW3D_DOWN',1);
 213DEFINE('SKEW3D_LEFT',2);
 214DEFINE('SKEW3D_RIGHT',3);
 215
 216
 217
 218//
 219// Get hold of gradient class (In Version 2.x)
 220// A client of the library has to manually include this
 221//
 222require_once 'jpgraph_gradient.php';
 223
 224
 225class ErrMsgText {
 226    var $lt=NULL;
 227    var $supportedLocales = array('en');
 228    function ErrMsgText() {
 229	GLOBAL $__jpg_err_locale;
 230	if( !in_array($__jpg_err_locale,$this->supportedLocales) )
 231	    $aLoc = 'en';
 232	require_once('lang/'.$__jpg_err_locale.'.inc.php');
 233	$this->lt = $_jpg_messages;
 234    }
 235
 236    function Get($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) {
 237	if( !isset($this->lt[$errnbr]) ) {
 238	    return 'Internal error: The specified error message does not exist in the chosen locale. (Please blame the translator...))';
 239	}
 240	$ea = $this->lt[$errnbr];
 241	$j=0;
 242	if( $a1 !== null ) {
 243	    $argv[$j++] = $a1;
 244	    if( $a2 !== null ) {
 245		$argv[$j++] = $a2;
 246		if( $a3 !== null ) {
 247		    $argv[$j++] = $a3;
 248		    if( $a4 !== null ) {
 249			$argv[$j++] = $a4;
 250			if( $a5 !== null ) {
 251			    $argv[$j++] = $a5;
 252			}
 253		    }
 254		}
 255	    }
 256	}
 257	$numargs = $j; 
 258	if( $ea[1] != $numargs ) {
 259	    // Error message argument count do not match.
 260	    // Just return the error message without arguments.
 261	    return $ea[0];
 262	}
 263	switch( $numargs ) {
 264	    case 1:
 265		$msg = sprintf($ea[0],$argv[0]);
 266		break;
 267	    case 2:
 268		$msg = sprintf($ea[0],$argv[0],$argv[1]);
 269		break;
 270	    case 3:
 271		$msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2]);
 272		break;
 273	    case 4:
 274		$msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3]);
 275		break;
 276	    case 5:
 277		$msg = sprintf($ea[0],$argv[0],$argv[1],$argv[2],$argv[3],$argv[4]);
 278		break;
 279	    case 0:
 280	    default:
 281		$msg = sprintf($ea[0]);
 282		break;
 283	}
 284	return $msg;
 285    }
 286}
 287
 288//
 289// A wrapper class that is used to access the specified error object
 290// (to hide the global error parameter and avoid having a GLOBAL directive
 291// in all methods.
 292//
 293GLOBAL $__jpg_err;
 294GLOBAL $__jpg_err_locale ;
 295$__jpg_err_locale = 'en';
 296class JpGraphError {
 297    function Install($aErrObject) {
 298	GLOBAL $__jpg_err;
 299	$__jpg_err = $aErrObject;
 300    }
 301    function Raise($aMsg,$aHalt=true){
 302	GLOBAL $__jpg_err;
 303	$tmp = new $__jpg_err;
 304	$tmp->Raise($aMsg,$aHalt);
 305    }
 306    function RaiseL($errnbr,$a1=null,$a2=null,$a3=null,$a4=null,$a5=null) {
 307	GLOBAL $__jpg_err;
 308	$t = new ErrMsgText();
 309	$msg = $t->Get($errnbr,$a1,$a2,$a3,$a4,$a5);
 310	$tmp = new $__jpg_err;
 311	$tmp->Raise($msg);
 312    }
 313}
 314 
 315//
 316// ... and install the default error handler
 317//
 318if( USE_IMAGE_ERROR_HANDLER ) {
 319    $__jpg_err = "JpGraphErrObjectImg";
 320}
 321else {
 322    $__jpg_err = "JpGraphErrObject"; 
 323}
 324
 325//
 326// Make GD sanity check
 327//
 328if( !function_exists("imagetypes") || !function_exists('imagecreatefromstring') ) {
 329    JpGraphError::RaiseL(25001);
 330//("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)");
 331}
 332
 333//
 334// Routine to determine if GD1 or GD2 is installed
 335//
 336function CheckGDVersion() {
 337    $GDfuncList = get_extension_funcs('gd');
 338    if( !$GDfuncList ) return 0 ;
 339    else {
 340	if( in_array('imagegd2',$GDfuncList) && 
 341	    in_array('imagecreatetruecolor',$GDfuncList))
 342	    return 2;
 343	else
 344	    return 1;
 345    } 
 346}
 347
 348//
 349// Check what version of the GD library is installed.
 350//
 351$GLOBALS['gd2'] = false;
 352if( USE_LIBRARY_GD2 === 'auto' ) {
 353    $gdversion = CheckGDVersion();
 354    if( $gdversion == 2 ) {
 355	$GLOBALS['gd2'] = true;
 356	$GLOBALS['copyfunc'] = 'imagecopyresampled';
 357    }
 358    elseif( $gdversion == 1 ) {
 359	$GLOBALS['gd2'] = false;
 360	$GLOBALS['copyfunc'] = 'imagecopyresized';
 361    }
 362    else {
 363	JpGraphError::RaiseL(25002);
 364//(" Your PHP installation does not seem to have the required GD library. Please see the PHP documentation on how to install and enable the GD library.");
 365    }
 366}
 367else {
 368    $GLOBALS['gd2'] = USE_LIBRARY_GD2;
 369    $GLOBALS['copyfunc'] = USE_LIBRARY_GD2 ? 'imagecopyresampled' : 'imagecopyresized';
 370}
 371
 372
 373//
 374// First of all set up a default error handler
 375//
 376
 377
 378//=============================================================
 379// The default trivial text error handler.
 380//=============================================================
 381class JpGraphErrObject {
 382
 383    var $iTitle = "JpGraph Error";
 384    var $iDest = false;
 385
 386    function JpGraphErrObject() {
 387	// Empty. Reserved for future use
 388    }
 389
 390    function SetTitle($aTitle) {
 391	$this->iTitle = $aTitle;
 392    }
 393
 394    function SetStrokeDest($aDest) { 
 395	$this->iDest = $aDest; 
 396    }
 397
 398    // If aHalt is true then execution can't continue. Typical used for fatal errors.
 399    function Raise($aMsg,$aHalt=true) {
 400	$aMsg = $this->iTitle.' '.$aMsg;
 401	if ($this->iDest) {
 402	    $f = @fopen($this->iDest,'a');
 403	    if( $f ) {
 404		@fwrite($f,$aMsg);
 405		@fclose($f);
 406	    }
 407	}
 408	else {
 409	    echo $aMsg;
 410	}
 411	if( $aHalt )
 412	    die();
 413    }
 414}
 415
 416//==============================================================
 417// An image based error handler
 418//==============================================================
 419class JpGraphErrObjectImg extends JpGraphErrObject {
 420
 421    function Raise($aMsg,$aHalt=true) {
 422	$img_iconerror = 
 423	    'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'.
 424	    'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'.
 425	    'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'.
 426	    'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'.
 427	    'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'.
 428	    'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'.
 429	    '2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'.
 430	    'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'.
 431	    'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'.
 432	    'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'.
 433	    '6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'.
 434	    'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'.
 435	    'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'.
 436	    'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'.
 437	    'qL72fwAAAABJRU5ErkJggg==' ;
 438
 439	if( function_exists("imagetypes") )
 440	    $supported = imagetypes();
 441	else
 442	    $supported = 0;
 443
 444	if( !function_exists('imagecreatefromstring') )
 445	    $supported = 0;
 446
 447	if( ob_get_length() || headers_sent() || !($supported & IMG_PNG) ) {
 448	    // Special case for headers already sent or that the installation doesn't support
 449	    // the PNG format (which the error icon is encoded in). 
 450	    // Dont return an image since it can't be displayed
 451	    die($this->iTitle.' '.$aMsg);		
 452	}
 453
 454	$aMsg = wordwrap($aMsg,55);
 455	$lines = substr_count($aMsg,"\n");
 456
 457	// Create the error icon GD
 458	$erricon = Image::CreateFromString(base64_decode($img_iconerror));   
 459
 460	// Create an image that contains the error text.
 461	$w=400; 	
 462	$h=100 + 15*max(0,$lines-3);
 463
 464	$img = new Image($w,$h);
 465
 466	// Drop shadow
 467	$img->SetColor("gray");
 468	$img->FilledRectangle(5,5,$w-1,$h-1,10);
 469	$img->SetColor("gray:0.7");
 470	$img->FilledRectangle(5,5,$w-3,$h-3,10);
 471	
 472	// Window background
 473	$img->SetColor("lightblue");
 474	$img->FilledRectangle(1,1,$w-5,$h-5);
 475	$img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40);
 476
 477	// Window border
 478	$img->SetColor("black");
 479	$img->Rectangle(1,1,$w-5,$h-5);
 480	$img->Rectangle(0,0,$w-4,$h-4);
 481	
 482	// Window top row
 483	$img->SetColor("darkred");
 484	for($y=3; $y < 18; $y += 2 ) 
 485	    $img->Line(1,$y,$w-6,$y);
 486
 487	// "White shadow"
 488	$img->SetColor("white");
 489
 490	// Left window edge
 491	$img->Line(2,2,2,$h-5);
 492	$img->Line(2,2,$w-6,2);
 493
 494	// "Gray button shadow"
 495	$img->SetColor("darkgray");
 496
 497	// Gray window shadow
 498	$img->Line(2,$h-6,$w-5,$h-6);
 499	$img->Line(3,$h-7,$w-5,$h-7);
 500
 501	// Window title
 502	$m = floor($w/2-5);
 503	$l = 100;
 504	$img->SetColor("lightgray:1.3");
 505	$img->FilledRectangle($m-$l,2,$m+$l,16);
 506
 507	// Stroke text
 508	$img->SetColor("darkred");
 509	$img->SetFont(FF_FONT2,FS_BOLD);
 510	$img->StrokeText($m-50,15,$this->iTitle);
 511	$img->SetColor("black");
 512	$img->SetFont(FF_FONT1,FS_NORMAL);
 513	$txt = new Text($aMsg,52,25);
 514	$txt->Align("left","top");
 515	$txt->Stroke($img);
 516	if ($this->iDest) {
 517           $img->Stream($this->iDest);
 518	} else {
 519	    $img->Headers();
 520	    $img->Stream();
 521	}
 522	if( $aHalt )
 523	    die();
 524    }
 525}
 526
 527//
 528// Setup PHP error handler
 529//
 530function _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) {
 531    // Respect current error level
 532    if( $errno & error_reporting() ) {
 533	JpGraphError::RaiseL(25003,basename($filename),$linenum,$errmsg); 
 534    }
 535}
 536
 537if( INSTALL_PHP_ERR_HANDLER ) {
 538    set_error_handler("_phpErrorHandler");
 539}
 540
 541//
 542//Check if there were any warnings, perhaps some wrong includes by the user
 543//
 544if( isset($GLOBALS['php_errormsg']) && CATCH_PHPERRMSG && 
 545    !preg_match('|Deprecated|', $GLOBALS['php_errormsg'])) {
 546    JpGraphError::RaiseL(25004,$GLOBALS['php_errormsg']);
 547}
 548
 549
 550// Useful mathematical function
 551function sign($a) {return $a >= 0 ? 1 : -1;}
 552
 553// Utility function to generate an image name based on the filename we
 554// are running from and assuming we use auto detection of graphic format
 555// (top level), i.e it is safe to call this function
 556// from a script that uses JpGraph
 557function GenImgName() {
 558    global $_SERVER;
 559
 560    // Determine what format we should use when we save the images
 561    $supported = imagetypes();
 562    if( $supported & IMG_PNG )	   $img_format="png";
 563    elseif( $supported & IMG_GIF ) $img_format="gif";
 564    elseif( $supported & IMG_JPG ) $img_format="jpeg";
 565
 566    if( !isset($_SERVER['PHP_SELF']) )
 567	JpGraphError::RaiseL(25005);
 568//(" 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.");
 569    $fname = basename($_SERVER['PHP_SELF']);
 570    if( !empty($_SERVER['QUERY_STRING']) ) {
 571	$q = @$_SERVER['QUERY_STRING'];
 572	$fname .= '?'.preg_replace("/\W/", "_", $q).'.'.$img_format;
 573    }
 574    else {
 575	$fname = substr($fname,0,strlen($fname)-4).'.'.$img_format;
 576    }
 577    return $fname;
 578}
 579
 580class LanguageConv {
 581    var $g2312 = null ;
 582
 583    function Convert($aTxt,$aFF) {
 584	if( LANGUAGE_CYRILLIC ) {
 585	    if( CYRILLIC_FROM_WINDOWS ) {
 586		$aTxt = convert_cyr_string($aTxt, "w", "k"); 
 587	    }
 588	    $isostring = convert_cyr_string($aTxt, "k", "i");
 589	    $unistring = LanguageConv::iso2uni($isostring);
 590	    return $unistring;
 591	}
 592	elseif( $aFF === FF_SIMSUN ) {
 593	    // Do Chinese conversion
 594	    if( $this->g2312 == null ) {
 595		include_once 'jpgraph_gb2312.php' ;
 596		$this->g2312 = new GB2312toUTF8();
 597	    }
 598	    return $this->g2312->gb2utf8($aTxt);
 599	}
 600	elseif( $aFF === FF_CHINESE ) {
 601	    if( !function_exists('iconv') ) {
 602		JpGraphError::RaiseL(25006);
 603//('Usage of FF_CHINESE (FF_BIG5) font family requires that your PHP setup has the iconv() function. By default this is not compiled into PHP (needs the "--width-iconv" when configured).');
 604	    }
 605	    return iconv('BIG5','UTF-8',$aTxt);
 606	}
 607	else 
 608	    return $aTxt;
 609    }
 610
 611    // Translate iso encoding to unicode
 612    function iso2uni ($isoline){
 613	$uniline='';
 614	for ($i=0; $i < strlen($isoline); $i++){
 615	    $thischar=substr($isoline,$i,1);
 616	    $charcode=ord($thischar);
 617	    $uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar;
 618	}
 619	return $uniline;
 620    }
 621}
 622
 623//===================================================
 624// CLASS JpgTimer
 625// Description: General timing utility class to handle
 626// time measurement of generating graphs. Multiple
 627// timers can be started.
 628//===================================================
 629class JpgTimer {
 630    var $start;
 631    var $idx;	
 632//---------------
 633// CONSTRUCTOR
 634    function JpgTimer() {
 635	$this->idx=0;
 636    }
 637
 638//---------------
 639// PUBLIC METHODS	
 640
 641    // Push a new timer start on stack
 642    function Push() {
 643	list($ms,$s)=explode(" ",microtime());	
 644	$this->start[$this->idx++]=floor($ms*1000) + 1000*$s;	
 645    }
 646
 647    // Pop the latest timer start and return the diff with the
 648    // current time
 649    function Pop() {
 650	assert($this->idx>0);
 651	list($ms,$s)=explode(" ",microtime());	
 652	$etime=floor($ms*1000) + (1000*$s);
 653	$this->idx--;
 654	return $etime-$this->start[$this->idx];
 655    }
 656} // Class
 657
 658$gJpgBrandTiming = BRAND_TIMING;
 659//===================================================
 660// CLASS DateLocale
 661// Description: Hold localized text used in dates
 662//===================================================
 663class DateLocale {
 664 
 665    var $iLocale = 'C'; // environmental locale be used by default
 666
 667    var $iDayAbb = null;
 668    var $iShortDay = null;
 669    var $iShortMonth = null;
 670    var $iMonthName = null;
 671
 672//---------------
 673// CONSTRUCTOR	
 674    function DateLocale() {
 675	settype($this->iDayAbb, 'array');
 676	settype($this->iShortDay, 'array');
 677	settype($this->iShortMonth, 'array');
 678	settype($this->iMonthName, 'array');
 679
 680
 681	$this->Set('C');
 682    }
 683
 684//---------------
 685// PUBLIC METHODS	
 686    function Set($aLocale) {
 687	if ( in_array($aLocale, array_keys($this->iDayAbb)) ){ 
 688	    $this->iLocale = $aLocale;
 689	    return TRUE;  // already cached nothing else to do!
 690	}
 691
 692	$pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME
 693	$res = @setlocale(LC_TIME, $aLocale);
 694	if ( ! $res ){
 695	    JpGraphError::RaiseL(25007,$aLocale);
 696//("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.");
 697	    return FALSE;
 698	}
 699 
 700	$this->iLocale = $aLocale;
 701
 702	for ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){
 703	    $day = strftime('%a', strtotime("$ofs day"));
 704	    $day{0} = strtoupper($day{0});
 705	    $this->iDayAbb[$aLocale][]= $day{0};
 706	    $this->iShortDay[$aLocale][]= $day;
 707	}
 708
 709	for($i=1; $i<=12; ++$i) {
 710	    list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01")));
 711	    $this->iShortMonth[$aLocale][] = ucfirst($short);
 712	    $this->iMonthName [$aLocale][] = ucfirst($full);
 713	}
 714
 715	// Return to original locale
 716	setlocale(LC_TIME, $pLocale);
 717
 718	return TRUE;
 719    }
 720
 721
 722    function GetDayAbb() {
 723	return $this->iDayAbb[$this->iLocale];
 724    }
 725	
 726    function GetShortDay() {
 727	return $this->iShortDay[$this->iLocale];
 728    }
 729
 730    function GetShortMonth() {
 731	return $this->iShortMonth[$this->iLocale];
 732    }
 733	
 734    function GetShortMonthName($aNbr) {
 735	return $this->iShortMonth[$this->iLocale][$aNbr];
 736    }
 737
 738    function GetLongMonthName($aNbr) {
 739	return $this->iMonthName[$this->iLocale][$aNbr];
 740    }
 741
 742    function GetMonth() {
 743	return $this->iMonthName[$this->iLocale];
 744    }
 745}
 746
 747$gDateLocale = new DateLocale();
 748$gJpgDateLocale = new DateLocale();
 749
 750
 751//=======================================================
 752// CLASS Footer
 753// Description: Encapsulates the footer line in the Graph
 754//=======================================================
 755class Footer {
 756    var $left,$center,$right;
 757    var $iLeftMargin = 3;
 758    var $iRightMargin = 3;
 759    var $iBottomMargin = 3;
 760
 761    function Footer() {
 762	$this->left = new Text();
 763	$this->left->ParagraphAlign('left');
 764	$this->center = new Text();
 765	$this->center->ParagraphAlign('center');
 766	$this->right = new Text();
 767	$this->right->ParagraphAlign('right');
 768    }
 769
 770    function Stroke(&$aImg) {
 771	$y = $aImg->height - $this->iBottomMargin;
 772	$x = $this->iLeftMargin;
 773	$this->left->Align('left','bottom');
 774	$this->left->Stroke($aImg,$x,$y);
 775
 776	$x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2;
 777	$this->center->Align('center','bottom');
 778	$this->center->Stroke($aImg,$x,$y);
 779
 780	$x = $aImg->width - $this->iRightMargin;
 781	$this->right->Align('right','bottom');
 782	$this->right->Stroke($aImg,$x,$y);
 783    }
 784}
 785
 786
 787//===================================================
 788// CLASS Graph
 789// Description: Main class to handle graphs
 790//===================================================
 791class Graph {
 792    var $cache=null;		// Cache object (singleton)
 793    var $img=null;			// Img object (singleton)
 794    var $plots=array();	// Array of all plot object in the graph (for Y 1 axis)
 795    var $y2plots=array();// Array of all plot object in the graph (for Y 2 axis)
 796    var $ynplots=array();
 797    var $xscale=null;		// X Scale object (could be instance of LinearScale or LogScale
 798    var $yscale=null,$y2scale=null, $ynscale=array();
 799    var $iIcons = array();      // Array of Icons to add to 
 800    var $cache_name;		// File name to be used for the current graph in the cache directory
 801    var $xgrid=null;		// X Grid object (linear or logarithmic)
 802    var $ygrid=null,$y2grid=null; 
 803    var $doframe=true,$frame_color=array(0,0,0), $frame_weight=1;	// Frame around graph
 804    var $boxed=false, $box_color=array(0,0,0), $box_weight=1;		// Box around plot area
 805    var $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102);	// Shadow for graph
 806    var $xaxis=null;		// X-axis (instane of Axis class)
 807    var $yaxis=null, $y2axis=null, $ynaxis=array();	// Y axis (instance of Axis class)
 808    var $margin_color=array(200,200,200);	// Margin color of graph
 809    var $plotarea_color=array(255,255,255);	// Plot area color
 810    var $title,$subtitle,$subsubtitle; 	// Title and subtitle(s) text object
 811    var $axtype="linlin";		// Type of axis
 812    var $xtick_factor;			// Factot to determine the maximum number of ticks depending on the plot with
 813    var $texts=null, $y2texts=null; 	// Text object to ge shown in the graph
 814    var $lines=null, $y2lines=null;
 815    var $bands=null, $y2bands=null;
 816    var $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale offset in fractions and for centering bars in absolute pixels
 817    var $background_image="",$background_image_type=-1,$background_image_format="png";
 818    var $background_image_bright=0,$background_image_contr=0,$background_image_sat=0;
 819    var $image_bright=0, $image_contr=0, $image_sat=0;
 820    var $inline;
 821    var $showcsim=0,$csimcolor="red"; //debug stuff, draw the csim boundaris on the image if <>0
 822    var $grid_depth=DEPTH_BACK;	// Draw grid under all plots as default
 823    var $iAxisStyle = AXSTYLE_SIMPLE;
 824    var $iCSIMdisplay=false,$iHasStroked = false;
 825    var $footer;
 826    var $csimcachename = '', $csimcachetimeout = 0;
 827    var $iDoClipping = false;
 828    var $y2orderback=true;
 829    var $tabtitle;
 830    var $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN;
 831    var $bkg_gradfrom='navy', $bkg_gradto='silver';
 832    var $titlebackground = false;
 833    var	$titlebackground_color = 'lightblue',
 834	$titlebackground_style = 1,
 835	$titlebackground_framecolor = 'blue',
 836	$titlebackground_framestyle = 2,
 837	$titlebackground_frameweight = 1,
 838	$titlebackground_bevelheight = 3 ;
 839    var $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;
 840    var $titlebkg_scolor1='black',$titlebkg_scolor2='white';
 841    var $framebevel = false, $framebeveldepth = 2 ;
 842    var $framebevelborder = false, $framebevelbordercolor='black';
 843    var $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4';
 844    var $background_image_mix=100;
 845    var $background_cflag = '';
 846    var $background_cflag_type = BGIMG_FILLPLOT;
 847    var $background_cflag_mix = 100;
 848    var $iImgTrans=false,
 849	$iImgTransHorizon = 100,$iImgTransSkewDist=150,
 850	$iImgTransDirection = 1, $iImgTransMinSize = true,
 851	$iImgTransFillColor='white',$iImgTransHighQ=false,
 852	$iImgTransBorder=false,$iImgTransHorizonPos=0.5;
 853    var $iYAxisDeltaPos=50;
 854    var $iIconDepth=DEPTH_BACK;
 855    var $iAxisLblBgType = 0,
 856	$iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black',
 857	$iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black';
 858    var $iTables=NULL;
 859
 860//---------------
 861// CONSTRUCTOR
 862
 863    // aWIdth 		Width in pixels of image
 864    // aHeight  	Height in pixels of image
 865    // aCachedName	Name for image file in cache directory 
 866    // aTimeOut		Timeout in minutes for image in cache
 867    // aInline		If true the image is streamed back in the call to Stroke()
 868    //			If false the image is just created in the cache
 869    function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) {
 870	GLOBAL $gJpgBrandTiming;
 871	// If timing is used create a new timing object
 872	if( $gJpgBrandTiming ) {
 873	    global $tim;
 874	    $tim = new JpgTimer();
 875	    $tim->Push();
 876	}
 877
 878	if( !is_numeric($aWidth) || !is_numeric($aHeight) ) {
 879	    JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric');
 880	}
 881		
 882	// Automatically generate the image file name based on the name of the script that
 883	// generates the graph
 884	if( $aCachedName=="auto" )
 885	    $aCachedName=GenImgName();
 886			
 887	// Should the image be streamed back to the browser or only to the cache?
 888	$this->inline=$aInline;
 889		
 890	$this->img	= new RotImage($aWidth,$aHeight);
 891
 892	$this->cache 	= new ImgStreamCache($this->img);
 893	$this->cache->SetTimeOut($aTimeOut);
 894
 895	$this->title = new Text();
 896	$this->title->ParagraphAlign('center');
 897	$this->title->SetFont(FF_FONT2,FS_BOLD);
 898	$this->title->SetMargin(3);
 899	$this->title->SetAlign('center');
 900
 901	$this->subtitle = new Text();
 902	$this->subtitle->ParagraphAlign('center');
 903	$this->subtitle->SetMargin(2);
 904	$this->subtitle->SetAlign('center');
 905
 906	$this->subsubtitle = new Text();
 907	$this->subsubtitle->ParagraphAlign('center');
 908	$this->subsubtitle->SetMargin(2);
 909	$this->subsubtitle->SetAlign('center');
 910
 911	$this->legend = new Legend();
 912	$this->footer = new Footer();
 913
 914	// Window doesn't like '?' in the file name so replace it with an '_'
 915	$aCachedName = str_replace("?","_",$aCachedName);
 916
 917	// If the cached version exist just read it directly from the
 918	// cache, stream it back to browser and exit
 919	if( $aCachedName!="" && READ_CACHE && $aInline )
 920	    if( $this->cache->GetAndStream($aCachedName) ) {
 921		exit();
 922	    }
 923				
 924	$this->cache_name = $aCachedName;
 925	$this->SetTickDensity(); // Normal density
 926
 927	$this->tabtitle = new GraphTabTitle();
 928    }
 929//---------------
 930// PUBLIC METHODS	
 931    // Enable final image perspective transformation
 932    function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) {
 933	$this->iImgTrans = true;
 934	$this->iImgTransHorizon = $aHorizon;
 935	$this->iImgTransSkewDist= $aSkewDist;
 936	$this->iImgTransDirection = $aDir;
 937	$this->iImgTransMinSize = $aMinSize;
 938	$this->iImgTransFillColor=$aFillColor;
 939	$this->iImgTransHighQ=$aQuality;
 940	$this->iImgTransBorder=$aBorder;
 941	$this->iImgTransHorizonPos=$aHorizonPos;
 942    }
 943
 944    // Set Image format and optional quality
 945    function SetImgFormat($aFormat,$aQuality=75) {
 946	$this->img->SetImgFormat($aFormat,$aQuality);
 947    }
 948
 949    // Should the grid be in front or back of the plot?
 950    function SetGridDepth($aDepth) {
 951	$this->grid_depth=$aDepth;
 952    }
 953
 954    function SetIconDepth($aDepth) {
 955	$this->iIconDepth=$aDepth;
 956    }
 957	
 958    // Specify graph angle 0-360 degrees.
 959    function SetAngle($aAngle) {
 960	$this->img->SetAngle($aAngle);
 961    }
 962
 963    function SetAlphaBlending($aFlg=true) {
 964	$this->img->SetAlphaBlending($aFlg);
 965    }
 966
 967    // Shortcut to image margin
 968    function SetMargin($lm,$rm,$tm,$bm) {
 969	$this->img->SetMargin($lm,$rm,$tm,$bm);
 970    }
 971
 972    function SetY2OrderBack($aBack=true) {
 973	$this->y2orderback = $aBack;
 974    }
 975
 976    // Rotate the graph 90 degrees and set the margin 
 977    // when we have done a 90 degree rotation
 978    function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) {
 979	$lm = $lm ==0 ? floor(0.2 * $this->img->width)  : $lm ;
 980	$rm = $rm ==0 ? floor(0.1 * $this->img->width)  : $rm ;
 981	$tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ;
 982	$bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ;
 983
 984	$adj = ($this->img->height - $this->img->width)/2;
 985	$this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj);
 986	$this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));
 987	$this->SetAngle(90);
 988	if( empty($this->yaxis) || empty($this->xaxis) ) {
 989	    JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()');
 990	}
 991	$this->xaxis->SetLabelAlign('right','center');
 992	$this->yaxis->SetLabelAlign('center','bottom');
 993    }
 994	
 995    function SetClipping($aFlg=true) {
 996	$this->iDoClipping = $aFlg ;
 997    }
 998
 999    // Add a plot object to the graph
1000    function Add(&$aPlot) {
1001	if( $aPlot == null )
1002	    JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph.");
1003	if( is_array($aPlot) && count($aPlot) > 0 )
1004	    $cl = $aPlot[0];
1005	else
1006	    $cl = $aPlot;
1007
1008	if( is_a($cl,'Text') ) 
1009	    $this->AddText($aPlot);
1010	elseif( is_a($cl,'PlotLine') )
1011	    $this->AddLine($aPlot);
1012	elseif( is_a($cl,'PlotBand') )
1013	    $this->AddBand($aPlot);
1014	elseif( is_a($cl,'IconPlot') )
1015	    $this->AddIcon($aPlot);
1016	elseif( is_a($cl,'GTextTable') )
1017	    $this->AddTable($aPlot);
1018	else
1019	    $this->plots[] = &$aPlot;
1020    }
1021
1022
1023    function AddTable(&$aTable) {
1024	if( is_array($aTable) ) {
1025	    for($i=0; $i < count($aTable); ++$i )
1026		$this->iTables[]=&$aTable[$i];
1027	}
1028	else {
1029	    $this->iTables[] = &$aTable ;
1030	}	
1031    }
1032
1033    function AddIcon(&$aIcon) {
1034	if( is_array($aIcon) ) {
1035	    for($i=0; $i < count($aIcon); ++$i )
1036		$this->iIcons[]=&$aIcon[$i];
1037	}
1038	else {
1039	    $this->iIcons[] = &$aIcon ;
1040	}	
1041    }
1042
1043    // Add plot to second Y-scale
1044    function AddY2(&$aPlot) {
1045	if( $aPlot == null )
1046	    JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph.");	
1047
1048	if( is_array($aPlot) && count($aPlot) > 0 )
1049	    $cl = $aPlot[0];
1050	else
1051	    $cl = $aPlot;
1052
1053	if( is_a($cl,'Text') ) 
1054	    $this->AddText($aPlot,true);
1055	elseif( is_a($cl,'PlotLine') )
1056	    $this->AddLine($aPlot,true);
1057	elseif( is_a($cl,'PlotBand') )
1058	    $this->AddBand($aPlot,true);
1059	else
1060	    $this->y2plots[] = &$aPlot;
1061    }
1062
1063    // Add plot to second Y-scale
1064    function AddY($aN,&$aPlot) {
1065
1066	if( $aPlot == null )
1067	    JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph.");	
1068
1069	if( is_array($aPlot) && count($aPlot) > 0 )
1070	    $cl = $aPlot[0];
1071	else
1072	    $cl = $aPlot;
1073
1074	if( is_a($cl,'Text') || is_a($cl,'PlotLine') || is_a($cl,'PlotBand') )
1075	    JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis');
1076	else
1077	    $this->ynplots[$aN][] = &$aPlot;
1078    }
1079    
1080    // Add text object to the graph
1081    function AddText(&$aTxt,$aToY2=false) {
1082	if( $aTxt == null )
1083	    JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph.");		
1084	if( $aToY2 ) {
1085	    if( is_array($aTxt) ) {
1086		for($i=0; $i < count($aTxt); ++$i )
1087		    $this->y2texts[]=&$aTxt[$i];
1088	    }
1089	    else
1090		$this->y2texts[] = &$aTxt;
1091	}
1092	else {
1093	    if( is_array($aTxt) ) {
1094		for($i=0; $i < count($aTxt); ++$i )
1095		    $this->texts[]=&$aTxt[$i];
1096	    }
1097	    else
1098		$this->texts[] = &$aTxt;
1099	}
1100    }
1101	
1102    // Add a line object (class PlotLine) to the graph
1103    function AddLine(&$aLine,$aToY2=false) {
1104	if( $aLine == null )
1105	    JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph.");	
1106
1107	if( $aToY2 ) {
1108 	    if( is_array($aLine) ) {
1109		for($i=0; $i < count($aLine); ++$i )
1110		    $this->y2lines[]=&$aLine[$i];
1111	    }
1112	    else
1113		$this->y2lines[] = &$aLine;
1114	}
1115	else {
1116 	    if( is_array($aLine) ) {
1117		for($i=0; $i < count($aLine); ++$i )
1118		    $this->lines[]=&$aLine[$i];
1119	    }
1120	    else
1121		$this->lines[] = &$aLine;
1122	}
1123    }
1124
1125    // Add vertical or horizontal band
1126    function AddBand(&$aBand,$aToY2=false) {
1127	if( $aBand == null )
1128	    JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph.");
1129
1130	if( $aToY2 ) {
1131	    if( is_array($aBand) ) {
1132		for($i=0; $i < count($aBand); ++$i )
1133		    $this->y2bands[] = &$aBand[$i];
1134	    }
1135	    else
1136		$this->y2bands[] = &$aBand;
1137	}
1138	else {
1139	    if( is_array($aBand) ) {
1140		for($i=0; $i < count($aBand); ++$i )
1141		    $this->bands[] = &$aBand[$i];
1142	    }
1143	    else
1144		$this->bands[] = &$aBand;
1145	}
1146    }
1147
1148    function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) {
1149	$this->bkg_gradtype=$aGradType;
1150	$this->bkg_gradstyle=$aStyle;
1151	$this->bkg_gradfrom = $aFrom;
1152	$this->bkg_gradto = $aTo;
1153    } 
1154	
1155    // Set a country flag in the background
1156    function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
1157	$this->background_cflag = $aName;
1158	$this->background_cflag_type = $aBgType;
1159	$this->background_cflag_mix = $aMix;
1160    }
1161
1162    // Alias for the above method
1163    function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
1164	$this->background_cflag = $aName;
1165	$this->background_cflag_type = $aBgType;
1166	$this->background_cflag_mix = $aMix;
1167    }
1168
1169
1170    // Specify a background image
1171    function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat="auto") {
1172
1173	if( $GLOBALS['gd2'] && !USE_TRUECOLOR ) {
1174	    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.");
1175	}
1176
1177	// Get extension to determine image type
1178	if( $aImgFormat == "auto" ) {
1179	    $e = explode('.',$aFileName);
1180	    if( !$e ) {
1181		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');
1182	    }
1183
1184	    $valid_formats = array('png', 'jpg', 'gif');
1185	    $aImgFormat = strtolower($e[count($e)-1]);
1186	    if ($aImgFormat == 'jpeg')  {
1187		$aImgFormat = 'jpg';
1188	    }
1189	    elseif (!in_array($aImgFormat, $valid_formats) )  {
1190		JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
1191	    }    
1192	}
1193
1194	$this->background_image = $aFileName;
1195	$this->background_image_type=$aBgType;
1196	$this->background_image_format=$aImgFormat;
1197    }
1198
1199    function SetBackgroundImageMix($aMix) {
1200	$this->background_image_mix = $aMix ;
1201    }
1202	
1203    // Adjust brightness and constrast for background image
1204    function AdjBackgroundImage($aBright,$aContr=0,$aSat=0) {
1205	$this->background_image_bright=$aBright;
1206	$this->background_image_contr=$aContr;
1207	$this->background_image_sat=$aSat;
1208    }
1209	
1210    // Adjust brightness and constrast for image
1211    function AdjImage($aBright,$aContr=0,$aSat=0) {
1212	$this->image_bright=$aBright;
1213	$this->image_contr=$aContr;
1214	$this->image_sat=$aSat;
1215    }
1216
1217    // Specify axis style (boxed or single)
1218    function SetAxisStyle($aStyle) {
1219        $this->iAxisStyle = $aStyle ;
1220    }
1221	
1222    // Set a frame around the plot area
1223    function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) {
1224	$this->boxed = $aDrawPlotFrame;
1225	$this->box_weight = $aPlotFrameWeight;
1226	$this->box_color = $aPlotFrameColor;
1227    }
1228	
1229    // Specify color for the plotarea (not the margins)
1230    function SetColor($aColor) {
1231	$this->plotarea_color=$aColor;
1232    }
1233	
1234    // Specify color for the margins (all areas outside the plotarea)
1235    function SetMarginColor($aColor) {
1236	$this->margin_color=$aColor;
1237    }
1238	
1239    // Set a frame around the entire image
1240    function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) {
1241	$this->doframe = $aDrawImgFrame;
1242	$this->frame_color = $aImgFrameColor;
1243	$this->frame_weight = $aImgFrameWeight;
1244    }
1245
1246    function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) {
1247	$this->framebevel = $aFlg ;
1248	$this->framebeveldepth = $aDepth ;
1249	$this->framebevelborder = $aBorder ;
1250	$this->framebevelbordercolor = $aBorderColor ;
1251	$this->framebevelcolor1 = $aColor1 ;
1252	$this->framebevelcolor2 = $aColor2 ;
1253
1254	$this->doshadow = false ;
1255    }
1256
1257    // Set the shadow around the whole image
1258    function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) {
1259	$this->doshadow = $aShowShadow;
1260	$this->shadow_color = $aShadowColor;
1261	$this->shadow_width = $aShadowWidth;
1262	$this->footer->iBottomMargin += $aShadowWidth;
1263	$this->footer->iRightMargin += $aShadowWidth;
1264    }
1265
1266    // Specify x,y scale. Note that if you manually specify the scale
1267    // you must also specify the tick distance with a call to Ticks::Set()
1268    function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) {
1269	$this->axtype = $aAxisType;
1270
1271	if( $aYMax < $aYMin || $aXMax < $aXMin )
1272	    JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
1273
1274	$yt=substr($aAxisType,-3,3);
1275	if( $yt=="lin" )
1276	    $this->yscale = new LinearScale($aYMin,$aYMax);
1277	elseif( $yt == "int" ) {
1278	    $this->yscale = new LinearScale($aYMin,$aYMax);
1279	    $this->yscale->SetIntScale();
1280	}
1281	elseif( $yt=="log" )
1282	    $this->yscale = new LogScale($aYMin,$aYMax);
1283	else
1284	    JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)");
1285			
1286	$xt=substr($aAxisType,0,3);
1287	if( $xt == "lin" || $xt == "tex" ) {
1288	    $this->xscale = new LinearScale($aXMin,$aXMax,"x");
1289	    $this->xscale->textscale = ($xt == "tex");
1290	}
1291	elseif( $xt == "int" ) {
1292	    $this->xscale = new LinearScale($aXMin,$aXMax,"x");
1293	    $this->xscale->SetIntScale();
1294	}
1295	elseif( $xt == "dat" ) {
1296	    $this->xscale = new DateScale($aXMin,$aXMax,"x");
1297	}
1298	elseif( $xt == "log" )
1299	    $this->xscale = new LogScale($aXMin,$aXMax,"x");
1300	else
1301	    JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)");
1302
1303	$this->xaxis = new Axis($this->img,$this->xscale);
1304	$this->yaxis = new Axis($this->img,$this->yscale);
1305	$this->xgrid = new Grid($this->xaxis);
1306	$this->ygrid = new Grid($this->yaxis);	
1307	$this->ygrid->Show();			
1308    }
1309	
1310    // Specify secondary Y scale
1311    function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) {
1312	if( $aAxisType=="lin" ) 
1313	    $this->y2scale = new LinearScale($aY2Min,$aY2Max);
1314	elseif( $aAxisType == "int" ) {
1315	    $this->y2scale = new LinearScale($aY2Min,$aY2Max);
1316	    $this->y2scale->SetIntScale();
1317	}
1318	elseif( $aAxisType=="log" ) {
1319	    $this->y2scale = new LogScale($aY2Min,$aY2Max);
1320	}
1321	else JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)");
1322			
1323	$this->y2axis = new Axis($this->img,$this->y2scale);
1324	$this->y2axis->scale->ticks->SetDirection(SIDE_LEFT); 
1325	$this->y2axis->SetLabelSide(SIDE_RIGHT); 
1326	$this->y2axis->SetPos('max');
1327	$this->y2axis->SetTitleSide(SIDE_RIGHT);
1328		
1329	// Deafult position is the max x-value
1330	$this->y2grid = new Grid($this->y2axis);							
1331    }
1332
1333    // Set the delta position (in pixels) between the multiple Y-axis
1334    function SetYDeltaDist($aDist) {
1335	$this->iYAxisDeltaPos = $aDist;
1336    }
1337	
1338    // Specify secondary Y scale
1339    function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) {
1340
1341	if( $aAxisType=="lin" ) 
1342	    $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
1343	elseif( $aAxisType == "int" ) {
1344	    $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
1345	    $this->ynscale[$aN]->SetIntScale();
1346	}
1347	elseif( $aAxisType=="log" ) {
1348	    $this->ynscale[$aN] = new LogScale($aYMin,$aYMax);
1349	}
1350	else JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)");
1351			
1352	$this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]);
1353	$this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT); 
1354	$this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT); 
1355    }
1356
1357	
1358    // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'
1359    // The dividing factor have been determined heuristically according to my aesthetic 
1360    // sense (or lack off) y.m.m.v !
1361    function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) {
1362	$this->xtick_factor=30;
1363	$this->ytick_factor=25;		
1364	switch( $aYDensity ) {
1365	    case TICKD_DENSE:
1366		$this->ytick_factor=12;			
1367		break;
1368	    case TICKD_NORMAL:
1369		$this->ytick_factor=25;			
1370		break;
1371	    case TICKD_SPARSE:
1372		$this->ytick_factor=40;			
1373		break;
1374	    case TICKD_VERYSPARSE:
1375		$this->ytick_factor=100;			
1376		break;		
1377	    default:
1378		JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy");
1379	}
1380	switch( $aXDensity ) {
1381	    case TICKD_DENSE:
1382		$this->xtick_factor=15;							
1383		break;
1384	    case TICKD_NORMAL:
1385		$this->xtick_factor=30;			
1386		break;
1387	    case TICKD_SPARSE:
1388		$this->xtick_factor=45;					
1389		break;
1390	    case TICKD_VERYSPARSE:
1391		$this->xtick_factor=60;								
1392		break;		
1393	    default:
1394		JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx");
1395	}		
1396    }
1397	
1398
1399    // Get a string of all image map areas	
1400    function GetCSIMareas() {
1401	if( !$this->iHasStroked )
1402	    $this->Stroke(_CSIM_SPECIALFILE);
1403
1404	$csim = $this->title->GetCSIMAreas();
1405	$csim .= $this->subtitle->GetCSIMAreas();
1406	$csim .= $this->subsubtitle->GetCSIMAreas();
1407	$csim .= $this->legend->GetCSIMAreas();
1408
1409	if( $this->y2axis != NULL ) {
1410	    $csim .= $this->y2axis->title->GetCSIMAreas();
1411	}
1412
1413	if( $this->texts != null ) {
1414	    $n = count($this->texts);
1415	    for($i=0; $i < $n; ++$i ) {
1416		$csim .= $this->texts[$i]->GetCSIMAreas();
1417	    }
1418	}
1419
1420	if( $this->y2texts != null && $this->y2scale != null ) {
1421	    $n = count($this->y2texts);
1422	    for($i=0; $i < $n; ++$i ) {
1423		$csim .= $this->y2texts[$i]->GetCSIMAreas();
1424	    }
1425	}
1426
1427	if( $this->yaxis != null && $this->xaxis != null ) {
1428	    $csim .= $this->yaxis->title->GetCSIMAreas();	
1429	    $csim .= $this->xaxis->title->GetCSIMAreas();
1430	}
1431
1432	$n = count($this->plots);
1433	for( $i=0; $i < $n; ++$i ) 
1434	    $csim .= $this->plots[$i]->GetCSIMareas();
1435
1436	$n = count($this->y2plots);
1437	for( $i=0; $i < $n; ++$i ) 
1438	    $csim .= $this->y2plots[$i]->GetCSIMareas();
1439
1440	$n = count($this->ynaxis);
1441	for( $i=0; $i < $n; ++$i ) {
1442	    $m = count($this->ynplots[$i]); 
1443	    for($j=0; $j < $m; ++$j ) {
1444		$csim .= $this->ynplots[$i][$j]->GetCSIMareas();
1445	    }
1446	}
1447
1448	$n = count($this->iTables);
1449	for( $i=0; $i < $n; ++$i ) {
1450	    $csim .= $this->iTables[$i]->GetCSIMareas();
1451	}
1452
1453	return $csim;
1454    }
1455	
1456    // Get a complete <MAP>..</MAP> tag for the final image map
1457    function GetHTMLImageMap($aMapName) {
1458	//$im = "<map name=\"$aMapName\" id=\"$aMapName\">\n";
1459	$im = "<map name=\"$aMapName\" />\n";
1460	$im .= $this->GetCSIMareas();
1461	$im .= "</map>"; 
1462	return $im;
1463    }
1464
1465    function CheckCSIMCache($aCacheName,$aTimeOut=60) {
1466	global $_SERVER;
1467
1468	if( $aCacheName=='auto' )
1469	    $aCacheName=basename($_SERVER['PHP_SELF']);
1470
1471	$this->csimcachename = CSIMCACHE_DIR.$aCacheName;
1472	$this->csimcachetimeout = $aTimeOut;
1473
1474	// First determine if we need to check for a cached version
1475	// This differs from the standard cache in the sense that the
1476	// image and CSIM map HTML file is written relative to the directory
1477	// the script executes in and not the specified cache directory.
1478	// The reason for this is that the cache directory is not necessarily
1479	// accessible from the HTTP server.
1480	if( $this->csimcachename != '' ) {
1481	    $dir = dirname($this->csimcachename);
1482	    $base = basename($this->csimcachename);
1483	    $base = strtok($base,'.');
1484	    $suffix = strtok('.');
1485	    $basecsim = $dir.'/'.$base.'_csim_.html';
1486	    $baseimg = $dir.'/'.$base.'.'.$this->img->img_format;
1487
1488	    $timedout=false;
1489		
1490	    // Does it exist at all ?
1491	    
1492	    if( file_exists($basecsim) && file_exists($baseimg) ) {
1493		// Check that it hasn't timed out
1494		$diff=time()-filemtime($basecsim);
1495		if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) {
1496		    $timedout=true;
1497		    @unlink($basecsim);
1498		    @unlink($baseimg);
1499		}
1500		else {
1501		    if ($fh = @fopen($basecsim, "r")) {
1502			fpassthru($fh);
1503			return true;
1504		    }
1505		    else
1506			JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading.");
1507		}
1508	    }
1509	}
1510	return false;
1511    }
1512
1513    function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) {
1514	if( $aCSIMName=='' ) {
1515	    // create a random map name
1516	    srand ((double) microtime() * 1000000);
1517	    $r = rand(0,100000);
1518	    $aCSIMName='__mapname'.$r.'__';
1519	}
1520
1521	if( $aScriptName=='auto' )
1522	    $aScriptName=basename($_SERVER['PHP_SELF']);
1523
1524	if( empty($_GET[_CSIM_DISPLAY]) ) {
1525	    // First determine if we need to check for a cached version
1526	    // This differs from the standard cache in the sense that the
1527	    // image and CSIM map HTML file is written relative to the directory
1528	    // the script executes in and not the specified cache directory.
1529	    // The reason for this is that the cache directory is not necessarily
1530	    // accessible from the HTTP server.
1531	    if( $this->csimcachename != '' ) {
1532		$dir = dirname($this->csimcachename);
1533		$base = basename($this->csimcachename);
1534		$base = strtok($base,'.');
1535		$suffix = strtok('.');
1536		$basecsim = $dir.'/'.$base.'_csim_.html';
1537		$baseimg = $base.'.'.$this->img->img_format;
1538
1539		// Check that apache can write to directory specified
1540
1541		if( file_exists($dir) && !is_writeable($dir) ) {
1542		    JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');
1543		}
1544		
1545		// Make sure directory exists
1546		$this->cache->MakeDirs($dir);
1547
1548		// Write the image file
1549		$this->Stroke(CSIMCACHE_DIR.$baseimg);
1550
1551		// Construct wrapper HTML and write to file and send it back to browser
1552		$htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n".
1553		    '<img src="'.htmlentities(CSIMCACHE_HTTP_DIR.$baseimg).'" ismap usemap="#'.$aCSIMName.'" border='.$aBorder.' width='.$this->img->width.' height='.$this->img->height." alt=\"\" />\n";
1554		if($fh =  @fopen($basecsim,'w') ) {
1555		    fwrite($fh,$htmlwrap);
1556		    fclose($fh);
1557		    echo $htmlwrap;
1558		}
1559		else
1560		    JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions.");
1561	    }
1562	    else {
1563
1564		if( $aScriptName=='' ) {
1565		    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().');
1566		    exit();
1567		}
1568
1569		
1570		// This is a JPGRAPH internal defined that prevents
1571		// us from recursively coming here again
1572		$urlarg='?'._CSIM_DISPLAY.'=1';
1573
1574		// Now reconstruct any user URL argument
1575		reset($_GET);
1576		while( list($key,$value) = each($_GET) ) {
1577		    if( is_array($value) ) {
1578			$n = count($value);
1579			for( $i=0; $i < $n; ++$i ) {
1580			    $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]);
1581			}
1582		    }
1583		    else {
1584			$urlarg .= '&'.$key.'='.urlencode($value);
1585		    }
1586		}
1587
1588		// It's not ideal to convert POST argument to GET arguments
1589		// but there is little else we can do. One idea for the 
1590		// future might be recreate the POST header in case.
1591		reset($_POST);
1592		while( list($key,$value) = each($_POST) ) {
1593		    if( is_array($value) ) {
1594			$n = count($value);
1595			for( $i=0; $i < $n; ++$i ) {
1596			    $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]);
1597			}
1598		    }
1599		    else {
1600			$urlarg .= '&'.$key.'='.urlencode($value);
1601		    }
1602		}
1603
1604		echo $this->GetHTMLImageMap($aCSIMName);
1605
1606		echo "<img src='".htmlentities($aScriptName.$urlarg)."' ismap usemap='#".$aCSIMName.'\' border='.$aBorder.'  width='.$this->img->width.' height='.$this->img->height." alt=\"\" />\n";
1607	    }
1608	}
1609	else {
1610	    $this->Stroke();
1611	}
1612    }
1613
1614    function GetTextsYMinMax($aY2=false) {
1615	if( $aY2 ) 
1616	    $txts = $this->y2texts;
1617	else
1618	    $txts = $this->texts;
1619	$n = count($txts);
1620	$min=null;
1621	$max=null;
1622	for( $i=0; $i < $n; ++$i ) {
1623	    if( $txts[$i]->iScalePosY !== null && 
1624		$txts[$i]->iScalePosX !== null  ) {
1625		if( $min === null  ) {
1626		    $min = $max = $txts[$i]->iScalePosY ;
1627		}
1628		else {
1629		    $min = min($min,$txts[$i]->iScalePosY);
1630		    $max = max($max,$txts[$i]->iScalePosY);
1631		}
1632	    }
1633	}
1634	if( $min !== null ) {
1635	    r…

Large files files are truncated, but you can click here to view the full file