/tags/rel-1_4_5rc1-20050616/locales/support/smstats/includes/jpgraph.php
PHP | 1996 lines | 1357 code | 253 blank | 386 comment | 253 complexity | 6847c08d3f69661c7ac484a53243f33a MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
Large files files are truncated, but you can click here to view the full file
- <?php
- //=======================================================================
- // File: JPGRAPH.PHP
- // Description: PHP4 Graph Plotting library. Base module.
- // Created: 2001-01-08
- // Author: Johan Persson (johanp@aditus.nu)
- // Ver: $Id: jpgraph.php 8819 2005-02-08 11:35:07Z tokul $
- //
- // License: This code is released under QPL 1.0
- // Copyright (C) 2001,2002 Johan Persson
- //========================================================================
- //------------------------------------------------------------------------
- // Directories. Must be updated to reflect your installation
- //------------------------------------------------------------------------
- // 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 (furter 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 '/'
- DEFINE("CACHE_DIR","/tmp/jpgraph_cache/");
- // Directory for jpGraph TTF fonts. Must end with '/'
- // Note: The fonts must follow the naming conventions as
- // used by the supplied TTF fonts in JpGraph.
- DEFINE("TTF_DIR","/home/www/smstats.topolis.inet/stats/fonts/");
- // 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 take 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 PHP.
- DEFINE("CSIMCACHE_DIR","csimcache/");
- DEFINE("CSIMCACHE_HTTP_DIR","csimcache/");
- //------------------------------------------------------------------------
- // Various JpGraph Settings. PLEASE adjust accordingly to you
- // system setup. Note that cache functionlity is turned off by
- // default (Enable by setting USE_CACHE to true)
- //------------------------------------------------------------------------
- // Specify if we should use GD 2.x or GD 1.x
- // If you have GD 2.x you MUST set this flag to true
- // If you don't have GD2 installed this must be set to false!
- DEFINE("USE_LIBRARY_GD2",true);
- // Should the image be a truecolor image?
- // Note 1: Can only be used with GD 2.0.2 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
- // => You can't have both background images and truetype fonts in the same
- // image until these bugs has been fixed in GD 2.01
- DEFINE('USE_TRUECOLOR',true);
- // 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",false);
- // 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");
- // 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.
- DEFINE("USE_IMAGE_ERROR_HANDLER",true);
- // If the color palette is full should JpGraph try to allocate
- // the closest match? If you plan on using background image 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 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",false);
- // 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","Generated in: %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);
- // Enable some extra debug information for CSIM etc to be shown.
- // (Should only be changed if your first name is Johan and you
- // happen to know what you are doing!!)
- DEFINE("JPG_DEBUG",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");
- //------------------------------------------------------------------
- // 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);
- //
- DEFINE("FF_BOOK",91); // Deprecated fonts from 1.9
- DEFINE("FF_HANDWRT",92); // Deprecated fonts from 1.9
- // TTF Font styles
- DEFINE("FS_NORMAL",1);
- DEFINE("FS_BOLD",2);
- DEFINE("FS_ITALIC",3);
- DEFINE("FS_BOLDIT",4);
- DEFINE("FS_BOLDITALIC",4);
- //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_UP",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);
- // Styles for gradient color fill
- DEFINE("GRAD_VER",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);
- // 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);
- //
- // 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) {
- 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 an image that contains the error text.
- $w=450; $h=110;
- $img = new Image($w,$h);
- $img->SetColor("darkred");
- $img->Rectangle(0,0,$w-1,$h-1);
- $img->SetFont(FF_FONT1,FS_BOLD);
- $img->StrokeText(10,20,"JpGraph Error:");
- $img->SetColor("black");
- $img->SetFont(FF_FONT1,FS_NORMAL);
- $txt = new Text(wordwrap($aMsg,70),10,20);
- $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");
- }
- //
- //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
- // At the moment this is used to verify that the user
- // really has GD2 if he has set USE_GD2 to true.
- //
- function CheckGDVersion() {
- ob_start();
- phpinfo(8); // Just get the modules loaded
- $a = ob_get_contents();
- ob_end_clean();
- if( preg_match('/.*GD Version.*(1[0-9|\.]+).*/',$a,$m) ) {
- $r=1;$v=$m[1];
- }
- elseif( preg_match('/.*GD Version.*(2[0-9|\.]+).*/',$a,$m) ) {
- $r=2;$v=$m[1];
- }
- else {
- $r=0;$v=$m[1];
- }
- return $r;
- }
- //
- // Check what version of the GD library the user has choosen to use. If the user
- // has choosen GD2 we also check that GD2 really exists.
- // (This might lock a bit strange but in order to avoid calling the CheckGDVersion
- // since it takes roughly 20ms we only call it for real in the case where the user
- // tries to use GD2. We then make sure that the user really have GD2 installed))
- $gdversion = 1;
- if( USE_LIBRARY_GD2 ) {
- $gdversion = CheckGDVersion();
- if( $gdversion == 2 ) {
- $GLOBALS['gd2'] = true;
- $GLOBALS['copyfunc'] = 'imagecopyresampled';
- }
- else
- JpGraphError::Raise('You have selected GD2 but you do not appear to have GD2 installed!');
- } elseif( $gdversion > 0 && function_exists('imagetypes')) {
- $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.");
- }
-
- // Usefull mathematical function
- function sign($a) {if( $a>=0) return 1; else return -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 $HTTP_SERVER_VARS;
- $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($HTTP_SERVER_VARS['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($HTTP_SERVER_VARS['PHP_SELF']);
- // Replace the ".php" extension with the image format extension
- return substr($fname,0,strlen($fname)-4).".".$img_format;
- }
- class LanguageConv {
- // 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;
- }
- function ToCyrillic($aTxt) {
- if( CYRILLIC_FROM_WINDOWS ) {
- $aTxt = convert_cyr_string($aTxt, "w", "k");
- }
- $isostring = convert_cyr_string($aTxt, "k", "i");
- $unistring = LanguageConv::iso2uni($isostring);
- return $unistring;
- }
- }
- //===================================================
- // 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;
- $gDateLocale = new DateLocale();
- $gJpgDateLocale = new DateLocale();
- //===================================================
- // CLASS DateLocale
- // Description: Hold localized text used in dates
- // ToDOo: Rewrite this to use the real local locale
- // instead.
- //===================================================
- class DateLocale {
-
- var $iLocale = ''; // 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($this->iLocale);
- }
- //---------------
- // PUBLIC METHODS
- function Set($aLocale) {
- if ( in_array($aLocale, array_keys($this->iDayAbb)) ){
- $this->iLocale = $aLocale;
- return TRUE; // already cahced nothing else to do!
- }
- $pLocale = setlocale(LC_TIME, 0); // get current locale for LC_TIME
- if ( !setlocale(LC_TIME, $aLocale) ){
- JpGraphError::Raise("Unsupported locale ($aLocale)");
- 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];
- }
- }
- //===================================================
- // 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);
- }
- }
- //===================================================
- // 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(198,198,198); // Margin coor 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;
- //---------------
- // 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
- }
- //---------------
- // 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);
- }
- // Shortcut to image margin
- function SetMargin($lm,$rm,$tm,$bm) {
- $this->img->SetMargin($lm,$rm,$tm,$bm);
- }
-
- // 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;
- }
-
- // 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);
- exit();
- }
- if( strtolower($e[1]) == 'png' )
- $aImgFormat = 'png';
- elseif( strtolower($e[1]) == 'jpg' || strtolower($e[1]) == 'jpeg')
- $aImgFormat = 'jpg';
- elseif( strtolower($e[1]) == 'gif' )
- $aImgFormat = 'gif';
- else {
- JpGraphError::Raise('Unknown file extension in Graph::SetBackgroundImage : '.$aFileName);
- exit();
- }
- }
- $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;
- }
-
- // 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;
- $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->SetLabelPos(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='';
- $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();
- $csim .= $this->legend->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) {
-
-
- $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
- srand ((double) microtime() * 1000000);
- $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) ) {
- $urlarg .= '&'.$key.'='.$value;
- }
- echo $this->GetHTMLImageMap($aCSIMName);
- echo "<img src='".$aScriptName.$urlarg."' ISMAP USEMAP='#".$aCSIMName."' border=$aBorder>";
- }
- }
- else {
- $this->Stroke();
- }
- }
- // Stroke the graph
- // $aStrokeFileName If != "" the image will be written to this file and NOT
- // streamed back to the browser
- function Stroke($aStrokeFileName="") {
- // 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]->Legend($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]->Legend($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);
- $this->yscale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
- }
- elseif( $this->yscale->IsSpecified() && $this->yscale->auto_ticks ) {
- // If the user has specified a min/max value for the scale we still use the
- // autoscaling to get a suitable tick distance. This might adjust the specified
- // min max values so they end up on a tick mark.
- $min = $this->yscale->scale[0];
- $max = $this->yscale->scale[1];
- $this->yscale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
- }
- 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 ) {
- // If the user has specified a min/max value for the scale we still use the
- // autoscaling to get a suitable tick distance. This might adjust the specified
- // min max values so they end up on a tick mark.
- $min = $this->y2scale->scale[0];
- $max = $this->y2scale->scale[1];
- $this->y2scale->AutoScale($this->img,$min,$max,$this->img->plotheight/$this->ytick_factor);
- }
- }
-
- //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,$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);
- }
- }
- $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);
- }
- }
-
- // 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);
- }
- // 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);
- }
- $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();
- $this->footer->Stroke($this->img);
- }
-
- 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->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;
- 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);
- // 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->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="png",$aBright=0,$aContr=0) {
- if( $aImgFormat == "jpg" )
- $f = "imagecreatefromjpeg";
- else
- $f = "imagecreatefrom".$aImgFormat;
- $imgtag = $aImgFormat;
- if( $aImgFormat == "jpeg" )
- $imgtag = "jpg";
- if( !strstr($this->background_image,$imgtag) && strstr($this->background_image,".") ) {
- $t = " Background image seems to be of different type (has different file extension)".
- " than specified imagetype. <br>Specified: '".
- $aImgFormat."'<br>File: '".$this->background_image."'";
- JpGraphError::Raise($t);
- }
- $img = $f($this->background_image);
- if( !$img ) {
- JpGraphError::Raise(" Can't read background image: '".$this->background_image."'");
- }
- return $img;
- }
- function StrokeFrameBackground() {
- $bkgimg = $this->LoadBkgIma…
Large files files are truncated, but you can click here to view the full file