PageRenderTime 81ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 2ms

/includes/jpgraph/jpgraph.php

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

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