PageRenderTime 67ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 3ms

/code/web/public_php/admin/jpgraph/jpgraph.php

https://bitbucket.org/0xcc/ryzomcore
PHP | 8563 lines | 6475 code | 998 blank | 1090 comment | 1307 complexity | cf2757885786d4194abb37ba5582567a MD5 | raw file
Possible License(s): AGPL-3.0, GPL-3.0, LGPL-2.1, Apache-2.0

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

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