PageRenderTime 64ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 2ms

/graph/jpgraph.php

http://eveow.googlecode.com/
PHP | 5906 lines | 4345 code | 740 blank | 821 comment | 1026 complexity | c214717c9b069cc19d185a8de3ab9221 MD5 | raw file
Possible License(s): LGPL-2.1, CC0-1.0

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

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

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