jpgraph.php
上传用户:gzy2002
上传日期:2010-02-11
资源大小:1785k
文件大小:248k
- <?php
- //=======================================================================
- // File: JPGRAPH.PHP
- // Description: PHP4 Graph Plotting library. Base module.
- // Created: 2001-01-08
- // Author: Johan Persson
- // Ver: $Id: jpgraph.php,v 1.25 2004/02/11 20:32:13 deskpro Exp $
- //
- // License: This code is released under QPL 1.0
- // Copyright (C) 2001 - 2004 Johan Persson
- //========================================================================
- //------------------------------------------------------------------------
- // Directories for cache and font directory.
- // Leave them undefined to use default values.
- //
- // Default values used if these defines are left commented out are:
- //
- // UNIX:
- // CACHE_DIR = /tmp/jpgraph_cache/
- // TTF_DIR = /usr/X11R6/lib/X11/fonts/truetype/
- //
- // WINDOWS:
- // CACHE_DIR = $SERVER_TEMP/jpgraph_cache/
- // TTF_DIR = $SERVER_SYSTEMROOT/fonts/
- //
- //
- //------------------------------------------------------------------------
- // The full absolute name of the directory to be used to store the
- // cached image files. This directory will not be used if the USE_CACHE
- // define (further down) is false. If you enable the cache please note that
- // this directory MUST be readable and writable for the process running PHP.
- // Must end with '/'
- $tmpdir = INCLUDE_PATH . '../admin/graphs';
- DEFINE("CACHE_DIR",$tmpdir);
- // Directory for jpGraph TTF fonts. Must end with '/'
- // DEFINE("TTF_DIR","/usr/X11R6/lib/X11/fonts/truetype/");
- //-------------------------------------------------------------------------
- // Cache directory specification for use with CSIM graphs that are
- // using the cache.
- // The directory must be the filesysystem name as seen by PHP
- // and the 'http' version must be the same directory but as
- // seen by the HTTP server relative to the 'htdocs' ddirectory.
- // If a relative path is specified it is taken to be relative from where
- // the image script is executed.
- // Note: The default setting is to create a subdirectory in the
- // directory from where the image script is executed and store all files
- // there. As ususal this directory must be writeable by the PHP process.
- DEFINE("CSIMCACHE_DIR","csimcache/");
- DEFINE("CSIMCACHE_HTTP_DIR","csimcache/");
- //------------------------------------------------------------------------
- // Various JpGraph Settings. Adjust accordingly to your
- // preferences. Note that cache functionality is turned off by
- // default (Enable by setting USE_CACHE to true)
- //------------------------------------------------------------------------
- // Deafult graphic format set to "auto" which will automatically
- // choose the best available format in the order png,gif,jpg
- // (The supported format depends on what your PHP installation supports)
- DEFINE("DEFAULT_GFORMAT","auto");
- // Should the image be a truecolor image?
- // Note 1: Has only effect with GD 2.0.1 and above.
- // Note 2: GD 2.0.1 + PHP 4.0.6 on Win32 crashes when trying to use
- // trucolor. Truecolor support is to be considered alpha since GD 2.x
- // is still not considered stable (especially on Win32).
- // Note 3: MUST be enabled to get background images working with GD2
- // Note 4: If enabled then truetype fonts will look very ugly with GD 2.0.1
- // => You can't have both background images and truetype fonts in the same
- // image until these bugs has been fixed in GD 2.01. There is a patch
- // available for GD 2.0.1 though. See the README file.
- DEFINE('USE_TRUECOLOR',true);
- // Specify what version of the GD library is installed.
- // If this is set to 'auto' the version will be automatically
- // determined.
- // However since determining the library takes ~1ms you can also
- // manually specify the version if you know what version you have.
- // This means that you should
- // set this define to true if you have GD 2.x installed to save 1ms.
- DEFINE("USE_LIBRARY_GD2",'auto');
- // Should the cache be used at all? By setting this to false no
- // files will be generated in the cache directory.
- // The difference from READ_CACHE being that setting READ_CACHE to
- // false will still create the image in the cache directory
- // just not use it. By setting USE_CACHE=false no files will even
- // be generated in the cache directory.
- DEFINE("USE_CACHE",false);
- // Should we try to find an image in the cache before generating it?
- // Set this define to false to bypass the reading of the cache and always
- // regenerate the image. Note that even if reading the cache is
- // disabled the cached will still be updated with the newly generated
- // image. Set also "USE_CACHE" below.
- DEFINE("READ_CACHE",true);
- // Determine if the error handler should be image based or purely
- // text based. Image based makes it easier since the script will
- // always return an image even in case of errors.
- if (!defined('NO_GRAPHIC_HANDLER')) {
- DEFINE("USE_IMAGE_ERROR_HANDLER",true);
- } else {
- DEFINE("USE_IMAGE_ERROR_HANDLER",false);
- }
- // If the color palette is full should JpGraph try to allocate
- // the closest match? If you plan on using background images or
- // gradient fills it might be a good idea to enable this.
- // If not you will otherwise get an error saying that the color palette is
- // exhausted. The drawback of using approximations is that the colors
- // might not be exactly what you specified.
- // Note1: This does only apply to paletted images, not truecolor
- // images since they don't have the limitations of maximum number
- // of colors.
- DEFINE("USE_APPROX_COLORS",true);
- // Special unicode cyrillic language support
- DEFINE("LANGUAGE_CYRILLIC",false);
- // If you are setting this config to true the conversion
- // will assume that the input text is windows 1251, if
- // false it will assume koi8-r
- DEFINE("CYRILLIC_FROM_WINDOWS",false);
- // Should usage of deprecated functions and parameters give a fatal error?
- // (Useful to check if code is future proof.)
- DEFINE("ERR_DEPRECATED",true);
- // Should the time taken to generate each picture be branded to the lower
- // left in corner in each generated image? Useful for performace measurements
- // generating graphs
- DEFINE("BRAND_TIMING",false);
- // What format should be used for the timing string?
- DEFINE("BRAND_TIME_FORMAT","(%01.3fs)");
- //------------------------------------------------------------------------
- // The following constants should rarely have to be changed !
- //------------------------------------------------------------------------
- // What group should the cached file belong to
- // (Set to "" will give the default group for the "PHP-user")
- // Please note that the Apache user must be a member of the
- // specified group since otherwise it is impossible for Apache
- // to set the specified group.
- DEFINE("CACHE_FILE_GROUP","wwwadmin");
- // What permissions should the cached file have
- // (Set to "" will give the default persmissions for the "PHP-user")
- DEFINE("CACHE_FILE_MOD",0664);
- // Decide if we should use the bresenham circle algorithm or the
- // built in Arc(). Bresenham gives better visual apperance of circles
- // but is more CPU intensive and slower then the built in Arc() function
- // in GD. Turned off by default for speed
- DEFINE("USE_BRESENHAM",false);
- // Special file name to indicate that we only want to calc
- // the image map in the call to Graph::Stroke() used
- // internally from the GetHTMLCSIM() method.
- DEFINE("_CSIM_SPECIALFILE","_csim_special_");
- // HTTP GET argument that is used with image map
- // to indicate to the script to just generate the image
- // and not the full CSIM HTML page.
- DEFINE("_CSIM_DISPLAY","_jpg_csimd");
- // Special filename for Graph::Stroke(). If this filename is given
- // then the image will NOT be streamed to browser of file. Instead the
- // Stroke call will return the handler for the created GD image.
- DEFINE("_IMG_HANDLER","__handle");
- // DON'T SET THIS FLAG YORSELF THIS IS ONLY FOR INTERNAL TESTING
- // PURPOSES. ENABLING THIS FLAG WILL MAKE SOME OF YOUR SCRIPT
- // STOP WORKING
- // Enable some extra debug information for CSIM etc to be shown.
- DEFINE("JPG_DEBUG",false);
- // Version info
- DEFINE('JPG_VERSION','1.12');
- //------------------------------------------------------------------------
- // Automatic settings of path for cache and font directory
- // if they have not been previously specified
- //------------------------------------------------------------------------
- if (!defined('CACHE_DIR')) {
- if ( strstr( PHP_OS, 'WIN') ) {
- if( empty($_SERVER['TEMP']) ) {
- die('JpGraph Error: No path specified for CACHE_DIR. Please specify a path for that DEFINE in jpgraph.php');
- }
- else {
- DEFINE('CACHE_DIR', $_SERVER['TEMP'] . '/');
- }
- } else {
- DEFINE('CACHE_DIR','/tmp/jpgraph_cache/');
- }
- }
- if (!defined('TTF_DIR')) {
- if (strstr( PHP_OS, 'WIN') ) {
- if( empty($_SERVER['SystemRoot']) ) {
- die('JpGraph Error: No path specified for TTF_DIR. Please specify a path for that DEFINE in jpgraph.php');
- }
- else {
- DEFINE('TTF_DIR', $_SERVER['SystemRoot'] . '/fonts/');
- }
- } else {
- DEFINE('TTF_DIR','/usr/X11R6/lib/X11/fonts/truetype/');
- }
- }
- //------------------------------------------------------------------
- // Constants which are used as parameters for the method calls
- //------------------------------------------------------------------
- // TTF Font families
- DEFINE("FF_COURIER",10);
- DEFINE("FF_VERDANA",11);
- DEFINE("FF_TIMES",12);
- DEFINE("FF_COMIC",14);
- DEFINE("FF_ARIAL",15);
- DEFINE("FF_GEORGIA",16);
- DEFINE("FF_TREBUCHE",17);
- // Chinese font
- DEFINE("FF_SIMSUN",18);
- // Gnome Vera font
- DEFINE("FF_VERA",19);
- DEFINE("FF_VERAMONO",20);
- DEFINE("FF_VERASERIF",21);
- // Older deprecated fonts
- DEFINE("FF_BOOK",91); // Deprecated fonts from 1.9
- DEFINE("FF_HANDWRT",92); // Deprecated fonts from 1.9
- // TTF Font styles
- DEFINE("FS_NORMAL",9001);
- DEFINE("FS_BOLD",9002);
- DEFINE("FS_ITALIC",9003);
- DEFINE("FS_BOLDIT",9004);
- DEFINE("FS_BOLDITALIC",9004);
- //Definitions for internal font, new style
- DEFINE("FF_FONT0",1);
- DEFINE("FF_FONT1",2);
- DEFINE("FF_FONT2",4);
- //Definitions for internal font, old style
- // (Only defined here to be able to generate an error mesage
- // when used)
- DEFINE("FONT0",99); // Deprecated from 1.2
- DEFINE("FONT1",98); // Deprecated from 1.2
- DEFINE("FONT1_BOLD",97); // Deprecated from 1.2
- DEFINE("FONT2",96); // Deprecated from 1.2
- DEFINE("FONT2_BOLD",95); // Deprecated from 1.2
- // Tick density
- DEFINE("TICKD_DENSE",1);
- DEFINE("TICKD_NORMAL",2);
- DEFINE("TICKD_SPARSE",3);
- DEFINE("TICKD_VERYSPARSE",4);
- // Side for ticks and labels.
- DEFINE("SIDE_LEFT",-1);
- DEFINE("SIDE_RIGHT",1);
- DEFINE("SIDE_DOWN",-1);
- DEFINE("SIDE_BOTTOM",-1);
- DEFINE("SIDE_UP",1);
- DEFINE("SIDE_TOP",1);
- // Legend type stacked vertical or horizontal
- DEFINE("LEGEND_VERT",0);
- DEFINE("LEGEND_HOR",1);
- // Mark types for plot marks
- DEFINE("MARK_SQUARE",1);
- DEFINE("MARK_UTRIANGLE",2);
- DEFINE("MARK_DTRIANGLE",3);
- DEFINE("MARK_DIAMOND",4);
- DEFINE("MARK_CIRCLE",5);
- DEFINE("MARK_FILLEDCIRCLE",6);
- DEFINE("MARK_CROSS",7);
- DEFINE("MARK_STAR",8);
- DEFINE("MARK_X",9);
- DEFINE("MARK_LEFTTRIANGLE",10);
- DEFINE("MARK_RIGHTTRIANGLE",11);
- DEFINE("MARK_FLASH",12);
- DEFINE("MARK_IMG",13);
- // Builtin images
- DEFINE("MARK_IMG_PUSHPIN",50);
- DEFINE("MARK_IMG_SPUSHPIN",50);
- DEFINE("MARK_IMG_LPUSHPIN",51);
- DEFINE("MARK_IMG_DIAMOND",52);
- DEFINE("MARK_IMG_SQUARE",53);
- DEFINE("MARK_IMG_STAR",54);
- DEFINE("MARK_IMG_BALL",55);
- DEFINE("MARK_IMG_SBALL",55);
- DEFINE("MARK_IMG_MBALL",56);
- DEFINE("MARK_IMG_LBALL",57);
- DEFINE("MARK_IMG_BEVEL",58);
- // Styles for gradient color fill
- DEFINE("GRAD_VER",1);
- DEFINE("GRAD_VERT",1);
- DEFINE("GRAD_HOR",2);
- DEFINE("GRAD_MIDHOR",3);
- DEFINE("GRAD_MIDVER",4);
- DEFINE("GRAD_CENTER",5);
- DEFINE("GRAD_WIDE_MIDVER",6);
- DEFINE("GRAD_WIDE_MIDHOR",7);
- DEFINE("GRAD_LEFT_REFLECTION",8);
- DEFINE("GRAD_RIGHT_REFLECTION",9);
- // Inline defines
- DEFINE("INLINE_YES",1);
- DEFINE("INLINE_NO",0);
- // Format for background images
- DEFINE("BGIMG_FILLPLOT",1);
- DEFINE("BGIMG_FILLFRAME",2);
- DEFINE("BGIMG_COPY",3);
- DEFINE("BGIMG_CENTER",4);
- // Depth of objects
- DEFINE("DEPTH_BACK",0);
- DEFINE("DEPTH_FRONT",1);
- // Direction
- DEFINE("VERTICAL",1);
- DEFINE("HORIZONTAL",0);
- // Constants for types of static bands in plot area
- DEFINE("BAND_RDIAG",1); // Right diagonal lines
- DEFINE("BAND_LDIAG",2); // Left diagonal lines
- DEFINE("BAND_SOLID",3); // Solid one color
- DEFINE("BAND_VLINE",4); // Vertical lines
- DEFINE("BAND_HLINE",5); // Horizontal lines
- DEFINE("BAND_3DPLANE",6); // "3D" Plane
- DEFINE("BAND_HVCROSS",7); // Vertical/Hor crosses
- DEFINE("BAND_DIAGCROSS",8); // Diagonal crosses
- // Axis styles for scientific style axis
- DEFINE('AXSTYLE_SIMPLE',1);
- DEFINE('AXSTYLE_BOXIN',2);
- DEFINE('AXSTYLE_BOXOUT',3);
- DEFINE('AXSTYLE_YBOXIN',4);
- DEFINE('AXSTYLE_YBOXOUT',5);
- // Style for title backgrounds
- DEFINE('TITLEBKG_STYLE1',1);
- DEFINE('TITLEBKG_STYLE2',2);
- DEFINE('TITLEBKG_STYLE3',3);
- DEFINE('TITLEBKG_FRAME_NONE',0);
- DEFINE('TITLEBKG_FRAME_FULL',1);
- DEFINE('TITLEBKG_FRAME_BOTTOM',2);
- DEFINE('TITLEBKG_FRAME_BEVEL',3);
- DEFINE('TITLEBKG_FILLSTYLE_HSTRIPED',1);
- DEFINE('TITLEBKG_FILLSTYLE_VSTRIPED',2);
- DEFINE('TITLEBKG_FILLSTYLE_SOLID',3);
- // Width of tab titles
- DEFINE('TABTITLE_WIDTHFIT',0);
- DEFINE('TABTITLE_WIDTHFULL',-1);
- //
- // Get hold of gradient class (In Version 2.x)
- // A client of the library has to manually include this
- //
- include INCLUDE_PATH . "graph/jpgraph_gradient.php";
- //
- // First of all set up a default error handler
- //
- //=============================================================
- // The default trivial text error handler.
- //=============================================================
- class JpGraphErrObject {
- function JpGraphErrObject() {
- // Empty. Reserved for future use
- }
- // If aHalt is true then execution can't continue. Typical used for
- // fatal errors
- function Raise($aMsg,$aHalt=true) {
- $aMsg = "<b>JpGraph Error:</b> ".$aMsg;
- if( $aHalt )
- die($aMsg);
- else
- echo $aMsg."<p>";
- }
- }
- //==============================================================
- // An image based error handler
- //==============================================================
- class JpGraphErrObjectImg {
- function Raise($aMsg,$aHalt=true) {
- $img_iconerror =
- 'iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAaV'.
- 'BMVEX//////2Xy8mLl5V/Z2VvMzFi/v1WyslKlpU+ZmUyMjEh/'.
- 'f0VyckJlZT9YWDxMTDjAwMDy8sLl5bnY2K/MzKW/v5yyspKlpY'.
- 'iYmH+MjHY/PzV/f2xycmJlZVlZWU9MTEXY2Ms/PzwyMjLFTjea'.
- 'AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACx'.
- 'IAAAsSAdLdfvwAAAAHdElNRQfTBgISOCqusfs5AAABLUlEQVR4'.
- '2tWV3XKCMBBGWfkranCIVClKLd/7P2Q3QsgCxjDTq+6FE2cPH+'.
- 'xJ0Ogn2lQbsT+Wrs+buAZAV4W5T6Bs0YXBBwpKgEuIu+JERAX6'.
- 'wM2rHjmDdEITmsQEEmWADgZm6rAjhXsoMGY9B/NZBwJzBvn+e3'.
- 'wHntCAJdGu9SviwIwoZVDxPB9+Rc0TSEbQr0j3SA1gwdSn6Db0'.
- '6Tm1KfV6yzWGQO7zdpvyKLKBDmRFjzeB3LYgK7r6A/noDAfjtS'.
- 'IXaIzbJSv6WgUebTMV4EoRB8a2mQiQjgtF91HdKDKZ1gtFtQjk'.
- 'YcWaR5OKOhkYt+ZsTFdJRfPAApOpQYJTNHvCRSJR6SJngQadfc'.
- 'vd69OLMddVOPCGVnmrFD8bVYd3JXfxXPtLR/+mtv59/ALWiiMx'.
- 'qL72fwAAAABJRU5ErkJggg==' ;
-
- if( headers_sent() ) {
- // Special case for headers already sent error. Dont
- // return an image since it can't be displayed
- die("<b>JpGraph Error:</b> ".$aMsg);
- }
- // Create the error icon GD
- $erricon = imagecreatefromstring(base64_decode($img_iconerror));
- // Create an image that contains the error text.
- $w=370; $h=100;
- $img = new Image($w,$h);
- // Drop shadow
- $img->SetColor("gray");
- $img->FilledRectangle(5,5,$w-1,$h-1,10);
- $img->SetColor("gray:0.7");
- $img->FilledRectangle(5,5,$w-3,$h-3,10);
-
- // Window background
- $img->SetColor("lightblue");
- $img->FilledRectangle(1,1,$w-5,$h-5);
- $img->CopyCanvasH($img->img,$erricon,5,30,0,0,40,40);
- // Window border
- $img->SetColor("black");
- $img->Rectangle(1,1,$w-5,$h-5);
- $img->Rectangle(0,0,$w-4,$h-4);
-
- // Window top row
- $img->SetColor("darkred");
- for($y=3; $y < 18; $y += 2 )
- $img->Line(1,$y,$w-25,$y);
- $img->Line(1,17,$w-5,17);
- $img->Line($w-25,1,$w-25,16);
-
- // "Close button"
- $img->Line($w-18,6,$w-12,12);
- $img->Line($w-18,7,$w-12,13);
- $img->Line($w-18,12,$w-12,6);
- $img->Line($w-18,13,$w-12,7);
- // "White shadow"
- $img->SetColor("white");
- // "Button"
- $img->Line($w-24,3,$w-24,15);
- $img->Line($w-24,2,$w-7,2);
- // Left window edge
- $img->Line(2,2,2,$h-5);
- $img->Line(2,2,$w-27,2);
- // "Gray button shadow"
- $img->SetColor("darkgray");
- $img->Line($w-6,3,$w-6,16);
- $img->Line($w-24,16,$w-7,16);
- // Gray window shadow
- $img->Line(2,$h-6,$w-5,$h-6);
- $img->Line(3,$h-7,$w-5,$h-7);
- // Window title
- $m = floor($w/2-5);
- $l = 100;
- $img->SetColor("lightgray:1.3");
- $img->FilledRectangle($m-$l,2,$m+$l,16);
- // Stroke text
- $img->SetColor("darkred");
- $img->SetFont(FF_FONT2,FS_BOLD);
- $img->StrokeText($m-50,15,"JpGraph Error");
- $img->SetColor("black");
- $img->SetFont(FF_FONT1,FS_NORMAL);
- $txt = new Text(wordwrap($aMsg,52),52,25);
- $txt->Align("left","top");
- $txt->Stroke($img);
- $img->Headers();
- $img->Stream();
- die();
- }
- }
- //
- // A wrapper class that is used to access the specified error object
- // (to hide the global error parameter and avoid having a GLOBAL directive
- // in all methods.
- //
- class JpGraphError {
- function Install($aErrObject) {
- GLOBAL $__jpg_err;
- $__jpg_err = $aErrObject;
- }
- function Raise($aMsg,$aHalt=true){
- GLOBAL $__jpg_err;
- $tmp = new $__jpg_err;
- $tmp->Raise($aMsg,$aHalt);
- }
- }
- //
- // ... and install the default error handler
- //
- if( USE_IMAGE_ERROR_HANDLER ) {
- JpGraphError::Install("JpGraphErrObjectImg");
- }
- else {
- JpGraphError::Install("JpGraphErrObject");
- }
- //
- // Setup PHP error handler
- //
- error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
- function _phpErrorHandler($errno,$errmsg,$filename, $linenum, $vars) {
- JpGraphError::Raise('In '.basename($filename).'#'.$linenum."n".$errmsg);
- }
- #set_error_handler("_phpErrorHandler");
- //
- //Check if there were any warnings, perhaps some wrong includes by the
- //user
- //
- if( isset($GLOBALS['php_errormsg']) ) {
- JpGraphError::Raise("<b>General PHP error:</b><br>".$GLOBALS['php_errormsg']);
- }
- //
- // Routine to determine if GD1 or GD2 is installed
- //
- function CheckGDVersion() {
- ob_start();
- phpinfo(8); // Just get the modules loaded
- $a = ob_get_contents();
- ob_end_clean();
- if( preg_match('/.*GD Version.*(1.).*/',$a,$m) ) {
- $r=1;$v=$m[1];
- }
- elseif( preg_match('/.*GD Version.*(2.).*/',$a,$m) ) {
- $r=2;$v=$m[1];
- }
- else {
- $r=0;$v=$m[1];
- }
- return $r;
- }
- //
- // Check what version of the GD library is installed.
- //
- if( USE_LIBRARY_GD2 === 'auto' ) {
- $gdversion = CheckGDVersion();
- if( $gdversion == 2 ) {
- $GLOBALS['gd2'] = true;
- $GLOBALS['copyfunc'] = 'imagecopyresampled';
- }
- elseif( $gdversion == 1 ) {
- $GLOBALS['gd2'] = false;
- $GLOBALS['copyfunc'] = 'imagecopyresized';
- }
- else {
- 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.");
- }
- }
- else {
- $GLOBALS['gd2'] = USE_LIBRARY_GD2;
- $GLOBALS['copyfunc'] = USE_LIBRARY_GD2 ? 'imagecopyresampled' : 'imagecopyresized';
- }
- // Usefull mathematical function
- function sign($a) {return $a >= 0 ? 1 : -1;}
- // Utility function to generate an image name based on the filename we
- // are running from and assuming we use auto detection of graphic format
- // (top level), i.e it is safe to call this function
- // from a script that uses JpGraph
- function GenImgName() {
- global $_SERVER;
- $supported = imagetypes();
- if( $supported & IMG_PNG )
- $img_format="png";
- elseif( $supported & IMG_GIF )
- $img_format="gif";
- elseif( $supported & IMG_JPG )
- $img_format="jpeg";
- if( !isset($_SERVER['PHP_SELF']) )
- 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.");
- $fname=basename($_SERVER['PHP_SELF']);
- // Replace the ".php" extension with the image format extension
- return substr($fname,0,strlen($fname)-4).".".$img_format;
- }
- class LanguageConv {
- var $g2312 = null ;
- function Convert($aTxt,$aFF) {
- if( LANGUAGE_CYRILLIC ) {
- if( CYRILLIC_FROM_WINDOWS ) {
- $aTxt = convert_cyr_string($aTxt, "w", "k");
- }
- $isostring = convert_cyr_string($aTxt, "k", "i");
- $unistring = LanguageConv::iso2uni($isostring);
- return $unistring;
- }
- elseif( $aFF === FF_SIMSUN ) {
- // Do Chinese conversion
- if( $this->g2312 == null ) {
- include_once 'jpgraph_gb2312.php' ;
- $this->g2312 = new GB2312toUTF8();
- }
- return $this->g2312->gb2utf8($aTxt);
- }
- else
- return $aTxt;
- }
- // Translate iso encoding to unicode
- function iso2uni ($isoline){
- for ($i=0; $i < strlen($isoline); $i++){
- $thischar=substr($isoline,$i,1);
- $charcode=ord($thischar);
- $uniline.=($charcode>175) ? "&#" . (1040+($charcode-176)). ";" : $thischar;
- }
- return $uniline;
- }
- }
- //===================================================
- // CLASS JpgTimer
- // Description: General timing utility class to handle
- // timne measurement of generating graphs. Multiple
- // timers can be started by pushing new on a stack.
- //===================================================
- class JpgTimer {
- var $start;
- var $idx;
- //---------------
- // CONSTRUCTOR
- function JpgTimer() {
- $this->idx=0;
- }
- //---------------
- // PUBLIC METHODS
- // Push a new timer start on stack
- function Push() {
- list($ms,$s)=explode(" ",microtime());
- $this->start[$this->idx++]=floor($ms*1000) + 1000*$s;
- }
- // Pop the latest timer start and return the diff with the
- // current time
- function Pop() {
- assert($this->idx>0);
- list($ms,$s)=explode(" ",microtime());
- $etime=floor($ms*1000) + (1000*$s);
- $this->idx--;
- return $etime-$this->start[$this->idx];
- }
- } // Class
- $gJpgBrandTiming = BRAND_TIMING;
- //===================================================
- // CLASS DateLocale
- // Description: Hold localized text used in dates
- // ToDOo: Rewrite this to use the real local locale
- // instead.
- //===================================================
- class DateLocale {
-
- var $iLocale = 'C'; // environmental locale be used by default
- var $iDayAbb = null;
- var $iShortDay = null;
- var $iShortMonth = null;
- var $iMonthName = null;
- //---------------
- // CONSTRUCTOR
- function DateLocale() {
- settype($this->iDayAbb, 'array');
- settype($this->iShortDay, 'array');
- settype($this->iShortMonth, 'array');
- settype($this->iMonthName, 'array');
- $this->Set('C');
- }
- //---------------
- // PUBLIC METHODS
- function Set($aLocale) {
- if ( in_array($aLocale, array_keys($this->iDayAbb)) ){
- $this->iLocale = $aLocale;
- return TRUE; // already cached nothing else to do!
- }
- $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME
- $res = setlocale(LC_TIME, $aLocale);
- if ( ! $res ){
- 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.");
- return FALSE;
- }
-
- $this->iLocale = $aLocale;
- for ( $i = 0, $ofs = 0 - strftime('%w'); $i < 7; $i++, $ofs++ ){
- $day = strftime('%a', strtotime("$ofs day"));
- $day{0} = strtoupper($day{0});
- $this->iDayAbb[$aLocale][]= $day{0};
- $this->iShortDay[$aLocale][]= $day;
- }
- for($i=1; $i<=12; ++$i) {
- list($short ,$full) = explode('|', strftime("%b|%B",strtotime("2001-$i-01")));
- $this->iShortMonth[$aLocale][] = ucfirst($short);
- $this->iMonthName [$aLocale][] = ucfirst($full);
- }
-
-
- setlocale(LC_TIME, $pLocale);
- return TRUE;
- }
- function GetDayAbb() {
- return $this->iDayAbb[$this->iLocale];
- }
-
- function GetShortDay() {
- return $this->iShortDay[$this->iLocale];
- }
- function GetShortMonth() {
- return $this->iShortMonth[$this->iLocale];
- }
-
- function GetShortMonthName($aNbr) {
- return $this->iShortMonth[$this->iLocale][$aNbr];
- }
- function GetLongMonthName($aNbr) {
- return $this->iMonthName[$this->iLocale][$aNbr];
- }
- function GetMonth() {
- return $this->iMonthName[$this->iLocale];
- }
- }
- $gDateLocale = new DateLocale();
- $gJpgDateLocale = new DateLocale();
- //===================================================
- // CLASS FuncGenerator
- // Description: Utility class to help generate data for function plots.
- // The class supports both parametric and regular functions.
- //===================================================
- class FuncGenerator {
- var $iFunc='',$iXFunc='',$iMin,$iMax,$iStepSize;
-
- function FuncGenerator($aFunc,$aXFunc='') {
- $this->iFunc = $aFunc;
- $this->iXFunc = $aXFunc;
- }
-
- function E($aXMin,$aXMax,$aSteps=50) {
- $this->iMin = $aXMin;
- $this->iMax = $aXMax;
- $this->iStepSize = ($aXMax-$aXMin)/$aSteps;
- if( $this->iXFunc != '' )
- $t = 'for($i='.$aXMin.'; $i<='.$aXMax.'; $i += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]='.$this->iXFunc.';}';
- elseif( $this->iFunc != '' )
- $t = 'for($x='.$aXMin.'; $x<='.$aXMax.'; $x += '.$this->iStepSize.') {$ya[]='.$this->iFunc.';$xa[]=$x;} $x='.$aXMax.';$ya[]='.$this->iFunc.';$xa[]=$x;';
- else
- JpGraphError::Raise('FuncGenerator : No function specified. ');
-
- @eval($t);
-
- // If there is an error in the function specifcation this is the only
- // way we can discover that.
- if( empty($xa) || empty($ya) )
- JpGraphError::Raise('FuncGenerator : Syntax error in function specification ');
-
- return array($xa,$ya);
- }
- }
- //=======================================================
- // CLASS Footer
- // Description: Encapsulates the footer line in the Graph
- //
- //=======================================================
- class Footer {
- var $left,$center,$right;
- var $iLeftMargin = 3;
- var $iRightMargin = 3;
- var $iBottomMargin = 3;
- function Footer() {
- $this->left = new Text();
- $this->left->ParagraphAlign('left');
- $this->center = new Text();
- $this->center->ParagraphAlign('center');
- $this->right = new Text();
- $this->right->ParagraphAlign('right');
- }
- function Stroke($aImg) {
- $y = $aImg->height - $this->iBottomMargin;
- $x = $this->iLeftMargin;
- $this->left->Align('left','bottom');
- $this->left->Stroke($aImg,$x,$y);
- $x = ($aImg->width - $this->iLeftMargin - $this->iRightMargin)/2;
- $this->center->Align('center','bottom');
- $this->center->Stroke($aImg,$x,$y);
- $x = $aImg->width - $this->iRightMargin;
- $this->right->Align('right','bottom');
- $this->right->Stroke($aImg,$x,$y);
- }
- }
- DEFINE('BGRAD_FRAME',1);
- DEFINE('BGRAD_MARGIN',2);
- DEFINE('BGRAD_PLOT',3);
- //===================================================
- // CLASS Graph
- // Description: Main class to handle graphs
- //===================================================
- class Graph {
- var $cache=null; // Cache object (singleton)
- var $img=null; // Img object (singleton)
- var $plots=array(); // Array of all plot object in the graph (for Y 1 axis)
- var $y2plots=array();// Array of all plot object in the graph (for Y 2 axis)
- var $xscale=null; // X Scale object (could be instance of LinearScale or LogScale
- var $yscale=null,$y2scale=null;
- var $cache_name; // File name to be used for the current graph in the cache directory
- var $xgrid=null; // X Grid object (linear or logarithmic)
- var $ygrid=null,$y2grid=null; //dito for Y
- var $doframe=true,$frame_color=array(0,0,0), $frame_weight=1; // Frame around graph
- var $boxed=false, $box_color=array(0,0,0), $box_weight=1; // Box around plot area
- var $doshadow=false,$shadow_width=4,$shadow_color=array(102,102,102); // Shadow for graph
- var $xaxis=null; // X-axis (instane of Axis class)
- var $yaxis=null, $y2axis=null; // Y axis (instance of Axis class)
- var $margin_color=array(200,200,200); // Margin color of graph
- var $plotarea_color=array(255,255,255); // Plot area color
- var $title,$subtitle,$subsubtitle; // Title and subtitle(s) text object
- var $axtype="linlin"; // Type of axis
- var $xtick_factor; // Factot to determine the maximum number of ticks depending on the plot with
- var $texts=null; // Text object to ge shown in the graph
- var $lines=null;
- var $bands=null;
- var $text_scale_off=0; // Text scale offset in world coordinates
- var $background_image="",$background_image_type=-1,$background_image_format="png";
- var $background_image_bright=0,$background_image_contr=0,$background_image_sat=0;
- var $image_bright=0, $image_contr=0, $image_sat=0;
- var $inline;
- var $showcsim=0,$csimcolor="red"; //debug stuff, draw the csim boundaris on the image if <>0
- var $grid_depth=DEPTH_BACK; // Draw grid under all plots as default
- var $iAxisStyle = AXSTYLE_SIMPLE;
- var $iCSIMdisplay=false,$iHasStroked = false;
- var $footer;
- var $csimcachename = '', $csimcachetimeout = 0;
- var $iDoClipping = false;
- var $y2orderback=true;
- var $tabtitle;
- var $bkg_gradtype=-1,$bkg_gradstyle=BGRAD_MARGIN;
- var $bkg_gradfrom='navy', $bkg_gradto='silver';
- var $titlebackground = false;
- var $titlebackground_color = 'lightblue',
- $titlebackground_style = 1,
- $titlebackground_framecolor = 'blue',
- $titlebackground_framestyle = 2,
- $titlebackground_frameweight = 1,
- $titlebackground_bevelheight = 3 ;
- var $titlebkg_fillstyle=TITLEBKG_FILLSTYLE_SOLID;
- var $titlebkg_scolor1='black',$titlebkg_scolor2='white';
- var $framebevel = false, $framebeveldepth = 2 ;
- var $framebevelborder = false, $framebevelbordercolor='black';
- var $framebevelcolor1='white@0.4', $framebevelcolor2='black@0.4';
- //---------------
- // CONSTRUCTOR
- // aWIdth Width in pixels of image
- // aHeight Height in pixels of image
- // aCachedName Name for image file in cache directory
- // aTimeOut Timeout in minutes for image in cache
- // aInline If true the image is streamed back in the call to Stroke()
- // If false the image is just created in the cache
- function Graph($aWidth=300,$aHeight=200,$aCachedName="",$aTimeOut=0,$aInline=true) {
- GLOBAL $gJpgBrandTiming;
- // If timing is used create a new timing object
- if( $gJpgBrandTiming ) {
- global $tim;
- $tim = new JpgTimer();
- $tim->Push();
- }
-
- // Automatically generate the image file name based on the name of the script that
- // generates the graph
- if( $aCachedName=="auto" )
- $aCachedName=GenImgName();
-
- // Should the image be streamed back to the browser or only to the cache?
- $this->inline=$aInline;
-
- $this->img = new RotImage($aWidth,$aHeight);
- $this->cache = new ImgStreamCache($this->img);
- $this->cache->SetTimeOut($aTimeOut);
- $this->title = new Text();
- $this->title->ParagraphAlign('center');
- $this->title->SetFont(FF_FONT2,FS_BOLD);
- $this->title->SetMargin(3);
- $this->subtitle = new Text();
- $this->subtitle->ParagraphAlign('center');
- $this->subsubtitle = new Text();
- $this->subsubtitle->ParagraphAlign('center');
- $this->legend = new Legend();
- $this->footer = new Footer();
- // If the cached version exist just read it directly from the
- // cache, stream it back to browser and exit
- if( $aCachedName!="" && READ_CACHE && $aInline )
- if( $this->cache->GetAndStream($aCachedName) ) {
- exit();
- }
-
- $this->cache_name = $aCachedName;
- $this->SetTickDensity(); // Normal density
- $this->tabtitle = new GraphTabTitle();
- }
- //---------------
- // PUBLIC METHODS
- // Should the grid be in front or back of the plot?
- function SetGridDepth($aDepth) {
- $this->grid_depth=$aDepth;
- }
-
- // Specify graph angle 0-360 degrees.
- function SetAngle($aAngle) {
- $this->img->SetAngle($aAngle);
- }
- function SetAlphaBlending($aFlg=true) {
- $this->img->SetAlphaBlending($aFlg);
- }
- // Shortcut to image margin
- function SetMargin($lm,$rm,$tm,$bm) {
- $this->img->SetMargin($lm,$rm,$tm,$bm);
- }
- function SetY2OrderBack($aBack=true) {
- $this->y2orderback = $aBack;
- }
- // Rotate the graph 90 degrees and set the margin
- // when we have done a 90 degree rotation
- function Set90AndMargin($lm=0,$rm=0,$tm=0,$bm=0) {
- $lm = $lm ==0 ? floor(0.2 * $this->img->width) : $lm ;
- $rm = $rm ==0 ? floor(0.1 * $this->img->width) : $rm ;
- $tm = $tm ==0 ? floor(0.2 * $this->img->height) : $tm ;
- $bm = $bm ==0 ? floor(0.1 * $this->img->height) : $bm ;
- $adj = ($this->img->height - $this->img->width)/2;
- $this->img->SetMargin($tm-$adj,$bm-$adj,$rm+$adj,$lm+$adj);
- $this->img->SetCenter(floor($this->img->width/2),floor($this->img->height/2));
- $this->SetAngle(90);
- $this->xaxis->SetLabelAlign('right','center');
- $this->yaxis->SetLabelAlign('center','bottom');
- }
-
- function SetClipping($aFlg=true) {
- $this->iDoClipping = $aFlg ;
- }
- // Add a plot object to the graph
- function Add(&$aPlot) {
- if( $aPlot == null )
- JpGraphError::Raise("<b></b> Graph::Add() You tried to add a null plot to the graph.");
- if( is_array($aPlot) && count($aPlot) > 0 )
- $cl = get_class($aPlot[0]);
- else
- $cl = get_class($aPlot);
- if( $cl == 'text' )
- $this->AddText($aPlot);
- elseif( $cl == 'plotline' )
- $this->AddLine($aPlot);
- elseif( $cl == 'plotband' )
- $this->AddBand($aPlot);
- else
- $this->plots[] = &$aPlot;
- }
- // Add plot to second Y-scale
- function AddY2(&$aPlot) {
- if( $aPlot == null )
- JpGraphError::Raise("<b></b> Graph::AddY2() You tried to add a null plot to the graph.");
- $this->y2plots[] = &$aPlot;
- }
-
- // Add text object to the graph
- function AddText(&$aTxt) {
- if( $aTxt == null )
- JpGraphError::Raise("<b></b> Graph::AddText() You tried to add a null text to the graph.");
- if( is_array($aTxt) ) {
- for($i=0; $i < count($aTxt); ++$i )
- $this->texts[]=&$aTxt[$i];
- }
- else
- $this->texts[] = &$aTxt;
- }
-
- // Add a line object (class PlotLine) to the graph
- function AddLine(&$aLine) {
- if( $aLine == null )
- JpGraphError::Raise("<b></b> Graph::AddLine() You tried to add a null line to the graph.");
- if( is_array($aLine) ) {
- for($i=0; $i<count($aLine); ++$i )
- $this->lines[]=&$aLine[$i];
- }
- else
- $this->lines[] = &$aLine;
- }
- // Add vertical or horizontal band
- function AddBand(&$aBand) {
- if( $aBand == null )
- JpGraphError::Raise(" Graph::AddBand() You tried to add a null band to the graph.");
- if( is_array($aBand) ) {
- for($i=0; $i<count($aBand); ++$i )
- $this->bands[] = &$aBand[$i];
- }
- else
- $this->bands[] = &$aBand;
- }
- function SetBackgroundGradient($aFrom='navy',$aTo='silver',$aGradType=GRAD_HOR,$aStyle=BGRAD_FRAME) {
- $this->bkg_gradtype=$aGradType;
- $this->bkg_gradstyle=$aStyle;
- $this->bkg_gradfrom = $aFrom;
- $this->bkg_gradto = $aTo;
- }
-
- // Specify a background image
- function SetBackgroundImage($aFileName,$aBgType=BGIMG_FILLPLOT,$aImgFormat="auto") {
- if( $GLOBALS['gd2'] && !USE_TRUECOLOR ) {
- 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.");
- }
- // Get extension to determine image type
- if( $aImgFormat == "auto" ) {
- $e = explode('.',$aFileName);
- if( !$e ) {
- JpGraphError::Raise('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type');
- }
- $valid_formats = array('png', 'jpg', 'gif');
- $aImgFormat = strtolower($e[count($e)-1]);
- if ($aImgFormat == 'jpeg') {
- $aImgFormat = 'jpg';
- }
- elseif (!in_array($aImgFormat, $valid_formats) ) {
- JpGraphError::Raise('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
- }
- }
- $this->background_image = $aFileName;
- $this->background_image_type=$aBgType;
- $this->background_image_format=$aImgFormat;
- }
-
- // Adjust brightness and constrast for background image
- function AdjBackgroundImage($aBright,$aContr=0,$aSat=0) {
- $this->background_image_bright=$aBright;
- $this->background_image_contr=$aContr;
- $this->background_image_sat=$aSat;
- }
-
- // Adjust brightness and constrast for image
- function AdjImage($aBright,$aContr=0,$aSat=0) {
- $this->image_bright=$aBright;
- $this->image_contr=$aContr;
- $this->image_sat=$aSat;
- }
- // Specify axis style (boxed or single)
- function SetAxisStyle($aStyle) {
- $this->iAxisStyle = $aStyle ;
- }
-
- // Set a frame around the plot area
- function SetBox($aDrawPlotFrame=true,$aPlotFrameColor=array(0,0,0),$aPlotFrameWeight=1) {
- $this->boxed = $aDrawPlotFrame;
- $this->box_weight = $aPlotFrameWeight;
- $this->box_color = $aPlotFrameColor;
- }
-
- // Specify color for the plotarea (not the margins)
- function SetColor($aColor) {
- $this->plotarea_color=$aColor;
- }
-
- // Specify color for the margins (all areas outside the plotarea)
- function SetMarginColor($aColor) {
- $this->margin_color=$aColor;
- }
-
- // Set a frame around the entire image
- function SetFrame($aDrawImgFrame=true,$aImgFrameColor=array(0,0,0),$aImgFrameWeight=1) {
- $this->doframe = $aDrawImgFrame;
- $this->frame_color = $aImgFrameColor;
- $this->frame_weight = $aImgFrameWeight;
- }
- function SetFrameBevel($aDepth=3,$aBorder=false,$aBorderColor='black',$aColor1='white@0.4',$aColor2='darkgray@0.4',$aFlg=true) {
- $this->framebevel = $aFlg ;
- $this->framebeveldepth = $aDepth ;
- $this->framebevelborder = $aBorder ;
- $this->framebevelbordercolor = $aBorderColor ;
- $this->framebevelcolor1 = $aColor1 ;
- $this->framebevelcolor2 = $aColor2 ;
- $this->doshadow = false ;
- }
- // Set the shadow around the whole image
- function SetShadow($aShowShadow=true,$aShadowWidth=5,$aShadowColor=array(102,102,102)) {
- $this->doshadow = $aShowShadow;
- $this->shadow_color = $aShadowColor;
- $this->shadow_width = $aShadowWidth;
- $this->footer->iBottomMargin += $aShadowWidth;
- $this->footer->iRightMargin += $aShadowWidth;
- }
- // Specify x,y scale. Note that if you manually specify the scale
- // you must also specify the tick distance with a call to Ticks::Set()
- function SetScale($aAxisType,$aYMin=1,$aYMax=1,$aXMin=1,$aXMax=1) {
- $this->axtype = $aAxisType;
- if( $aYMax < $aYMin || $aXMax < $aXMin )
- JpGraphError::Raise('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
- $yt=substr($aAxisType,-3,3);
- if( $yt=="lin" )
- $this->yscale = new LinearScale($aYMin,$aYMax);
- elseif( $yt == "int" ) {
- $this->yscale = new LinearScale($aYMin,$aYMax);
- $this->yscale->SetIntScale();
- }
- elseif( $yt=="log" )
- $this->yscale = new LogScale($aYMin,$aYMax);
- else
- JpGraphError::Raise("Unknown scale specification for Y-scale. ($aAxisType)");
-
- $xt=substr($aAxisType,0,3);
- if( $xt == "lin" || $xt == "tex" ) {
- $this->xscale = new LinearScale($aXMin,$aXMax,"x");
- $this->xscale->textscale = ($xt == "tex");
- }
- elseif( $xt == "int" ) {
- $this->xscale = new LinearScale($aXMin,$aXMax,"x");
- $this->xscale->SetIntScale();
- }
- elseif( $xt == "log" )
- $this->xscale = new LogScale($aXMin,$aXMax,"x");
- else
- JpGraphError::Raise(" Unknown scale specification for X-scale. ($aAxisType)");
- $this->xscale->Init($this->img);
- $this->yscale->Init($this->img);
-
- $this->xaxis = new Axis($this->img,$this->xscale);
- $this->yaxis = new Axis($this->img,$this->yscale);
- $this->xgrid = new Grid($this->xaxis);
- $this->ygrid = new Grid($this->yaxis);
- $this->ygrid->Show();
- }
-
- // Specify secondary Y scale
- function SetY2Scale($aAxisType="lin",$aY2Min=1,$aY2Max=1) {
- if( $aAxisType=="lin" )
- $this->y2scale = new LinearScale($aY2Min,$aY2Max);
- elseif( $aAxisType == "int" ) {
- $this->y2scale = new LinearScale($aY2Min,$aY2Max);
- $this->y2scale->SetIntScale();
- }
- elseif( $aAxisType=="log" ) {
- $this->y2scale = new LogScale($aY2Min,$aY2Max);
- }
- else JpGraphError::Raise("JpGraph: Unsupported Y2 axis type: $axtype<br>");
-
- $this->y2scale->Init($this->img);
- $this->y2axis = new Axis($this->img,$this->y2scale);
- $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
- $this->y2axis->SetLabelSide(SIDE_RIGHT);
-
- // Deafult position is the max x-value
- $this->y2grid = new Grid($this->y2axis);
- }
-
- // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'
- // The dividing factor have been determined heuristically according to my aesthetic
- // sense (or lack off) y.m.m.v !
- function SetTickDensity($aYDensity=TICKD_NORMAL,$aXDensity=TICKD_NORMAL) {
- $this->xtick_factor=30;
- $this->ytick_factor=25;
- switch( $aYDensity ) {
- case TICKD_DENSE:
- $this->ytick_factor=12;
- break;
- case TICKD_NORMAL:
- $this->ytick_factor=25;
- break;
- case TICKD_SPARSE:
- $this->ytick_factor=40;
- break;
- case TICKD_VERYSPARSE:
- $this->ytick_factor=100;
- break;
- default:
- JpGraphError::Raise("JpGraph: Unsupported Tick density: $densy");
- }
- switch( $aXDensity ) {
- case TICKD_DENSE:
- $this->xtick_factor=15;
- break;
- case TICKD_NORMAL:
- $this->xtick_factor=30;
- break;
- case TICKD_SPARSE:
- $this->xtick_factor=45;
- break;
- case TICKD_VERYSPARSE:
- $this->xtick_factor=60;
- break;
- default:
- JpGraphError::Raise("JpGraph: Unsupported Tick density: $densx");
- }
- }
-
- // Get a string of all image map areas
- function GetCSIMareas() {
- if( !$this->iHasStroked )
- $this->Stroke(_CSIM_SPECIALFILE);
- $csim=$this->legend->GetCSIMAreas();
- $n = count($this->plots);
- for( $i=0; $i<$n; ++$i )
- $csim .= $this->plots[$i]->GetCSIMareas();
- $n = count($this->y2plots);
- for( $i=0; $i<$n; ++$i )
- $csim .= $this->y2plots[$i]->GetCSIMareas();
- return $csim;
- }
-
- // Get a complete <MAP>..</MAP> tag for the final image map
- function GetHTMLImageMap($aMapName) {
- $im = "<MAP NAME="$aMapName">n";
- $im .= $this->GetCSIMareas();
- $im .= "</MAP>";
- return $im;
- }
- function CheckCSIMCache($aCacheName,$aTimeOut=60) {
- global $_SERVER;
- if( $aCacheName=='auto' )
- $aCacheName=basename($_SERVER['PHP_SELF']);
- $this->csimcachename = CSIMCACHE_DIR.$aCacheName;
- $this->csimcachetimeout = $aTimeOut;
- // First determine if we need to check for a cached version
- // This differs from the standard cache in the sense that the
- // image and CSIM map HTML file is written relative to the directory
- // the script executes in and not the specified cache directory.
- // The reason for this is that the cache directory is not necessarily
- // accessible from the HTTP server.
- if( $this->csimcachename != '' ) {
- $dir = dirname($this->csimcachename);
- $base = basename($this->csimcachename);
- $base = strtok($base,'.');
- $suffix = strtok('.');
- $basecsim = $dir.'/'.$base.'_csim_.html';
- $baseimg = $dir.'/'.$base.'.'.$this->img->img_format;
- $timedout=false;
-
- // Does it exist at all ?
-
- if( file_exists($basecsim) && file_exists($baseimg) ) {
- // Check that it hasn't timed out
- $diff=time()-filemtime($basecsim);
- if( $this->csimcachetimeout>0 && ($diff > $this->csimcachetimeout*60) ) {
- $timedout=true;
- @unlink($basecsim);
- @unlink($baseimg);
- }
- else {
- if ($fh = @fopen($basecsim, "r")) {
- fpassthru($fh);
- exit();
- }
- else
- JpGraphError::Raise(" Can't open cached CSIM "$basecsim" for reading.");
- }
- }
- }
- return false;
- }
- function StrokeCSIM($aScriptName='',$aCSIMName='',$aBorder=0) {
- GLOBAL $HTTP_GET_VARS;
- if( $aCSIMName=='' ) {
- // create a random map name
- $r = rand(0,100000);
- $aCSIMName='__mapname'.$r.'__';
- }
- if( empty($HTTP_GET_VARS[_CSIM_DISPLAY]) ) {
- // First determine if we need to check for a cached version
- // This differs from the standard cache in the sense that the
- // image and CSIM map HTML file is written relative to the directory
- // the script executes in and not the specified cache directory.
- // The reason for this is that the cache directory is not necessarily
- // accessible from the HTTP server.
- if( $this->csimcachename != '' ) {
- $dir = dirname($this->csimcachename);
- $base = basename($this->csimcachename);
- $base = strtok($base,'.');
- $suffix = strtok('.');
- $basecsim = $dir.'/'.$base.'_csim_.html';
- $baseimg = $base.'.'.$this->img->img_format;
- // Check that apache can write to directory specified
- if( file_exists($dir) && !is_writeable($dir) ) {
- JpgraphError::Raise('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');
- }
-
- // Make sure directory exists
- $this->cache->MakeDirs($dir);
- // Write the image file
- $this->Stroke(CSIMCACHE_DIR.$baseimg);
- // Construct wrapper HTML and write to file and send it back to browser
- $htmlwrap = $this->GetHTMLImageMap($aCSIMName)."n".
- '<img src="'.CSIMCACHE_HTTP_DIR.$baseimg.'" ISMAP USEMAP="#'.$aCSIMName.'" border='.$aBorder.'>'."n";
- if($fh = @fopen($basecsim,'w') ) {
- fwrite($fh,$htmlwrap);
- fclose($fh);
- echo $htmlwrap;
- }
- else
- JpGraphError::Raise(" Can't write CSIM "$basecsim" for writing. Check free space and permissions.");
- }
- else {
- if( $aScriptName=='' ) {
- 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().');
- exit();
- }
- // Construct the HTML wrapper page
- // Get all user defined URL arguments
- reset($HTTP_GET_VARS);
-
- // This is a JPGRAPH internal defined that prevents
- // us from recursively coming here again
- $urlarg='?'._CSIM_DISPLAY.'=1';
- while( list($key,$value) = each($HTTP_GET_VARS) ) {
- if( is_array($value) ) {
- $n = count($value);
- for( $i=0; $i < $n; ++$i ) {
- $urlarg .= '&'.$key.'%5B%5D='.urlencode($value[$i]);
- }
- }
- else {
- $urlarg .= '&'.$key.'='.urlencode($value);
- }
- }
-
- echo $this->GetHTMLImageMap($aCSIMName);
- echo "<img src='".$aScriptName.$urlarg."' ISMAP USEMAP='#".$aCSIMName."' border=$aBorder>";
- }
- }
- else {
- $this->Stroke();
- }
- }
- function GetTextsYMinMax() {
- $n = count($this->texts);
- $min=null;
- $max=null;
- for( $i=0; $i < $n; ++$i ) {
- if( $this->texts[$i]->iScalePosY !== null &&
- $this->texts[$i]->iScalePosX !== null ) {
- if( $min === null ) {
- $min = $max = $this->texts[$i]->iScalePosY ;
- }
- else {
- $min = min($min,$this->texts[$i]->iScalePosY);
- $max = max($max,$this->texts[$i]->iScalePosY);
- }
- }
- }
- if( $min !== null ) {
- return array($min,$max);
- }
- else
- return null;
- }
- function GetTextsXMinMax() {
- $n = count($this->texts);
- $min=null;
- $max=null;
- for( $i=0; $i < $n; ++$i ) {
- if( $this->texts[$i]->iScalePosY !== null &&
- $this->texts[$i]->iScalePosX !== null ) {
- if( $min === null ) {
- $min = $max = $this->texts[$i]->iScalePosX ;
- }
- else {
- $min = min($min,$this->texts[$i]->iScalePosX);
- $max = max($max,$this->texts[$i]->iScalePosX);
- }
- }
- }
- if( $min !== null ) {
- return array($min,$max);
- }
- else
- return null;
- }
- function GetXMinMax() {
- list($min,$ymin) = $this->plots[0]->Min();
- list($max,$ymax) = $this->plots[0]->Max();
- foreach( $this->plots as $p ) {
- list($xmin,$ymin) = $p->Min();
- list($xmax,$ymax) = $p->Max();
- $min = Min($xmin,$min);
- $max = Max($xmax,$max);
- }
- if( $this->y2axis != null ) {
- foreach( $this->y2plots as $p ) {
- list($xmin,$ymin) = $p->Min();
- list($xmax,$ymax) = $p->Max();
- $min = Min($xmin,$min);
- $max = Max($xmax,$max);
- }
- }
- return array($min,$max);
- }
- function AdjustMarginsForTitles() {
- $totrequired =
- ($this->title->t != '' ?
- $this->title->GetTextHeight($this->img) + $this->title->margin + 5 : 0 ) +
- ($this->subtitle->t != '' ?
- $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 : 0 ) +
- ($this->subsubtitle->t != '' ?
- $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 : 0 ) ;
-
- $btotrequired = 0;
- if( !$this->xaxis->hide && !$this->xaxis->hide_labels ) {
- // Minimum bottom margin
- if( $this->xaxis->title->t != '' ) {
- if( $this->img->a == 90 )
- $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 5 ;
- else
- $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 5 ;
- }
- else
- $btotrequired = 0;
-
- if( $this->img->a == 90 ) {
- $this->img->SetFont($this->yaxis->font_family,$this->yaxis->font_style,
- $this->yaxis->font_size);
- $lh = $this->img->GetTextHeight('Mg',$this->yaxis->label_angle);
- }
- else {
- $this->img->SetFont($this->xaxis->font_family,$this->xaxis->font_style,
- $this->xaxis->font_size);
- $lh = $this->img->GetTextHeight('Mg',$this->xaxis->label_angle);
- }
-
- $btotrequired += $lh + 5;
- }
- if( $this->img->a == 90 ) {
- // DO Nothing. It gets too messy to do this properly for 90 deg...
- }
- else{
- if( $this->img->top_margin < $totrequired ) {
- $this->SetMargin($this->img->left_margin,$this->img->right_margin,
- $totrequired,$this->img->bottom_margin);
- }
- if( $this->img->bottom_margin < $btotrequired ) {
- $this->SetMargin($this->img->left_margin,$this->img->right_margin,
- $this->img->top_margin,$btotrequired);
- }
- }
- }
- // Stroke the graph
- // $aStrokeFileName If != "" the image will be written to this file and NOT
- // streamed back to the browser
- function Stroke($aStrokeFileName="") {
- // Start by adjusting the margin so that potential titles will fit.
- $this->AdjustMarginsForTitles();
- // If the filename is the predefined value = '_csim_special_'
- // we assume that the call to stroke only needs to do enough
- // to correctly generate the CSIM maps.
- // We use this variable to skip things we don't strictly need
- // to do to generate the image map to improve performance
- // a best we can. Therefor you will see a lot of tests !$_csim in the
- // code below.
- $_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
- // We need to know if we have stroked the plot in the
- // GetCSIMareas. Otherwise the CSIM hasn't been generated
- // and in the case of GetCSIM called before stroke to generate
- // CSIM without storing an image to disk GetCSIM must call Stroke.
- $this->iHasStroked = true;
- // Do any pre-stroke adjustment that is needed by the different plot types
- // (i.e bar plots want's to add an offset to the x-labels etc)
- for($i=0; $i<count($this->plots) ; ++$i ) {
- $this->plots[$i]->PreStrokeAdjust($this);
- $this->plots[$i]->DoLegend($this);
- }
-
- // Any plots on the second Y scale?
- if( $this->y2scale != null ) {
- for($i=0; $i<count($this->y2plots) ; ++$i ) {
- $this->y2plots[$i]->PreStrokeAdjust($this);
- $this->y2plots[$i]->DoLegend($this);
- }
- }
-
- // Bail out if any of the Y-axis not been specified and
- // has no plots. (This means it is impossible to do autoscaling and
- // no other scale was given so we can't possible draw anything). If you use manual
- // scaling you also have to supply the tick steps as well.
- if( (!$this->yscale->IsSpecified() && count($this->plots)==0) ||
- ($this->y2scale!=null && !$this->y2scale->IsSpecified() && count($this->y2plots)==0) ) {
- $e = "Can't draw unspecified Y-scale.<br>nYou have either:<br>n";
- $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>n";
- $e .= "2. Specified a scale manually but have forgot to specify the tick steps";
- JpGraphError::Raise($e);
- }
-
- // Bail out if no plots and no specified X-scale
- if( (!$this->xscale->IsSpecified() && count($this->plots)==0 && count($this->y2plots)==0) )
- JpGraphError::Raise("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>");
- //Check if we should autoscale y-axis
- if( !$this->yscale->IsSpecified() && count($this->plots)>0 ) {
- list($min,$max) = $this->GetPlotsYMinMax($this->plots);
- $lres = $this->GetLinesYMinMax($this->lines);
- if( $lres ) {
- list($linmin,$linmax) = $lres ;
- $min = min($min,$linmin);
- $max = max($max,$linmax);
- }
- $tres = $this->GetTextsYMinMax();
- if( $tres ) {
- list($tmin,$tmax) = $tres ;
- $min = min($min,$tmin);
- $max = max($max,$tmax);
- }
- $this->yscale->AutoScale($this->img,$min,$max,
- $this->img->plotheight/$this->ytick_factor);
- }
- elseif( $this->yscale->IsSpecified() &&
- ( $this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified()) ) {
- // The tick calculation will use the user suplied min/max values to determine
- // the ticks. If auto_ticks is false the exact user specifed min and max
- // values will be used for the scale.
- // If auto_ticks is true then the scale might be slightly adjusted
- // so that the min and max values falls on an even major step.
- $min = $this->yscale->scale[0];
- $max = $this->yscale->scale[1];
- $this->yscale->AutoScale($this->img,$min,$max,
- $this->img->plotheight/$this->ytick_factor,
- $this->yscale->auto_ticks);
- }
- if( $this->y2scale != null) {
- if( !$this->y2scale->IsSpecified() && count($this->y2plots)>0 ) {
- list($min,$max) = $this->GetPlotsYMinMax($this->y2plots);
- $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
- }
- elseif( $this->y2scale->IsSpecified() &&
- ( $this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified()) ) {
- // The tick calculation will use the user suplied min/max values to determine
- // the ticks. If auto_ticks is false the exact user specifed min and max
- // values will be used for the scale.
- // If auto_ticks is true then the scale might be slightly adjusted
- // so that the min and max values falls on an even major step.
- $min = $this->y2scale->scale[0];
- $max = $this->y2scale->scale[1];
- $this->y2scale->AutoScale($this->img,$min,$max,
- $this->img->plotheight/$this->ytick_factor,
- $this->y2scale->auto_ticks);
- }
- }
-
- //Check if we should autoscale x-axis
- if( !$this->xscale->IsSpecified() ) {
- if( substr($this->axtype,0,4) == "text" ) {
- $max=0;
- foreach( $this->plots as $p ) {
- $max=max($max,$p->numpoints-1);
- }
- $min=0;
- if( $this->y2axis != null ) {
- foreach( $this->y2plots as $p ) {
- $max=max($max,$p->numpoints-1);
- }
- }
- $this->xscale->Update($this->img,$min,$max);
- $this->xscale->ticks->Set($this->xaxis->tick_step,1);
- $this->xscale->ticks->SupressMinorTickMarks();
- }
- else {
- list($min,$max) = $this->GetXMinMax();
- $lres = $this->GetLinesXMinMax($this->lines);
- if( $lres ) {
- list($linmin,$linmax) = $lres ;
- $min = min($min,$linmin);
- $max = max($max,$linmax);
- }
- $tres = $this->GetTextsXMinMax();
- if( $tres ) {
- list($tmin,$tmax) = $tres ;
- $min = min($min,$tmin);
- $max = max($max,$tmax);
- }
- $this->xscale->AutoScale($this->img,$min,$max,$this->img->plotwidth/$this->xtick_factor);
- }
-
- //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale
- if( !is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos) )
- $this->yaxis->SetPos($this->xscale->GetMinVal());
- if( $this->y2axis != null ) {
- if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) )
- $this->y2axis->SetPos($this->xscale->GetMaxVal());
- $this->y2axis->SetTitleSide(SIDE_RIGHT);
- }
- }
- elseif( $this->xscale->IsSpecified() &&
- ( $this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified()) ) {
- // The tick calculation will use the user suplied min/max values to determine
- // the ticks. If auto_ticks is false the exact user specifed min and max
- // values will be used for the scale.
- // If auto_ticks is true then the scale might be slightly adjusted
- // so that the min and max values falls on an even major step.
- $min = $this->xscale->scale[0];
- $max = $this->xscale->scale[1];
- $this->xscale->AutoScale($this->img,$min,$max,
- $this->img->plotwidth/$this->xtick_factor,
- false);
- if( $this->y2axis != null ) {
- if( !is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos) )
- $this->y2axis->SetPos($this->xscale->GetMaxVal());
- $this->y2axis->SetTitleSide(SIDE_RIGHT);
- }
- }
-
- // If we have a negative values and x-axis position is at 0
- // we need to supress the first and possible the last tick since
- // they will be drawn on top of the y-axis (and possible y2 axis)
- // The test below might seem strange the reasone being that if
- // the user hasn't specified a value for position this will not
- // be set until we do the stroke for the axis so as of now it
- // is undefined.
- // For X-text scale we ignore all this since the tick are usually
- // much further in and not close to the Y-axis. Hence the test
- // for 'text'
- if( ($this->yaxis->pos==$this->xscale->GetMinVal() ||
- (is_string($this->yaxis->pos) && $this->yaxis->pos=='min')) &&
- !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 &&
- substr($this->axtype,0,4) != 'text' && $this->xaxis->pos!="min" ) {
- //$this->yscale->ticks->SupressZeroLabel(false);
- $this->xscale->ticks->SupressFirst();
- if( $this->y2axis != null ) {
- $this->xscale->ticks->SupressLast();
- }
- }
- elseif( !is_numeric($this->yaxis->pos) && $this->yaxis->pos=='max' ) {
- $this->xscale->ticks->SupressLast();
- }
-
- if( !$_csim ) {
- $this->StrokePlotArea();
- $this->StrokeAxis();
- }
- // Stroke bands
- if( $this->bands != null && !$_csim)
- for($i=0; $i<count($this->bands); ++$i) {
- // Stroke all bands that asks to be in the background
- if( $this->bands[$i]->depth == DEPTH_BACK )
- $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);
- }
- if( $this->grid_depth == DEPTH_BACK && !$_csim) {
- $this->ygrid->Stroke();
- $this->xgrid->Stroke();
- }
-
- // Stroke Y2-axis
- if( $this->y2axis != null && !$_csim) {
- $this->y2axis->Stroke($this->xscale);
- $this->y2grid->Stroke();
- }
-
- $oldoff=$this->xscale->off;
- if(substr($this->axtype,0,4)=="text") {
- $this->xscale->off +=
- ceil($this->xscale->scale_factor*$this->text_scale_off*$this->xscale->ticks->minor_step);
- }
- if( $this->iDoClipping ) {
- $oldimage = $this->img->CloneCanvasH();
- }
- if( ! $this->y2orderback ) {
- // Stroke all plots for Y1 axis
- for($i=0; $i < count($this->plots); ++$i) {
- $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
- $this->plots[$i]->StrokeMargin($this->img);
- }
- }
- // Stroke all plots for Y2 axis
- if( $this->y2scale != null )
- for($i=0; $i< count($this->y2plots); ++$i ) {
- $this->y2plots[$i]->Stroke($this->img,$this->xscale,$this->y2scale);
- }
- if( $this->y2orderback ) {
- // Stroke all plots for Y1 axis
- for($i=0; $i < count($this->plots); ++$i) {
- $this->plots[$i]->Stroke($this->img,$this->xscale,$this->yscale);
- $this->plots[$i]->StrokeMargin($this->img);
- }
- }
- if( $this->iDoClipping ) {
- // Clipping only supports graphs at 0 and 90 degrees
- if( $this->img->a == 0 ) {
- $this->img->CopyCanvasH($oldimage,$this->img->img,
- $this->img->left_margin,$this->img->top_margin,
- $this->img->left_margin,$this->img->top_margin,
- $this->img->plotwidth+1,$this->img->plotheight);
- }
- elseif( $this->img->a == 90 ) {
- $adj = ($this->img->height - $this->img->width)/2;
- $this->img->CopyCanvasH($oldimage,$this->img->img,
- $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
- $this->img->bottom_margin-$adj,$this->img->left_margin+$adj,
- $this->img->plotheight+1,$this->img->plotwidth);
- }
- else {
- JpGraphError::Raise('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.');
- }
- $this->img->Destroy();
- $this->img->SetCanvasH($oldimage);
- }
- $this->xscale->off=$oldoff;
-
- if( $this->grid_depth == DEPTH_FRONT && !$_csim ) {
- $this->ygrid->Stroke();
- $this->xgrid->Stroke();
- }
- // Stroke bands
- if( $this->bands!= null )
- for($i=0; $i<count($this->bands); ++$i) {
- // Stroke all bands that asks to be in the foreground
- if( $this->bands[$i]->depth == DEPTH_FRONT )
- $this->bands[$i]->Stroke($this->img,$this->xscale,$this->yscale);
- }
- // Stroke any lines added
- if( $this->lines != null ) {
- for($i=0; $i<count($this->lines); ++$i) {
- $this->lines[$i]->Stroke($this->img,$this->xscale,$this->yscale);
- }
- }
-
- // Finally draw the axis again since some plots may have nagged
- // the axis in the edges.
- if( !$_csim )
- $this->StrokeAxis();
- if( $this->y2scale != null && !$_csim )
- $this->y2axis->Stroke($this->xscale);
-
- if( !$_csim ) {
- $this->StrokePlotBox();
- }
-
- if( !$_csim ) {
- // The titles and legends never gets rotated so make sure
- // that the angle is 0 before stroking them
- $aa = $this->img->SetAngle(0);
- $this->StrokeTitles();
- $this->footer->Stroke($this->img);
- }
- $this->legend->Stroke($this->img);
- if( !$_csim ) {
- $this->StrokeTexts();
- $this->img->SetAngle($aa);
-
- // Draw an outline around the image map
- if(JPG_DEBUG)
- $this->DisplayClientSideaImageMapAreas();
-
- // Adjust the appearance of the image
- $this->AdjustSaturationBrightnessContrast();
- // If the filename is given as the special "__handle"
- // then the image handler is returned and the image is NOT
- // streamed back
- if( $aStrokeFileName == _IMG_HANDLER ) {
- return $this->img->img;
- }
- else {
- // Finally stream the generated picture
- $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,
- $aStrokeFileName);
- }
- }
- }
- //---------------
- // PRIVATE METHODS
- function StrokeAxis() {
-
- // Stroke axis
- if( $this->iAxisStyle != AXSTYLE_SIMPLE ) {
- switch( $this->iAxisStyle ) {
- case AXSTYLE_BOXIN :
- $toppos = SIDE_DOWN;
- $bottompos = SIDE_UP;
- $leftpos = SIDE_RIGHT;
- $rightpos = SIDE_LEFT;
- break;
- case AXSTYLE_BOXOUT :
- $toppos = SIDE_UP;
- $bottompos = SIDE_DOWN;
- $leftpos = SIDE_LEFT;
- $rightpos = SIDE_RIGHT;
- break;
- case AXSTYLE_YBOXIN:
- $toppos = -100;
- $bottompos = SIDE_UP;
- $leftpos = SIDE_RIGHT;
- $rightpos = SIDE_LEFT;
- break;
- case AXSTYLE_YBOXOUT:
- $toppos = -100;
- $bottompos = SIDE_DOWN;
- $leftpos = SIDE_LEFT;
- $rightpos = SIDE_RIGHT;
- break;
- default:
- JpGRaphError::Raise('Unknown AxisStyle() : '.$this->iAxisStyle);
- break;
- }
- $this->xaxis->SetPos('min');
-
- // By default we hide the first label so it doesn't cross the
- // Y-axis in case the positon hasn't been set by the user.
- // However, if we use a box we always want the first value
- // displayed so we make sure it will be displayed.
- $this->xscale->ticks->SupressFirst(false);
-
- $this->xaxis->SetLabelSide(SIDE_DOWN);
- $this->xaxis->scale->ticks->SetSide($bottompos);
- $this->xaxis->Stroke($this->yscale);
- if( $toppos != -100 ) {
- // To avoid side effects we work on a new copy
- $maxis = $this->xaxis;
- $maxis->SetPos('max');
- $maxis->SetLabelSide(SIDE_UP);
- $maxis->SetLabelMargin(7);
- $this->xaxis->scale->ticks->SetSide($toppos);
- $maxis->Stroke($this->yscale);
- }
- $this->yaxis->SetPos('min');
- $this->yaxis->SetLabelMargin(10);
- $this->yaxis->SetLabelSide(SIDE_LEFT);
- $this->yaxis->scale->ticks->SetSide($leftpos);
- $this->yaxis->Stroke($this->xscale);
- $myaxis = $this->yaxis;
- $myaxis->SetPos('max');
- $myaxis->SetLabelMargin(10);
- $myaxis->SetLabelSide(SIDE_RIGHT);
- $myaxis->title->Set('');
- $myaxis->scale->ticks->SetSide($rightpos);
- $myaxis->Stroke($this->xscale);
-
- }
- else {
- $this->xaxis->Stroke($this->yscale);
- $this->yaxis->Stroke($this->xscale);
- }
- }
- // Private helper function for backgound image
- function LoadBkgImage($aImgFormat='',$aFile='') {
- if( $aFile == '' )
- $aFile = $this->background_image;
- // Remove case sensitivity and setup appropriate function to create image
- // Get file extension. This should be the LAST '.' separated part of the filename
- $e = explode('.',$aFile);
- $ext = strtolower($e[count($e)-1]);
- if ($ext == "jpeg") {
- $ext = "jpg";
- }
-
- if( trim($ext) == '' )
- $ext = 'png'; // Assume PNG if no extension specified
- if( $aImgFormat == '' )
- $imgtag = $ext;
- else
- $imgtag = $aImgFormat;
- if( $imgtag == "jpg" || $imgtag == "jpeg")
- {
- $f = "imagecreatefromjpeg";
- $imgtag = "jpg";
- }
- else
- {
- $f = "imagecreatefrom".$imgtag;
- }
- // Compare specified image type and file extension
- if( $imgtag != $ext ) {
- $t = " Background image seems to be of different type (has different file extension)".
- " than specified imagetype. <br>Specified: '".
- $aImgFormat."'<br>File: '".$aFile."'";
- JpGraphError::Raise($t);
- }
- $img = @$f($aFile);
- if( !$img ) {
- JpGraphError::Raise(" Can't read background image: '".$aFile."'");
- }
- return $img;
- }
- function StrokeBackgroundGrad() {
- if( $this->bkg_gradtype < 0 )
- return;
- $grad = new Gradient($this->img);
- if( $this->bkg_gradstyle == BGRAD_PLOT ) {
- $xl = $this->img->left_margin;
- $yt = $this->img->top_margin;
- $xr = $xl + $this->img->plotwidth ;
- $yb = $yt + $this->img->plotheight ;
- }
- else {
- $xl = 0;
- $yt = 0;
- $xr = $xl + $this->img->width - 1;
- $yb = $yt + $this->img->height - 1;
- }
- if( $this->doshadow ) {
- $xr -= $this->shadow_width;
- $yb -= $this->shadow_width;
- }
- $grad->FilledRectangle($xl,$yt,$xr,$yb,
- $this->bkg_gradfrom,$this->bkg_gradto,
- $this->bkg_gradtype);
- }
- function StrokeFrameBackground() {
- if( $this->background_image == "" )
- return;
- $bkgimg = $this->LoadBkgImage($this->background_image_format);
- $this->img->_AdjBrightContrast($bkgimg,$this->background_image_bright,
- $this->background_image_contr);
- $this->img->_AdjSat($bkgimg,$this->background_image_sat);
- $bw = ImageSX($bkgimg);
- $bh = ImageSY($bkgimg);
- // No matter what the angle is we always stroke the image and frame
- // assuming it is 0 degree
- $aa = $this->img->SetAngle(0);
-
- switch( $this->background_image_type ) {
- case BGIMG_FILLPLOT: // Resize to just fill the plotarea
- $this->StrokeFrame();
- $GLOBALS['copyfunc']($this->img->img,$bkgimg,
- $this->img->left_margin,$this->img->top_margin,
- 0,0,$this->img->plotwidth,$this->img->plotheight,
- $bw,$bh);
- break;
- case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit
- $GLOBALS['copyfunc']($this->img->img,$bkgimg,
- 0,0,0,0,
- $this->img->width,$this->img->height,
- $bw,$bh);
- $this->StrokeFrame();
- break;
- case BGIMG_COPY: // Just copy the image from left corner, no resizing
- $GLOBALS['copyfunc']($this->img->img,$bkgimg,
- 0,0,0,0,
- $bw,$bh,
- $bw,$bh);
- $this->StrokeFrame();
- break;
- case BGIMG_CENTER: // Center original image in the plot area
- $centerx = round($this->img->plotwidth/2+$this->img->left_margin-$bw/2);
- $centery = round($this->img->plotheight/2+$this->img->top_margin-$bh/2);
- $GLOBALS['copyfunc']($this->img->img,$bkgimg,
- $centerx,$centery,
- 0,0,
- $bw,$bh,
- $bw,$bh);
- $this->StrokeFrame();
- break;
- default:
- JpGraphError::Raise(" Unknown background image layout");
- }
- $this->img->SetAngle($aa);
- }
- // Private
- // Draw a frame around the image
- function StrokeFrame() {
- if( !$this->doframe ) return;
- if( $this->background_image_type <= 1 &&
- ($this->bkg_gradtype < 0 ||
- ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_PLOT) ) )
- $c = $this->margin_color;
- else
- $c = false;
-
- if( $this->doshadow ) {
- $this->img->SetColor($this->frame_color);
- $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height,
- $c,$this->shadow_width,$this->shadow_color);
- }
- elseif( $this->framebevel ) {
- if( $c ) {
- $this->img->SetColor($this->margin_color);
- $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
- }
- $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
- $this->framebeveldepth,
- $this->framebevelcolor1,$this->framebevelcolor2);
- if( $this->framebevelborder ) {
- $this->img->SetColor($this->framebevelbordercolor);
- $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
- }
- }
- else {
- $this->img->SetLineWeight($this->frame_weight);
- if( $c ) {
- $this->img->SetColor($this->margin_color);
- $this->img->FilledRectangle(0,0,$this->img->width-1,$this->img->height-1);
- }
- $this->img->SetColor($this->frame_color);
- $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
- }
- }
- // Stroke the plot area with either a solid color or a background image
- function StrokePlotArea() {
- // Note: To be consistent we really should take a possible shadow
- // into account. However, that causes some problem for the LinearScale class
- // since in the current design it does not have any links to class Graph which
- // means it has no way of compensating for the adjusted plotarea in case of a
- // shadow. So, until I redesign LinearScale we can't compensate for this.
- // So just set the two adjustment parameters to zero for now.
- $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ;
- $adj = 0; //$this->doshadow ? $this->shadow_width : 0 ;
- if( $this->background_image != "" ) {
- $this->StrokeFrameBackground();
- }
- else {
- $aa = $this->img->SetAngle(0);
- $this->StrokeFrame();
- $aa = $this->img->SetAngle($aa);
- $this->StrokeBackgroundGrad();
- if( $this->bkg_gradtype < 0 ||
- ($this->bkg_gradtype > 0 && $this->bkg_gradstyle==BGRAD_MARGIN ) ) {
- $this->img->PushColor($this->plotarea_color);
- $this->img->FilledRectangle($this->img->left_margin+$boxadj,
- $this->img->top_margin+$boxadj,
- $this->img->width-$this->img->right_margin-$adj-2*$boxadj,
- $this->img->height-$this->img->bottom_margin-$adj-2*$boxadj);
- $this->img->PopColor();
- }
- }
- }
-
-
- function StrokePlotBox() {
- // Should we draw a box around the plot area?
- if( $this->boxed ) {
- $this->img->SetLineWeight($this->box_weight);
- $this->img->SetColor($this->box_color);
- $this->img->Rectangle(
- $this->img->left_margin,$this->img->top_margin,
- $this->img->width-$this->img->right_margin,
- $this->img->height-$this->img->bottom_margin);
- }
- }
- function SetTitleBackgroundFillStyle($aStyle,$aColor1='black',$aColor2='white') {
- $this->titlebkg_fillstyle = $aStyle;
- $this->titlebkg_scolor1 = $aColor1;
- $this->titlebkg_scolor2 = $aColor2;
- }
- function SetTitleBackground($aBackColor='gray', $aStyle=TITLEBKG_STYLE1, $aFrameStyle=TITLEBKG_FRAME_NONE, $aFrameColor='black', $aFrameWeight=1, $aBevelHeight=3, $aEnable=true) {
- $this->titlebackground = $aEnable;
- $this->titlebackground_color = $aBackColor;
- $this->titlebackground_style = $aStyle;
- $this->titlebackground_framecolor = $aFrameColor;
- $this->titlebackground_framestyle = $aFrameStyle;
- $this->titlebackground_frameweight = $aFrameWeight;
- $this->titlebackground_bevelheight = $aBevelHeight ;
- }
- function StrokeTitles() {
- $margin=3;
- if( $this->titlebackground ) {
- // Find out height
- $this->title->margin += 2 ;
- $h = $this->title->GetTextHeight($this->img)+$this->title->margin+$margin;
- if( $this->subtitle->t != "" && !$this->subtitle->hide ) {
- $h += $this->subtitle->GetTextHeight($this->img)+$margin+
- $this->subtitle->margin;
- }
- if( $this->subsubtitle->t != "" && !$this->subsubtitle->hide ) {
- $h += $this->subsubtitle->GetTextHeight($this->img)+$margin+
- $this->subsubtitle->margin;
- }
- $this->img->PushColor($this->titlebackground_color);
- if( $this->titlebackground_style === 1 ) {
- // Inside the frame
- if( $this->framebevel ) {
- $x1 = $y1 = $this->framebeveldepth + 1 ;
- $x2 = $this->img->width - $this->framebeveldepth - 2 ;
- $this->title->margin += $this->framebeveldepth + 1 ;
- $h += $y1 ;
- }
- else {
- $x1 = $y1 = $this->frame_weight;
- $x2 = $this->img->width - 2*$x1;
- }
- }
- elseif( $this->titlebackground_style === 2 ) {
- // Cover the frame as well
- $x1 = $y1 = 0;
- $x2 = $this->img->width - 1 ;
- }
- elseif( $this->titlebackground_style === 3) {
- // Cover the frame as well (the difference is that
- // for style==3 a bevel frame border is on top
- // of the title background)
- $x1 = $y1 = 0;
- $x2 = $this->img->width - 1 ;
- $h += $this->framebeveldepth ;
- $this->title->margin += $this->framebeveldepth ;
- }
- else {
- JpGraphError::Raise('Unknown title background style.');
- }
- if( $this->titlebackground_framestyle === 3 ) {
- $h += $this->titlebackground_bevelheight*2 + 1 ;
- $this->title->margin += $this->titlebackground_bevelheight ;
- }
- if( $this->doshadow ) {
- $x2 -= $this->shadow_width ;
- }
-
- if( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_HSTRIPED ) {
- $this->img->FilledRectangle2($x1,$y1,$x2,$h,
- $this->titlebkg_scolor1,
- $this->titlebkg_scolor2);
- }
- elseif( $this->titlebkg_fillstyle==TITLEBKG_FILLSTYLE_VSTRIPED ) {
- $this->img->FilledRectangle2($x1,$y1,$x2,$h,
- $this->titlebkg_scolor1,
- $this->titlebkg_scolor2,2);
- }
- else {
- // Solid fill
- $this->img->FilledRectangle($x1,$y1,$x2,$h);
- }
- $this->img->PopColor();
- $this->img->PushColor($this->titlebackground_framecolor);
- $this->img->SetLineWeight($this->titlebackground_frameweight);
- if( $this->titlebackground_framestyle == 1 ) {
- // Frame background
- $this->img->Rectangle($x1,$y1,$x2,$h);
- }
- elseif( $this->titlebackground_framestyle == 2 ) {
- // Bottom line only
- $this->img->Line($x1,$h,$x2,$h);
- }
- elseif( $this->titlebackground_framestyle == 3 ) {
- $this->img->Bevel($x1,$y1,$x2,$h,$this->titlebackground_bevelheight);
- }
- $this->img->PopColor();
- // This is clumsy. But we neeed to stroke the whole graph frame if it is
- // set to bevel to get the bevel shading on top of the text background
- if( $this->framebevel && $this->doframe &&
- $this->titlebackground_style === 3 ) {
- $this->img->Bevel(1,1,$this->img->width-2,$this->img->height-2,
- $this->framebeveldepth,
- $this->framebevelcolor1,$this->framebevelcolor2);
- if( $this->framebevelborder ) {
- $this->img->SetColor($this->framebevelbordercolor);
- $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
- }
- }
- }
- // Stroke title
- $y = $this->title->margin;
- $this->title->Center(0,$this->img->width,$y);
- $this->title->Stroke($this->img);
-
- // ... and subtitle
- $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
- $this->subtitle->Center(0,$this->img->width,$y);
- $this->subtitle->Stroke($this->img);
- // ... and subsubtitle
- $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
- $this->subsubtitle->Center(0,$this->img->width,$y);
- $this->subsubtitle->Stroke($this->img);
- // ... and fancy title
- $this->tabtitle->Stroke($this->img);
- }
- function StrokeTexts() {
- // Stroke any user added text objects
- if( $this->texts != null ) {
- for($i=0; $i<count($this->texts); ++$i) {
- $this->texts[$i]->StrokeWithScale($this->img,$this->xscale,$this->yscale);
- }
- }
- }
- function DisplayClientSideaImageMapAreas() {
- // Debug stuff - display the outline of the image map areas
- foreach ($this->plots as $p) {
- $csim.= $p->GetCSIMareas();
- }
- $csim .= $this->legend->GetCSIMareas();
- if (preg_match_all("/area shape="(w+)" coords="([0-9, ]+)"/", $csim, $coords)) {
- $this->img->SetColor($this->csimcolor);
- for ($i=0; $i<count($coords[0]); $i++) {
- if ($coords[1][$i]=="poly") {
- preg_match_all('/s*([0-9]+)s*,s*([0-9]+)s*,*/',$coords[2][$i],$pts);
- $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
- for ($j=0; $j<count($pts[0]); $j++) {
- $this->img->LineTo($pts[1][$j],$pts[2][$j]);
- }
- } else if ($coords[1][$i]=="rect") {
- $pts = preg_split('/,/', $coords[2][$i]);
- $this->img->SetStartPoint($pts[0],$pts[1]);
- $this->img->LineTo($pts[2],$pts[1]);
- $this->img->LineTo($pts[2],$pts[3]);
- $this->img->LineTo($pts[0],$pts[3]);
- $this->img->LineTo($pts[0],$pts[1]);
- }
- }
- }
- }
- function AdjustSaturationBrightnessContrast() {
- // Adjust the brightness and contrast of the image
- if( $this->image_contr || $this->image_bright )
- $this->img->AdjBrightContrast($this->image_bright,$this->image_contr);
- if( $this->image_sat )
- $this->img->AdjSat($this->image_sat);
- }
- // Text scale offset in world coordinates
- function SetTextScaleOff($aOff) {
- $this->text_scale_off = $aOff;
- $this->xscale->text_scale_off = $aOff;
- }
- // Get Y min and max values for added lines
- function GetLinesYMinMax( $aLines ) {
- $n = count($aLines);
- if( $n == 0 ) return false;
- $min = $aLines[0]->scaleposition ;
- $max = $min ;
- $flg = false;
- for( $i=0; $i < $n; ++$i ) {
- if( $aLines[$i]->direction == HORIZONTAL ) {
- $flg = true ;
- $v = $aLines[$i]->scaleposition ;
- if( $min > $v ) $min = $v ;
- if( $max < $v ) $max = $v ;
- }
- }
- return $flg ? array($min,$max) : false ;
- }
- // Get X min and max values for added lines
- function GetLinesXMinMax( $aLines ) {
- $n = count($aLines);
- if( $n == 0 ) return false ;
- $min = $aLines[0]->scaleposition ;
- $max = $min ;
- $flg = false;
- for( $i=0; $i < $n; ++$i ) {
- if( $aLines[$i]->direction == VERTICAL ) {
- $flg = true ;
- $v = $aLines[$i]->scaleposition ;
- if( $min > $v ) $min = $v ;
- if( $max < $v ) $max = $v ;
- }
- }
- return $flg ? array($min,$max) : false ;
- }
- // Get min and max values for all included plots
- function GetPlotsYMinMax(&$aPlots) {
- list($xmax,$max) = $aPlots[0]->Max();
- list($xmin,$min) = $aPlots[0]->Min();
- for($i=0; $i<count($aPlots); ++$i ) {
- list($xmax,$ymax)=$aPlots[$i]->Max();
- list($xmin,$ymin)=$aPlots[$i]->Min();
- if (!is_string($ymax) || $ymax != "") $max=max($max,$ymax);
- if (!is_string($ymin) || $ymin != "") $min=min($min,$ymin);
- }
- if( $min == "" ) $min = 0;
- if( $max == "" ) $max = 0;
- if( $min == 0 && $max == 0 ) {
- // Special case if all values are 0
- $min=0;$max=1;
- }
- return array($min,$max);
- }
- } // Class
- //===================================================
- // CLASS TTF
- // Description: Handle TTF font names
- //===================================================
- class TTF {
- var $font_files,$style_names;
- //---------------
- // CONSTRUCTOR
- function TTF() {
- $this->style_names=array(FS_NORMAL=>'normal',FS_BOLD=>'bold',FS_ITALIC=>'italic',FS_BOLDITALIC=>'bolditalic');
- // File names for available fonts
- $this->font_files=array(
- FF_COURIER => array(FS_NORMAL=>'cour.ttf', FS_BOLD=>'courbd.ttf', FS_ITALIC=>'couri.ttf', FS_BOLDITALIC=>'courbi.ttf' ),
- FF_GEORGIA => array(FS_NORMAL=>'georgia.ttf', FS_BOLD=>'georgiab.ttf', FS_ITALIC=>'georgiai.ttf', FS_BOLDITALIC=>'' ),
- FF_TREBUCHE =>array(FS_NORMAL=>'trebuc.ttf', FS_BOLD=>'trebucbd.ttf', FS_ITALIC=>'trebucit.ttf', FS_BOLDITALIC=>'trebucbi.ttf' ),
- FF_VERDANA => array(FS_NORMAL=>'verdana.ttf', FS_BOLD=>'verdanab.ttf', FS_ITALIC=>'verdanai.ttf', FS_BOLDITALIC=>'' ),
- FF_TIMES => array(FS_NORMAL=>'times.ttf', FS_BOLD=>'timesbd.ttf', FS_ITALIC=>'timesi.ttf', FS_BOLDITALIC=>'timesbi.ttf' ),
- FF_COMIC => array(FS_NORMAL=>'comic.ttf', FS_BOLD=>'comicbd.ttf', FS_ITALIC=>'.ttf', FS_BOLDITALIC=>'' ),
- FF_ARIAL => array(FS_NORMAL=>'arial.ttf', FS_BOLD=>'arialbd.ttf', FS_ITALIC=>'ariali.ttf', FS_BOLDITALIC=>'arialbi.ttf' ) ,
- FF_SIMSUN => array(FS_NORMAL=>'simsun.ttc', FS_BOLD=>'simhei.ttf', FS_ITALIC=>'', FS_BOLDITALIC=>'' ),
- FF_VERA => array(FS_NORMAL=>'Vera.ttf', FS_BOLD=>'VeraBd.ttf', FS_ITALIC=>'VeraIt.ttf', FS_BOLDITALIC=>'VeraBI.ttf' ),
- FF_VERAMONO => array(FS_NORMAL=>'VeraMono.ttf', FS_BOLD=>'VeraMoBd.ttf', FS_ITALIC=>'VeraMoIt.ttf', FS_BOLDITALIC=>'VeraMoBI.ttf' ),
- FF_VERASERIF => array(FS_NORMAL=>'VeraSe.ttf', FS_BOLD=>'VeraSeBd.ttf', FS_ITALIC=>'', FS_BOLDITALIC=>'' )
- );
- }
- //---------------
- // PUBLIC METHODS
- // Create the TTF file from the font specification
- function File($family,$style=FS_NORMAL) {
-
- if( $family == FF_HANDWRT || $family==FF_BOOK ) {
- JpGraphError::Raise('Font families FF_HANDWRT and FF_BOOK are no longer available due to copyright problem with these fonts. Fonts can no longer be distributed with JpGraph.');
- }
- $fam = @$this->font_files[$family];
- if( !$fam ) {
- JpGraphError::Raise(
- "Specified TTF font family (id=$family) is unknown or does not exist. ".
- "Please note that TTF fonts are not distributed with JpGraph for copyright reasons.".
- " You can find the MS TTF WEB-fonts");
- }
- $f = @$fam[$style];
- if( $f==='' )
- JpGraphError::Raise('Style "'.$this->style_names[$style].'" is not available for font family '.$this->font_files[$family][FS_NORMAL].'.');
- if( !$f )
- JpGraphError::Raise("Unknown font style specification [$fam].");
- $f = TTF_DIR.$f;
- if( file_exists($f) === false || is_readable($f) === false ) {
- JpGraphError::Raise("Font file "$f" is not readable or does not exist.");
- }
- return $f;
- }
- } // Class
- //===================================================
- // CLASS LineProperty
- // Description: Holds properties for a line
- //===================================================
- class LineProperty {
- var $iWeight=1, $iColor="black",$iStyle="solid";
- var $iShow=true;
-
- //---------------
- // PUBLIC METHODS
- function SetColor($aColor) {
- $this->iColor = $aColor;
- }
-
- function SetWeight($aWeight) {
- $this->iWeight = $aWeight;
- }
-
- function SetStyle($aStyle) {
- $this->iStyle = $aStyle;
- }
-
- function Show($aShow=true) {
- $this->iShow=$aShow;
- }
-
- function Stroke($aImg,$aX1,$aY1,$aX2,$aY2) {
- if( $this->iShow ) {
- $aImg->SetColor($this->iColor);
- $aImg->SetLineWeight($this->iWeight);
- $aImg->SetLineStyle($this->iStyle);
- $aImg->StyleLine($aX1,$aY1,$aX2,$aY2);
- }
- }
- }
- //===================================================
- // CLASS Text
- // Description: Arbitrary text object that can be added to the graph
- //===================================================
- class Text {
- var $t,$x=0,$y=0,$halign="left",$valign="top",$color=array(0,0,0);
- var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12;
- var $hide=false, $dir=0;
- var $boxed=false; // Should the text be boxed
- var $paragraph_align="left";
- var $margin;
- var $icornerradius=0,$ishadowwidth=3;
- var $iScalePosY=null,$iScalePosX=null;
- //---------------
- // CONSTRUCTOR
- // Create new text at absolute pixel coordinates
- function Text($aTxt="",$aXAbsPos=0,$aYAbsPos=0) {
- $this->t = $aTxt;
- $this->x = round($aXAbsPos);
- $this->y = round($aYAbsPos);
- $this->margin = 0;
- }
- //---------------
- // PUBLIC METHODS
- // Set the string in the text object
- function Set($aTxt) {
- $this->t = $aTxt;
- }
-
- // Alias for Pos()
- function SetPos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") {
- $this->Pos($aXAbsPos,$aYAbsPos,$aHAlign,$aVAlign);
- }
-
- // Specify the position and alignment for the text object
- function Pos($aXAbsPos=0,$aYAbsPos=0,$aHAlign="left",$aVAlign="top") {
- $this->x = $aXAbsPos;
- $this->y = $aYAbsPos;
- $this->halign = $aHAlign;
- $this->valign = $aVAlign;
- }
- function SetScalePos($aX,$aY) {
- $this->iScalePosX = $aX;
- $this->iScalePosY = $aY;
- }
-
- // Specify alignment for the text
- function Align($aHAlign,$aVAlign="top",$aParagraphAlign="") {
- $this->halign = $aHAlign;
- $this->valign = $aVAlign;
- if( $aParagraphAlign != "" )
- $this->paragraph_align = $aParagraphAlign;
- }
-
- // Alias
- function SetAlign($aHAlign,$aVAlign="top",$aParagraphAlign="") {
- $this->Align($aHAlign,$aVAlign,$aParagraphAlign);
- }
- // Specifies the alignment for a multi line text
- function ParagraphAlign($aAlign) {
- $this->paragraph_align = $aAlign;
- }
- function SetShadow($aShadowColor='gray',$aShadowWidth=3) {
- $this->ishadowwidth=$aShadowWidth;
- $this->shadow=$aShadowColor;
- $this->boxed=true;
- }
-
- // Specify that the text should be boxed. fcolor=frame color, bcolor=border color,
- // $shadow=drop shadow should be added around the text.
- function SetBox($aFrameColor=array(255,255,255),$aBorderColor=array(0,0,0),$aShadowColor=false,$aCornerRadius=4,$aShadowWidth=3) {
- if( $aFrameColor==false )
- $this->boxed=false;
- else
- $this->boxed=true;
- $this->fcolor=$aFrameColor;
- $this->bcolor=$aBorderColor;
- // For backwards compatibility when shadow was just true or false
- if( $aShadowColor === true )
- $aShadowColor = 'gray';
- $this->shadow=$aShadowColor;
- $this->icornerradius=$aCornerRadius;
- $this->ishadowwidth=$aShadowWidth;
- }
-
- // Hide the text
- function Hide($aHide=true) {
- $this->hide=$aHide;
- }
-
- // This looks ugly since it's not a very orthogonal design
- // but I added this "inverse" of Hide() to harmonize
- // with some classes which I designed more recently (especially)
- // jpgraph_gantt
- function Show($aShow=true) {
- $this->hide=!$aShow;
- }
-
- // Specify font
- function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) {
- $this->font_family=$aFamily;
- $this->font_style=$aStyle;
- $this->font_size=$aSize;
- }
-
- // Center the text between $left and $right coordinates
- function Center($aLeft,$aRight,$aYAbsPos=false) {
- $this->x = $aLeft + ($aRight-$aLeft )/2;
- $this->halign = "center";
- if( is_numeric($aYAbsPos) )
- $this->y = $aYAbsPos;
- }
-
- // Set text color
- function SetColor($aColor) {
- $this->color = $aColor;
- }
-
- function SetAngle($aAngle) {
- $this->SetOrientation($aAngle);
- }
-
- // Orientation of text. Note only TTF fonts can have an arbitrary angle
- function SetOrientation($aDirection=0) {
- if( is_numeric($aDirection) )
- $this->dir=$aDirection;
- elseif( $aDirection=="h" )
- $this->dir = 0;
- elseif( $aDirection=="v" )
- $this->dir = 90;
- else JpGraphError::Raise(" Invalid direction specified for text.");
- }
-
- // Total width of text
- function GetWidth($aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $w = $aImg->GetTextWidth($this->t,$this->dir);
- return $w;
- }
-
- // Hight of font
- function GetFontHeight($aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $h = $aImg->GetFontHeight();
- return $h;
- }
- function GetTextHeight($aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $h = $aImg->GetTextHeight($this->t,$this->dir);
- return $h;
- }
- // Set the margin which will be interpretated differently depending
- // on the context.
- function SetMargin($aMarg) {
- $this->margin = $aMarg;
- }
- function StrokeWithScale($aImg,$axscale,$ayscale) {
- if( $this->iScalePosX === null ||
- $this->iScalePosY === null ) {
- $this->Stroke($aImg);
- }
- else {
- $this->Stroke($aImg,
- round($axscale->Translate($this->iScalePosX)),
- round($ayscale->Translate($this->iScalePosY)));
- }
- }
-
- // Display text in image
- function Stroke($aImg,$x=null,$y=null) {
- if( !empty($x) ) $this->x = round($x);
- if( !empty($y) ) $this->y = round($y);
- // If position been given as a fraction of the image size
- // calculate the absolute position
- if( $this->x < 1 && $this->x > 0 ) $this->x *= $aImg->width;
- if( $this->y < 1 && $this->y > 0 ) $this->y *= $aImg->height;
- $aImg->PushColor($this->color);
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $aImg->SetTextAlign($this->halign,$this->valign);
- if( $this->boxed ) {
- if( $this->fcolor=="nofill" )
- $this->fcolor=false;
- $aImg->SetLineWeight(1);
- $aImg->StrokeBoxedText($this->x,$this->y,$this->t,
- $this->dir,$this->fcolor,$this->bcolor,$this->shadow,
- $this->paragraph_align,6,2,$this->icornerradius,
- $this->ishadowwidth);
- }
- else {
- $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir,
- $this->paragraph_align);
- }
- $aImg->PopColor($this->color);
- }
- } // Class
- class GraphTabTitle extends Text{
- var $corner = 6 , $posx = 7, $posy = 4;
- var $color='darkred',$fillcolor='lightyellow',$bordercolor='black';
- var $align = 'left', $width=TABTITLE_WIDTHFIT;
- function GraphTabTitle() {
- $this->t = '';
- $this->font_style = FS_BOLD;
- $this->hide = true;
- }
- function SetColor($aTxtColor,$aFillColor='lightyellow',$aBorderColor='black') {
- $this->color = $aTxtColor;
- $this->fillcolor = $aFillColor;
- $this->bordercolor = $aBorderColor;
- }
- function SetFillColor($aFillColor) {
- $this->fillcolor = $aFillColor;
- }
- function SetTabAlign($aAlign) {
- // Synonym for SetPos
- $this->align = $aAlign;
- }
- function SetPos($aAlign) {
- $this->align = $aAlign;
- }
-
- function SetWidth($aWidth) {
- $this->width = $aWidth ;
- }
- function Set($t) {
- $this->t = $t;
- $this->hide = false;
- }
- function SetCorner($aD) {
- $this->corner = $aD ;
- }
- function Stroke($aImg) {
- if( $this->hide )
- return;
- $this->boxed = false;
- $w = $this->GetWidth($aImg) + 2*$this->posx;
- $h = $this->GetTextHeight($aImg) + 2*$this->posy;
- $x = $aImg->left_margin;
- $y = $aImg->top_margin;
- if( $this->width === TABTITLE_WIDTHFIT ) {
- if( $this->align == 'left' ) {
- $p = array($x, $y,
- $x, $y-$h+$this->corner,
- $x + $this->corner,$y-$h,
- $x + $w - $this->corner, $y-$h,
- $x + $w, $y-$h+$this->corner,
- $x + $w, $y);
- }
- elseif( $this->align == 'center' ) {
- $x += round($aImg->plotwidth/2) - round($w/2);
- $p = array($x, $y,
- $x, $y-$h+$this->corner,
- $x + $this->corner, $y-$h,
- $x + $w - $this->corner, $y-$h,
- $x + $w, $y-$h+$this->corner,
- $x + $w, $y);
- }
- else {
- $x += $aImg->plotwidth -$w;
- $p = array($x, $y,
- $x, $y-$h+$this->corner,
- $x + $this->corner,$y-$h,
- $x + $w - $this->corner, $y-$h,
- $x + $w, $y-$h+$this->corner,
- $x + $w, $y);
- }
- }
- else {
- if( $this->width === TABTITLE_WIDTHFULL )
- $w = $aImg->plotwidth ;
- else
- $w = $this->width ;
- // Make the tab fit the width of the plot area
- $p = array($x, $y,
- $x, $y-$h+$this->corner,
- $x + $this->corner,$y-$h,
- $x + $w - $this->corner, $y-$h,
- $x + $w, $y-$h+$this->corner,
- $x + $w, $y);
-
- }
- $aImg->SetTextAlign('left','bottom');
- $x += $this->posx;
- $y -= $this->posy;
- $aImg->SetColor($this->fillcolor);
- $aImg->FilledPolygon($p);
- $aImg->SetColor($this->bordercolor);
- $aImg->Polygon($p,true);
-
- $aImg->SetColor($this->color);
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $aImg->StrokeText($x,$y,$this->t,0,'center');
- }
- }
- //===================================================
- // CLASS SuperScriptText
- // Description: Format a superscript text
- //===================================================
- class SuperScriptText extends Text {
- var $iSuper="";
- var $sfont_family="",$sfont_style="",$sfont_size=8;
- var $iSuperMargin=2,$iVertOverlap=4,$iSuperScale=0.65;
- var $iSDir=0;
- var $iSimple=false;
- function SuperScriptText($aTxt="",$aSuper="",$aXAbsPos=0,$aYAbsPos=0) {
- parent::Text($aTxt,$aXAbsPos,$aYAbsPos);
- $this->iSuper = $aSuper;
- }
- function FromReal($aVal,$aPrecision=2) {
- // Convert a floating point number to scientific notation
- $neg=1.0;
- if( $aVal < 0 ) {
- $neg = -1.0;
- $aVal = -$aVal;
- }
-
- $l = floor(log10($aVal));
- $a = sprintf("%0.".$aPrecision."f",round($aVal / pow(10,$l),$aPrecision));
- $a *= $neg;
- if( $this->iSimple && ($a == 1 || $a==-1) ) $a = '';
-
- if( $a != '' )
- $this->t = $a.' * 10';
- else {
- if( $neg == 1 )
- $this->t = '10';
- else
- $this->t = '-10';
- }
- $this->iSuper = $l;
- }
- function Set($aTxt,$aSuper="") {
- $this->t = $aTxt;
- $this->iSuper = $aSuper;
- }
- function SetSuperFont($aFontFam,$aFontStyle=FS_NORMAL,$aFontSize=8) {
- $this->sfont_family = $aFontFam;
- $this->sfont_style = $aFontStyle;
- $this->sfont_size = $aFontSize;
- }
- // Total width of text
- function GetWidth(&$aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $w = $aImg->GetTextWidth($this->t);
- $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
- $w += $aImg->GetTextWidth($this->iSuper);
- $w += $this->iSuperMargin;
- return $w;
- }
-
- // Hight of font (approximate the height of the text)
- function GetFontHeight(&$aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $h = $aImg->GetFontHeight();
- $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
- $h += $aImg->GetFontHeight();
- return $h;
- }
- // Hight of text
- function GetTextHeight(&$aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- $h = $aImg->GetTextHeight($this->t);
- $aImg->SetFont($this->sfont_family,$this->sfont_style,$this->sfont_size);
- $h += $aImg->GetTextHeight($this->iSuper);
- return $h;
- }
- function Stroke($aImg,$ax=-1,$ay=-1) {
-
- // To position the super script correctly we need different
- // cases to handle the alignmewnt specified since that will
- // determine how we can interpret the x,y coordinates
-
- $w = parent::GetWidth($aImg);
- $h = parent::GetTextHeight($aImg);
- switch( $this->valign ) {
- case 'top':
- $sy = $this->y;
- break;
- case 'center':
- $sy = $this->y - $h/2;
- break;
- case 'bottom':
- $sy = $this->y - $h;
- break;
- default:
- JpGraphError::Raise('PANIC: Internal error in SuperScript::Stroke(). Unknown vertical alignment for text');
- exit();
- }
- switch( $this->halign ) {
- case 'left':
- $sx = $this->x + $w;
- break;
- case 'center':
- $sx = $this->x + $w/2;
- break;
- case 'right':
- $sx = $this->x;
- break;
- default:
- JpGraphError::Raise('PANIC: Internal error in SuperScript::Stroke(). Unknown horizontal alignment for text');
- exit();
- }
- $sx += $this->iSuperMargin;
- $sy += $this->iVertOverlap;
- // Should we automatically determine the font or
- // has the user specified it explicetly?
- if( $this->sfont_family == "" ) {
- if( $this->font_family <= FF_FONT2 ) {
- if( $this->font_family == FF_FONT0 ) {
- $sff = FF_FONT0;
- }
- elseif( $this->font_family == FF_FONT1 ) {
- if( $this->font_style == FS_NORMAL )
- $sff = FF_FONT0;
- else
- $sff = FF_FONT1;
- }
- else {
- $sff = FF_FONT1;
- }
- $sfs = $this->font_style;
- $sfz = $this->font_size;
- }
- else {
- // TTF fonts
- $sff = $this->font_family;
- $sfs = $this->font_style;
- $sfz = floor($this->font_size*$this->iSuperScale);
- if( $sfz < 8 ) $sfz = 8;
- }
- $this->sfont_family = $sff;
- $this->sfont_style = $sfs;
- $this->sfont_size = $sfz;
- }
- else {
- $sff = $this->sfont_family;
- $sfs = $this->sfont_style;
- $sfz = $this->sfont_size;
- }
- parent::Stroke($aImg,$ax,$ay);
- // For the builtin fonts we need to reduce the margins
- // since the bounding bx reported for the builtin fonts
- // are much larger than for the TTF fonts.
- if( $sff <= FF_FONT2 ) {
- $sx -= 2;
- $sy += 3;
- }
- $aImg->SetTextAlign('left','bottom');
- $aImg->SetFont($sff,$sfs,$sfz);
- $aImg->PushColor($this->color);
- $aImg->StrokeText($sx,$sy,$this->iSuper,$this->iSDir,'left');
- $aImg->PopColor();
- }
- }
- //===================================================
- // CLASS Grid
- // Description: responsible for drawing grid lines in graph
- //===================================================
- class Grid {
- var $img;
- var $scale;
- var $grid_color='#DDDDDD',$grid_mincolor='#DDDDDD';
- var $type="solid";
- var $show=false, $showMinor=false,$weight=1;
- var $fill=false,$fillcolor=array('#EFEFEF','#BBCCFF');
- //---------------
- // CONSTRUCTOR
- function Grid(&$aAxis) {
- $this->scale = &$aAxis->scale;
- $this->img = &$aAxis->img;
- }
- //---------------
- // PUBLIC METHODS
- function SetColor($aMajColor,$aMinColor=false) {
- $this->grid_color=$aMajColor;
- if( $aMinColor === false )
- $aMinColor = $aMajColor ;
- $this->grid_mincolor = $aMinColor;
- }
-
- function SetWeight($aWeight) {
- $this->weight=$aWeight;
- }
-
- // Specify if grid should be dashed, dotted or solid
- function SetLineStyle($aType) {
- $this->type = $aType;
- }
-
- // Decide if both major and minor grid should be displayed
- function Show($aShowMajor=true,$aShowMinor=false) {
- $this->show=$aShowMajor;
- $this->showMinor=$aShowMinor;
- }
-
- function SetFill($aFlg=true,$aColor1='lightgray',$aColor2='lightblue') {
- $this->fill = $aFlg;
- $this->fillcolor = array( $aColor1, $aColor2 );
- }
-
- // Display the grid
- function Stroke() {
- if( $this->showMinor ) {
- $tmp = $this->grid_color;
- $this->grid_color = $this->grid_mincolor;
- $this->DoStroke($this->scale->ticks->ticks_pos);
- $this->grid_color = $tmp;
- $this->DoStroke($this->scale->ticks->maj_ticks_pos);
- }
- else {
- $this->DoStroke($this->scale->ticks->maj_ticks_pos);
- }
- }
-
- //--------------
- // Private methods
- // Draw the grid
- function DoStroke(&$aTicksPos) {
- if( !$this->show )
- return;
- $nbrgrids = count($aTicksPos);
- if( $this->scale->type=="y" ) {
- $xl=$this->img->left_margin;
- $xr=$this->img->width-$this->img->right_margin;
-
- if( $this->fill ) {
- // Draw filled areas
- $y2 = $aTicksPos[0];
- $i=1;
- while( $i < $nbrgrids ) {
- $y1 = $y2;
- $y2 = $aTicksPos[$i++];
- $this->img->SetColor($this->fillcolor[$i & 1]);
- $this->img->FilledRectangle($xl,$y1,$xr,$y2);
- }
- }
- $this->img->SetColor($this->grid_color);
- $this->img->SetLineWeight($this->weight);
- // Draw grid lines
- for($i=0; $i<$nbrgrids; ++$i) {
- $y=$aTicksPos[$i];
- if( $this->type == "solid" )
- $this->img->Line($xl,$y,$xr,$y);
- elseif( $this->type == "dotted" )
- $this->img->DashedLine($xl,$y,$xr,$y,1,6);
- elseif( $this->type == "dashed" )
- $this->img->DashedLine($xl,$y,$xr,$y,2,4);
- elseif( $this->type == "longdashed" )
- $this->img->DashedLine($xl,$y,$xr,$y,8,6);
- }
- }
- elseif( $this->scale->type=="x" ) {
- $yu=$this->img->top_margin;
- $yl=$this->img->height-$this->img->bottom_margin;
- $limit=$this->img->width-$this->img->right_margin;
- if( $this->fill ) {
- // Draw filled areas
- $x2 = $aTicksPos[0];
- $i=1;
- while( $i < $nbrgrids ) {
- $x1 = $x2;
- $x2 = min($aTicksPos[$i++],$limit) ;
- $this->img->SetColor($this->fillcolor[$i & 1]);
- $this->img->FilledRectangle($x1,$yu,$x2,$yl);
- }
- }
- $this->img->SetColor($this->grid_color);
- $this->img->SetLineWeight($this->weight);
- // We must also test for limit since we might have
- // an offset and the number of ticks is calculated with
- // assumption offset==0 so we might end up drawing one
- // to many gridlines
- $i=0;
- $x=$aTicksPos[$i];
- while( $i<count($aTicksPos) && ($x=$aTicksPos[$i]) <= $limit ) {
- if( $this->type == "solid" )
- $this->img->Line($x,$yl,$x,$yu);
- elseif( $this->type == "dotted" )
- $this->img->DashedLine($x,$yl,$x,$yu,1,6);
- elseif( $this->type == "dashed" )
- $this->img->DashedLine($x,$yl,$x,$yu,2,4);
- elseif( $this->type == "longdashed" )
- $this->img->DashedLine($x,$yl,$x,$yu,8,6);
- ++$i;
- }
- }
- else {
- JpGraphError::Raise('Internal error: Unknown grid axis ['.$this->scale->type.']');
- }
- return true;
- }
- } // Class
- //===================================================
- // CLASS Axis
- // Description: Defines X and Y axis. Notes that at the
- // moment the code is not really good since the axis on
- // several occasion must know wheter it's an X or Y axis.
- // This was a design decision to make the code easier to
- // follow.
- //===================================================
- class Axis {
- var $pos = false;
- var $weight=1;
- var $color=array(0,0,0),$label_color=array(0,0,0);
- var $img=null,$scale=null;
- var $hide=false;
- var $ticks_label=false, $ticks_label_colors=null;
- var $show_first_label=true,$show_last_label=true;
- var $label_step=1; // Used by a text axis to specify what multiple of major steps
- // should be labeled.
- var $tick_step=1;
- var $labelPos=0; // Which side of the axis should the labels be?
- var $title=null,$title_adjust,$title_margin,$title_side=SIDE_LEFT;
- var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$label_angle=0;
- var $tick_label_margin=5;
- var $label_halign = '',$label_valign = '', $label_para_align='left';
- var $hide_line=false,$hide_labels=false;
- //var $hide_zero_label=false;
- //---------------
- // CONSTRUCTOR
- function Axis(&$img,&$aScale,$color=array(0,0,0)) {
- $this->img = &$img;
- $this->scale = &$aScale;
- $this->color = $color;
- $this->title=new Text("");
-
- if( $aScale->type=="y" ) {
- $this->title_margin = 25;
- $this->title_adjust="middle";
- $this->title->SetOrientation(90);
- $this->tick_label_margin=7;
- $this->labelPos=SIDE_LEFT;
- //$this->SetLabelFormat('%.1f');
- }
- else {
- $this->title_margin = 5;
- $this->title_adjust="high";
- $this->title->SetOrientation(0);
- $this->tick_label_margin=3;
- $this->labelPos=SIDE_DOWN;
- //$this->SetLabelFormat('%.0f');
- }
- }
- //---------------
- // PUBLIC METHODS
-
- function SetLabelFormat($aFormStr) {
- $this->scale->ticks->SetLabelFormat($aFormStr);
- }
-
- function SetLabelFormatString($aFormStr) {
- $this->scale->ticks->SetLabelFormat($aFormStr);
- }
-
- function SetLabelFormatCallback($aFuncName) {
- $this->scale->ticks->SetFormatCallback($aFuncName);
- }
- function SetLabelAlign($aHAlign,$aVAlign="top",$aParagraphAlign='left') {
- $this->label_halign = $aHAlign;
- $this->label_valign = $aVAlign;
- $this->label_para_align = $aParagraphAlign;
- }
- // Don't display the first label
- function HideFirstTickLabel($aShow=false) {
- $this->show_first_label=$aShow;
- }
- function HideLastTickLabel($aShow=false) {
- $this->show_last_label=$aShow;
- }
- function HideTicks($aHideMinor=true,$aHideMajor=true) {
- $this->scale->ticks->SupressMinorTickMarks($aHideMinor);
- $this->scale->ticks->SupressTickMarks($aHideMajor);
- }
- // Hide zero label
- function HideZeroLabel($aFlag=true) {
- $this->scale->ticks->SupressZeroLabel();
- //$this->hide_zero_label = $aFlag;
- }
-
- function HideFirstLastLabel() {
- // The two first calls to ticks method will supress
- // automatically generated scale values. However, that
- // will not affect manually specified value, e.g text-scales.
- // therefor we also make a kludge here to supress manually
- // specified scale labels.
- $this->scale->ticks->SupressLast();
- $this->scale->ticks->SupressFirst();
- $this->show_first_label = false;
- $this->show_last_label = false;
- }
-
- // Hide the axis
- function Hide($aHide=true) {
- $this->hide=$aHide;
- }
- // Hide the actual axis-line, but still print the labels
- function HideLine($aHide=true) {
- $this->hide_line = $aHide;
- }
- function HideLabels($aHide=true) {
- $this->hide_labels = $aHide;
- }
-
- // Weight of axis
- function SetWeight($aWeight) {
- $this->weight = $aWeight;
- }
- // Axis color
- function SetColor($aColor,$aLabelColor=false) {
- $this->color = $aColor;
- if( !$aLabelColor ) $this->label_color = $aColor;
- else $this->label_color = $aLabelColor;
- }
-
- // Title on axis
- function SetTitle($aTitle,$aAdjustAlign="high") {
- $this->title->Set($aTitle);
- $this->title_adjust=$aAdjustAlign;
- }
-
- // Specify distance from the axis
- function SetTitleMargin($aMargin) {
- $this->title_margin=$aMargin;
- }
-
- // Which side of the axis should the axis title be?
- function SetTitleSide($aSideOfAxis) {
- $this->title_side = $aSideOfAxis;
- }
- // Utility function to set the direction for tick marks
- function SetTickDirection($aDir) {
- // Will be deprecated from 1.7
- if( ERR_DEPRECATED )
- JpGraphError::Raise('Axis::SetTickDirection() is deprecated. Use Axis::SetTickSide() instead');
- $this->scale->ticks->SetSide($aDir);
- }
-
- function SetTickSide($aDir) {
- $this->scale->ticks->SetSide($aDir);
- }
-
- // Specify text labels for the ticks. One label for each data point
- function SetTickLabels($aLabelArray,$aLabelColorArray=null) {
- $this->ticks_label = $aLabelArray;
- $this->ticks_label_colors = $aLabelColorArray;
- }
-
- // How far from the axis should the labels be drawn
- function SetTickLabelMargin($aMargin) {
- if( ERR_DEPRECATED )
- JpGraphError::Raise('SetTickLabelMargin() is deprecated. Use Axis::SetLabelMargin() instead.');
- $this->tick_label_margin=$aMargin;
- }
- function SetLabelMargin($aMargin) {
- $this->tick_label_margin=$aMargin;
- }
-
- // Specify that every $step of the ticks should be displayed starting
- // at $start
- // DEPRECATED FUNCTION: USE SetTextTickInterval() INSTEAD
- function SetTextTicks($step,$start=0) {
- JpGraphError::Raise(" SetTextTicks() is deprecated. Use SetTextTickInterval() instead.");
- }
- // Specify that every $step of the ticks should be displayed starting
- // at $start
- function SetTextTickInterval($aStep,$aStart=0) {
- $this->scale->ticks->SetTextLabelStart($aStart);
- $this->tick_step=$aStep;
- }
-
- // Specify that every $step tick mark should have a label
- // should be displayed starting
- function SetTextLabelInterval($aStep) {
- if( $aStep < 1 )
- JpGraphError::Raise(" Text label interval must be specified >= 1.");
- $this->label_step=$aStep;
- }
-
- // Which side of the axis should the labels be on?
- function SetLabelPos($aSidePos) {
- // This will be deprecated from 1.7
- if( ERR_DEPRECATED )
- JpGraphError::Raise('SetLabelPos() is deprecated. Use Axis::SetLabelSide() instead.');
- $this->labelPos=$aSidePos;
- }
-
- function SetLabelSide($aSidePos) {
- $this->labelPos=$aSidePos;
- }
- // Set the font
- function SetFont($aFamily,$aStyle=FS_NORMAL,$aSize=10) {
- $this->font_family = $aFamily;
- $this->font_style = $aStyle;
- $this->font_size = $aSize;
- }
- // Position for axis line on the "other" scale
- function SetPos($aPosOnOtherScale) {
- $this->pos=$aPosOnOtherScale;
- }
-
- // Specify the angle for the tick labels
- function SetLabelAngle($aAngle) {
- $this->label_angle = $aAngle;
- }
-
- // Stroke the axis.
- function Stroke($aOtherAxisScale) {
- if( $this->hide ) return;
- if( is_numeric($this->pos) ) {
- $pos=$aOtherAxisScale->Translate($this->pos);
- }
- else { // Default to minimum of other scale if pos not set
- if( ($aOtherAxisScale->GetMinVal() >= 0 && $this->pos==false) || $this->pos=="min" ) {
- $pos = $aOtherAxisScale->scale_abs[0];
- }
- elseif($this->pos == "max") {
- $pos = $aOtherAxisScale->scale_abs[1];
- }
- else { // If negative set x-axis at 0
- $this->pos=0;
- $pos=$aOtherAxisScale->Translate(0);
- }
- }
- $this->img->SetLineWeight($this->weight);
- $this->img->SetColor($this->color);
- $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
- if( $this->scale->type == "x" ) {
- if( !$this->hide_line )
- $this->img->FilledRectangle($this->img->left_margin,$pos,
- $this->img->width-$this->img->right_margin,$pos+$this->weight-1);
- $y=$pos+$this->img->GetFontHeight()+$this->title_margin+$this->title->margin;
- if( $this->title_adjust=="high" )
- $this->title->Pos($this->img->width-$this->img->right_margin,$y,"right","top");
- elseif( $this->title_adjust=="middle" || $this->title_adjust=="center" )
- $this->title->Pos(($this->img->width-$this->img->left_margin-$this->img->right_margin)/2+$this->img->left_margin,$y,"center","top");
- elseif($this->title_adjust=="low")
- $this->title->Pos($this->img->left_margin,$y,"left","top");
- else {
- JpGraphError::Raise('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')');
- }
- }
- elseif( $this->scale->type == "y" ) {
- // Add line weight to the height of the axis since
- // the x-axis could have a width>1 and we want the axis to fit nicely together.
- if( !$this->hide_line )
- $this->img->FilledRectangle($pos-$this->weight+1,$this->img->top_margin,
- $pos,$this->img->height-$this->img->bottom_margin+$this->weight-1);
- $x=$pos ;
- if( $this->title_side == SIDE_LEFT ) {
- $x -= $this->title_margin;
- $x -= $this->title->margin;
- $halign="right";
- }
- else {
- $x += $this->title_margin;
- $x += $this->title->margin;
- $halign="left";
- }
- // If the user has manually specified an hor. align
- // then we override the automatic settings with this
- // specifed setting. Since default is 'left' we compare
- // with that. (This means a manually set 'left' align
- // will have no effect.)
- if( $this->title->halign != 'left' )
- $halign = $this->title->halign;
- if( $this->title_adjust=="high" )
- $this->title->Pos($x,$this->img->top_margin,$halign,"top");
- elseif($this->title_adjust=="middle" || $this->title_adjust=="center")
- $this->title->Pos($x,($this->img->height-$this->img->top_margin-$this->img->bottom_margin)/2+$this->img->top_margin,$halign,"center");
- elseif($this->title_adjust=="low")
- $this->title->Pos($x,$this->img->height-$this->img->bottom_margin,$halign,"bottom");
- else
- JpGraphError::Raise('Unknown alignment specified for Y-axis title. ('.$this->title_adjust.')');
-
- }
- $this->scale->ticks->Stroke($this->img,$this->scale,$pos);
- if( !$this->hide_labels ) {
- $this->StrokeLabels($pos);
- }
- $this->title->Stroke($this->img);
- }
- //---------------
- // PRIVATE METHODS
- // Draw all the tick labels on major tick marks
- function StrokeLabels($aPos,$aMinor=false,$aAbsLabel=false) {
- $this->img->SetColor($this->label_color);
- $this->img->SetFont($this->font_family,$this->font_style,$this->font_size);
- $yoff=$this->img->GetFontHeight()/2;
- // Only draw labels at major tick marks
- $nbr = count($this->scale->ticks->maj_ticks_label);
- // We have the option to not-display the very first mark
- // (Usefull when the first label might interfere with another
- // axis.)
- $i = $this->show_first_label ? 0 : 1 ;
- if( !$this->show_last_label ) --$nbr;
- // Now run through all labels making sure we don't overshoot the end
- // of the scale.
- $ncolor=0;
- if( isset($this->ticks_label_colors) )
- $ncolor=count($this->ticks_label_colors);
-
- while( $i<$nbr ) {
- // $tpos holds the absolute text position for the label
- $tpos=$this->scale->ticks->maj_ticklabels_pos[$i];
- // Note. the $limit is only used for the x axis since we
- // might otherwise overshoot if the scale has been centered
- // This is due to us "loosing" the last tick mark if we center.
- if( $this->scale->type=="x" && $tpos > $this->img->width-$this->img->right_margin+1 ) {
- return;
- }
- // we only draw every $label_step label
- if( ($i % $this->label_step)==0 ) {
- // Set specific label color if specified
- if( $ncolor > 0 )
- $this->img->SetColor($this->ticks_label_colors[$i % $ncolor]);
-
- // If the label has been specified use that and in other case
- // just label the mark with the actual scale value
- $m=$this->scale->ticks->GetMajor();
-
- // ticks_label has an entry for each data point and is the array
- // that holds the labels set by the user. If the user hasn't
- // specified any values we use whats in the automatically asigned
- // labels in the maj_ticks_label
- if( isset($this->ticks_label[$i*$m]) )
- $label=$this->ticks_label[$i*$m];
- else {
- if( $aAbsLabel )
- $label=abs($this->scale->ticks->maj_ticks_label[$i]);
- else
- $label=$this->scale->ticks->maj_ticks_label[$i];
- if( $this->scale->textscale ) {
- ++$label;
-
- }
- }
-
- //if( $this->hide_zero_label && $label==0.0 ) {
- // ++$i;
- // continue;
- //}
-
- if( $this->scale->type == "x" ) {
- if( $this->labelPos == SIDE_DOWN ) {
- if( $this->label_angle==0 || $this->label_angle==90 ) {
- if( $this->label_halign=='' && $this->label_valign=='')
- $this->img->SetTextAlign('center','top');
- else
- $this->img->SetTextAlign($this->label_halign,$this->label_valign);
-
- }
- else {
- if( $this->label_halign=='' && $this->label_valign=='')
- $this->img->SetTextAlign("right","top");
- else
- $this->img->SetTextAlign($this->label_halign,$this->label_valign);
- }
- $this->img->StrokeText($tpos,$aPos+$this->tick_label_margin,$label,
- $this->label_angle,$this->label_para_align);
- }
- else {
- if( $this->label_angle==0 || $this->label_angle==90 ) {
- if( $this->label_halign=='' && $this->label_valign=='')
- $this->img->SetTextAlign("center","bottom");
- else
- $this->img->SetTextAlign($this->label_halign,$this->label_valign);
- }
- else {
- if( $this->label_halign=='' && $this->label_valign=='')
- $this->img->SetTextAlign("right","bottom");
- else
- $this->img->SetTextAlign($this->label_halign,$this->label_valign);
- }
- $this->img->StrokeText($tpos,$aPos-$this->tick_label_margin,$label,
- $this->label_angle,$this->label_para_align);
- }
- }
- else {
- // scale->type == "y"
- //if( $this->label_angle!=0 )
- //JpGraphError::Raise(" Labels at an angle are not supported on Y-axis");
- if( $this->labelPos == SIDE_LEFT ) { // To the left of y-axis
- if( $this->label_halign=='' && $this->label_valign=='')
- $this->img->SetTextAlign("right","center");
- else
- $this->img->SetTextAlign($this->label_halign,$this->label_valign);
- $this->img->StrokeText($aPos-$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
- }
- else { // To the right of the y-axis
- if( $this->label_halign=='' && $this->label_valign=='')
- $this->img->SetTextAlign("left","center");
- else
- $this->img->SetTextAlign($this->label_halign,$this->label_valign);
- $this->img->StrokeText($aPos+$this->tick_label_margin,$tpos,$label,$this->label_angle,$this->label_para_align);
- }
- }
- }
- ++$i;
- }
- }
- } // Class
- //===================================================
- // CLASS Ticks
- // Description: Abstract base class for drawing linear and logarithmic
- // tick marks on axis
- //===================================================
- class Ticks {
- var $minor_abs_size=3, $major_abs_size=5;
- var $direction=1; // Should ticks be in(=1) the plot area or outside (=-1)?
- var $scale;
- var $is_set=false;
- var $precision;
- var $supress_zerolabel=false,$supress_first=false;
- var $supress_last=false,$supress_tickmarks=false,$supress_minor_tickmarks=false;
- var $mincolor="",$majcolor="";
- var $weight=1;
- var $label_formatstr=''; // C-style format string to use for labels
- var $label_formfunc='';
- //---------------
- // CONSTRUCTOR
- function Ticks(&$aScale) {
- $this->scale=&$aScale;
- $this->precision = -1;
- }
- //---------------
- // PUBLIC METHODS
- // Set format string for automatic labels
- function SetLabelFormat($aFormatString) {
- $this->label_formatstr=$aFormatString;
- }
-
- function SetFormatCallback($aCallbackFuncName) {
- $this->label_formfunc = $aCallbackFuncName;
- }
-
- // Don't display the first zero label
- function SupressZeroLabel($aFlag=true) {
- $this->supress_zerolabel=$aFlag;
- }
-
- // Don't display minor tick marks
- function SupressMinorTickMarks($aHide=true) {
- $this->supress_minor_tickmarks=$aHide;
- }
-
- // Don't display major tick marks
- function SupressTickMarks($aHide=true) {
- $this->supress_tickmarks=$aHide;
- }
-
- // Hide the first tick mark
- function SupressFirst($aHide=true) {
- $this->supress_first=$aHide;
- }
-
- // Hide the last tick mark
- function SupressLast($aHide=true) {
- $this->supress_last=$aHide;
- }
- // Size (in pixels) of minor tick marks
- function GetMinTickAbsSize() {
- return $this->minor_abs_size;
- }
-
- // Size (in pixels) of major tick marks
- function GetMajTickAbsSize() {
- return $this->major_abs_size;
- }
-
- function SetSize($aMajSize,$aMinSize=3) {
- $this->major_abs_size = $aMajSize;
- $this->minor_abs_size = $aMinSize;
- }
- // Have the ticks been specified
- function IsSpecified() {
- return $this->is_set;
- }
-
- // Set the distance between major and minor tick marks
- function Set($aMaj,$aMin) {
- // "Virtual method"
- // Should be implemented by the concrete subclass
- // if any action is wanted.
- }
-
- // Specify number of decimals in automatic labels
- // Deprecated from 1.4. Use SetFormatString() instead
- function SetPrecision($aPrecision) {
- if( ERR_DEPRECATED )
- JpGraphError::Raise('Ticks::SetPrecision() is deprecated. Use Ticks::SetLabelFormat() (or Ticks::SetFormatCallback()) instead');
- $this->precision=$aPrecision;
- }
- function SetSide($aSide) {
- $this->direction=$aSide;
- }
-
- // Which side of the axis should the ticks be on
- function SetDirection($aSide=SIDE_RIGHT) {
- $this->direction=$aSide;
- }
-
- // Set colors for major and minor tick marks
- function SetMarkColor($aMajorColor,$aMinorColor="") {
- $this->SetColor($aMajorColor,$aMinorColor);
- }
-
- function SetColor($aMajorColor,$aMinorColor="") {
- $this->majcolor=$aMajorColor;
-
- // If not specified use same as major
- if( $aMinorColor=="" )
- $this->mincolor=$aMajorColor;
- else
- $this->mincolor=$aMinorColor;
- }
-
- function SetWeight($aWeight) {
- $this->weight=$aWeight;
- }
-
- } // Class
- //===================================================
- // CLASS LinearTicks
- // Description: Draw linear ticks on axis
- //===================================================
- class LinearTicks extends Ticks {
- var $minor_step=1, $major_step=2;
- var $xlabel_offset=0,$xtick_offset=0;
- var $label_offset=0; // What offset should the displayed label have
- // i.e should we display 0,1,2 or 1,2,3,4 or 2,3,4 etc
- var $text_label_start=0;
- //---------------
- // CONSTRUCTOR
- function LinearTicks() {
- $this->precision = -1;
- }
- //---------------
- // PUBLIC METHODS
-
-
- // Return major step size in world coordinates
- function GetMajor() {
- return $this->major_step;
- }
-
- // Return minor step size in world coordinates
- function GetMinor() {
- return $this->minor_step;
- }
-
- // Set Minor and Major ticks (in world coordinates)
- function Set($aMajStep,$aMinStep=false) {
- if( $aMinStep==false )
- $aMinStep=$aMajStep;
-
- if( $aMajStep <= 0 || $aMinStep <= 0 ) {
- JpGraphError::Raise(" Minor or major step size is 0. Check that you haven't
- got an accidental SetTextTicks(0) in your code.<p>
- If this is not the case you might have stumbled upon a bug in JpGraph.
- Please report this and if possible include the data that caused the
- problem.");
- }
-
- $this->major_step=$aMajStep;
- $this->minor_step=$aMinStep;
- $this->is_set = true;
- }
- // Draw linear ticks
- function Stroke(&$img,&$scale,$pos) {
- $maj_step_abs = $scale->scale_factor*$this->major_step;
- $min_step_abs = $scale->scale_factor*$this->minor_step;
- if( $min_step_abs==0 || $maj_step_abs==0 )
- JpGraphError::Raise(" A plot has an illegal scale. This could for example be that you are trying to use text autoscaling to draw a line plot with only one point or that the plot area is too small. Try increasing the graph size or correct the lineplot.");
- $limit = $scale->scale_abs[1];
- $nbrmajticks=floor(1.000001*(($scale->GetMaxVal()-$scale->GetMinVal())/$this->major_step))+1;
- $first=0;
-
- // If precision hasn't been specified set it to a sensible value
- if( $this->precision==-1 ) {
- $t = log10($this->minor_step);
- if( $t > 0 )
- $precision = 0;
- else
- $precision = -floor($t);
- }
- else
- $precision = $this->precision;
-
- $img->SetLineWeight($this->weight);
-
- // Handle ticks on X-axis
- if( $scale->type == "x" ) {
- // Draw the minor tick marks
-
- $yu = $pos - $this->direction*$this->GetMinTickAbsSize();
- $label = $scale->GetMinVal();
- $x=$scale->scale_abs[0];
- $i=0;
- $j=0;
- $step = round($maj_step_abs/$min_step_abs);
- while( $x < $limit ) {
- $this->ticks_pos[]=$x;
- $this->ticks_label[]=$label;
- $label+=$this->minor_step;
- if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) {
- if( $this->mincolor!="" ) $img->PushColor($this->mincolor);
- $img->Line($x,$pos,$x,$yu);
- if( $this->mincolor!="" ) $img->PopColor();
- }
- if( $i % $step == 0 ) {
- $this->maj_ticks_pos[$j]=round($x);//$xtick;
- ++$j;
- }
- ++$i;
- $x += $min_step_abs;
-
- }
- $this->maj_ticks_pos[$j]=$x;
- // Draw the major tick marks
-
- $yu = $pos - $this->direction*$this->GetMajTickAbsSize();
-
- // TODO: Add logic to set label_offset for text labels
- $label = (float)$scale->GetMinVal()+$this->text_label_start+$this->label_offset;
-
- $start_abs=$scale->scale_factor*$this->text_label_start;
-
- $nbrmajticks=ceil(($scale->GetMaxVal()-$scale->GetMinVal()-$this->text_label_start )/$this->major_step)+1;
-
-
- $x = $scale->scale_abs[0]+$start_abs+$this->xlabel_offset*$min_step_abs;
- for( $i=0; $label<=$scale->GetMaxVal()+$this->label_offset; ++$i ) {
- // Apply format
- if( $this->label_formfunc != "" ) {
- $f=$this->label_formfunc;
- $l = $f($label);
- }
- elseif( $this->label_formatstr != "" )
- $l = sprintf($this->label_formatstr,$label);
- else {
- $v = round($label,$precision);
- $l = sprintf("%01.".$precision."f",$v);
- }
-
- if( ($this->supress_zerolabel && $l==0) ||
- ($this->supress_first && $i==0) ||
- ($this->supress_last && $i==$nbrmajticks-1) ) {
- $l="";
- }
- $this->maj_ticks_label[$i]=$l;
- $label+=$this->major_step;
- $this->maj_ticklabels_pos[$i] = $x;
- // $this->maj_ticklabels_pos[$i] = $this->maj_ticks_pos[$i];
- // The x-position of the tick marks can be different from the labels.
- // Note that we record the tick position (not the label) so that the grid
- // happen upon tick marks and not labels.
- $xtick=$scale->scale_abs[0]+$start_abs+$this->xtick_offset*$min_step_abs+$i*$maj_step_abs;
- $this->maj_ticks_pos[$i]=$xtick;
- if(!($this->xtick_offset > 0 && $i==$nbrmajticks-1) &&
- !$this->supress_tickmarks) {
- if( $this->majcolor!="" ) $img->PushColor($this->majcolor);
- $img->Line($this->maj_ticks_pos[$i],$pos,$this->maj_ticks_pos[$i],$yu);
- if( $this->majcolor!="" ) $img->PopColor();
- }
- $x += $maj_step_abs;
- }
- }
- elseif( $scale->type == "y" ) {
- // Draw the major tick marks
- $xr = $pos + $this->direction*$this->GetMajTickAbsSize();
- $label = $scale->GetMinVal();
-
- $tmpmaj=array();
- $tmpmin=array();
- for( $i=0; $i<$nbrmajticks; ++$i) {
- $y=$scale->scale_abs[0]+$i*$maj_step_abs;
- $tmpmaj[]=$y;
-
- // THe following two lines might seem to be unecessary but they are not!
- // The reason being that for X-axis we separate the position of the labels
- // and the tick marks which we don't do for the Y-axis.
- // We therefore need to make sure both arrays are corcectly filled
- // since Axis::StrokeLabels() uses the label positions and Grid::Stroke() uses
- // the tick positions.
- $this->maj_ticklabels_pos[$i]=$y;
- $this->maj_ticks_pos[$i]=$y;
-
- if( $this->label_formfunc != "" ) {
- $f=$this->label_formfunc;
- $l = $f($label);
- }
- elseif( $this->label_formatstr != "" )
- $l = sprintf($this->label_formatstr,$label);
- else
- $l = sprintf("%01.".$precision."f",round($label,$precision));
-
- if( ($this->supress_zerolabel && ($l + 0)==0) || ($this->supress_first && $i==0) ||
- ($this->supress_last && $i==$nbrmajticks-1) ) {
- $l="";
- }
-
- $this->maj_ticks_label[$i]=$l;
- $label+=$this->major_step;
- if( !$this->supress_tickmarks ) {
- if( $this->majcolor!="" ) $img->PushColor($this->majcolor);
- $img->Line($pos,$y,$xr,$y);
- if( $this->majcolor!="" ) $img->PopColor();
- }
- }
- // Draw the minor tick marks
- $xr = $pos + $this->direction*$this->GetMinTickAbsSize();
- $label = $scale->GetMinVal();
- for( $i=0,$y=$scale->scale_abs[0]; $y>=$limit; ) {
- $tmpmin[]=$y;
- $this->ticks_pos[$i]=$y;
- $this->ticks_label[$i]=$label;
- $label+=$this->minor_step;
- if( !$this->supress_tickmarks && !$this->supress_minor_tickmarks) {
- if( $this->mincolor!="" ) $img->PushColor($this->mincolor);
- $img->Line($pos,$y,$xr,$y);
- if( $this->mincolor!="" ) $img->PopColor();
- }
- ++$i;
- $y=$scale->scale_abs[0]+$i*$min_step_abs;
- }
- }
- }
- //---------------
- // PRIVATE METHODS
- // Spoecify the offset of the displayed tick mark with the tick "space"
- // Legal values for $o is [0,1] used to adjust where the tick marks and label
- // should be positioned within the major tick-size
- // $lo specifies the label offset and $to specifies the tick offset
- // this comes in handy for example in bar graphs where we wont no offset for the
- // tick but have the labels displayed halfway under the bars.
- function SetXLabelOffset($aLabelOff,$aTickOff=-1) {
- $this->xlabel_offset=$aLabelOff;
- if( $aTickOff==-1 ) // Same as label offset
- $this->xtick_offset=$aLabelOff;
- else
- $this->xtick_offset=$aTickOff;
- if( $aLabelOff>0 )
- $this->SupressLast(); // The last tick wont fit
- }
- // Which tick label should we start with?
- function SetTextLabelStart($aTextLabelOff) {
- $this->text_label_start=$aTextLabelOff;
- }
-
- } // Class
- //===================================================
- // CLASS LinearScale
- // Description: Handle linear scaling between screen and world
- //===================================================
- class LinearScale {
- var $scale=array(0,0);
- var $scale_abs=array(0,0);
- var $scale_factor; // Scale factor between world and screen
- var $world_size; // Plot area size in world coordinates
- var $world_abs_size; // Plot area size in pixels
- var $off; // Offset between image edge and plot area
- var $type; // is this x or y scale ?
- var $ticks=null; // Store ticks
- var $autoscale_min=false; // Forced minimum value, auto determine max
- var $autoscale_max=false; // Forced maximum value, auto determine min
- var $gracetop=0,$gracebottom=0;
- var $intscale=false; // Restrict autoscale to integers
- var $textscale=false; // Just a flag to let the Plot class find out if
- // we are a textscale or not. This is a cludge since
- // this ionformatyion is availabale in Graph::axtype but
- // we don't have access to the graph object in the Plots
- // stroke method. So we let graph store the status here
- // when the linear scale is created. A real cludge...
- var $text_scale_off = 0;
- var $auto_ticks=false; // When using manual scale should the ticks be automatically set?
- var $name = 'lin';
- //---------------
- // CONSTRUCTOR
- function LinearScale($aMin=0,$aMax=0,$aType="y") {
- assert($aType=="x" || $aType=="y" );
- assert($aMin<=$aMax);
-
- $this->type=$aType;
- $this->scale=array($aMin,$aMax);
- $this->world_size=$aMax-$aMin;
- $this->ticks = new LinearTicks();
- }
- //---------------
- // PUBLIC METHODS
- // Second phase constructor
- function Init(&$aImg) {
- $this->InitConstants($aImg);
- // We want image to notify us when the margins changes so we
- // can recalculate the constants.
- // PHP <= 4.04 BUGWARNING: IT IS IMPOSSIBLE TO DO THIS IN THE CONSTRUCTOR
- // SINCE (FOR SOME REASON) IT IS IMPOSSIBLE TO PASS A REFERENCE
- // TO 'this' INSTEAD IT WILL ADD AN ANONYMOUS COPY OF THIS OBJECT WHICH WILL
- // GET ALL THE NOTIFICATIONS. (This took a while to track down...)
-
- // Add us as an observer to class Image
- $aImg->AddObserver("InitConstants",$this);
- }
-
- // Check if scale is set or if we should autoscale
- // We should do this is either scale or ticks has not been set
- function IsSpecified() {
- if( $this->GetMinVal()==$this->GetMaxVal() ) { // Scale not set
- return false;
- }
- return true;
- }
-
- // Set the minimum data value when the autoscaling is used.
- // Usefull if you want a fix minimum (like 0) but have an
- // automatic maximum
- function SetAutoMin($aMin) {
- $this->autoscale_min=$aMin;
- }
- // Set the minimum data value when the autoscaling is used.
- // Usefull if you want a fix minimum (like 0) but have an
- // automatic maximum
- function SetAutoMax($aMax) {