/bin/jpgraph.php
PHP | 5369 lines | 4111 code | 498 blank | 760 comment | 518 complexity | 70348d1c1359125edad9b13c8c67f68e MD5 | raw file
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$
- //
- // 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 directory to be used as a cache. This directory MUST
- // be readable and writable for PHP. Must end with '/'
- DEFINE("CACHE_DIR","/tmp/jpgraph_cache/");
- // The URL relative name where the cache can be found, i.e
- // under what HTTP directory can the cache be found. Normally
- // you would probably assign an alias in apache configuration
- // for the cache directory.
- DEFINE("APACHE_CACHE_DIR","/jpgraph_cache/");
- // Directory for TTF fonts. Must end with '/'
- DEFINE("TTF_DIR",'/usr/share/fonts/truetype/');
- //------------------------------------------------------------------------
- // Various JpGraph Settings. The default should be fine for most
- // users.
- //------------------------------------------------------------------------
- // Specify if we should use GD 2.x or GD 1.x
- // If you have GD 2.x installed it is recommended that you use it
- // since it will give a slightly, slightly better visual apperance
- // for arcs.
- 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 1: MUST be enabled to get background images working with GD2
- // Note 2: 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);
- // Deafult graphic format set to "auto" which will automtically
- // 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);
- // 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);
- // 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);
- // 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);
- // 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","Generated in: %01.3fs");
- // 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 unicode language support
- DEFINE("LANGUAGE_CYRILLIC",false);
- // Enable some extra debug information to be shown.
- // (Should only be used if your first name is Johan)
- DEFINE("JPG_DEBUG",false);
- //------------------------------------------------------------------
- // 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_HANDWRT",13);
- DEFINE("FF_COMIC",14);
- DEFINE("FF_ARIAL",15);
- DEFINE("FF_BOOK",16);
- // TTF Font styles
- DEFINE("FS_NORMAL",1);
- DEFINE("FS_BOLD",2);
- DEFINE("FS_ITALIC",3);
- DEFINE("FS_BOLDIT",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_LVERT",4); // Vertical lines
- DEFINE("BAND_LHOR",5); // Horizontal lines
- 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
- //
- // 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 {
- // Split a line by inserting a newline after aWordCnt words
- function InsertLineBreaks($aStr,$aWordCnt=11) {
- $tok = strtok($aStr," ");
- $cnt = 0;
- $s = "";
- while( $tok ) {
- $s .= $tok;
- if( $cnt==$aWordCnt-1 ) {
- $s .= "\n";
- $cnt = 0;
- }
- else
- $s .= " ";
- $cnt++;
- $tok = strtok(" ");
- }
- return $s;
- }
- function Raise($aMsg,$aHalt=true) {
- $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($this->InsertLineBreaks($aMsg),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']);
- }
- //
- // Check what version of the GD library is being used
- //
- if( USE_LIBRARY_GD2 ) {
- $gd2 = true;
- $copyfunc = "imagecopyresampled";
- } elseif(function_exists('imagecopyresized')) {
- $copyfunc = "imagecopyresized";
- $gd2 = false;
- }
- else {
- JpGraphError::Raise(" Your PHP installation does not
- 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, $PHP_SELF;
- $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']) ) $fname=basename($HTTP_SERVER_VARS['PHP_SELF']);
- else $fname=basename($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.");
- // 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) {
- $koistring = $aTxt;
- $isostring = convert_cyr_string($koistring, "k", "i");
- $unistring = LanguageConv::iso2uni($isostring);
- $this->t = $unistring;
- return $aTxt;
- }
- }
- //===================================================
- // 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
- //===================================================
- // 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; // Title and subtitle 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
- //---------------
- // 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) {
-
- // If timing is used create a new timing object
- if( BRAND_TIMING ) {
- global $tim;
- $tim = new JpgTimer();
- $tim->Push();
- }
-
- // Automtically 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->subtitle = new Text();
- $this->legend = new Legend();
-
- // 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);
- }
-
- // 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.");
- $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=BKIMG_FILLPLOT,$aImgFormat="png") {
- 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.");
- }
- $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;
- }
-
- // 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;
- }
- // 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. ($axtype)");
-
- $xt=substr($aAxisType,0,3);
- if( $xt == "lin" || $xt == "tex" )
- $this->xscale = new LinearScale($aXMin,$aXMax,"x");
- 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=="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->y2axis->SetPos($this->xscale->GetMaxVal());
- $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=18;
- 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() {
- $csim="";
- foreach ($this->plots as $p) {
- $csim.= $p->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;
- }
- // Stroke the graph
- // $aStrokeFileName If != "" the image will be written to this file and NOT
- // streamed back to the browser
- function Stroke($aStrokeFileName="") {
-
- // 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) ) {
- JpGraphError::Raise("<strong>JpGraph: Can't draw unspecified Y-scale.</strong><br>
- You have either:
- <br>* Specified an Y axis for autoscaling but have not supplied any plots
- <br>* Specified a scale manually but have forgot to specify the tick steps");
- }
-
- // 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);
- }
- 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);
- }
-
- //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
- $this->yaxis->SetPos($this->xscale->GetMinVal());
- if( $this->y2axis != null ) {
- $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.
-
- if( !$this->xaxis->pos && $this->yscale->GetMinVal() < 0 ) {
- $this->yscale->ticks->SupressZeroLabel(false);
- $this->xscale->ticks->SupressFirst();
- if( $this->y2axis != null ) {
- $this->xscale->ticks->SupressLast();
- }
- }
-
- $this->StrokePlotArea();
-
- // Stroke axis
- $this->xaxis->Stroke($this->yscale);
- $this->yaxis->Stroke($this->xscale);
- // Stroke bands
- if( $this->bands != null )
- 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 ) {
- $this->ygrid->Stroke();
- $this->xgrid->Stroke();
- }
-
- // Stroke Y2-axis
- if( $this->y2axis != null ) {
- $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 ) {
- $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.
- $this->yaxis->Stroke($this->xscale);
- $this->xaxis->Stroke($this->yscale);
-
- if( $this->y2scale != null)
- $this->y2axis->Stroke($this->xscale);
-
- $this->StrokePlotBox();
-
- // 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);
- $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();
-
- // Finally stream the generated picture
- $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);
- }
- //---------------
- // PRIVATE METHODS
- // Private helper function for backgound image
- function LoadBkgImage($aImgFormat="png",$aBright=0,$aContr=0) {
- $f = "imagecreatefrom".$aImgFormat;
- $imgtag = $aImgFormat;
- if( $aImgFormat == "jpeg" )
- $imgtag = "jpg";
- if( !strstr($this->background_image,$imgtag) && strstr($this->background_image,".") )
- JpGraphError::Raise(" Background image seems to be of different type (has different file extension)
- than specified imagetype. <br>Specified: '".$aImgFormat."'<br>File: '".$this->background_image."'");
- $img = $f($this->background_image);
- if( !$img ) {
- JpGraphError::Raise(" Can't read background image: '".$this->background_image."'");
- }
- return $img;
- }
- // Private
- // Stroke the plot area with either a solid color or a background image
- function StrokePlotArea() {
- // Copy in background image
- if( $this->background_image != "" ) {
- $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);
- $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);
- }
- else {
- $aa = $this->img->SetAngle(0);
- $this->StrokeFrame();
- $this->img->SetAngle($aa);
- $this->img->PushColor($this->plotarea_color);
- // 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 ;
- $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();
- }
- $this->img->SetAngle($aa);
- }
-
-
- 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 StrokeTitles() {
- // Stroke title
- $this->title->Center($this->img->left_margin,$this->img->width-$this->img->right_margin,5);
- $this->title->Stroke($this->img);
-
- // ... and subtitle
- $this->subtitle->Center($this->img->left_margin,$this->img->width-$this->img->right_margin,
- 7+$this->title->GetFontHeight($this->img));
- $this->subtitle->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]->Stroke($this->img);
- }
- }
- }
- 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;
- }
-
- // 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);
- }
- // Draw a frame around the image
- function StrokeFrame() {
- if( !$this->doframe ) return;
- if( $this->doshadow ) {
- $this->img->SetColor($this->frame_color);
- if( $this->background_image_type <= 1 )
- $c = $this->margin_color;
- else
- $c = false;
- $this->img->ShadowRectangle(0,0,$this->img->width,$this->img->height,
- $c,$this->shadow_width);
- }
- else {
- $this->img->SetLineWeight($this->frame_weight);
- if( $this->background_image_type <= 1 ) {
- $this->img->SetColor($this->margin_color);
- $this->img->FilledRectangle(1,1,$this->img->width-2,$this->img->height-2);
- }
- $this->img->SetColor($this->frame_color);
- $this->img->Rectangle(0,0,$this->img->width-1,$this->img->height-1);
- }
- }
- } // Class
- //===================================================
- // CLASS TTF
- // Description: Handle TTF font names
- //===================================================
- class TTF {
- var $font_fam;
- //---------------
- // CONSTRUCTOR
- function TTF() {
- // Base file names for available fonts
- $this->font_fam=array(
- FF_COURIER => TTF_DIR."courier",
- FF_VERDANA => TTF_DIR."verdana",
- FF_TIMES => TTF_DIR."times",
- FF_HANDWRT => TTF_DIR."handwriting",
- FF_COMIC => TTF_DIR."comic",
- FF_ARIAL => TTF_DIR."arial",
- FF_BOOK => TTF_DIR."bookant");
- }
- //---------------
- // PUBLIC METHODS
- // Create the TTF file from the font specification
- function File($fam,$style=FS_NORMAL) {
- $f=$this->font_fam[$fam];
- if( !$f ) JpGraphError::Raise(" Unknown TTF font family.");
- switch( $style ) {
- case FS_NORMAL:
- break;
- case FS_BOLD: $f .= "bd";
- break;
- case FS_ITALIC: $f .= "i";
- break;
- case FS_BOLDIT: $f .= "bi";
- break;
- default:
- JpGraphError::Raise(" Unknown TTF Style.");
- }
- $f .= ".ttf";
-
- // Check that file exist
- if( !file_exists($f) )
- JpGraphError::Raise(" Can't open font file \"$f\". Wrong directory?");
-
- 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,$hide=false,$dir=0;
- var $boxed=false; // Should the text be boxed
- var $paragraph_align="left";
- //---------------
- // CONSTRUCTOR
- // Create new text at absolute pixel coordinates
- function Text($aTxt="",$aXAbsPos=0,$aYAbsPos=0) {
- $this->t = $aTxt;
- $this->x = $aXAbsPos;
- $this->y = $aYAbsPos;
- }
- //---------------
- // PUBLIC METHODS
- // Set the string in the text object
- function Set($aTxt) {
- $this->t = $aTxt;
- }
-
- // 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;
- }
-
- // Specify alignment for the text
- function Align($aHAlign,$aVAlign="top") {
- $this->halign = $aHAlign;
- $this->valign = $aVAlign;
- }
- // Specifies the alignment for a multi line text
- function ParagraphAlign($aAlign) {
- $this->paragraph_align = $aAlign;
- }
-
- // 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),$aShadow=false) {
- if( $aFrameColor==false )
- $this->boxed=false;
- else
- $this->boxed=true;
- $this->fcolor=$aFrameColor;
- $this->bcolor=$aBorderColor;
- $this->shadow=$aShadow;
- }
-
- // 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;
- }
-
- // 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);
- return $aImg->GetTextWidth($this->t);
- }
-
- // Hight of font
- function GetFontHeight(&$aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- return $aImg->GetFontHeight();
- }
- function GetTextHeight(&$aImg) {
- $aImg->SetFont($this->font_family,$this->font_style,$this->font_size);
- return $aImg->GetTextHeight($this->t);
- }
-
- // Display text in image
- function Stroke(&$aImg,$x=-1,$y=-1) {
- if( $x>-1 ) $this->x = $x;
- if( $y>-1 ) $this->y = $y;
- // If position been given as a fraction of the image size
- // calculate the absolute position
- if( $this->x < 1 ) $this->x *= $aImg->width;
- if( $this->y < 1 ) $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->StrokeBoxedText($this->x,$this->y,$this->t,
- $this->dir,$this->fcolor,$this->bcolor,$this->shadow,
- $this->paragraph_align);
- }
- else {
- $aImg->StrokeText($this->x,$this->y,$this->t,$this->dir,
- $this->paragraph_align);
- }
- $aImg->PopColor($this->color);
- }
- } // Class
- //===================================================
- // CLASS Grid
- // Description: responsible for drawing grid lines in graph
- //===================================================
- class Grid {
- var $img;
- var $scale;
- var $grid_color=array(196,196,196);
- var $type="solid";
- var $show=false, $showMinor=false,$weight=1;
- //---------------
- // CONSTRUCTOR
- function Grid(&$aAxis) {
- $this->scale = &$aAxis->scale;
- $this->img = &$aAxis->img;
- }
- //---------------
- // PUBLIC METHODS
- function SetColor($aColor) {
- $this->grid_color=$aColor;
- }
-
- 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;
- }
-
- // Display the grid
- function Stroke() {
- if( $this->showMinor )
- $this->DoStroke($this->scale->ticks->ticks_pos);
- else
- $this->DoStroke($this->scale->ticks->maj_ticks_pos);
- }
-
- //--------------
- // Private methods
- // Draw the grid
- function DoStroke(&$aTicksPos) {
- if( !$this->show )
- return;
- $this->img->SetColor($this->grid_color);
- $this->img->SetLineWeight($this->weight);
- $nbrgrids = count($aTicksPos);
- if( $this->scale->type=="y" ) {
- $xl=$this->img->left_margin;
- $xr=$this->img->width-$this->img->right_margin;
- 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);
- }
- }
-
- if( $this->scale->type=="x" ) {
- $yu=$this->img->top_margin;
- $yl=$this->img->height-$this->img->bottom_margin;
- $x=$aTicksPos[0];
- $limit=$this->img->width-$this->img->right_margin;
- $i=0;
- // 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
- while( $x<=$limit && $i<count($aTicksPos)) {
- $x=$aTicksPos[$i];
- 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;
- }
- }
- 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;
- var $show_first_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=6;
- //---------------
- // 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=6;
- $this->labelPos=SIDE_LEFT;
- }
- else {
- $this->title_margin = 5;
- $this->title_adjust="high";
- $this->title->SetOrientation(0);
- $this->tick_label_margin=3;
- $this->labelPos=SIDE_DOWN;
- }
- }
- //---------------
- // PUBLIC METHODS
- // Utility function to set the direction for tick marks
- function SetTickDirection($aDir) {
- $this->scale->ticks->SetDirection($aDir);
- }
-
- function SetLabelFormatString($aFormStr) {
- $this->scale->ticks->SetLabelFormat($aFormStr);
- }
-
- function SetLabelFormatCallback($aFuncName) {
- $this->scale->ticks->SetFormatCallback($aFuncName);
- }
- // Don't display the first label
- function HideFirstTickLabel($aHide=false) {
- $this->show_first_label=$aHide;
- }
-
- // Hide the axis
- function Hide($aHide=true) {
- $this->hide=$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;
- …
Large files files are truncated, but you can click here to view the full file