PageRenderTime 71ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 2ms

/lib/jpgraph/src/jpgraph.php

https://github.com/web2project/web2project
PHP | 8581 lines | 6480 code | 1002 blank | 1099 comment | 1315 complexity | 2fbbb0cff41c6a8a9e375e17996b37f0 MD5 | raw file
Possible License(s): LGPL-2.1

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$
  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']) && !preg_match('|deprecated|', $GLOBALS['php_errormsg']) && !preg_match('|Non-static|', $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. /* Auto-detect whether the cyrillic conversion
  507. ** based on the character_set info that has
  508. ** been passed to jpgraph from the including
  509. ** application.
  510. **
  511. ** Call the cyrillic converter only when a cyrillic
  512. ** charset derivate is used. Otherwise do nothing
  513. ** and prevent from erraneously converted strings.
  514. */
  515. if( CYRILLIC_FROM_WINDOWS && ( !defined('LANGUAGE_CHARSET') || stristr(LANGUAGE_CHARSET, 'windows-1251') ) ) {
  516. $aTxt = convert_cyr_string($aTxt, "w", "k");
  517. }
  518. if (!defined('LANGUAGE_CHARSET') || stristr(LANGUAGE_CHARSET, 'koi8-r') || stristr(LANGUAGE_CHARSET, 'windows-1251')) {
  519. $isostring = convert_cyr_string($aTxt, "k", "i");
  520. $unistring = LanguageConv::iso2uni($isostring);
  521. } else {
  522. $unistring = $aTxt;
  523. }
  524. return $unistring;
  525. }
  526. elseif( $aFF === FF_SIMSUN ) {
  527. // Do Chinese conversion
  528. if( $this->g2312 == null ) {
  529. include_once 'jpgraph_gb2312.php' ;
  530. $this->g2312 = new GB2312toUTF8();
  531. }
  532. return $this->g2312->gb2utf8($aTxt);
  533. }
  534. elseif( $aFF === FF_CHINESE ) {
  535. if( !function_exists('iconv') ) {
  536. JpGraphError::RaiseL(25006);
  537. //('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).');
  538. }
  539. return iconv('BIG5','UTF-8',$aTxt);
  540. }
  541. else
  542. return $aTxt;
  543. }
  544. // Translate iso encoding to unicode
  545. function iso2uni ($isoline){
  546. $uniline='';
  547. for ($i=0; $i < strlen($isoline); $i++){
  548. $thischar=substr($isoline,$i,1);
  549. $charcode=ord($thischar);
  550. $uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar;
  551. }
  552. return $uniline;
  553. }
  554. }
  555. //===================================================
  556. // CLASS JpgTimer
  557. // Description: General timing utility class to handle
  558. // time measurement of generating graphs. Multiple
  559. // timers can be started.
  560. //===================================================
  561. class JpgTimer {
  562. var $start;
  563. var $idx;
  564. //---------------
  565. // CONSTRUCTOR
  566. function JpgTimer() {
  567. $this->idx=0;
  568. }
  569. //---------------
  570. // PUBLIC METHODS
  571. // Push a new timer start on stack
  572. function Push() {
  573. list($ms,$s)=explode(" ",microtime());
  574. $this->start[$this->idx++]=floor($ms*1000) + 1000*$s;
  575. }
  576. // Pop the latest timer start and return the diff with the
  577. // current time
  578. function Pop() {
  579. assert($this->idx>0);
  580. list($ms,$s)=explode(" ",microtime());
  581. $etime=floor($ms*1000) + (1000*$s);
  582. $this->idx--;
  583. return $etime-$this->start[$this->idx];
  584. }
  585. } // Class
  586. $gJpgBrandTiming = BRAND_TIMING;
  587. //===================================================
  588. // CLASS DateLocale
  589. // Description: Hold localized text used in dates
  590. //===================================================
  591. class DateLocale {
  592. var $iLocale = 'C'; // environmental locale be used by default
  593. var $iDayAbb = null;
  594. var $iShortDay = null;
  595. var $iShortMonth = null;
  596. var $iMonthName = null;
  597. //---------------
  598. // CONSTRUCTOR
  599. function DateLocale() {
  600. settype($this->iDayAbb, 'array');
  601. settype($this->iShortDay, 'array');
  602. settype($this->iShortMonth, 'array');
  603. settype($this->iMonthName, 'array');
  604. $this->Set('C');
  605. }
  606. //---------------
  607. // PUBLIC METHODS
  608. function Set($aLocale) {
  609. if ( in_array($aLocale, array_keys($this->iDayAbb)) ){
  610. $this->iLocale = $aLocale;
  611. return TRUE; // already cached nothing else to do!
  612. }
  613. $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME
  614. $res = @setlocale(LC_TIME, $aLocale);
  615. if ( ! $res ){
  616. JpGraphError::RaiseL(25007,$aLocale);
  617. //("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.");
  618. return FALSE;
  619. }
  620. $this->iLocale = $aLocale;
  621. for ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){
  622. $day = strftime('%a', strtotime("$ofs day"));
  623. $day{0} = strtoupper($day{0});
  624. $this->iDayAbb[$aLocale][]= $day{0};
  625. $this->iShortDay[$aLocale][]= $day;
  626. }
  627. for($i=1; $i<=12; ++$i) {
  628. list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01")));
  629. $this->iShortMonth[$aLocale][] = ucfirst($short);
  630. $this->iMonthName [$aLocale][] = ucfirst($full);
  631. }
  632. // Return to original locale
  633. setlocale(LC_TIME, $pLocale);
  634. return TRUE;
  635. }
  636. function GetDayAbb() {
  637. return $this->iDayAbb[$this->iLocale];
  638. }
  639. function GetShortDay() {
  640. return $this->iShortDay[$this->iLocale];
  641. }
  642. function GetShortMonth() {
  643. return $this->iShortMonth[$this->iLocale];
  644. }
  645. function GetShortMonthName($aNbr) {
  646. return $this->iShortMonth[$this->iLocale][$aNbr];
  647. }
  648. function GetLongMonthName($aNbr) {
  649. return $this->iMonthName[$this->iLocale][$aNbr];
  650. }
  651. function GetMonth() {
  652. return $this->iMonthName[$this->iLocale];
  653. }
  654. }
  655. $gDateLocale = new DateLocale();
  656. $gJpgDateLocale = new DateLocale();
  657. //=======================================================
  658. // CLASS Footer
  659. // Description: Encapsulates the footer line in the Graph
  660. //=======================================================
  661. class Footer {
  662. var $left,$center,$right;
  663. var $iLeftMargin = 3;
  664. var $iRightMargin = 3;
  665. var $iBottomMargin = 3;
  666. function Footer() {
  667. $this->left = new Text();
  668. $this->left->ParagraphAlign('left');
  669. $this->center = new Text();
  670. $this->center->ParagraphAlign('center');
  671. $this->right = new Text();
  672. $this->right->ParagraphAlign('right');
  673. }
  674. function Stroke(&$aImg) {
  675. $y = $aImg->height - $this->iBottomMargin;
  676. $x = $this->iLeftMargin;
  677. $this->left->Align('left','bottom');
  678. $this->left->Stroke($aImg,$x,$y);
  679. $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2;
  680. $this->center->Align('center','bottom');
  681. $this->center->Stroke($aImg,$x,$y);
  682. $x = $aImg->width - $this->iRightMargin;
  683. $this->right->Align('right','bottom');
  684. $this->right->Stroke($aImg,$x,$y);
  685. }
  686. }
  687. //===================================================
  688. // CLASS Graph
  689. // Description: Main class to handle graphs
  690. //===================================================
  691. class Graph {
  692. var $cache=null; // Cache object (singleton)
  693. var $img=null; // Img object (singleton)
  694. var $plots=array(); // Array of all plot object in the graph (for Y 1 axis)
  695. var $y2plots=array();// Array of all plot object in the graph (for Y 2 axis)
  696. var $ynplots=array();
  697. var $xscale=null; // X Scale object (could be instance of LinearScale or LogScale
  698. var $yscale=null,$y2scale=null, $ynscale=array();
  699. var $iIcons = array(); // Array of Icons to add to
  700. var $cache_name; // File name to be used for the current graph in the cache directory
  701. var $xgrid=null; // X Grid object (linear or logarithmic)
  702. var $ygrid=null,$y2grid=null;
  703. var $doframe=true,$frame_color=array(0,0,0), $frame_weight=1; // Frame around graph
  704. var $boxed=false, $box_color=array(0,0,0), $box_weight=1; // Box around plot area
  705. var $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102); // Shadow for graph
  706. var $xaxis=null; // X-axis (instane of Axis class)
  707. var $yaxis=null, $y2axis=null, $ynaxis=array(); // Y axis (instance of Axis class)
  708. var $margin_color=array(200,200,200); // Margin color of graph
  709. var $plotarea_color=array(255,255,255); // Plot area color
  710. var $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object
  711. var $axtype="linlin"; // Type of axis
  712. var $xtick_factor; // Factot to determine the maximum number of ticks depending on the plot with
  713. var $texts=null, $y2texts=null; // Text object to ge shown in the graph
  714. var $lines=null, $y2lines=null;
  715. var $bands=null, $y2bands=null;
  716. var $text_scale_off=0, $text_scale_abscenteroff=-1; // Text scale offset in fractions and for centering bars in absolute pixels
  717. var $background_image="",$background_image_type=-1,$background_image_format="png";
  718. var $background_image_bright=0,$background_image_contr=0,$background_image_sat=0;
  719. var $image_bright=0, $image_contr=0, $image_sat=0;
  720. var $inline;
  721. var $showcsim=0,$csimcolor="red"; //debug stuff, draw the csim boundaris on the image if <>0
  722. var $grid_depth=DEPTH_BACK; // Draw grid under all plots as default
  723. var $iAxisStyle = AXSTYLE_SIMPLE;
  724. var $iCSIMdisplay=false,$iHasStroked = false;
  725. var $footer;
  726. var $csimcachename = '', $csimcachetimeout = 0;
  727. var $iDoClipping = false;
  728. var $y2orderback=true;
  729. var $tabtitle;
  730. var $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN;
  731. var $bkg_gradfrom='navy', $bkg_gradto='silver';
  732. var $titlebackground = false;
  733. var $titlebackground_color = 'lightblue',
  734. $titlebackground_style = 1,
  735. $titlebackground_framecolor = 'blue',
  736. $titlebackground_framestyle = 2,
  737. $titlebackground_frameweight = 1,
  738. $titlebackground_bevelheight = 3 ;
  739. var $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;
  740. var $titlebkg_scolor1='black',$titlebkg_scolor2='white';
  741. var $framebevel = false, $framebeveldepth = 2 ;
  742. var $framebevelborder = false, $framebevelbordercolor='black';
  743. var $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4';
  744. var $background_image_mix=100;
  745. var $background_cflag = '';
  746. var $background_cflag_type = BGIMG_FILLPLOT;
  747. var $background_cflag_mix = 100;
  748. var $iImgTrans=false,
  749. $iImgTransHorizon = 100,$iImgTransSkewDist=150,
  750. $iImgTransDirection = 1, $iImgTransMinSize = true,
  751. $iImgTransFillColor='white',$iImgTransHighQ=false,
  752. $iImgTransBorder=false,$iImgTransHorizonPos=0.5;
  753. var $iYAxisDeltaPos=50;
  754. var $iIconDepth=DEPTH_BACK;
  755. var $iAxisLblBgType = 0,
  756. $iXAxisLblBgFillColor = 'lightgray', $iXAxisLblBgColor = 'black',
  757. $iYAxisLblBgFillColor = 'lightgray', $iYAxisLblBgColor = 'black';
  758. var $iTables=NULL;
  759. //---------------
  760. // CONSTRUCTOR
  761. // aWIdth Width in pixels of image
  762. // aHeight Height in pixels of image
  763. // aCachedName Name for image file in cache directory
  764. // aTimeOut Timeout in minutes for image in cache
  765. // aInline If true the image is streamed back in the call to Stroke()
  766. // If false the image is just created in the cache
  767. function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) {
  768. GLOBAL $gJpgBrandTiming;
  769. // If timing is used create a new timing object
  770. if( $gJpgBrandTiming ) {
  771. global $tim;
  772. $tim = new JpgTimer();
  773. $tim->Push();
  774. }
  775. if( !is_numeric($aWidth) || !is_numeric($aHeight) ) {
  776. JpGraphError::RaiseL(25008);//('Image width/height argument in Graph::Graph() must be numeric');
  777. }
  778. // Automatically generate the image file name based on the name of the script that
  779. // generates the graph
  780. if( $aCachedName=="auto" )
  781. $aCachedName=GenImgName();
  782. // Should the image be streamed back to the browser or only to the cache?
  783. $this->inline=$aInline;
  784. $this->img = new RotImage($aWidth,$aHeight);
  785. $this->cache = new ImgStreamCache($this->img);
  786. $this->cache->SetTimeOut($aTimeOut);
  787. $this->title = new Text();
  788. $this->title->ParagraphAlign('center');
  789. $this->title->SetFont(FF_FONT2,FS_BOLD);
  790. $this->title->SetMargin(3);
  791. $this->title->SetAlign('center');
  792. $this->subtitle = new Text();
  793. $this->subtitle->ParagraphAlign('center');
  794. $this->subtitle->SetMargin(2);
  795. $this->subtitle->SetAlign('center');
  796. $this->subsubtitle = new Text();
  797. $this->subsubtitle->ParagraphAlign('center');
  798. $this->subsubtitle->SetMargin(2);
  799. $this->subsubtitle->SetAlign('center');
  800. $this->legend = new Legend();
  801. $this->footer = new Footer();
  802. // Window doesn't like '?' in the file name so replace it with an '_'
  803. $aCachedName = str_replace("?","_",$aCachedName);
  804. // If the cached version exist just read it directly from the
  805. // cache, stream it back to browser and exit
  806. if( $aCachedName!="" && READ_CACHE && $aInline )
  807. if( $this->cache->GetAndStream($aCachedName) ) {
  808. exit();
  809. }
  810. $this->cache_name = $aCachedName;
  811. $this->SetTickDensity(); // Normal density
  812. $this->tabtitle = new GraphTabTitle();
  813. }
  814. //---------------
  815. // PUBLIC METHODS
  816. // Enable final image perspective transformation
  817. function Set3DPerspective($aDir=1,$aHorizon=100,$aSkewDist=120,$aQuality=false,$aFillColor='#FFFFFF',$aBorder=false,$aMinSize=true,$aHorizonPos=0.5) {
  818. $this->iImgTrans = true;
  819. $this->iImgTransHorizon = $aHorizon;
  820. $this->iImgTransSkewDist= $aSkewDist;
  821. $this->iImgTransDirection = $aDir;
  822. $this->iImgTransMinSize = $aMinSize;
  823. $this->iImgTransFillColor=$aFillColor;
  824. $this->iImgTransHighQ=$aQuality;
  825. $this->iImgTransBorder=$aBorder;
  826. $this->iImgTransHorizonPos=$aHorizonPos;
  827. }
  828. // Set Image format and optional quality
  829. function SetImgFormat($aFormat,$aQuality=75) {
  830. $this->img->SetImgFormat($aFormat,$aQuality);
  831. }
  832. // Should the grid be in front or back of the plot?
  833. function SetGridDepth($aDepth) {
  834. $this->grid_depth=$aDepth;
  835. }
  836. function SetIconDepth($aDepth) {
  837. $this->iIconDepth=$aDepth;
  838. }
  839. // Specify graph angle 0-360 degrees.
  840. function SetAngle($aAngle) {
  841. $this->img->SetAngle($aAngle);
  842. }
  843. function SetAlphaBlending($aFlg=true) {
  844. $this->img->SetAlphaBlending($aFlg);
  845. }
  846. // Shortcut to image margin
  847. function SetMargin($lm,$rm,$tm,$bm) {
  848. $this->img->SetMargin($lm,$rm,$tm,$bm);
  849. }
  850. function SetY2OrderBack($aBack=true) {
  851. $this->y2orderback = $aBack;
  852. }
  853. // Rotate the graph 90 degrees and set the margin
  854. // when we have done a 90 degree rotation
  855. function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) {
  856. $lm = $lm ==0 ? floor(0.2 * $this->img->width) : $lm ;
  857. $rm = $rm ==0 ? floor(0.1 * $this->img->width) : $rm ;
  858. $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ;
  859. $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ;
  860. $adj = ($this->img->height - $this->img->width)/2;
  861. $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj);
  862. $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));
  863. $this->SetAngle(90);
  864. if( empty($this->yaxis) || empty($this->xaxis) ) {
  865. JpgraphError::RaiseL(25009);//('You must specify what scale to use with a call to Graph::SetScale()');
  866. }
  867. $this->xaxis->SetLabelAlign('right','center');
  868. $this->yaxis->SetLabelAlign('center','bottom');
  869. }
  870. function SetClipping($aFlg=true) {
  871. $this->iDoClipping = $aFlg ;
  872. }
  873. // Add a plot object to the graph
  874. function Add(&$aPlot) {
  875. if( $aPlot == null )
  876. JpGraphError::RaiseL(25010);//("Graph::Add() You tried to add a null plot to the graph.");
  877. if( is_array($aPlot) && count($aPlot) > 0 )
  878. $cl = $aPlot[0];
  879. else
  880. $cl = $aPlot;
  881. if( is_a($cl,'Text') )
  882. $this->AddText($aPlot);
  883. elseif( is_a($cl,'PlotLine') )
  884. $this->AddLine($aPlot);
  885. elseif( is_a($cl,'PlotBand') )
  886. $this->AddBand($aPlot);
  887. elseif( is_a($cl,'IconPlot') )
  888. $this->AddIcon($aPlot);
  889. elseif( is_a($cl,'GTextTable') )
  890. $this->AddTable($aPlot);
  891. else
  892. $this->plots[] = &$aPlot;
  893. }
  894. function AddTable(&$aTable) {
  895. if( is_array($aTable) ) {
  896. for($i=0; $i < count($aTable); ++$i )
  897. $this->iTables[]=&$aTable[$i];
  898. }
  899. else {
  900. $this->iTables[] = &$aTable ;
  901. }
  902. }
  903. function AddIcon(&$aIcon) {
  904. if( is_array($aIcon) ) {
  905. for($i=0; $i < count($aIcon); ++$i )
  906. $this->iIcons[]=&$aIcon[$i];
  907. }
  908. else {
  909. $this->iIcons[] = &$aIcon ;
  910. }
  911. }
  912. // Add plot to second Y-scale
  913. function AddY2(&$aPlot) {
  914. if( $aPlot == null )
  915. JpGraphError::RaiseL(25011);//("Graph::AddY2() You tried to add a null plot to the graph.");
  916. if( is_array($aPlot) && count($aPlot) > 0 )
  917. $cl = $aPlot[0];
  918. else
  919. $cl = $aPlot;
  920. if( is_a($cl,'Text') )
  921. $this->AddText($aPlot,true);
  922. elseif( is_a($cl,'PlotLine') )
  923. $this->AddLine($aPlot,true);
  924. elseif( is_a($cl,'PlotBand') )
  925. $this->AddBand($aPlot,true);
  926. else
  927. $this->y2plots[] = &$aPlot;
  928. }
  929. // Add plot to second Y-scale
  930. function AddY($aN,&$aPlot) {
  931. if( $aPlot == null )
  932. JpGraphError::RaiseL(25012);//("Graph::AddYN() You tried to add a null plot to the graph.");
  933. if( is_array($aPlot) && count($aPlot) > 0 )
  934. $cl = $aPlot[0];
  935. else
  936. $cl = $aPlot;
  937. if( is_a($cl,'Text') || is_a($cl,'PlotLine') || is_a($cl,'PlotBand') )
  938. JpGraph::RaiseL(25013);//('You can only add standard plots to multiple Y-axis');
  939. else
  940. $this->ynplots[$aN][] = &$aPlot;
  941. }
  942. // Add text object to the graph
  943. function AddText(&$aTxt,$aToY2=false) {
  944. if( $aTxt == null )
  945. JpGraphError::RaiseL(25014);//("Graph::AddText() You tried to add a null text to the graph.");
  946. if( $aToY2 ) {
  947. if( is_array($aTxt) ) {
  948. for($i=0; $i < count($aTxt); ++$i )
  949. $this->y2texts[]=&$aTxt[$i];
  950. }
  951. else
  952. $this->y2texts[] = &$aTxt;
  953. }
  954. else {
  955. if( is_array($aTxt) ) {
  956. for($i=0; $i < count($aTxt); ++$i )
  957. $this->texts[]=&$aTxt[$i];
  958. }
  959. else
  960. $this->texts[] = &$aTxt;
  961. }
  962. }
  963. // Add a line object (class PlotLine) to the graph
  964. function AddLine(&$aLine,$aToY2=false) {
  965. if( $aLine == null )
  966. JpGraphError::RaiseL(25015);//("Graph::AddLine() You tried to add a null line to the graph.");
  967. if( $aToY2 ) {
  968. if( is_array($aLine) ) {
  969. for($i=0; $i < count($aLine); ++$i )
  970. $this->y2lines[]=&$aLine[$i];
  971. }
  972. else
  973. $this->y2lines[] = &$aLine;
  974. }
  975. else {
  976. if( is_array($aLine) ) {
  977. for($i=0; $i < count($aLine); ++$i )
  978. $this->lines[]=&$aLine[$i];
  979. }
  980. else
  981. $this->lines[] = &$aLine;
  982. }
  983. }
  984. // Add vertical or horizontal band
  985. function AddBand(&$aBand,$aToY2=false) {
  986. if( $aBand == null )
  987. JpGraphError::RaiseL(25016);//(" Graph::AddBand() You tried to add a null band to the graph.");
  988. if( $aToY2 ) {
  989. if( is_array($aBand) ) {
  990. for($i=0; $i < count($aBand); ++$i )
  991. $this->y2bands[] = &$aBand[$i];
  992. }
  993. else
  994. $this->y2bands[] = &$aBand;
  995. }
  996. else {
  997. if( is_array($aBand) ) {
  998. for($i=0; $i < count($aBand); ++$i )
  999. $this->bands[] = &$aBand[$i];
  1000. }
  1001. else
  1002. $this->bands[] = &$aBand;
  1003. }
  1004. }
  1005. function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=2,$aStyle=BGRAD_FRAME) {
  1006. $this->bkg_gradtype=$aGradType;
  1007. $this->bkg_gradstyle=$aStyle;
  1008. $this->bkg_gradfrom = $aFrom;
  1009. $this->bkg_gradto = $aTo;
  1010. }
  1011. // Set a country flag in the background
  1012. function SetBackgroundCFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
  1013. $this->background_cflag = $aName;
  1014. $this->background_cflag_type = $aBgType;
  1015. $this->background_cflag_mix = $aMix;
  1016. }
  1017. // Alias for the above method
  1018. function SetBackgroundCountryFlag($aName,$aBgType=BGIMG_FILLPLOT,$aMix=100) {
  1019. $this->background_cflag = $aName;
  1020. $this->background_cflag_type = $aBgType;
  1021. $this->background_cflag_mix = $aMix;
  1022. }
  1023. // Specify a background image
  1024. function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat="auto") {
  1025. if( $GLOBALS['gd2'] && !USE_TRUECOLOR ) {
  1026. 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.");
  1027. }
  1028. // Get extension to determine image type
  1029. if( $aImgFormat == "auto" ) {
  1030. $e = explode('.',$aFileName);
  1031. if( !$e ) {
  1032. 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');
  1033. }
  1034. $valid_formats = array('png', 'jpg', 'gif');
  1035. $aImgFormat = strtolower($e[count($e)-1]);
  1036. if ($aImgFormat == 'jpeg') {
  1037. $aImgFormat = 'jpg';
  1038. }
  1039. elseif (!in_array($aImgFormat, $valid_formats) ) {
  1040. JpGraphError::RaiseL(25019,$aImgFormat);//('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
  1041. }
  1042. }
  1043. $this->background_image = $aFileName;
  1044. $this->background_image_type=$aBgType;
  1045. $this->background_image_format=$aImgFormat;
  1046. }
  1047. function SetBackgroundImageMix($aMix) {
  1048. $this->background_image_mix = $aMix ;
  1049. }
  1050. // Adjust brightness and constrast for background image
  1051. function AdjBackgroundImage($aBright,$aContr=0,$aSat=0) {
  1052. $this->background_image_bright=$aBright;
  1053. $this->background_image_contr=$aContr;
  1054. $this->background_image_sat=$aSat;
  1055. }
  1056. // Adjust brightness and constrast for image
  1057. function AdjImage($aBright,$aContr=0,$aSat=0) {
  1058. $this->image_bright=$aBright;
  1059. $this->image_contr=$aContr;
  1060. $this->image_sat=$aSat;
  1061. }
  1062. // Specify axis style (boxed or single)
  1063. function SetAxisStyle($aStyle) {
  1064. $this->iAxisStyle = $aStyle ;
  1065. }
  1066. // Set a frame around the plot area
  1067. function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) {
  1068. $this->boxed = $aDrawPlotFrame;
  1069. $this->box_weight = $aPlotFrameWeight;
  1070. $this->box_color = $aPlotFrameColor;
  1071. }
  1072. // Specify color for the plotarea (not the margins)
  1073. function SetColor($aColor) {
  1074. $this->plotarea_color=$aColor;
  1075. }
  1076. // Specify color for the margins (all areas outside the plotarea)
  1077. function SetMarginColor($aColor) {
  1078. $this->margin_color=$aColor;
  1079. }
  1080. // Set a frame around the entire image
  1081. function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) {
  1082. $this->doframe = $aDrawImgFrame;
  1083. $this->frame_color = $aImgFrameColor;
  1084. $this->frame_weight = $aImgFrameWeight;
  1085. }
  1086. function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) {
  1087. $this->framebevel = $aFlg ;
  1088. $this->framebeveldepth = $aDepth ;
  1089. $this->framebevelborder = $aBorder ;
  1090. $this->framebevelbordercolor = $aBorderColor ;
  1091. $this->framebevelcolor1 = $aColor1 ;
  1092. $this->framebevelcolor2 = $aColor2 ;
  1093. $this->doshadow = false ;
  1094. }
  1095. // Set the shadow around the whole image
  1096. function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) {
  1097. $this->doshadow = $aShowShadow;
  1098. $this->shadow_color = $aShadowColor;
  1099. $this->shadow_width = $aShadowWidth;
  1100. $this->footer->iBottomMargin += $aShadowWidth;
  1101. $this->footer->iRightMargin += $aShadowWidth;
  1102. }
  1103. // Specify x,y scale. Note that if you manually specify the scale
  1104. // you must also specify the tick distance with a call to Ticks::Set()
  1105. function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) {
  1106. $this->axtype = $aAxisType;
  1107. if( $aYMax < $aYMin || $aXMax < $aXMin )
  1108. JpGraphError::RaiseL(25020);//('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
  1109. $yt=substr($aAxisType,-3,3);
  1110. if( $yt=="lin" )
  1111. $this->yscale = new LinearScale($aYMin,$aYMax);
  1112. elseif( $yt == "int" ) {
  1113. $this->yscale = new LinearScale($aYMin,$aYMax);
  1114. $this->yscale->SetIntScale();
  1115. }
  1116. elseif( $yt=="log" )
  1117. $this->yscale = new LogScale($aYMin,$aYMax);
  1118. else
  1119. JpGraphError::RaiseL(25021,$aAxisType);//("Unknown scale specification for Y-scale. ($aAxisType)");
  1120. $xt=substr($aAxisType,0,3);
  1121. if( $xt == "lin" || $xt == "tex" ) {
  1122. $this->xscale = new LinearScale($aXMin,$aXMax,"x");
  1123. $this->xscale->textscale = ($xt == "tex");
  1124. }
  1125. elseif( $xt == "int" ) {
  1126. $this->xscale = new LinearScale($aXMin,$aXMax,"x");
  1127. $this->xscale->SetIntScale();
  1128. }
  1129. elseif( $xt == "dat" ) {
  1130. $this->xscale = new DateScale($aXMin,$aXMax,"x");
  1131. }
  1132. elseif( $xt == "log" )
  1133. $this->xscale = new LogScale($aXMin,$aXMax,"x");
  1134. else
  1135. JpGraphError::RaiseL(25022,$aAxisType);//(" Unknown scale specification for X-scale. ($aAxisType)");
  1136. $this->xaxis = new Axis($this->img,$this->xscale);
  1137. $this->yaxis = new Axis($this->img,$this->yscale);
  1138. $this->xgrid = new Grid($this->xaxis);
  1139. $this->ygrid = new Grid($this->yaxis);
  1140. $this->ygrid->Show();
  1141. }
  1142. // Specify secondary Y scale
  1143. function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) {
  1144. if( $aAxisType=="lin" )
  1145. $this->y2scale = new LinearScale($aY2Min,$aY2Max);
  1146. elseif( $aAxisType == "int" ) {
  1147. $this->y2scale = new LinearScale($aY2Min,$aY2Max);
  1148. $this->y2scale->SetIntScale();
  1149. }
  1150. elseif( $aAxisType=="log" ) {
  1151. $this->y2scale = new LogScale($aY2Min,$aY2Max);
  1152. }
  1153. else JpGraphError::RaiseL(25023,$aAxisType);//("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)");
  1154. $this->y2axis = new Axis($this->img,$this->y2scale);
  1155. $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
  1156. $this->y2axis->SetLabelSide(SIDE_RIGHT);
  1157. $this->y2axis->SetPos('max');
  1158. $this->y2axis->SetTitleSide(SIDE_RIGHT);
  1159. // Deafult position is the max x-value
  1160. $this->y2grid = new Grid($this->y2axis);
  1161. }
  1162. // Set the delta position (in pixels) between the multiple Y-axis
  1163. function SetYDeltaDist($aDist) {
  1164. $this->iYAxisDeltaPos = $aDist;
  1165. }
  1166. // Specify secondary Y scale
  1167. function SetYScale($aN,$aAxisType="lin",$aYMin=1,$aYMax=1) {
  1168. if( $aAxisType=="lin" )
  1169. $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
  1170. elseif( $aAxisType == "int" ) {
  1171. $this->ynscale[$aN] = new LinearScale($aYMin,$aYMax);
  1172. $this->ynscale[$aN]->SetIntScale();
  1173. }
  1174. elseif( $aAxisType=="log" ) {
  1175. $this->ynscale[$aN] = new LogScale($aYMin,$aYMax);
  1176. }
  1177. else JpGraphError::RaiseL(25024,$aAxisType);//("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)");
  1178. $this->ynaxis[$aN] = new Axis($this->img,$this->ynscale[$aN]);
  1179. $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT);
  1180. $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT);
  1181. }
  1182. // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'
  1183. // The dividing factor have been determined heuristically according to my aesthetic
  1184. // sense (or lack off) y.m.m.v !
  1185. function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) {
  1186. $this->xtick_factor=30;
  1187. $this->ytick_factor=25;
  1188. switch( $aYDensity ) {
  1189. case TICKD_DENSE:
  1190. $this->ytick_factor=12;
  1191. break;
  1192. case TICKD_NORMAL:
  1193. $this->ytick_factor=25;
  1194. break;
  1195. case TICKD_SPARSE:
  1196. $this->ytick_factor=40;
  1197. break;
  1198. case TICKD_VERYSPARSE:
  1199. $this->ytick_factor=100;
  1200. break;
  1201. default:
  1202. JpGraphError::RaiseL(25025,$densy);//("JpGraph: Unsupported Tick density: $densy");
  1203. }
  1204. switch( $aXDensity ) {
  1205. case TICKD_DENSE:
  1206. $this->xtick_factor=15;
  1207. break;
  1208. case TICKD_NORMAL:
  1209. $this->xtick_factor=30;
  1210. break;
  1211. case TICKD_SPARSE:
  1212. $this->xtick_factor=45;
  1213. break;
  1214. case TICKD_VERYSPARSE:
  1215. $this->xtick_factor=60;
  1216. break;
  1217. default:
  1218. JpGraphError::RaiseL(25025,$densx);//("JpGraph: Unsupported Tick density: $densx");
  1219. }
  1220. }
  1221. // Get a string of all image map areas
  1222. function GetCSIMareas() {
  1223. if( !$this->iHasStroked )
  1224. $this->Stroke(_CSIM_SPECIALFILE);
  1225. $csim = $this->title->GetCSIMAreas();
  1226. $csim .= $this->subtitle->GetCSIMAreas();
  1227. $csim .= $this->subsubtitle->GetCSIMAreas();
  1228. $csim .= $this->legend->GetCSIMAreas();
  1229. if( $this->y2axis != NULL ) {
  1230. $csim .= $this->y2axis->title->GetCSIMAreas();
  1231. }
  1232. if( $this->texts != null ) {
  1233. $n = count($this->texts);
  1234. for($i=0; $i < $n; ++$i ) {
  1235. $csim .= $this->texts[$i]->GetCSIMAreas();
  1236. }
  1237. }
  1238. if( $this->y2texts != null && $this->y2scale != null ) {
  1239. $n = count($this->y2texts);
  1240. for($i=0; $i < $n; ++$i ) {
  1241. $csim .= $this->y2texts[$i]->GetCSIMAreas();
  1242. }
  1243. }
  1244. if( $this->yaxis != null && $this->xaxis != null ) {
  1245. $csim .= $this->yaxis->title->GetCSIMAreas();
  1246. $csim .= $this->xaxis->title->GetCSIMAreas();
  1247. }
  1248. $n = count($this->plots);
  1249. for( $i=0; $i < $n; ++$i )
  1250. $csim .= $this->plots[$i]->GetCSIMareas();
  1251. $n = count($this->y2plots);
  1252. for( $i=0; $i < $n; ++$i )
  1253. $csim .= $this->y2plots[$i]->GetCSIMareas();
  1254. $n = count($this->ynaxis);
  1255. for( $i=0; $i < $n; ++$i ) {
  1256. $m = count($this->ynplots[$i]);
  1257. for($j=0; $j < $m; ++$j ) {
  1258. $csim .= $this->ynplots[$i][$j]->GetCSIMareas();
  1259. }
  1260. }
  1261. $n = count($this->iTables);
  1262. for( $i=0; $i < $n; ++$i ) {
  1263. $csim .= $this->iTables[$i]->GetCSIMareas();
  1264. }
  1265. return $csim;
  1266. }
  1267. // Get a complete <MAP>..</MAP> tag for the final image map
  1268. function GetHTMLImageMap($aMapName) {
  1269. //$im = "<map name=\"$aMapName\" id=\"$aMapName\">\n";
  1270. $im = "<map name=\"$aMapName\" />\n";
  1271. $im .= $this->GetCSIMareas();
  1272. $im .= "</map>";
  1273. return $im;
  1274. }
  1275. function CheckCSIMCache($aCacheName,$aTimeOut=60) {
  1276. global $_SERVER;
  1277. if( $aCacheName=='auto' )
  1278. $aCacheName=basename($_SERVER['PHP_SELF']);
  1279. $this->csimcachename = CSIMCACHE_DIR.$aCacheName;
  1280. $this->csimcachetimeout = $aTimeOut;
  1281. // First determine if we need to check for a cached version
  1282. // This differs from the standard cache in the sense that the
  1283. // image and CSIM map HTML file is written relative to the directory
  1284. // the script executes in and not the specified cache directory.
  1285. // The reason for this is that the cache directory is not necessarily
  1286. // accessible from the HTTP server.
  1287. if( $this->csimcachename != '' ) {
  1288. $dir = dirname($this->csimcachename);
  1289. $base = basename($this->csimcachename);
  1290. $base = strtok($base,'.');
  1291. $suffix = strtok('.');
  1292. $basecsim = $dir.'/'.$base.'_csim_.html';
  1293. $baseimg = $dir.'/'.$base.'.'.$this->img->img_format;
  1294. $timedout=false;
  1295. // Does it exist at all ?
  1296. if( file_exists($basecsim) && file_exists($baseimg) ) {
  1297. // Check that it hasn't timed out
  1298. $diff=time()-filemtime($basecsim);
  1299. if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) {
  1300. $timedout=true;
  1301. @unlink($basecsim);
  1302. @unlink($baseimg);
  1303. }
  1304. else {
  1305. if ($fh = @fopen($basecsim, "r")) {
  1306. fpassthru($fh);
  1307. return true;
  1308. }
  1309. else
  1310. JpGraphError::RaiseL(25027,$basecsim);//(" Can't open cached CSIM \"$basecsim\" for reading.");
  1311. }
  1312. }
  1313. }
  1314. return false;
  1315. }
  1316. function StrokeCSIM($aScriptName='auto',$aCSIMName='',$aBorder=0) {
  1317. if( $aCSIMName=='' ) {
  1318. // create a random map name
  1319. srand ((double) microtime() * 1000000);
  1320. $r = rand(0,100000);
  1321. $aCSIMName='__mapname'.$r.'__';
  1322. }
  1323. if( $aScriptName=='auto' )
  1324. $aScriptName=basename($_SERVER['PHP_SELF']);
  1325. if( empty($_GET[_CSIM_DISPLAY]) ) {
  1326. // First determine if we need to check for a cached version
  1327. // This differs from the standard cache in the sense that the
  1328. // image and CSIM map HTML file is written relative to the directory
  1329. // the script executes in and not the specified cache directory.
  1330. // The reason for this is that the cache directory is not necessarily
  1331. // accessible from the HTTP server.
  1332. if( $this->csimcachename != '' ) {
  1333. $dir = dirname($this->csimcachename);
  1334. $base = basename($this->csimcachename);
  1335. $base = strtok($base,'.');
  1336. $suffix = strtok('.');
  1337. $basecsim = $dir.'/'.$base.'_csim_.html';
  1338. $baseimg = $base.'.'.$this->img->img_format;
  1339. // Check that apache can write to directory specified
  1340. if( file_exists($dir) && !is_writeable($dir) ) {
  1341. JpgraphError::RaiseL(25028,$dir);//('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');
  1342. }
  1343. // Make sure directory exists
  1344. $this->cache->MakeDirs($dir);
  1345. // Write the image file
  1346. $this->Stroke(CSIMCACHE_DIR.$baseimg);
  1347. // Construct wrapper HTML and write to file and send it back to browser
  1348. $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."\n".
  1349. '<img src="'.htmlentities(CSIMCACHE_HTTP_DIR.$baseimg).'" ismap usemap="#'.$aCSIMName.'" border='.$aBorder.' width='.$this->img->width.' height='.$this->img->height." alt=\"\" />\n";
  1350. if($fh = @fopen($basecsim,'w') ) {
  1351. fwrite($fh,$htmlwrap);
  1352. fclose($fh);
  1353. echo $htmlwrap;
  1354. }
  1355. else
  1356. JpGraphError::RaiseL(25029,$basecsim);//(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions.");
  1357. }
  1358. else {
  1359. if( $aScriptName=='' ) {
  1360. 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().');
  1361. exit();
  1362. }
  1363. // This is a JPGRAPH internal defined that prevents
  1364. // us from recursively coming here again
  1365. $urlarg='?'._CSIM_DISPLAY.'=1';
  1366. // Now reconstruct any user URL argument
  1367. reset($_GET);
  1368. while( list($key,$value) = each($_GET) ) {
  1369. if( is_array($value) ) {
  1370. $n = count($value);
  1371. for( $i=0; $i < $n; ++$i ) {
  1372. $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]);
  1373. }
  1374. }
  1375. else {
  1376. $urlarg .= '&'.$key.'='.urlencode($value);
  1377. }
  1378. }
  1379. // It's not ideal to convert POST argument to GET arguments
  1380. // but there is little else we can do. One idea for the
  1381. // future might be recreate the POST header in case.
  1382. reset($_POST);
  1383. while( list($key,$value) = each($_POST) ) {
  1384. if( is_array($value) ) {
  1385. $n = count($value);
  1386. for( $i=0; $i < $n; ++$i ) {
  1387. $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]);
  1388. }
  1389. }
  1390. else {
  1391. $urlarg .= '&'.$key.'='.urlencode($value);
  1392. }
  1393. }
  1394. echo $this->GetHTMLImageMap($aCSIMName);
  1395. echo "<img src='".htmlentities($aScriptName.$urlarg)."' ismap usemap='#".$aCSIMName.'\' border='.$aBorder.' width='.$this->img->width.' height='.$this->img->height." alt=\"\" />\n";
  1396. }
  1397. }
  1398. else {
  1399. $this->Stroke();
  1400. }
  1401. }
  1402. function GetTextsYMinMax($aY2=false) {
  1403. if( $aY2 )
  1404. $txts = $this->y2texts;
  1405. else
  1406. $txts = $this->texts;
  1407. $n = count($txts);
  1408. $min=null;
  1409. $max=null;
  1410. for( $i=0; $i < $n; ++$i ) {
  1411. if( $txts[$i]->iScalePosY !== null &&
  1412. $txts[$i]->iScalePosX !== null ) {
  1413. if( $min === null ) {
  1414. $min = $max = $txts[$i]->iScalePosY ;
  1415. }
  1416. else {
  1417. $min = min($min,$txts[$i]->iScalePosY);
  1418. $max = max($max,$txts[$i]->iScalePosY);
  1419. }
  1420. }
  1421. }
  1422. if( $min !== null ) {
  1423. return array($min,$max);
  1424. }
  1425. else
  1426. return null;
  1427. }
  1428. function GetTextsXMinMax($aY2=false) {
  1429. if( $aY2 )
  1430. $txts = $this->y2texts;
  1431. else
  1432. $txts = $this->texts;
  1433. $n = count($txts);
  1434. $min=null;
  1435. $max=null;
  1436. for( $i=0; $i < $n; ++$i ) {
  1437. if( $txts[$i]->iScalePosY !== null &&
  1438. $txts[$i]->iScalePosX !== null ) {
  1439. if( $min === null ) {
  1440. $min = $max = $txts[$i]->iScalePosX ;
  1441. }
  1442. else {
  1443. $min = min($min,$txts[$i]->iScalePosX);
  1444. $max = max($max,$txts[$i]->iScalePosX);
  1445. }
  1446. }
  1447. }
  1448. if( $min !== null ) {
  1449. return array($min,$max);
  1450. }
  1451. else
  1452. return null;
  1453. }
  1454. function GetXMinMax() {
  1455. list($min,$ymin) = $this->plots[0]->Min();
  1456. list($max,$ymax) = $this->plots[0]->Max();
  1457. foreach( $this->plots as $p ) {
  1458. list($xmin,$ymin) = $p->Min();
  1459. list($xmax,$ymax) = $p->Max();
  1460. $min = Min($xmin,$min);
  1461. $max = Max($xmax,$max);
  1462. }
  1463. if( $this->y2axis != null ) {
  1464. foreach( $this->y2plots as $p ) {
  1465. list($xmin,$ymin) = $p->Min();
  1466. lis

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