• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Modules/SurveyQuestionPool/phplot/phplot.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /* $Id: phplot.php 18634 2009-01-20 17:18:53Z hschottm $ */
00004 
00005 /*
00006  * PHPLOT Version 5.0.5
00007  * Copyright (C) 1998-2008 Afan Ottenheimer.  Released under
00008  * the GPL and PHP licenses as stated in the the README file which should
00009  * have been included with this document.
00010  *
00011  * Co-author and maintainer (2003-2005)
00012  * Miguel de Benito Delgado <nonick AT vodafone DOT es>
00013  *
00014  * Maintainer (2006-present)
00015  * <lbayuk AT users DOT sourceforge DOT net>
00016  *
00017  * Visit http://sourceforge.net/projects/phplot/
00018  * for PHPlot documentation, downloads, and discussions.
00019  *
00020  * Requires PHP 5.2.x or later. (PHP 4 is unsupported as of Jan 2008)
00021  */
00022 
00023 class PHPlot {
00024 
00025     /* I have removed internal variable declarations, some isset() checking was required,
00026      * but now the variables left are those which can be tweaked by the user. This is intended to
00027      * be the first step towards moving most of the Set...() methods into a subclass which will be
00028      * used only when strictly necessary. Many users will be able to put default values here in the
00029      * class and thus avoid memory overhead and reduce parsing times.
00030      */
00032 
00033     var $is_inline = FALSE;             // FALSE = Sends headers, TRUE = sends just raw image data
00034     var $browser_cache = FALSE;         // FALSE = Sends headers for browser to not cache the image,
00035                                         // (only if is_inline = FALSE also)
00036 
00037     var $safe_margin = 5;               // Extra margin used in several places. In pixels
00038 
00039     var $x_axis_position = '';          // Where to draw both axis (world coordinates),
00040     var $y_axis_position = '';          // leave blank for X axis at 0 and Y axis at left of plot.
00041 
00042     var $xscale_type = 'linear';        // linear, log
00043     var $yscale_type = 'linear';
00044 
00045 //Fonts
00046     var $use_ttf  = FALSE;                  // Use True Type Fonts?
00047     var $ttf_path = '.';                    // Default path to look in for TT Fonts.
00048     var $default_ttfont = 'benjamingothic.ttf';
00049     var $line_spacing = 4;                  // Pixels between lines.
00050 
00051     // Font angles: 0 or 90 degrees for fixed fonts, any for TTF
00052     var $x_label_angle = 0;                 // For labels on X axis (tick and data)
00053     var $y_label_angle = 0;                 // For labels on Y axis (tick and data)
00054 
00055 //Formats
00056     var $file_format = 'png';
00057     var $output_file = '';                  // For output to a file instead of stdout
00058 
00059 //Data
00060     var $data_type = 'text-data';           // text-data, data-data-error, data-data, text-data-single
00061     var $plot_type= 'linepoints';           // bars, lines, linepoints, area, points, pie, thinbarline, squared
00062 
00063     var $label_scale_position = 0.5;        // Shifts data labes in pie charts. 1 = top, 0 = bottom
00064     var $group_frac_width = 0.7;            // Bars use this fraction (0 to 1) of a group's space
00065     var $bar_extra_space = 0.5;             // Number of extra bar's worth of space in a group
00066     var $bar_width_adjust = 1;              // 1 = bars of normal width, must be > 0
00067 
00068     var $y_precision = 1;
00069     var $x_precision = 1;
00070 
00071     var $data_units_text = '';              // Units text for 'data' labels (i.e: '¤', '$', etc.)
00072 
00073 // Titles
00074     var $title_txt = '';
00075 
00076     var $x_title_txt = '';
00077     var $x_title_pos = 'plotdown';          // plotdown, plotup, both, none
00078 
00079     var $y_title_txt = '';
00080     var $y_title_pos = 'plotleft';          // plotleft, plotright, both, none
00081 
00082 
00083 //Labels
00084     // There are two types of labels in PHPlot:
00085     //    Tick labels: they follow the grid, next to ticks in axis.   (DONE)
00086     //                 they are drawn at grid drawing time, by DrawXTicks() and DrawYTicks()
00087     //    Data labels: they follow the data points, and can be placed on the axis or the plot (x/y)  (TODO)
00088     //                 they are drawn at graph plotting time, by Draw*DataLabel(), called by DrawLines(), etc.
00089     //                 Draw*DataLabel() also draws H/V lines to datapoints depending on draw_*_data_label_lines
00090 
00091     // Tick Labels
00092     var $x_tick_label_pos = 'plotdown';     // plotdown, plotup, both, xaxis, none
00093     var $y_tick_label_pos = 'plotleft';     // plotleft, plotright, both, yaxis, none
00094 
00095     // Data Labels:
00096     var $x_data_label_pos = 'plotdown';     // plotdown, plotup, both, plot, all, none
00097     var $y_data_label_pos = 'plotleft';     // plotleft, plotright, both, plot, all, plotin, none
00098 
00099     var $draw_x_data_label_lines = FALSE;   // Draw a line from the data point to the axis?
00100     var $draw_y_data_label_lines = FALSE;   // TODO
00101 
00102     // Label types: (for tick, data and plot labels)
00103     var $x_label_type = '';                 // data, time. Leave blank for no formatting.
00104     var $y_label_type = '';                 // data, time. Leave blank for no formatting.
00105     var $x_time_format = '%H:%M:%S';        // See http://www.php.net/manual/html/function.strftime.html
00106     var $y_time_format = '%H:%M:%S';        // SetYTimeFormat() too...
00107 
00108     // Skipping labels
00109     // var $x_label_inc = 1;                   // Draw a label every this many (1 = all) (TODO)
00110     // var $y_label_inc = 1;
00111     // var $_x_label_cnt = 0;                  // internal count FIXME: work in progress
00112 
00113 // Legend
00114     var $legend = '';                       // An array with legend titles
00115     // These variables are unset to take default values:
00116     // var $legend_x_pos;                   // User-specified upper left coordinates of legend box
00117     // var $legend_y_pos;
00118     // var $legend_xy_world;                // If set, legend_x/y_pos are world coords, else pixel coords
00119     // var $legend_text_align;              // left or right, Unset means right
00120     // var $legend_colorbox_align;          // left, right, or none; Unset means same as text_align
00121 
00122 //Ticks
00123     var $x_tick_length = 5;                 // tick length in pixels for upper/lower axis
00124     var $y_tick_length = 5;                 // tick length in pixels for left/right axis
00125 
00126     var $x_tick_cross = 3;                  // ticks cross x axis this many pixels
00127     var $y_tick_cross = 3;                  // ticks cross y axis this many pixels
00128 
00129     var $x_tick_pos = 'plotdown';           // plotdown, plotup, both, xaxis, none
00130     var $y_tick_pos = 'plotleft';           // plotright, plotleft, both, yaxis, none
00131 
00132     var $num_x_ticks = '';
00133     var $num_y_ticks = '';
00134 
00135     var $x_tick_inc = '';                   // Set num_x_ticks or x_tick_inc, not both.
00136     var $y_tick_inc = '';                   // Set num_y_ticks or y_tick_inc, not both.
00137 
00138     var $skip_top_tick = FALSE;
00139     var $skip_bottom_tick = FALSE;
00140     var $skip_left_tick = FALSE;
00141     var $skip_right_tick = FALSE;
00142 
00143 //Grid Formatting
00144     var $draw_x_grid = FALSE;
00145     var $draw_y_grid = TRUE;
00146 
00147     var $dashed_grid = TRUE;
00148     var $grid_at_foreground = FALSE;        // Chooses whether to draw the grid below or above the graph
00149 
00150 //Colors and styles       (all colors can be array (R,G,B) or named color)
00151     var $color_array = 'small';             // 'small', 'large' or array (define your own colors)
00152                                             // See rgb.inc.php and SetRGBArray()
00153     var $i_border = array(194, 194, 194);
00154     var $plot_bg_color = 'white';
00155     var $bg_color = 'white';
00156     var $label_color = 'black';
00157     var $text_color = 'black';
00158     var $grid_color = 'black';
00159     var $light_grid_color = 'gray';
00160     var $tick_color = 'black';
00161     var $title_color = 'black';
00162     var $data_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1');
00163     var $error_bar_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1');
00164     var $data_border_colors = array('black');
00165 
00166     var $line_widths = 1;                  // single value or array
00167     var $line_styles = array('solid', 'solid', 'dashed');   // single value or array
00168     var $dashed_style = '2-4';              // colored dots-transparent dots
00169 
00170     var $point_sizes = array(5,5,3);         // single value or array
00171     var $point_shapes = array('diamond');   // rect, circle, diamond, triangle, dot, line, halfline, cross
00172 
00173     var $error_bar_size = 5;                // right and left size of tee
00174     var $error_bar_shape = 'tee';           // 'tee' or 'line'
00175     var $error_bar_line_width = 1;          // single value (or array TODO)
00176 
00177     var $plot_border_type = 'sides';        // left, sides, none, full
00178     var $image_border_type = 'none';        // 'raised', 'plain', 'none'
00179 
00180     var $shading = 5;                       // 0 for no shading, > 0 is size of shadows in pixels
00181 
00182     var $draw_plot_area_background = FALSE;
00183     var $draw_broken_lines = FALSE;          // Tells not to draw lines for missing Y data.
00184 
00185 //Miscellaneous
00186     var $callbacks = array(                  // Valid callback reasons (see SetCallBack)
00187         'draw_setup' => NULL,
00188         'draw_image_background' => NULL,
00189         'draw_plotarea_background' => NULL,
00190         'draw_titles' => NULL,
00191         'draw_axes' => NULL,
00192         'draw_graph' => NULL,
00193         'draw_border' => NULL,
00194         'draw_legend' => NULL,
00195         'debug_textbox' => NULL,  // For testing/debugging text box alignment
00196         'debug_scale' => NULL,    // For testing/debugging scale setup
00197     );
00198 
00199 
00201 //BEGIN CODE
00203 
00212     function PHPlot($which_width=600, $which_height=400, $which_output_file=NULL, $which_input_file=NULL)
00213     {
00214         $this->SetRGBArray($this->color_array);
00215 
00216         $this->background_done = FALSE;     // TRUE after background image is drawn once
00217         $this->plot_margins_set = FALSE;    // TRUE with user-set plot area or plot margins.
00218 
00219         if ($which_output_file)
00220             $this->SetOutputFile($which_output_file);
00221 
00222         if ($which_input_file)
00223             $this->SetInputFile($which_input_file);
00224         else {
00225             $this->image_width = $which_width;
00226             $this->image_height = $which_height;
00227 
00228             $this->img = ImageCreate($this->image_width, $this->image_height);
00229             if (! $this->img)
00230                 return $this->PrintError('PHPlot(): Could not create image resource.');
00231 
00232         }
00233 
00234         $this->SetDefaultStyles();
00235         $this->SetDefaultFonts();
00236 
00237         $this->SetTitle('');
00238         $this->SetXTitle('');
00239         $this->SetYTitle('');
00240 
00241         $this->print_image = TRUE;      // Use for multiple plots per image (TODO: automatic)
00242     }
00243 
00249     function GetImage($image_filename, &$width, &$height)
00250     {
00251         $error = '';
00252         $size = getimagesize($image_filename);
00253         if (!$size) {
00254             $error = "Unable to query image file $image_filename";
00255         } else {
00256             $image_type = $size[2];
00257             switch($image_type) {
00258             case IMAGETYPE_GIF:
00259                 $img = @ ImageCreateFromGIF ($image_filename);
00260                 break;
00261             case IMAGETYPE_PNG:
00262                 $img = @ ImageCreateFromPNG ($image_filename);
00263                 break;
00264             case IMAGETYPE_JPEG:
00265                 $img = @ ImageCreateFromJPEG ($image_filename);
00266                 break;
00267             default:
00268                 $error = "Unknown image type ($image_type) for image file $image_filename";
00269                 break;
00270             }
00271         }
00272         if (empty($error) && !$img) {
00273             # getimagesize is OK, but GD won't read it. Maybe unsupported format.
00274             $error = "Failed to read image file $image_filename";
00275         }
00276         if (!empty($error)) {
00277             return $this->PrintError("GetImage(): $error");
00278         }
00279         $width = $size[0];
00280         $height = $size[1];
00281         return $img;
00282     }
00283 
00289     function SetInputFile($which_input_file)
00290     {
00291         $im = $this->GetImage($which_input_file, $this->image_width, $this->image_height);
00292         if (!$im)
00293             return FALSE;  // GetImage already produced an error message.
00294 
00295         // Deallocate any resources previously allocated
00296         if (isset($this->img))
00297             imagedestroy($this->img);
00298 
00299         $this->img = $im;
00300 
00301         // Do not overwrite the input file with the background color.
00302         $this->background_done = TRUE;
00303 
00304         return TRUE;
00305     }
00306 
00310 
00317     function SetIndexColor($which_color)
00318     {
00319         list ($r, $g, $b) = $this->SetRGBColor($which_color);  //Translate to RGB
00320         if (!isset($r)) return NULL;
00321         return ImageColorResolve($this->img, $r, $g, $b);
00322     }
00323 
00324 
00329     function SetIndexDarkColor($which_color)
00330     {
00331         list ($r, $g, $b) = $this->SetRGBColor($which_color);
00332         if (!isset($r)) return NULL;
00333         $r = max(0, $r - 0x30);
00334         $g = max(0, $g - 0x30);
00335         $b = max(0, $b - 0x30);
00336         return ImageColorResolve($this->img, $r, $g, $b);
00337     }
00338 
00347     function SetDefaultStyles()
00348     {
00349         /* Some of the Set*() functions use default values when they get no parameters. */
00350 
00351         if (! isset($this->session_set)) {
00352             // If sessions are enabled, this variable will be preserved, so upon future executions, we
00353             // will have it set, as well as color names (though not color indices, that's why we
00354             // need to rebuild them)
00355             $this->session_set = TRUE;
00356 
00357             // These only need to be set once
00358             $this->SetLineWidths();
00359             $this->SetLineStyles();
00360             $this->SetDefaultDashedStyle($this->dashed_style);
00361             $this->SetPointSizes($this->point_sizes);
00362         }
00363 
00364         $this->SetImageBorderColor($this->i_border);
00365         $this->SetPlotBgColor($this->plot_bg_color);
00366         $this->SetBackgroundColor($this->bg_color);
00367         $this->SetLabelColor($this->label_color);
00368         $this->SetTextColor($this->text_color);
00369         $this->SetGridColor($this->grid_color);
00370         $this->SetLightGridColor($this->light_grid_color);
00371         $this->SetTickColor($this->tick_color);
00372         $this->SetTitleColor($this->title_color);
00373         $this->SetDataColors();
00374         $this->SetErrorBarColors();
00375         $this->SetDataBorderColors();
00376         return TRUE;
00377     }
00378 
00379 
00380     /*
00381      *
00382      */
00383     function SetBackgroundColor($which_color)
00384     {
00385         $this->bg_color= $which_color;
00386         $this->ndx_bg_color= $this->SetIndexColor($this->bg_color);
00387         return isset($this->ndx_bg_color);
00388     }
00389 
00390     /*
00391      *
00392      */
00393     function SetPlotBgColor($which_color)
00394     {
00395         $this->plot_bg_color= $which_color;
00396         $this->ndx_plot_bg_color= $this->SetIndexColor($this->plot_bg_color);
00397         return isset($this->ndx_plot_bg_color);
00398     }
00399 
00400    /*
00401     *
00402     */
00403     function SetTitleColor($which_color)
00404     {
00405         $this->title_color= $which_color;
00406         $this->ndx_title_color= $this->SetIndexColor($this->title_color);
00407         return isset($this->ndx_title_color);
00408     }
00409 
00410     /*
00411      *
00412      */
00413     function SetTickColor ($which_color)
00414     {
00415         $this->tick_color= $which_color;
00416         $this->ndx_tick_color= $this->SetIndexColor($this->tick_color);
00417         return isset($this->ndx_tick_color);
00418     }
00419 
00420 
00421     /*
00422      * Do not use. Use SetTitleColor instead.
00423      */
00424     function SetLabelColor ($which_color)
00425     {
00426         $this->label_color = $which_color;
00427         $this->ndx_title_color= $this->SetIndexColor($this->label_color);
00428         return isset($this->ndx_title_color);
00429     }
00430 
00431 
00432     /*
00433      *
00434      */
00435     function SetTextColor ($which_color)
00436     {
00437         $this->text_color= $which_color;
00438         $this->ndx_text_color= $this->SetIndexColor($this->text_color);
00439         return isset($this->ndx_text_color);
00440     }
00441 
00442 
00443     /*
00444      *
00445      */
00446     function SetLightGridColor ($which_color)
00447     {
00448         $this->light_grid_color= $which_color;
00449         $this->ndx_light_grid_color= $this->SetIndexColor($this->light_grid_color);
00450         return isset($this->ndx_light_grid_color);
00451     }
00452 
00453 
00454     /*
00455      *
00456      */
00457     function SetGridColor ($which_color)
00458     {
00459         $this->grid_color = $which_color;
00460         $this->ndx_grid_color= $this->SetIndexColor($this->grid_color);
00461         return isset($this->ndx_grid_color);
00462     }
00463 
00464 
00465     /*
00466      *
00467      */
00468     function SetImageBorderColor($which_color)
00469     {
00470         $this->i_border = $which_color;
00471         $this->ndx_i_border = $this->SetIndexColor($this->i_border);
00472         $this->ndx_i_border_dark = $this->SetIndexDarkColor($this->i_border);
00473         return isset($this->ndx_i_border);
00474     }
00475 
00476 
00477     /*
00478      *
00479      */
00480     function SetTransparentColor($which_color)
00481     {
00482         $ndx = $this->SetIndexColor($which_color);
00483         if (!isset($ndx))
00484             return FALSE;
00485         ImageColorTransparent($this->img, $ndx);
00486         return TRUE;
00487     }
00488 
00489 
00497     function SetRGBArray ($which_color_array)
00498     {
00499         if ( is_array($which_color_array) ) {           // User defined array
00500             $this->rgb_array = $which_color_array;
00501             return TRUE;
00502         } elseif ($which_color_array == 'small') {      // Small predefined color array
00503             $this->rgb_array = array(
00504                 'white'          => array(255, 255, 255),
00505                 'snow'           => array(255, 250, 250),
00506                 'PeachPuff'      => array(255, 218, 185),
00507                 'ivory'          => array(255, 255, 240),
00508                 'lavender'       => array(230, 230, 250),
00509                 'black'          => array(  0,   0,   0),
00510                 'DimGrey'        => array(105, 105, 105),
00511                 'gray'           => array(190, 190, 190),
00512                 'grey'           => array(190, 190, 190),
00513                 'navy'           => array(  0,   0, 128),
00514                 'SlateBlue'      => array(106,  90, 205),
00515                 'blue'           => array(  0,   0, 255),
00516                 'SkyBlue'        => array(135, 206, 235),
00517                 'cyan'           => array(  0, 255, 255),
00518                 'DarkGreen'      => array(  0, 100,   0),
00519                 'green'          => array(  0, 255,   0),
00520                 'YellowGreen'    => array(154, 205,  50),
00521                 'yellow'         => array(255, 255,   0),
00522                 'orange'         => array(255, 165,   0),
00523                 'gold'           => array(255, 215,   0),
00524                 'peru'           => array(205, 133,  63),
00525                 'beige'          => array(245, 245, 220),
00526                 'wheat'          => array(245, 222, 179),
00527                 'tan'            => array(210, 180, 140),
00528                 'brown'          => array(165,  42,  42),
00529                 'salmon'         => array(250, 128, 114),
00530                 'red'            => array(255,   0,   0),
00531                 'pink'           => array(255, 192, 203),
00532                 'maroon'         => array(176,  48,  96),
00533                 'magenta'        => array(255,   0, 255),
00534                 'violet'         => array(238, 130, 238),
00535                 'plum'           => array(221, 160, 221),
00536                 'orchid'         => array(218, 112, 214),
00537                 'purple'         => array(160,  32, 240),
00538                 'azure1'         => array(240, 255, 255),
00539                 'aquamarine1'    => array(127, 255, 212)
00540                 );
00541             return TRUE;
00542         } elseif ($which_color_array === 'large')  {    // Large color array
00543             include("./rgb.inc.php");
00544             $this->rgb_array = $RGBArray;
00545         } else {                                        // Default to black and white only.
00546             $this->rgb_array = array('white' => array(255, 255, 255), 'black' => array(0, 0, 0));
00547         }
00548 
00549         return TRUE;
00550     }
00551 
00557     function SetRGBColor($color_asked)
00558     {
00559         if (empty($color_asked)) {
00560             $ret_val = array(0, 0, 0);
00561         } elseif (count($color_asked) == 3 ) {    // already array of 3 rgb
00562             $ret_val = $color_asked;
00563         } elseif ($color_asked[0] == '#') {       // Hex RGB notation #RRGGBB
00564             $ret_val = array(hexdec(substr($color_asked, 1, 2)),
00565                              hexdec(substr($color_asked, 3, 2)),
00566                              hexdec(substr($color_asked, 5, 2)));
00567 
00568         } elseif (isset($this->rgb_array[$color_asked])) {  // Color by name
00569             $ret_val = $this->rgb_array[$color_asked];
00570         } else {
00571             return $this->PrintError("SetRGBColor(): Color '$color_asked' is not valid.");
00572         }
00573         return $ret_val;
00574     }
00575 
00576 
00580     function SetDataColors($which_data = NULL, $which_border = NULL)
00581     {
00582         if (is_null($which_data) && is_array($this->data_colors)) {
00583             // use already set data_colors
00584         } else if (! is_array($which_data)) {
00585             $this->data_colors = ($which_data) ? array($which_data) : array('blue', 'red', 'green', 'orange');
00586         } else {
00587             $this->data_colors = $which_data;
00588         }
00589 
00590         $i = 0;
00591         foreach ($this->data_colors as $col) {
00592             $ndx = $this->SetIndexColor($col);
00593             if (!isset($ndx))
00594                 return FALSE;
00595             $this->ndx_data_colors[$i] = $ndx;
00596             $this->ndx_data_dark_colors[$i] = $this->SetIndexDarkColor($col);
00597             $i++;
00598         }
00599 
00600         // For past compatibility:
00601         return $this->SetDataBorderColors($which_border);
00602     } // function SetDataColors()
00603 
00604 
00608     function SetDataBorderColors($which_br = NULL)
00609     {
00610         if (is_null($which_br) && is_array($this->data_border_colors)) {
00611             // use already set data_border_colors
00612         } else if (! is_array($which_br)) {
00613             // Create new array with specified color
00614             $this->data_border_colors = ($which_br) ? array($which_br) : array('black');
00615         } else {
00616             $this->data_border_colors = $which_br;
00617         }
00618 
00619         $i = 0;
00620         foreach($this->data_border_colors as $col) {
00621             $ndx = $this->SetIndexColor($col);
00622             if (!isset($ndx))
00623                 return FALSE;
00624             $this->ndx_data_border_colors[$i] = $ndx;
00625             $i++;
00626         }
00627         return TRUE;
00628     } // function SetDataBorderColors()
00629 
00630 
00634     function SetErrorBarColors($which_err = NULL)
00635     {
00636         if (is_null($which_err) && is_array($this->error_bar_colors)) {
00637             // use already set error_bar_colors
00638         } else if (! is_array($which_err)) {
00639             $this->error_bar_colors = ($which_err) ? array($which_err) : array('black');
00640         } else {
00641             $this->error_bar_colors = $which_err;
00642         }
00643 
00644         $i = 0;
00645         foreach($this->error_bar_colors as $col) {
00646             $ndx = $this->SetIndexColor($col);
00647             if (!isset($ndx))
00648                 return FALSE;
00649             $this->ndx_error_bar_colors[$i] = $ndx;
00650             $i++;
00651         }
00652         return TRUE;
00653     } // function SetErrorBarColors()
00654 
00655 
00662     function SetDefaultDashedStyle($which_style)
00663     {
00664         // String: "numcol-numtrans-numcol-numtrans..."
00665         $asked = explode('-', $which_style);
00666 
00667         if (count($asked) < 2) {
00668             return $this->PrintError("SetDefaultDashedStyle(): Wrong parameter '$which_style'.");
00669         }
00670 
00671         // Build the string to be eval()uated later by SetDashedStyle()
00672         $this->default_dashed_style = 'array( ';
00673 
00674         $t = 0;
00675         foreach($asked as $s) {
00676             if ($t % 2 == 0) {
00677                 $this->default_dashed_style .= str_repeat('$which_ndxcol,', $s);
00678             } else {
00679                 $this->default_dashed_style .= str_repeat('IMG_COLOR_TRANSPARENT,', $s);
00680             }
00681             $t++;
00682         }
00683         // Remove trailing comma and add closing parenthesis
00684         $this->default_dashed_style = substr($this->default_dashed_style, 0, -1);
00685         $this->default_dashed_style .= ')';
00686 
00687         return TRUE;
00688     }
00689 
00690 
00695     function SetDashedStyle($which_ndxcol)
00696     {
00697         // See SetDefaultDashedStyle() to understand this.
00698         eval ("\$style = $this->default_dashed_style;");
00699         return imagesetstyle($this->img, $style);
00700     }
00701 
00702 
00706     function SetLineWidths($which_lw=NULL)
00707     {
00708         if (is_null($which_lw)) {
00709             // Do nothing, use default value.
00710         } else if (is_array($which_lw)) {
00711             // Did we get an array with line widths?
00712             $this->line_widths = $which_lw;
00713         } else {
00714             $this->line_widths = array($which_lw);
00715         }
00716         return TRUE;
00717     }
00718 
00722     function SetLineStyles($which_ls=NULL)
00723     {
00724         if (is_null($which_ls)) {
00725             // Do nothing, use default value.
00726         } else if ( is_array($which_ls)) {
00727             // Did we get an array with line styles?
00728             $this->line_styles = $which_ls;
00729         } else {
00730             $this->line_styles = ($which_ls) ? array($which_ls) : array('solid');
00731         }
00732         return TRUE;
00733     }
00734 
00735 
00739 
00740 
00744     function SetLineSpacing($which_spc)
00745     {
00746         $this->line_spacing = $which_spc;
00747         return TRUE;
00748     }
00749 
00750 
00756     function SetUseTTF($which_ttf)
00757     {
00758         $this->use_ttf = $which_ttf;
00759         return $this->SetDefaultFonts();
00760     }
00761 
00765     function SetTTFPath($which_path)
00766     {
00767         // Maybe someone needs really dynamic config. He'll need this:
00768         // clearstatcache();
00769 
00770         if (is_dir($which_path) && is_readable($which_path)) {
00771             $this->ttf_path = $which_path;
00772             return TRUE;
00773         }
00774         return $this->PrintError("SetTTFPath(): $which_path is not a valid path.");
00775     }
00776 
00783     function SetDefaultTTFont($which_font)
00784     {
00785         $this->default_ttfont = $which_font;
00786         return $this->SetUseTTF(TRUE);
00787     }
00788 
00792     function SetDefaultFonts()
00793     {
00794         // TTF:
00795         if ($this->use_ttf) {
00796             return $this->SetFont('generic', '', 8)
00797                 && $this->SetFont('title', '', 14)
00798                 && $this->SetFont('legend', '', 8)
00799                 && $this->SetFont('x_label', '', 6)
00800                 && $this->SetFont('y_label', '', 6)
00801                 && $this->SetFont('x_title', '', 10)
00802                 && $this->SetFont('y_title', '', 10);
00803         }
00804         // Fixed GD Fonts:
00805         return $this->SetFont('generic', 2)
00806             && $this->SetFont('title', 5)
00807             && $this->SetFont('legend', 2)
00808             && $this->SetFont('x_label', 1)
00809             && $this->SetFont('y_label', 1)
00810             && $this->SetFont('x_title', 3)
00811             && $this->SetFont('y_title', 3);
00812     }
00813 
00825     function SetFont($which_elem, $which_font, $which_size = 12)
00826     {
00827         // TTF:
00828         if ($this->use_ttf) {
00829             // Empty font name means use the default font.
00830             if (empty($which_font))
00831                 $which_font = $this->default_ttfont;
00832             $path = $which_font;
00833 
00834             // First try the font name directly, if not then try with path.
00835             if (!is_file($path) || !is_readable($path)) {
00836                 $path = $this->ttf_path . '/' . $which_font;
00837                 if (!is_file($path) || !is_readable($path)) {
00838                     return $this->PrintError("SetFont(): Can't find TrueType font $which_font");
00839                 }
00840             }
00841 
00842             switch ($which_elem) {
00843             case 'generic':
00844                 $this->generic_font['font'] = $path;
00845                 $this->generic_font['size'] = $which_size;
00846                 break;
00847             case 'title':
00848                 $this->title_font['font'] = $path;
00849                 $this->title_font['size'] = $which_size;
00850                 break;
00851             case 'legend':
00852                 $this->legend_font['font'] = $path;
00853                 $this->legend_font['size'] = $which_size;
00854                 break;
00855             case 'x_label':
00856                 $this->x_label_font['font'] = $path;
00857                 $this->x_label_font['size'] = $which_size;
00858                 break;
00859             case 'y_label':
00860                 $this->y_label_font['font'] = $path;
00861                 $this->y_label_font['size'] = $which_size;
00862                 break;
00863             case 'x_title':
00864                 $this->x_title_font['font'] = $path;
00865                 $this->x_title_font['size'] = $which_size;
00866                 break;
00867             case 'y_title':
00868                 $this->y_title_font['font'] = $path;
00869                 $this->y_title_font['size'] = $which_size;
00870                 break;
00871             default:
00872                 return $this->PrintError("SetFont(): Unknown element '$which_elem' specified.");
00873             }
00874             return TRUE;
00875 
00876         }
00877 
00878         // Fixed fonts:
00879         if ($which_font > 5 || $which_font < 0) {
00880             return $this->PrintError('SetFont(): Non-TTF font size must be 1, 2, 3, 4 or 5');
00881         }
00882 
00883         switch ($which_elem) {
00884         case 'generic':
00885             $this->generic_font['font'] = $which_font;
00886             $this->generic_font['height'] = ImageFontHeight($which_font);
00887             $this->generic_font['width'] = ImageFontWidth($which_font);
00888             break;
00889         case 'title':
00890            $this->title_font['font'] = $which_font;
00891            $this->title_font['height'] = ImageFontHeight($which_font);
00892            $this->title_font['width'] = ImageFontWidth($which_font);
00893            break;
00894         case 'legend':
00895             $this->legend_font['font'] = $which_font;
00896             $this->legend_font['height'] = ImageFontHeight($which_font);
00897             $this->legend_font['width'] = ImageFontWidth($which_font);
00898             break;
00899         case 'x_label':
00900             $this->x_label_font['font'] = $which_font;
00901             $this->x_label_font['height'] = ImageFontHeight($which_font);
00902             $this->x_label_font['width'] = ImageFontWidth($which_font);
00903             break;
00904         case 'y_label':
00905             $this->y_label_font['font'] = $which_font;
00906             $this->y_label_font['height'] = ImageFontHeight($which_font);
00907             $this->y_label_font['width'] = ImageFontWidth($which_font);
00908             break;
00909         case 'x_title':
00910             $this->x_title_font['font'] = $which_font;
00911             $this->x_title_font['height'] = ImageFontHeight($which_font);
00912             $this->x_title_font['width'] = ImageFontWidth($which_font);
00913             break;
00914         case 'y_title':
00915             $this->y_title_font['font'] = $which_font;
00916             $this->y_title_font['height'] = ImageFontHeight($which_font);
00917             $this->y_title_font['width'] = ImageFontWidth($which_font);
00918             break;
00919         default:
00920             return $this->PrintError("SetFont(): Unknown element '$which_elem' specified.");
00921         }
00922         return TRUE;
00923     }
00924 
00988     /*
00989      * ProcessTextGD() - Draw or size GD fixed-font text.
00990      * This is intended for use only by ProcessText().
00991      *    $draw_it : True to draw the text, False to just return the orthogonal width and height.
00992      *    $font_number : GD font number, 1-5.
00993      *    $font_width : Fixed character cell width for the font
00994      *    $font_height : Fixed character cell height for the font
00995      *    $angle : Text angle in degrees. GD only supports 0 and 90. We treat >= 45 as 90, else 0.
00996      *    $x, $y : Reference point for the text (ignored if !$draw_it)
00997      *    $color : GD color index to use for drawing the text (ignored if !$draw_it)
00998      *    $text : The text to draw or size. Put a newline between lines.
00999      *    $h_factor : Horizontal alignment factor: 0(left), .5(center), or 1(right) (ignored if !$draw_it)
01000      *    $v_factor : Vertical alignment factor: 0(top), .5(center), or 1(bottom) (ignored if !$draw_it)
01001      * Returns: True, if drawing text, or an array of ($width, $height) if not.
01002      */
01003     function ProcessTextGD($draw_it, $font_number, $font_width, $font_height, $angle, $x, $y, $color,
01004                            $text, $h_factor, $v_factor)
01005     {
01006         # Break up the text into lines, trim whitespace, find longest line.
01007         # Save the lines and length for drawing below.
01008         $longest = 0;
01009         foreach (explode("\n", $text) as $each_line) {
01010             $lines[] = $line = trim($each_line);
01011             $line_lens[] = $line_len = strlen($line);
01012             if ($line_len > $longest) $longest = $line_len;
01013         }
01014         $n_lines = count($lines);
01015         $spacing = $this->line_spacing * ($n_lines - 1); // Total inter-line spacing
01016 
01017         # Width, height are based on font size and longest line, line count respectively.
01018         # These are relative to the text angle.
01019         $total_width = $longest * $font_width;
01020         $total_height = $n_lines * $font_height + $spacing;
01021 
01022         if (!$draw_it) {
01023             if ($angle < 45) return array($total_width, $total_height);
01024             return array($total_height, $total_width);
01025         }
01026 
01027         $interline_step = $font_height + $this->line_spacing; // Line-to-line step
01028 
01029         if ($angle >= 45) {
01030             // Vertical text (90 degrees):
01031             // (Remember the alignment convention with vertical text)
01032             // For 90 degree text, alignment factors change like this:
01033             $temp = $v_factor;
01034             $v_factor = $h_factor;
01035             $h_factor = 1 - $temp;
01036 
01037             $draw_func = 'ImageStringUp';
01038 
01039             // Rotation matrix "R" for 90 degrees (with Y pointing down):
01040             $r00 = 0;  $r01 = 1;
01041             $r10 = -1; $r11 = 0;
01042 
01043         } else {
01044             // Horizontal text (0 degrees):
01045             $draw_func = 'ImageString';
01046 
01047             // Rotation matrix "R" for 0 degrees:
01048             $r00 = 1; $r01 = 0;
01049             $r10 = 0; $r11 = 1;
01050         }
01051 
01052         // Adjust for vertical alignment (horizontal text) or horizontal aligment (vertical text):
01053         $factor = (int)($total_height * $v_factor);
01054         $xpos = $x - $r01 * $factor;
01055         $ypos = $y - $r11 * $factor;
01056 
01057         # Debug callback provides the bounding box:
01058         if ($this->GetCallback('debug_textbox')) {
01059             if ($angle >= 45) {
01060                 $bbox_width  = $total_height;
01061                 $bbox_height = $total_width;
01062                 $px = $xpos;
01063                 $py = $ypos - (1 - $h_factor) * $total_width;
01064             } else {
01065                 $bbox_width  = $total_width;
01066                 $bbox_height = $total_height;
01067                 $px = $xpos - $h_factor * $total_width;
01068                 $py = $ypos;
01069             }
01070             $this->DoCallback('debug_textbox', $px, $py, $bbox_width, $bbox_height);
01071         }
01072 
01073         for ($i = 0; $i < $n_lines; $i++) {
01074 
01075             $line = $lines[$i];
01076             $line_len = $line_lens[$i];
01077 
01078             // Adjust for alignment of this line within the text block:
01079             $factor = (int)($line_len * $font_width * $h_factor);
01080             $x = $xpos - $r00 * $factor;
01081             $y = $ypos - $r10 * $factor;
01082 
01083             // Call ImageString or ImageStringUp:
01084             $draw_func($this->img, $font_number, $x, $y, $line, $color);
01085 
01086             // Step to the next line of text. This is a rotation of (x=0, y=interline_spacing)
01087             $xpos += $r01 * $interline_step;
01088             $ypos += $r11 * $interline_step;
01089         }
01090         return TRUE;
01091     }
01092 
01093 
01094     /*
01095      * ProcessTextTTF() - Draw or size TTF text.
01096      * This is intended for use only by ProcessText().
01097      *    $draw_it : True to draw the text, False to just return the orthogonal width and height.
01098      *    $font_file : Path or filename to a TTF font file.
01099      *    $font_size : Font size in "points".
01100      *    $angle : Text angle in degrees.
01101      *    $x, $y : Reference point for the text (ignored if !$draw_it)
01102      *    $color : GD color index to use for drawing the text (ignored if !$draw_it)
01103      *    $text : The text to draw or size. Put a newline between lines.
01104      *    $h_factor : Horizontal alignment factor: 0(left), .5(center), or 1(right) (ignored if !$draw_it)
01105      *    $v_factor : Vertical alignment factor: 0(top), .5(center), or 1(bottom) (ignored if !$draw_it)
01106      * Returns: True, if drawing text, or an array of ($width, $height) if not.
01107      */
01108     function ProcessTextTTF($draw_it, $font_file, $font_size, $angle, $x, $y, $color,
01109                             $text, $h_factor, $v_factor)
01110     {
01111         # Break up the text into lines, trim whitespace.
01112         # Calculate the total width and height of the text box at 0 degrees.
01113         # This has to be done line-by-line so the interline-spacing is right.
01114         # Save the trimmed line, and its 0-degree height and width for later
01115         # when the text is drawn.
01116         # Note: Total height = sum of each line height plus inter-line spacing
01117         #   (which is added after the loop). Total width = width of widest line.
01118         $total_height = 0;
01119         $total_width = 0;
01120         foreach (explode("\n", $text) as $each_line) {
01121             $lines[] = $line = trim($each_line);
01122             $bbox = ImageTTFBBox($font_size, 0, $font_file, $line);
01123             $height = $bbox[1] - $bbox[5];
01124             $width = $bbox[2] - $bbox[0];
01125             $total_height += $height;
01126             if ($width > $total_width) $total_width = $width;
01127             $line_widths[] = $width;
01128             $line_heights[] = $height;
01129         }
01130         $n_lines = count($lines);
01131         $total_height += ($n_lines - 1) * $this->line_spacing;
01132 
01133         # Calculate the rotation matrix for the text's angle. Remember that GD points Y down,
01134         # so the sin() terms change sign.
01135         $theta = deg2rad($angle);
01136         $cos_t = cos($theta);
01137         $sin_t = sin($theta);
01138         $r00 = $cos_t;    $r01 = $sin_t;
01139         $r10 = -$sin_t;   $r11 = $cos_t;
01140 
01141         # Make a bounding box of the right size, with upper left corner at (0,0).
01142         # By convention, the point order is: LL, LR, UR, UL.
01143         # Note this is still working with the text at 0 degrees.
01144         $b[0] = 0;             $b[1] = $total_height;
01145         $b[2] = $total_width;  $b[3] = $b[1];
01146         $b[4] = $b[2];         $b[5] = 0;
01147         $b[6] = $b[0];         $b[7] = $b[5];
01148 
01149         # Rotate the bounding box, then offset to the reference point:
01150         for ($i = 0; $i < 8; $i += 2) {
01151             $x_b = $b[$i];
01152             $y_b = $b[$i+1];
01153             $c[$i]   = $x + $r00 * $x_b + $r01 * $y_b;
01154             $c[$i+1] = $y + $r10 * $x_b + $r11 * $y_b;
01155         }
01156 
01157         # Get an orthogonal (aligned with X and Y axes) bounding box around it, by
01158         # finding the min and max X and Y:
01159         $bbox_ref_x = $bbox_max_x = $c[0];
01160         $bbox_ref_y = $bbox_max_y = $c[1];
01161         for ($i = 2; $i < 8; $i += 2) {
01162             $x_b = $c[$i];
01163             if ($x_b < $bbox_ref_x) $bbox_ref_x = $x_b; elseif ($bbox_max_x < $x_b) $bbox_max_x = $x_b;
01164             $y_b = $c[$i+1];
01165             if ($y_b < $bbox_ref_y) $bbox_ref_y = $y_b; elseif ($bbox_max_y < $y_b) $bbox_max_y = $y_b;
01166         }
01167         $bbox_width = $bbox_max_x - $bbox_ref_x;
01168         $bbox_height = $bbox_max_y - $bbox_ref_y;
01169 
01170         if (!$draw_it) {
01171             # Return the bounding box, rounded up (so it always contains the text):
01172             return array((int)ceil($bbox_width), (int)ceil($bbox_height));
01173         }
01174 
01175         # Calculate the offsets from the supplied reference point to the
01176         # required upper-left corner of the text.
01177         # Start at the reference point at the upper left corner of the bounding
01178         # box (bbox_ref_x, bbox_ref_y) then adjust it for the 9 point alignment.
01179         # h,v_factor are 0,0 for top,left, .5,.5 for center,center, 1,1 for bottom,right.
01180         #    $off_x = $bbox_ref_x + $bbox_width * $h_factor - $x;
01181         #    $off_y = $bbox_ref_y + $bbox_height * $v_factor - $y;
01182         # Then use that offset to calculate back to the supplied reference point x, y
01183         # to get the text base point.
01184         #    $qx = $x - $off_x;
01185         #    $qy = $y - $off_y;
01186         # Reduces to:
01187         $qx = 2 * $x - $bbox_ref_x - $bbox_width * $h_factor;
01188         $qy = 2 * $y - $bbox_ref_y - $bbox_height * $v_factor;
01189 
01190         # Check for debug callback. Don't calculate bounding box unless it is wanted.
01191         if ($this->GetCallback('debug_textbox')) {
01192             # Calculate the orthogonal bounding box coordinates for debug testing.
01193 
01194             # qx, qy is upper left corner relative to the text.
01195             # Calculate px,py: upper left corner (absolute) of the bounding box.
01196             # There are 4 equation sets for this, depending on the quadrant:
01197             if ($sin_t > 0) {
01198                 if ($cos_t > 0) {
01199                     # Quadrant: 0d - 90d:
01200                     $px = $qx; $py = $qy - $total_width * $sin_t;
01201                 } else {
01202                     # Quadrant: 90d - 180d:
01203                    $px = $qx + $total_width * $cos_t; $py = $qy - $bbox_height;
01204                 }
01205             } else {
01206                 if ($cos_t < 0) {
01207                     # Quadrant: 180d - 270d:
01208                     $px = $qx - $bbox_width; $py = $qy + $total_height * $cos_t;
01209                 } else {
01210                     # Quadrant: 270d - 360d:
01211                     $px = $qx + $total_height * $sin_t; $py = $qy;
01212                 }
01213             }
01214             $this->DoCallback('debug_textbox', $px, $py, $bbox_width, $bbox_height);
01215         }
01216 
01217         # Since alignment is applied after rotation, which parameter is used
01218         # to control alignment of each line within the text box varies with
01219         # the angle.
01220         #   Angle (degrees):       Line alignment controlled by:
01221         #  -45 < angle <= 45          h_align
01222         #   45 < angle <= 135         reversed v_align
01223         #  135 < angle <= 225         reversed h_align
01224         #  225 < angle <= 315         v_align
01225         if ($cos_t >= $sin_t) {
01226             if ($cos_t >= -$sin_t) $line_align_factor = $h_factor;
01227             else $line_align_factor = $v_factor;
01228         } else {
01229             if ($cos_t >= -$sin_t) $line_align_factor = 1-$v_factor;
01230             else $line_align_factor = 1-$h_factor;
01231         }
01232 
01233         # Now we have the start point, spacing and in-line alignment factor.
01234         # We are finally ready to start drawing the text, line by line.
01235         for ($i = 0; $i < $n_lines; $i++) {
01236             $line = $lines[$i];
01237             # These are height and width at 0 degrees, calculated above:
01238             $height = $line_heights[$i];
01239             $width = $line_widths[$i];
01240 
01241             # For drawing TTF text, the lower left corner is the base point.
01242             # The adjustment is inside the loop, since lines can have different
01243             # heights. The following also adjusts for horizontal (relative to
01244             # the text) alignment of the current line within the box.
01245             # What is happening is rotation of this vector by the text angle:
01246             #    (x = (total_width - line_width) * factor, y = line_height)
01247 
01248             $width_factor = ($total_width - $width) * $line_align_factor;
01249             $rx = $qx + $r00 * $width_factor + $r01 * $height;
01250             $ry = $qy + $r10 * $width_factor + $r11 * $height;
01251 
01252             # Finally, draw the text:
01253             ImageTTFText($this->img, $font_size, $angle, $rx, $ry, $color, $font_file, $line);
01254 
01255             # Step to position of next line.
01256             # This is a rotation of (x=0,y=text_height+line_height) by $angle:
01257             $interline_step = $this->line_spacing + $height;
01258             $qx += $r01 * $interline_step;
01259             $qy += $r11 * $interline_step;
01260         }
01261         return True;
01262     }
01263 
01264     /*
01265      * ProcessText() - Wrapper for ProcessTextTTF() and ProcessTextGD(). See notes above.
01266      * This is intended for use from within PHPlot only, and only by DrawText() and SizeText().
01267      *    $draw_it : True to draw the text, False to just return the orthogonal width and height.
01268      *    $font : PHPlot font array. (Contents depend on use_ttf flag).
01269      *    $angle : Text angle in degrees
01270      *    $x, $y : Reference point for the text (ignored if !$draw_it)
01271      *    $color : GD color index to use for drawing the text (ignored if !$draw_it)
01272      *    $text : The text to draw or size. Put a newline between lines.
01273      *    $halign : Horizontal alignment: left, center, or right (ignored if !$draw_it)
01274      *    $valign : Vertical alignment: top, center, or bottom (ignored if !$draw_it)
01275      *      Note: Alignment is relative to the image, not the text.
01276      * Returns: True, if drawing text, or an array of ($width, $height) if not.
01277      */
01278     function ProcessText($draw_it, $font, $angle, $x, $y, $color, $text, $halign, $valign)
01279     {
01280         # Empty text case:
01281         if ($text === '') {
01282             if ($draw_it) return TRUE;
01283             return array(0, 0);
01284         }
01285 
01286         # Calculate width and height offset factors using the alignment args:
01287         if ($valign == 'top') $v_factor = 0;
01288         elseif ($valign == 'center') $v_factor = 0.5;
01289         else $v_factor = 1.0; # 'bottom'
01290         if ($halign == 'left') $h_factor = 0;
01291         elseif ($halign == 'center') $h_factor = 0.5;
01292         else $h_factor = 1.0; # 'right'
01293 
01294         if ($this->use_ttf) {
01295             return $this->ProcessTextTTF($draw_it, $font['font'], $font['size'],
01296                                          $angle, $x, $y, $color, $text, $h_factor, $v_factor);
01297         }
01298 
01299         return $this->ProcessTextGD($draw_it, $font['font'], $font['width'], $font['height'],
01300                                     $angle, $x, $y, $color, $text, $h_factor, $v_factor);
01301     }
01302 
01303 
01304     /*
01305      * Draws a block of text. See comments above before ProcessText().
01306      *    $which_font : PHPlot font array. (Contents depend on use_ttf flag).
01307      *    $which_angle : Text angle in degrees
01308      *    $which_xpos, $which_ypos: Reference point for the text
01309      *    $which_color : GD color index to use for drawing the text
01310      *    $which_text :  The text to draw, with newlines (\n) between lines.
01311      *    $which_halign : Horizontal (relative to the image) alignment: left, center, or right.
01312      *    $which_valign : Vertical (relative to the image) alignment: top, center, or bottom.
01313      */
01314     function DrawText($which_font, $which_angle, $which_xpos, $which_ypos, $which_color, $which_text,
01315                       $which_halign = 'left', $which_valign = 'bottom')
01316     {
01317         return $this->ProcessText(True,
01318                            $which_font, $which_angle, $which_xpos, $which_ypos,
01319                            $which_color, $which_text, $which_halign, $which_valign);
01320     }
01321 
01322     /*
01323      * Returns the size of block of text. This is the orthogonal width and height of a bounding
01324      * box aligned with the X and Y axes of the text. Only for angle=0 is this the actual
01325      * width and height of the text block, but for any angle it is the amount of space needed
01326      * to contain the text.
01327      *    $which_font : PHPlot font array. (Contents depend on use_ttf flag).
01328      *    $which_angle : Text angle in degrees
01329      *    $which_text :  The text to draw, with newlines (\n) between lines.
01330      * Returns a two element array with: $width, $height.
01331      * This is just a wrapper for ProcessText() - see above.
01332      */
01333     function SizeText($which_font, $which_angle, $which_text)
01334     {
01335         // Color, position, and alignment are not used when calculating the size.
01336         return $this->ProcessText(False,
01337                            $which_font, $which_angle, 0, 0, 1, $which_text, '', '');
01338     }
01339 
01340 
01344 
01348     function SetFileFormat($format)
01349     {
01350         $asked = $this->CheckOption($format, 'jpg, png, gif, wbmp', __FUNCTION__);
01351         if (!$asked) return False;
01352         switch ($asked) {
01353         case 'jpg':
01354             $format_test = IMG_JPG;
01355             break;
01356         case 'png':
01357             $format_test = IMG_PNG;
01358             break;
01359         case 'gif':
01360             $format_test = IMG_GIF;
01361             break;
01362         case 'wbmp':
01363             $format_test = IMG_WBMP;
01364             break;
01365         }
01366         if (!(imagetypes() & $format_test)) {
01367             return $this->PrintError("SetFileFormat(): File format '$format' not supported");
01368         }
01369         $this->file_format = $asked;
01370         return TRUE;
01371     }
01372 
01373 
01380     function SetBgImage($input_file, $mode='centeredtile')
01381     {
01382         $this->bgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
01383         $this->bgimg  = $input_file;
01384         return (boolean)$this->bgmode;
01385     }
01386 
01393     function SetPlotAreaBgImage($input_file, $mode='tile')
01394     {
01395         $this->plotbgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
01396         $this->plotbgimg  = $input_file;
01397         return (boolean)$this->plotbgmode;
01398     }
01399 
01400 
01404     function SetOutputFile($which_output_file)
01405     {
01406         $this->output_file = $which_output_file;
01407         return TRUE;
01408     }
01409 
01414     function SetIsInline($which_ii)
01415     {
01416         $this->is_inline = (bool)$which_ii;
01417         return TRUE;
01418     }
01419 
01420 
01424     function PrintImage()
01425     {
01426         // Browser cache stuff submitted by Thiemo Nagel
01427         if ( (! $this->browser_cache) && (! $this->is_inline)) {
01428             header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
01429             header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');
01430             header('Cache-Control: no-cache, must-revalidate');
01431             header('Pragma: no-cache');
01432         }
01433 
01434         switch($this->file_format) {
01435         case 'png':
01436             if (! $this->is_inline) {
01437                 Header('Content-type: image/png');
01438             }
01439             if ($this->is_inline && $this->output_file != '') {
01440                 ImagePng($this->img, $this->output_file);
01441             } else {
01442                 ImagePng($this->img);
01443             }
01444             break;
01445         case 'jpg':
01446             if (! $this->is_inline) {
01447                 Header('Content-type: image/jpeg');
01448             }
01449             if ($this->is_inline && $this->output_file != '') {
01450                 ImageJPEG($this->img, $this->output_file);
01451             } else {
01452                 ImageJPEG($this->img);
01453             }
01454             break;
01455         case 'gif':
01456             if (! $this->is_inline) {
01457                 Header('Content-type: image/gif');
01458             }
01459             if ($this->is_inline && $this->output_file != '') {
01460                 ImageGIF($this->img, $this->output_file);
01461             } else {
01462                 ImageGIF($this->img);
01463             }
01464 
01465             break;
01466         case 'wbmp':        // wireless bitmap, 2 bit.
01467             if (! $this->is_inline) {
01468                 Header('Content-type: image/wbmp');
01469             }
01470             if ($this->is_inline && $this->output_file != '') {
01471                 ImageWBMP($this->img, $this->output_file);
01472             } else {
01473                 ImageWBMP($this->img);
01474             }
01475 
01476             break;
01477         default:
01478             return $this->PrintError('PrintImage(): Please select an image type!');
01479         }
01480         return TRUE;
01481     }
01482 
01506     function PrintError($error_message)
01507     {
01508         // Be sure not to loop recursively, e.g. PrintError - PrintImage - PrintError.
01509         if (isset($this->in_error)) return FALSE;
01510         $this->in_error = TRUE;
01511 
01512         // Output an image containing the error message:
01513         if (!empty($this->img)) {
01514             $ypos = $this->image_height/2;
01515             $xpos = $this->image_width/2;
01516             $bgcolor = ImageColorResolve($this->img, 255, 255, 255);
01517             $fgcolor = ImageColorResolve($this->img, 0, 0, 0);
01518             ImageFilledRectangle($this->img, 0, 0, $this->image_width, $this->image_height, $bgcolor);
01519 
01520             // Switch to built-in fonts, in case of error with TrueType fonts:
01521             $this->SetUseTTF(FALSE);
01522 
01523             $this->DrawText($this->generic_font, 0, $xpos, $ypos, $fgcolor,
01524                             wordwrap($error_message), 'center', 'center');
01525 
01526             $this->PrintImage();
01527         } elseif (! $this->is_inline) {
01528             Header('HTTP/1.0 500 Internal Server Error');
01529         }
01530         trigger_error($error_message, E_USER_ERROR);
01531         unset($this->in_error);
01532         return FALSE;  # In case error handler returns, rather than doing exit().
01533     }
01534 
01541     function DrawError($error_message, $where_x = NULL, $where_y = NULL)
01542     {
01543         return $this->PrintError($error_message);
01544     }
01545 
01549 
01550 
01554     function SetXDataLabelPos($which_xdlp)
01555     {
01556         $which_xdlp = $this->CheckOption($which_xdlp, 'plotdown, plotup, both, xaxis, all, none',
01557                                          __FUNCTION__);
01558         if (!$which_xdlp) return FALSE;
01559         $this->x_data_label_pos = $which_xdlp;
01560         if ($this->x_data_label_pos != 'none')
01561             $this->x_tick_label_pos = 'none';
01562 
01563         return TRUE;
01564     }
01565 
01571     function SetYDataLabelPos($which_ydlp, $which_distance_from_point=0)
01572     {
01573         $which_ydlp = $this->CheckOption($which_ydlp, 'plotleft, plotright, both, yaxis, all, plotin, none',
01574                                           __FUNCTION__);
01575         if (!$which_ydlp) return FALSE;
01576         $this->y_data_label_pos = $which_ydlp;
01577         //This bit in SetYDataLabelPos about plotleft is for those who were 
01578         //using this function to set SetYTickLabelPos.
01579         if ( ($which_ydlp == 'plotleft') || ($which_ydlp == 'plotright') || 
01580              ($which_ydlp == 'both') || ($which_ydlp == 'yaxis') ) { 
01581 
01582             //Call sety_TICK_labelpos instead of sety_DATA_labelpos
01583             $this->SetYTickLabelPos($which_ydlp);
01584 
01585         } elseif ($which_ydlp != 'none') { 
01586             //right now its plotin or none
01587             $this->y_data_label_pos = 'plotin';
01588         }
01589 
01590         return TRUE;
01591     }
01592 
01593 
01597     function SetXTickLabelPos($which_xtlp)
01598     {
01599         $which_xtlp = $this->CheckOption($which_xtlp, 'plotdown, plotup, both, xaxis, all, none',
01600                                          __FUNCTION__);
01601         if (!$which_xtlp) return FALSE;
01602         $this->x_tick_label_pos = $which_xtlp;
01603         if ($which_xtlp != 'none')
01604             $this->x_data_label_pos = 'none';
01605 
01606         return TRUE;
01607     }
01608 
01612     function SetYTickLabelPos($which_ytlp)
01613     {
01614         $this->y_tick_label_pos = $this->CheckOption($which_ytlp, 'plotleft, plotright, both, yaxis, all, none',
01615                                                       __FUNCTION__);
01616         return (boolean)$this->y_tick_label_pos;
01617     }
01618 
01623     function SetXLabelType($which_xlt)
01624     {
01625         $this->x_label_type = $this->CheckOption($which_xlt, 'data, time, title', __FUNCTION__);
01626         return (boolean)$this->x_label_type;
01627     }
01628 
01632     function SetYLabelType($which_ylt)
01633     {
01634         $this->y_label_type = $this->CheckOption($which_ylt, 'data, time', __FUNCTION__);
01635         return (boolean)$this->y_label_type;
01636     }
01637 
01638     function SetXTimeFormat($which_xtf)
01639     {
01640         $this->x_time_format = $which_xtf;
01641         return TRUE;
01642     }
01643 
01644     function SetYTimeFormat($which_ytf)
01645     {
01646         $this->y_time_format = $which_ytf;
01647         return TRUE;
01648     }
01649 
01650     function SetNumberFormat($decimal_point, $thousands_sep)
01651     {
01652         $this->decimal_point = $decimal_point;
01653         $this->thousands_sep = $thousands_sep;
01654         return TRUE;
01655     }
01656 
01657 
01658     function SetXLabelAngle($which_xla)
01659     {
01660         $this->x_label_angle = $which_xla;
01661         return TRUE;
01662     }
01663 
01664     function SetYLabelAngle($which_yla)
01665     {
01666         $this->y_label_angle = $which_yla;
01667         return TRUE;
01668     }
01669 
01673 
01683     function CheckOption($which_opt, $which_acc, $which_func)
01684     {
01685         $asked = strtolower(trim($which_opt));
01686 
01687         # Look for the supplied value in a comma/space separated list.
01688         if (strpos(", $which_acc,", ", $asked,") !== False)
01689             return $asked;
01690 
01691         $this->PrintError("$which_func(): '$which_opt' not in available choices: '$which_acc'.");
01692         return NULL;
01693     }
01694 
01695 
01699     function SetBrowserCache($which_browser_cache)
01700     {
01701         $this->browser_cache = $which_browser_cache;
01702         return TRUE;
01703     }
01704 
01708     function SetPrintImage($which_pi)
01709     {
01710         $this->print_image = $which_pi;
01711         return TRUE;
01712     }
01713 
01717     function SetLegend($which_leg)
01718     {
01719         if (is_array($which_leg)) {             // use array
01720             $this->legend = $which_leg;
01721         } elseif (! is_null($which_leg)) {     // append string
01722             $this->legend[] = $which_leg;
01723         } else {
01724             return $this->PrintError("SetLegend(): argument must not be null.");
01725         }
01726         return TRUE;
01727     }
01728 
01733     function SetLegendPixels($which_x, $which_y)
01734     {
01735         $this->legend_x_pos = $which_x;
01736         $this->legend_y_pos = $which_y;
01737         // Make sure this is unset, meaning we have pixel coords:
01738         unset($this->legend_xy_world);
01739 
01740         return TRUE;
01741     }
01742 
01750     function SetLegendWorld($which_x, $which_y)
01751     {
01752         $this->legend_x_pos = $which_x;
01753         $this->legend_y_pos = $which_y;
01754         $this->legend_xy_world = True;
01755 
01756         return TRUE;
01757     }
01758 
01759     /*
01760      * Set legend text alignment, color box alignment, and style options
01761      *     $text_align accepts 'left' or 'right'.
01762      *     $colorbox_align accepts 'left', 'right', 'none', or missing/empty. If missing or empty,
01763      *        the same alignment as $text_align is used. Color box is positioned first.
01764      *     $style is reserved for future use.
01765      */
01766     function SetLegendStyle($text_align, $colorbox_align = '', $style = '')
01767     {
01768         $this->legend_text_align = $this->CheckOption($text_align, 'left, right', __FUNCTION__);
01769         if (empty($colorbox_align))
01770             $this->legend_colorbox_align = $this->legend_text_align;
01771         else
01772             $this->legend_colorbox_align = $this->CheckOption($colorbox_align, 'left, right, none', __FUNCTION__);
01773         return ((boolean)$this->legend_text_align && (boolean)$this->legend_colorbox_align);
01774     }
01775 
01779     function SetPlotBorderType($pbt)
01780     {
01781         $this->plot_border_type = $this->CheckOption($pbt, 'left, sides, none, full', __FUNCTION__);
01782         return (boolean)$this->plot_border_type;
01783     }
01784 
01788     function SetImageBorderType($sibt)
01789     {
01790         $this->image_border_type = $this->CheckOption($sibt, 'raised, plain', __FUNCTION__);
01791         return (boolean)$this->image_border_type;
01792     }
01793 
01794 
01798     function SetDrawPlotAreaBackground($dpab)
01799     {
01800         $this->draw_plot_area_background = (bool)$dpab;
01801         return TRUE;
01802     }
01803 
01804 
01808     function SetDrawYGrid($dyg)
01809     {
01810         $this->draw_y_grid = (bool)$dyg;
01811         return TRUE;
01812     }
01813 
01814 
01818     function SetDrawXGrid($dxg)
01819     {
01820         $this->draw_x_grid = (bool)$dxg;
01821         return TRUE;
01822     }
01823 
01824 
01828     function SetDrawDashedGrid($ddg)
01829     {
01830         $this->dashed_grid = (bool)$ddg;
01831         return TRUE;
01832     }
01833 
01834 
01838     function SetDrawXDataLabelLines($dxdl)
01839     {
01840         $this->draw_x_data_label_lines = (bool)$dxdl;
01841         return TRUE;
01842     }
01843 
01844 
01849     function SetDrawYDataLabelLines($dydl)
01850     {
01851         $this->draw_y_data_label_lines = $dydl;
01852         return TRUE;
01853     }
01854 
01859     function SetTitle($which_title)
01860     {
01861         $this->title_txt = $which_title;
01862         return TRUE;
01863     }
01864 
01868     function SetXTitle($which_xtitle, $which_xpos = 'plotdown')
01869     {
01870         if ($which_xtitle == '')
01871             $which_xpos = 'none';
01872 
01873         $this->x_title_pos = $this->CheckOption($which_xpos, 'plotdown, plotup, both, none', __FUNCTION__);
01874         if (!$this->x_title_pos) return FALSE;
01875         $this->x_title_txt = $which_xtitle;
01876         return TRUE;
01877     }
01878 
01879 
01883     function SetYTitle($which_ytitle, $which_ypos = 'plotleft')
01884     {
01885         if ($which_ytitle == '')
01886             $which_ypos = 'none';
01887 
01888         $this->y_title_pos = $this->CheckOption($which_ypos, 'plotleft, plotright, both, none', __FUNCTION__);
01889         if (!$this->y_title_pos) return FALSE;
01890         $this->y_title_txt = $which_ytitle;
01891         return TRUE;
01892     }
01893 
01898     function SetShading($which_s)
01899     {
01900         $this->shading = (int)$which_s;
01901         return TRUE;
01902     }
01903 
01904     function SetPlotType($which_pt)
01905     {
01906         $this->plot_type = $this->CheckOption($which_pt,
01907                            'bars, stackedbars, lines, linepoints, area, points, pie, thinbarline, squared',
01908                             __FUNCTION__);
01909         return (boolean)$this->plot_type;
01910     }
01911 
01916     function SetYAxisPosition($pos)
01917     {
01918         $this->y_axis_position = (int)$pos;
01919         return TRUE;
01920     }
01921 
01926     function SetXAxisPosition($pos)
01927     {
01928         $this->x_axis_position = (int)$pos;
01929         return TRUE;
01930     }
01931 
01932 
01933     function SetXScaleType($which_xst)
01934     {
01935         $this->xscale_type = $this->CheckOption($which_xst, 'linear, log', __FUNCTION__);
01936         return (boolean)$this->xscale_type;
01937     }
01938 
01939     function SetYScaleType($which_yst)
01940     {
01941         $this->yscale_type = $this->CheckOption($which_yst, 'linear, log',  __FUNCTION__);
01942         return (boolean)$this->yscale_type;
01943     }
01944 
01945     function SetPrecisionX($which_prec)
01946     {
01947         $this->x_precision = $which_prec;
01948         $this->SetXLabelType('data');
01949         return TRUE;
01950     }
01951 
01952     function SetPrecisionY($which_prec)
01953     {
01954         $this->y_precision = $which_prec;
01955         $this->SetYLabelType('data');
01956         return TRUE;
01957     }
01958 
01959     function SetErrorBarLineWidth($which_seblw)
01960     {
01961         $this->error_bar_line_width = $which_seblw;
01962         return TRUE;
01963     }
01964 
01965     function SetLabelScalePosition($which_blp)
01966     {
01967         //0 to 1
01968         $this->label_scale_position = $which_blp;
01969         return TRUE;
01970     }
01971 
01972     function SetErrorBarSize($which_ebs)
01973     {
01974         //in pixels
01975         $this->error_bar_size = $which_ebs;
01976         return TRUE;
01977     }
01978 
01982     function SetErrorBarShape($which_ebs)
01983     {
01984         $this->error_bar_shape = $this->CheckOption($which_ebs, 'tee, line', __FUNCTION__);
01985         return (boolean)$this->error_bar_shape;
01986     }
01987 
01993     function SetPointShapes($which_pt)
01994     {
01995         if (is_null($which_pt)) {
01996             // Do nothing, use default value.
01997         } else if (is_array($which_pt)) {
01998             // Did we get an array with point shapes?
01999             $this->point_shapes = $which_pt;
02000         } else {
02001             // Single value into array
02002             $this->point_shapes = array($which_pt);
02003         }
02004 
02005         foreach ($this->point_shapes as $shape)
02006         {
02007             if (!$this->CheckOption($shape,
02008                'halfline, line, plus, cross, rect, circle, dot, diamond, triangle, trianglemid, none',
02009                 __FUNCTION__))
02010                 return FALSE;
02011         }
02012 
02013         // Make both point_shapes and point_sizes same size.
02014         $ps = count($this->point_sizes);
02015         $pt = count($this->point_shapes);
02016 
02017         if ($ps < $pt) {
02018             $this->pad_array($this->point_sizes, $pt);
02019         } else if ($pt > $ps) {
02020             $this->pad_array($this->point_shapes, $ps);
02021         }
02022         return TRUE;
02023     }
02024 
02030     function SetPointSizes($which_ps)
02031     {
02032         if (is_null($which_ps)) {
02033             // Do nothing, use default value.
02034         } else if (is_array($which_ps)) {
02035             // Did we get an array with point sizes?
02036             $this->point_sizes = $which_ps;
02037         } else {
02038             // Single value into array
02039             $this->point_sizes = array($which_ps);
02040         }
02041 
02042         // Make both point_shapes and point_sizes same size.
02043         $ps = count($this->point_sizes);
02044         $pt = count($this->point_shapes);
02045 
02046         if ($ps < $pt) {
02047             $this->pad_array($this->point_sizes, $pt);
02048         } else if ($pt > $ps) {
02049             $this->pad_array($this->point_shapes, $ps);
02050         }
02051 
02052         // Fix odd point sizes for point shapes which need it
02053         for ($i = 0; $i < $pt; $i++) {
02054             if ($this->point_shapes[$i] == 'diamond' or $this->point_shapes[$i] == 'triangle') {
02055                 if ($this->point_sizes[$i] % 2 != 0) {
02056                     $this->point_sizes[$i]++;
02057                 }
02058             }
02059         }
02060         return TRUE;
02061     }
02062 
02063 
02068     function SetDrawBrokenLines($bl)
02069     {
02070         $this->draw_broken_lines = (bool)$bl;
02071         return TRUE;
02072     }
02073 
02074 
02081     function SetDataType($which_dt)
02082     {
02083         //The next four lines are for past compatibility.
02084         if ($which_dt == 'text-linear') { $which_dt = 'text-data'; }
02085         elseif ($which_dt == 'linear-linear') { $which_dt = 'data-data'; }
02086         elseif ($which_dt == 'linear-linear-error') { $which_dt = 'data-data-error'; }
02087         elseif ($which_dt == 'text-data-pie') { $which_dt = 'text-data-single'; }
02088 
02089 
02090         $this->data_type = $this->CheckOption($which_dt, 'text-data, text-data-single, '.
02091                                                          'data-data, data-data-error', __FUNCTION__);
02092         return (boolean)$this->data_type;
02093     }
02094 
02100     function SetDataValues(&$which_dv)
02101     {
02102         $this->num_data_rows = count($which_dv);
02103         $this->total_records = 0;               // Perform some useful calculations.
02104         $this->records_per_group = 1;
02105         for ($i = 0, $recs = 0; $i < $this->num_data_rows; $i++) {
02106             // Copy
02107             $this->data[$i] = array_values($which_dv[$i]);   // convert to numerical indices.
02108 
02109             // Compute some values
02110             $recs = count($this->data[$i]);
02111             $this->total_records += $recs;
02112 
02113             if ($recs > $this->records_per_group)
02114                 $this->records_per_group = $recs;
02115 
02116             $this->num_recs[$i] = $recs;
02117         }
02118         return TRUE;
02119     }
02120 
02126     function PadArrays()
02127     {
02128         $this->pad_array($this->line_widths, $this->records_per_group);
02129         $this->pad_array($this->line_styles, $this->records_per_group);
02130 
02131         $this->pad_array($this->data_colors, $this->records_per_group);
02132         $this->pad_array($this->data_border_colors, $this->records_per_group);
02133         $this->pad_array($this->error_bar_colors, $this->records_per_group);
02134 
02135         $this->SetDataColors();
02136         $this->SetDataBorderColors();
02137         $this->SetErrorBarColors();
02138 
02139         return TRUE;
02140     }
02141 
02150     function pad_array(&$arr, $size)
02151     {
02152         if (! is_array($arr)) {
02153             $arr = array($arr);
02154         }
02155         $n = count($arr);
02156         $base = 0;
02157         while ($n < $size) $arr[$n++] = $arr[$base++];
02158     }
02159 
02160     /*
02161      * Format a floating-point number.
02162      * This is like PHP's number_format, but uses class variables for separators.
02163      * The separators will default to locale-specific values, if available.
02164      */
02165     function number_format($number, $decimals=0)
02166     {
02167         if (!isset($this->decimal_point) || !isset($this->thousands_sep)) {
02168             // Load locale-specific values from environment:
02169             @setlocale(LC_ALL, '');
02170             // Fetch locale settings:
02171             $locale = @localeconv();
02172             if (!empty($locale) && isset($locale['decimal_point']) &&
02173                     isset($locale['thousands_sep'])) {
02174               $this->decimal_point = $locale['decimal_point'];
02175               $this->thousands_sep = $locale['thousands_sep'];
02176             } else {
02177               // Locale information not available.
02178               $this->decimal_point = '.';
02179               $this->thousands_sep = ',';
02180             }
02181         }
02182         return number_format($number, $decimals, $this->decimal_point, $this->thousands_sep);
02183     }
02184 
02185     /*
02186      * Register a callback (hook) function
02187      *   reason - A pre-defined name where a callback can be defined.
02188      *   function - The name of a function to register for callback, or an instance/method
02189      *      pair in an array (see 'callbacks' in the PHP reference manual).
02190      *   arg - Optional argument to supply to the callback function when it is triggered.
02191      *      (Often called "clientData")
02192      * Returns: True if the callback reason is valid, else False.
02193      */
02194     function SetCallback($reason, $function, $arg = NULL)
02195     {
02196         // Use array_key_exists because valid reason keys have NULL as value.
02197         if (!array_key_exists($reason, $this->callbacks))
02198             return False;
02199         $this->callbacks[$reason] = array($function, $arg);
02200         return True;
02201     }
02202 
02203     /*
02204      * Return the name of a function registered for callback. See SetCallBack.
02205      *   reason - A pre-defined name where a callback can be defined.
02206      * Returns the current callback function (name or array) for the given reason,
02207      * or False if there was no active callback or the reason is not valid.
02208      * Note you can safely test the return value with a simple 'if', as
02209      * no valid function name evaluates to false.
02210      */
02211     function GetCallback($reason)
02212     {
02213         if (isset($this->callbacks[$reason]))
02214             return $this->callbacks[$reason][0];
02215         return False;
02216     }
02217 
02218     /*
02219      * Un-register (remove) a function registered for callback.
02220      *   reason - A pre-defined name where a callback can be defined.
02221      * Returns: True if it was a valid callback reason, else False.
02222      * Note: Returns True whether or not there was a callback registered.
02223      */
02224     function RemoveCallback($reason)
02225     {
02226         if (!array_key_exists($reason, $this->callbacks))
02227             return False;
02228         $this->callbacks[$reason] = NULL;
02229         return True;
02230     }
02231 
02232     /*
02233      * Invoke a callback, if one is registered.
02234      * Accepts a variable number of arguments >= 1:
02235      *    reason : A string naming the callback.
02236      *    ... : Zero or more additional arguments to be passed to the
02237      *      callback function, after the passthru argument:
02238      *           callback_function($image, $passthru, ...)
02239      * Returns: nothing.
02240      */
02241     function DoCallback()  # Note: Variable arguments
02242     {
02243         $args = func_get_args();
02244         $reason = $args[0];
02245         if (!isset($this->callbacks[$reason]))
02246             return;
02247         list($function, $args[0]) = $this->callbacks[$reason];
02248         array_unshift($args, $this->img);
02249         # Now args[] looks like: img, passthru, extra args...
02250         call_user_func_array($function, $args);
02251     }
02252 
02253 
02257 
02266     function FindDataLimits()
02267     {
02268         // Set some default min and max values before running through the data
02269         switch ($this->data_type) {
02270         case 'text-data':
02271         case 'text-data-single':
02272             $minx = 0;
02273             $maxx = $this->num_data_rows - 1 ;
02274             $miny = $this->data[0][1];
02275             $maxy = $miny;
02276             break;
02277         default:  //Everything else: data-data, etc, take first value
02278             $minx = $this->data[0][1];
02279             $maxx = $minx;
02280             $miny = $this->data[0][2];
02281             $maxy = $miny;
02282             break;
02283         }
02284 
02285         $mine = 0;  // Maximum value for the -error bar (assume error bars always > 0)
02286         $maxe = 0;  // Maximum value for the +error bar (assume error bars always > 0)
02287 
02288         if ($this->plot_type == 'stackedbars') {
02289             $maxmaxy = $minminy = 0;
02290         } else {
02291             $minminy = $miny;
02292             $maxmaxy = $maxy;
02293         }
02294 
02295         // Process each row of data
02296         for ($i=0; $i < $this->num_data_rows; $i++) {
02297             $j = 1; // Skip over the data label for this row.
02298 
02299             switch ($this->data_type) {
02300             case 'text-data':           // Data is passed in as (title, y1, y2, y3, ...)
02301             case 'text-data-single':    // This one is for some pie charts
02302                 // $numrecs = @ count($this->data[$i]);
02303                 $maxy = (double)$this->data[$i][$j++];
02304                 if ($this->plot_type == 'stackedbars') {
02305                     $miny = 0;
02306                 } else {
02307                     $miny = $maxy;
02308                 }
02309                 for (; $j < $this->num_recs[$i]; $j++) {
02310                     $val = (double)$this->data[$i][$j];
02311                     if ($this->plot_type == 'stackedbars') {
02312                         $maxy += abs($val);      // only positive values for the moment
02313                     } else {
02314                         if ($val > $maxy) $maxy = $val;
02315                         if ($val < $miny) $miny = $val;
02316                     }
02317                 }
02318                 break;
02319             case 'data-data':           // Data is passed in as (title, x, y, y2, y3, ...)
02320                 // X value:
02321                 $val = (double)$this->data[$i][$j++];
02322                 if ($val > $maxx) $maxx = $val;
02323                 if ($val < $minx) $minx = $val;
02324 
02325                 $miny = $maxy = (double)$this->data[$i][$j++];
02326                 // $numrecs = @ count($this->data[$i]);
02327                 for (; $j < $this->num_recs[$i]; $j++) {
02328                     $val = (double)$this->data[$i][$j];
02329                     if ($val > $maxy) $maxy = $val;
02330                     if ($val < $miny) $miny = $val;
02331                 }
02332                 break;
02333             case 'data-data-error':     // Data is passed in as (title, x, y, err+, err-, y2, err2+, err2-,...)
02334                 // X value:
02335                 $val = (double)$this->data[$i][$j++];
02336                 if ($val > $maxx) $maxx = $val;
02337                 if ($val < $minx) $minx = $val;
02338 
02339                 $miny = $maxy = (double)$this->data[$i][$j];
02340                 // $numrecs = @ count($this->data[$i]);
02341                 for (; $j < $this->num_recs[$i];) {
02342                     // Y value:
02343                     $val = (double)$this->data[$i][$j++];
02344                     if ($val > $maxy) $maxy = $val;
02345                     if ($val < $miny) $miny = $val;
02346                     // Error +:
02347                     $val = (double)$this->data[$i][$j++];
02348                     if ($val > $maxe) $maxe = $val;
02349                     // Error -:
02350                     $val = (double)$this->data[$i][$j++];
02351                     if ($val > $mine) $mine = $val;
02352                 }
02353                 $maxy = $maxy + $maxe;
02354                 $miny = $miny - $mine;      // assume error bars are always > 0
02355                 break;
02356             default:
02357                 return $this->PrintError("FindDataLimits(): Unknown data type '$this->data_type'.");
02358             }
02359             // Remember this row's min and max Y values:
02360             $this->data_miny[$i] = $miny;
02361             $this->data_maxy[$i] = $maxy;
02362 
02363             if ($miny < $minminy) $minminy = $miny;   // global min
02364             if ($maxy > $maxmaxy) $maxmaxy = $maxy;   // global max
02365         }
02366 
02367         $this->min_x = $minx;
02368         $this->max_x = $maxx;
02369         $this->min_y = $minminy;
02370         $this->max_y = $maxmaxy;
02371 
02372         if ($this->GetCallback('debug_scale')) {
02373             $this->DoCallback('debug_scale', __FUNCTION__, array(
02374                 'min_x' => $this->min_x, 'min_y' => $this->min_y,
02375                 'max_x' => $this->max_x, 'max_y' => $this->max_y));
02376         }
02377         return TRUE;
02378     }
02379 
02419     function CalcMargins($maximize)
02420     {
02421         // This is the line-to-line or line-to-text spacing:
02422         $gap = $this->safe_margin;
02423 
02424         // Minimum margin on each side. This reduces the chance that the
02425         // right-most tick label (for example) will run off the image edge
02426         // if there are no titles on that side.
02427         $min_margin = 3 * $gap;
02428 
02429         // Calculate the title sizes:
02430         list($unused, $title_height) = $this->SizeText($this->title_font, 0, $this->title_txt);
02431         list($unused, $x_title_height) = $this->SizeText($this->x_title_font, 0, $this->x_title_txt);
02432         list($y_title_width, $unused) = $this->SizeText($this->y_title_font, 90, $this->y_title_txt);
02433 
02434         // Special case for maximum area usage with no X/Y titles or labels, only main title:
02435         if ($maximize) {
02436             if (!$this->plot_margins_set) {
02437                 $this->x_left_margin = $gap;
02438                 $this->x_right_margin = $gap;
02439                 $this->y_top_margin = $gap;
02440                 $this->y_bot_margin = $gap;
02441                 if ($title_height > 0)
02442                     $this->y_top_margin += $title_height + $gap;
02443             }
02444             return TRUE;
02445         }
02446 
02447         // Make local variables for these. (They get used a lot and I'm tired of this, this, this.)
02448         $x_tick_label_pos = $this->x_tick_label_pos;
02449         $x_data_label_pos = $this->x_data_label_pos;
02450         $x_tick_pos       = $this->x_tick_pos;
02451         $x_tick_len       = $this->x_tick_length;
02452         $y_tick_label_pos = $this->y_tick_label_pos;
02453         $y_tick_pos       = $this->y_tick_pos;
02454         $y_tick_len       = $this->y_tick_length;
02455 
02457 
02458         // Calculate maximum height of X tick or data labels, depending on which one is on.
02459         // It is possible for both to be on, but this is only valid if all the data labels are empty.
02460         if ($x_data_label_pos == 'none') {
02461             $x_label_height = 0;
02462         } else {
02463             $x_label_height = $this->CalcMaxDataLabelSize();
02464         }
02465         if ($x_tick_label_pos != 'none' &&
02466             ($height = $this->CalcMaxTickLabelSize('x')) > $x_label_height) {
02467                 $x_label_height = $height;
02468         }
02469 
02470         // If Y tick labels are on, calculate the width of the widest tick label:
02471         if ($y_tick_label_pos == 'none')
02472             $y_label_width = 0;
02473         else
02474             $y_label_width = $this->CalcMaxTickLabelSize('y');
02475 
02477 
02478         // For X/Y tick and label position of 'xaxis' or 'yaxis', determine if the axis happens to be
02479         // on an edge of a plot. If it is, we need to account for the margins there.
02480         if ($this->x_axis_position <= $this->plot_min_y)
02481             $x_axis_pos = 'bottom';
02482         elseif ($this->x_axis_position >= $this->plot_max_y)
02483             $x_axis_pos = 'top';
02484         else
02485             $x_axis_pos = 'none';
02486 
02487         if ($this->y_axis_position <= $this->plot_min_x)
02488             $y_axis_pos = 'left';
02489         elseif ($this->y_axis_position >= $this->plot_max_x)
02490             $y_axis_pos = 'right';
02491         else
02492             $y_axis_pos = 'none';
02493 
02494         // y_top_margin: Main title, Upper X title, X ticks and tick labels, and X data labels:
02495         // y_bot_margin: Lower title, ticks and tick labels, and data labels:
02496         $top_margin = $gap;
02497         $bot_margin = $gap;
02498         $this->x_title_top_offset = $gap;
02499         $this->x_title_bot_offset = $gap;
02500 
02501         if ($title_height > 0)
02502             $top_margin += $title_height + $gap;
02503 
02504         if ($x_title_height > 0) {
02505             $pos = $this->x_title_pos;
02506             if ($pos == 'plotup' || $pos == 'both')
02507                 $top_margin += $x_title_height + $gap;
02508             if ($pos == 'plotdown' || $pos == 'both')
02509                 $bot_margin += $x_title_height + $gap;
02510         }
02511 
02512         if ($x_tick_label_pos == 'plotup' || $x_tick_label_pos == 'both'
02513            || $x_data_label_pos == 'plotup' || $x_data_label_pos == 'both'
02514            || ($x_tick_label_pos == 'xaxis' && $x_axis_pos == 'top')) {
02515             // X Tick or Data Labels above the plot:
02516             $top_margin += $x_label_height + $gap;
02517             $this->x_title_top_offset += $x_label_height + $gap;
02518         }
02519         if ($x_tick_label_pos == 'plotdown' || $x_tick_label_pos == 'both'
02520            || $x_data_label_pos == 'plotdown' || $x_data_label_pos == 'both'
02521            || ($x_tick_label_pos == 'xaxis' && $x_axis_pos == 'bottom')) {
02522             // X Tick or Data Labels below the plot:
02523             $bot_margin += $x_label_height + $gap;
02524             $this->x_title_bot_offset += $x_label_height + $gap;
02525         }
02526         if ($x_tick_pos == 'plotup' || $x_tick_pos == 'both'
02527            || ($x_tick_pos == 'xaxis' && $x_axis_pos == 'top')) {
02528             // X Ticks above the plot:
02529             $top_margin += $x_tick_len;
02530             $this->x_label_top_offset = $x_tick_len + $gap;
02531             $this->x_title_top_offset += $x_tick_len;
02532         } else {
02533             // No X Ticks above the plot:
02534             $this->x_label_top_offset = $gap;
02535         }
02536         if ($x_tick_pos == 'plotdown' || $x_tick_pos == 'both'
02537            || ($x_tick_pos == 'xaxis' && $x_axis_pos == 'bottom')) {
02538             // X Ticks below the plot:
02539             $bot_margin += $x_tick_len;
02540             $this->x_label_bot_offset = $x_tick_len + $gap;
02541             $this->x_title_bot_offset += $x_tick_len;
02542         } else {
02543             // No X Ticks below the plot:
02544             $this->x_label_bot_offset = $gap;
02545         }
02546         // Label offsets for on-axis ticks:
02547         if ($x_tick_pos == 'xaxis') {
02548             $this->x_label_axis_offset = $x_tick_len + $gap;
02549         } else {
02550             $this->x_label_axis_offset = $gap;
02551         }
02552 
02553         // x_left_margin: Left Y title, Y ticks and tick labels:
02554         // x_right_margin: Right Y title, Y ticks and tick labels:
02555         $left_margin = $gap;
02556         $right_margin = $gap;
02557         $this->y_title_left_offset = $gap;
02558         $this->y_title_right_offset = $gap;
02559 
02560         if ($y_title_width > 0) {
02561             $pos = $this->y_title_pos;
02562             if ($pos == 'plotleft' || $pos == 'both')
02563                 $left_margin += $y_title_width + $gap;
02564             if ($pos == 'plotright' || $pos == 'both')
02565                 $right_margin += $y_title_width + $gap;
02566         }
02567 
02568         if ($y_tick_label_pos == 'plotleft' || $y_tick_label_pos == 'both'
02569            || ($y_tick_label_pos == 'yaxis' && $y_axis_pos == 'left')) {
02570             // Y Tick Labels left of plot:
02571             $left_margin += $y_label_width + $gap;
02572             $this->y_title_left_offset += $y_label_width + $gap;
02573         }
02574         if ($y_tick_label_pos == 'plotright' || $y_tick_label_pos == 'both'
02575            || ($y_tick_label_pos == 'yaxis' && $y_axis_pos == 'right')) {
02576             // Y Tick Labels right of plot:
02577             $right_margin += $y_label_width + $gap;
02578             $this->y_title_right_offset += $y_label_width + $gap;
02579         }
02580         if ($y_tick_pos == 'plotleft' || $y_tick_pos == 'both'
02581            || ($y_tick_pos == 'yaxis' && $y_axis_pos == 'left')) {
02582             // Y Ticks left of plot:
02583             $left_margin += $y_tick_len;
02584             $this->y_label_left_offset = $y_tick_len + $gap;
02585             $this->y_title_left_offset += $y_tick_len;
02586         } else {
02587             // No Y Ticks left of plot:
02588             $this->y_label_left_offset = $gap;
02589         }
02590         if ($y_tick_pos == 'plotright' || $y_tick_pos == 'both'
02591            || ($y_tick_pos == 'yaxis' && $y_axis_pos == 'right')) {
02592             // Y Ticks right of plot:
02593             $right_margin += $y_tick_len;
02594             $this->y_label_right_offset = $y_tick_len + $gap;
02595             $this->y_title_right_offset += $y_tick_len;
02596         } else {
02597             // No Y Ticks right of plot:
02598             $this->y_label_right_offset = $gap;
02599         }
02600 
02601         // Label offsets for on-axis ticks:
02602         if ($x_tick_pos == 'yaxis') {
02603             $this->y_label_axis_offset = $y_tick_len + $gap;
02604         } else {
02605             $this->y_label_axis_offset = $gap;
02606         }
02607 
02608         // Apply the minimum margins and store in the object.
02609         // Do not set margins if they are user-defined (see note at top of function).
02610         if (!$this->plot_margins_set) {
02611             $this->y_top_margin = max($min_margin, $top_margin);
02612             $this->y_bot_margin = max($min_margin, $bot_margin);
02613             $this->x_left_margin = max($min_margin, $left_margin);
02614             $this->x_right_margin = max($min_margin, $right_margin);
02615         }
02616  
02617         if ($this->GetCallback('debug_scale')) {
02618             // (Too bad compact() doesn't work on class member variables...)
02619             $this->DoCallback('debug_scale', __FUNCTION__, array(
02620                 'x_label_height' => $x_label_height,
02621                 'y_label_width' => $y_label_width,
02622                 'x_tick_len' => $x_tick_len,
02623                 'y_tick_len' => $y_tick_len,
02624                 'x_left_margin' => $this->x_left_margin,
02625                 'x_right_margin' => $this->x_right_margin,
02626                 'y_top_margin' => $this->y_top_margin,
02627                 'y_bot_margin' => $this->y_bot_margin,
02628                 'x_label_top_offset' => $this->x_label_top_offset,
02629                 'x_label_bot_offset' => $this->x_label_bot_offset,
02630                 'y_label_left_offset' => $this->y_label_left_offset,
02631                 'y_label_right_offset' => $this->y_label_right_offset,
02632                 'x_title_top_offset' => $this->x_title_top_offset,
02633                 'x_title_bot_offset' => $this->x_title_bot_offset,
02634                 'y_title_left_offset' => $this->y_title_left_offset,
02635                 'y_title_right_offset' => $this->y_title_right_offset));
02636         }
02637 
02638         return TRUE;
02639     }
02640 
02641     /*
02642      * Calculate the plot area (device coordinates) from the margins.
02643      * (This used to be part of SetPlotAreaPixels.)
02644      * The margins might come from SetMarginsPixels, SetPlotAreaPixels,
02645      * or CalcMargins.
02646      */
02647     function CalcPlotAreaPixels()
02648     {
02649         $this->plot_area = array($this->x_left_margin, $this->y_top_margin,
02650                                  $this->image_width - $this->x_right_margin,
02651                                  $this->image_height - $this->y_bot_margin);
02652         $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0];
02653         $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1];
02654 
02655         $this->DoCallback('debug_scale', __FUNCTION__, $this->plot_area);
02656         return TRUE;
02657     }
02658 
02659 
02665     function SetMarginsPixels($which_lm, $which_rm, $which_tm, $which_bm)
02666     {
02667         $this->x_left_margin = $which_lm;
02668         $this->x_right_margin = $which_rm;
02669         $this->y_top_margin = $which_tm;
02670         $this->y_bot_margin = $which_bm;
02671 
02672         $this->plot_margins_set = TRUE;
02673 
02674         return TRUE;
02675     }
02676 
02687     function SetPlotAreaPixels($x1, $y1, $x2, $y2)
02688     {
02689         $this->x_left_margin = $x1;
02690         $this->x_right_margin = $this->image_width - $x2;
02691         $this->y_top_margin = $y1;
02692         $this->y_bot_margin = $this->image_height - $y2;
02693 
02694         $this->plot_margins_set = TRUE;
02695 
02696         return TRUE;
02697     }
02698 
02699     /*
02700      * Calculate the World Coordinate limits of the plot area.
02701      * This goes with SetPlotAreaWorld, but the calculations are
02702      * deferred until the graph is being drawn.
02703      * Uses: plot_min_x, plot_max_x, plot_min_y, plot_max_y
02704      * which can be user-supplied or NULL to auto-calculate.
02705      * Pre-requisites: FindDataLimits()
02706      */
02707     function CalcPlotAreaWorld()
02708     {
02709         if (isset($this->plot_min_x) && $this->plot_min_x !== '')
02710             $xmin = $this->plot_min_x;
02711         elseif ($this->data_type == 'text-data')  // Valid for data without X values only.
02712             $xmin = 0;
02713         else
02714             $xmin = $this->min_x;
02715 
02716         if (isset($this->plot_max_x) && $this->plot_max_x !== '')
02717             $xmax = $this->plot_max_x;
02718         elseif ($this->data_type == 'text-data')  // Valid for data without X values only.
02719             $xmax = $this->max_x + 1;
02720         else
02721             $xmax = $this->max_x;
02722 
02723         // Leave room above and below the highest and lowest data points.
02724 
02725         if (!isset($this->plot_min_y) || $this->plot_min_y === '')
02726             $ymin = floor($this->min_y - abs($this->min_y) * 0.1);
02727         else
02728             $ymin = $this->plot_min_y;
02729 
02730         if (!isset($this->plot_max_y) || $this->plot_max_y === '')
02731             $ymax = ceil($this->max_y + abs($this->max_y) * 0.1);
02732         else
02733             $ymax = $this->plot_max_y;
02734 
02735         // Error checking
02736 
02737         if ($ymin == $ymax)     // Minimum height
02738             $ymax += 1;
02739 
02740         if ($this->yscale_type == 'log') {
02741             if ($ymin <= 0) {
02742                 $ymin = 1;
02743             }
02744             if ($ymax <= 0) {
02745                 // Note: Error messages reference the user function, not this function.
02746                 return $this->PrintError('SetPlotAreaWorld(): Log plots need data greater than 0');
02747             }
02748         }
02749 
02750         if ($ymax <= $ymin) {
02751             return $this->PrintError('SetPlotAreaWorld(): Error in data - max not greater than min');
02752         }
02753 
02754         $this->plot_min_x = $xmin;
02755         $this->plot_max_x = $xmax;
02756         $this->plot_min_y = $ymin;
02757         $this->plot_max_y = $ymax;
02758         if ($this->GetCallback('debug_scale')) {
02759             $this->DoCallback('debug_scale', __FUNCTION__, array(
02760                 'plot_min_x' => $this->plot_min_x, 'plot_min_y' => $this->plot_min_y,
02761                 'plot_max_x' => $this->plot_max_x, 'plot_max_y' => $this->plot_max_y));
02762         }
02763 
02764         return TRUE;
02765     }
02766 
02772     function SetPlotAreaWorld($xmin=NULL, $ymin=NULL, $xmax=NULL, $ymax=NULL)
02773     {
02774         $this->plot_min_x = $xmin;
02775         $this->plot_max_x = $xmax;
02776         $this->plot_min_y = $ymin;
02777         $this->plot_max_y = $ymax;
02778         return TRUE;
02779     } //function SetPlotAreaWorld
02780 
02781 
02785     function CalcBarWidths()
02786     {
02787         // group_width is the width of a group, including padding
02788         $group_width = $this->plot_area_width / $this->num_data_rows;
02789 
02790         // Actual number of bar spaces in the group. This includes the drawn bars, and
02791         // 'bar_extra_space'-worth of extra bars.
02792         // Note that 'records_per_group' includes the label, so subtract one to get
02793         // the number of points in the group. 'stackedbars' have 1 bar space per group.
02794         if ($this->plot_type == 'stackedbars') {
02795           $num_spots = 1 + $this->bar_extra_space;
02796         } else {
02797           $num_spots = $this->records_per_group - 1 + $this->bar_extra_space;
02798         }
02799 
02800         // record_bar_width is the width of each bar's allocated area.
02801         // If bar_width_adjust=1 this is the width of the bar, otherwise
02802         // the bar is centered inside record_bar_width.
02803         // The equation is:
02804         //   group_frac_width * group_width = record_bar_width * num_spots
02805         $this->record_bar_width = $this->group_frac_width * $group_width / $num_spots;
02806 
02807         // Note that the extra space due to group_frac_width and bar_extra_space will be
02808         // evenly divided on each side of the group: the drawn bars are centered in the group.
02809 
02810         // Within each bar's allocated space, if bar_width_adjust=1 the bar fills the 
02811         // space, otherwise it is centered.
02812         // This is the actual drawn bar width:
02813         $this->actual_bar_width = $this->record_bar_width * $this->bar_width_adjust;
02814         // This is the gap on each side of the bar (0 if bar_width_adjust=1):
02815         $this->bar_adjust_gap = ($this->record_bar_width - $this->actual_bar_width) / 2;
02816 
02817         return TRUE;
02818     }
02819 
02820     /*
02821      * Calculate X and Y Axis Positions, world coordinates.
02822      * This needs the min/max x/y range set by CalcPlotAreaWorld.
02823      * It adjusts or sets x_axis_position and y_axis_position per the data.
02824      * Empty string means the values need to be calculated; otherwise they
02825      * are supplied but need to be validated against the World area.
02826      *
02827      * Note: This used to be in CalcTranslation, but CalcMargins needs it too.
02828      * This does not calculate the pixel values of the axes. That happens in
02829      * CalcTranslation, after scaling is set up (which has to happen after
02830      * margins are set up).
02831      */
02832     function CalcAxisPositions()
02833     {
02834         // If no user-provided Y axis position, default to axis on left side.
02835         // Otherwise, make sure user-provided position is inside the plot area.
02836         if ($this->y_axis_position === '')
02837             $this->y_axis_position = $this->plot_min_x;
02838         else
02839             $this->y_axis_position = min(max($this->plot_min_x, $this->y_axis_position), $this->plot_max_x);
02840 
02841         // If no user-provided X axis position, default to axis at Y=0 (if in range), or min_y
02842         //   if the range does not include 0, or 1 for log plots.
02843         // Otherwise, make sure user-provided position is inside the plot area.
02844         if ($this->x_axis_position === '') {
02845             if ($this->yscale_type == 'log')
02846                 $this->x_axis_position = 1;
02847             elseif ($this->plot_min_y <= 0 && 0 <= $this->plot_max_y)
02848                 $this->x_axis_position = 0;
02849              else 
02850                 $this->x_axis_position = $this->plot_min_y;
02851         } else
02852             $this->x_axis_position = min(max($this->plot_min_y, $this->x_axis_position), $this->plot_max_y);
02853 
02854         if ($this->GetCallback('debug_scale')) {
02855             $this->DoCallback('debug_scale', __FUNCTION__, array(
02856                 'x_axis_position' => $this->x_axis_position,
02857                 'y_axis_position' => $this->y_axis_position));
02858         }
02859 
02860         return TRUE;
02861     }
02862 
02866     function CalcTranslation()
02867     {
02868         if ($this->plot_max_x - $this->plot_min_x == 0) { // Check for div by 0
02869             $this->xscale = 0;
02870         } else {
02871             if ($this->xscale_type == 'log') {
02872                 $this->xscale = ($this->plot_area_width)/(log10($this->plot_max_x) - log10($this->plot_min_x));
02873             } else {
02874                 $this->xscale = ($this->plot_area_width)/($this->plot_max_x - $this->plot_min_x);
02875             }
02876         }
02877 
02878         if ($this->plot_max_y - $this->plot_min_y == 0) { // Check for div by 0
02879             $this->yscale = 0;
02880         } else {
02881             if ($this->yscale_type == 'log') {
02882                 $this->yscale = ($this->plot_area_height)/(log10($this->plot_max_y) - log10($this->plot_min_y));
02883             } else {
02884                 $this->yscale = ($this->plot_area_height)/($this->plot_max_y - $this->plot_min_y);
02885             }
02886         }
02887         // GD defines x = 0 at left and y = 0 at TOP so -/+ respectively
02888         if ($this->xscale_type == 'log') {
02889             $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * log10($this->plot_min_x) );
02890         } else {
02891             $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * $this->plot_min_x);
02892         }
02893         if ($this->yscale_type == 'log') {
02894             $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * log10($this->plot_min_y));
02895         } else {
02896             $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * $this->plot_min_y);
02897         }
02898 
02899         // Convert axis positions to device coordinates:
02900         $this->y_axis_x_pixels = $this->xtr($this->y_axis_position);
02901         $this->x_axis_y_pixels = $this->ytr($this->x_axis_position);
02902 
02903         if ($this->GetCallback('debug_scale')) {
02904             $this->DoCallback('debug_scale', __FUNCTION__, array(
02905                 'xscale' => $this->xscale, 'yscale' => $this->yscale,
02906                 'plot_origin_x' => $this->plot_origin_x, 'plot_origin_y' => $this->plot_origin_y,
02907                 'y_axis_x_pixels' => $this->y_axis_x_pixels,
02908                 'x_axis_y_pixels' => $this->x_axis_y_pixels));
02909         }
02910 
02911         return TRUE;
02912     } // function CalcTranslation()
02913 
02914 
02919     function xtr($x_world)
02920     {
02921         if ($this->xscale_type == 'log') {
02922             $x_pixels = $this->plot_origin_x + log10($x_world) * $this->xscale ;
02923         } else {
02924             $x_pixels = $this->plot_origin_x + $x_world * $this->xscale ;
02925         }
02926         return round($x_pixels);
02927     }
02928 
02929 
02934     function ytr($y_world)
02935     {
02936         if ($this->yscale_type == 'log') {
02937             //minus because GD defines y = 0 at top. doh!
02938             $y_pixels =  $this->plot_origin_y - log10($y_world) * $this->yscale ;
02939         } else {
02940             $y_pixels =  $this->plot_origin_y - $y_world * $this->yscale ;
02941         }
02942         return round($y_pixels);
02943     }
02944 
02945     /*
02946      * Calculate tick parameters: Start, end, and delta values. This is used
02947      * by both DrawXTicks() and DrawYTicks().
02948      * This currently uses the same simplistic method previously used by
02949      * PHPlot (basically just range/10), but splitting this out into its
02950      * own function is the first step in replacing the method.
02951      * This is also used by CalcMaxTickSize() for CalcMargins().
02952      *
02953      *   $which : 'x' or 'y' : Which tick parameters to calculate
02954      *
02955      * Returns an array of 3 elements: tick_start, tick_end, tick_step
02956      */
02957     function CalcTicks($which)
02958     {
02959         if ($which == 'x') {
02960             $num_ticks = $this->num_x_ticks;
02961             $tick_inc = $this->x_tick_inc;
02962             $data_max = $this->plot_max_x;
02963             $data_min = $this->plot_min_x;
02964             $skip_lo = $this->skip_left_tick;
02965             $skip_hi = $this->skip_right_tick;
02966         } elseif ($which == 'y') {
02967             $num_ticks = $this->num_y_ticks;
02968             $tick_inc = $this->y_tick_inc;
02969             $data_max = $this->plot_max_y;
02970             $data_min = $this->plot_min_y;
02971             $skip_lo = $this->skip_bottom_tick;
02972             $skip_hi = $this->skip_top_tick;
02973         } else {
02974           return $this->PrintError("CalcTicks: Invalid usage ($which)");
02975         }
02976 
02977         if (!empty($tick_inc)) {
02978             $tick_step = $tick_inc;
02979         } elseif (!empty($num_ticks)) {
02980             $tick_step = ($data_max - $data_min) / $num_ticks;
02981         } else {
02982             $tick_step = ($data_max - $data_min) / 10;
02983         }
02984 
02985         // NOTE: When working with floats, because of approximations when adding $tick_step,
02986         // the value may not quite reach the end, or may exceed it very slightly.
02987         // So apply a "fudge" factor.
02988         $tick_start = (double)$data_min;
02989         $tick_end = (double)$data_max + ($data_max - $data_min) / 10000.0;
02990 
02991         if ($skip_lo)
02992             $tick_start += $tick_step;
02993 
02994         if ($skip_hi)
02995             $tick_end -= $tick_step;
02996 
02997         return array($tick_start, $tick_end, $tick_step);
02998     }
02999 
03000     /*
03001      * Calculate the size of the biggest tick label. This is used by CalcMargins().
03002      * For 'x' ticks, it returns the height . For 'y' ticks, it returns the width.
03003      * This means height along Y, or width along X - not relative to the text angle.
03004      * That is what we need to calculate the needed margin space.
03005      * (Previous versions of PHPlot estimated this, using the maximum X or Y value,
03006      * or maybe the longest string. That doesn't work. -10 is longer than 9, etc.
03007      * So this gets the actual size of each label, slow as that may be.
03008      */
03009     function CalcMaxTickLabelSize($which)
03010     {
03011         list($tick_val, $tick_end, $tick_step) = $this->CalcTicks($which);
03012 
03013         if ($which == 'x') {
03014           $font = $this->x_label_font;
03015           $angle = $this->x_label_angle;
03016         } elseif ($which == 'y') {
03017           $font = $this->y_label_font;
03018           $angle = $this->y_label_angle;
03019         } else {
03020           return $this->PrintError("CalcMaxTickLabelSize: Invalid usage ($which)");
03021         }
03022 
03023         $max_width = 0;
03024         $max_height = 0;
03025 
03026         // Loop over ticks, same as DrawXTicks and DrawYTicks:
03027         while ($tick_val <= $tick_end) {
03028             $tick_label = $this->FormatLabel($which, $tick_val);
03029             list($width, $height) = $this->SizeText($font, $angle, $tick_label);
03030             if ($width > $max_width) $max_width = $width;
03031             if ($height > $max_height) $max_height = $height;
03032             $tick_val += $tick_step;
03033         }
03034         if ($this->GetCallback('debug_scale')) {
03035             $this->DoCallback('debug_scale', __FUNCTION__, array(
03036                 'which' => $which, 'height' => $max_height, 'width' => $max_width));
03037         }
03038 
03039         if ($which == 'x')
03040             return $max_height;
03041         return $max_width;
03042     }
03043 
03044     /*
03045      * Calculate the size of the biggest X data label. This is used by CalcMargins().
03046      * Returns the height along Y axis of the biggest X data label.
03047      * (This calculates width and height, but only height is used at present.)
03048      */
03049     function CalcMaxDataLabelSize()
03050     {
03051         $font = $this->x_label_font;
03052         $angle = $this->x_label_angle;
03053         $max_width = 0;
03054         $max_height = 0;
03055 
03056         // Loop over all data labels and find the biggest:
03057         for ($i = 0; $i < $this->num_data_rows; $i++) {
03058             $label = $this->FormatLabel('x', $this->data[$i][0]);
03059             list($width, $height) = $this->SizeText($font, $angle, $label);
03060             if ($width > $max_width) $max_width = $width;
03061             if ($height > $max_height) $max_height = $height;
03062         }
03063         if ($this->GetCallback('debug_scale')) {
03064             $this->DoCallback('debug_scale', __FUNCTION__, array(
03065                 'height' => $max_height, 'width' => $max_width));
03066         }
03067 
03068         return $max_height;
03069     }
03070 
03077     function FormatLabel($which_pos, $which_lab)
03078     {
03079         $lab = $which_lab;   // Default to no formatting.
03080         if ($lab !== '') {   // Don't format empty strings (especially as time or numbers)
03081             if ($which_pos == 'x') {
03082                 switch ($this->x_label_type) {
03083                 case 'title':  // Note: This is obsolete
03084                     $lab = @ $this->data[$which_lab][0];
03085                     break;
03086                 case 'data':
03087                     $lab = $this->number_format($which_lab, $this->x_precision).$this->data_units_text;
03088                     break;
03089                 case 'time':
03090                     $lab = strftime($this->x_time_format, $which_lab);
03091                     break;
03092                 }
03093             } elseif ($which_pos == 'y') {
03094                 switch ($this->y_label_type) {
03095                 case 'data':
03096                     $lab = $this->number_format($which_lab, $this->y_precision).$this->data_units_text;
03097                     break;
03098                 case 'time':
03099                     $lab = strftime($this->y_time_format, $which_lab);
03100                     break;
03101                 }
03102             }
03103         }
03104         return $lab;
03105     } //function FormatLabel
03106 
03107 
03108 
03112 
03116     function SetXTickIncrement($which_ti='')
03117     {
03118         $this->x_tick_inc = $which_ti;
03119         if (!empty($which_ti)) {
03120             $this->num_x_ticks = ''; //either use num_x_ticks or x_tick_inc, not both
03121         }
03122         return TRUE;
03123     }
03124 
03128     function SetYTickIncrement($which_ti='')
03129     {
03130         $this->y_tick_inc = $which_ti;
03131         if (!empty($which_ti)) {
03132             $this->num_y_ticks = ''; //either use num_y_ticks or y_tick_inc, not both
03133         }
03134         return TRUE;
03135     }
03136 
03137 
03138     function SetNumXTicks($which_nt)
03139     {
03140         $this->num_x_ticks = $which_nt;
03141         if (!empty($which_nt)) {
03142             $this->x_tick_inc = '';  //either use num_x_ticks or x_tick_inc, not both
03143         }
03144         return TRUE;
03145     }
03146 
03147     function SetNumYTicks($which_nt)
03148     {
03149         $this->num_y_ticks = $which_nt;
03150         if (!empty($which_nt)) {
03151             $this->y_tick_inc = '';  //either use num_y_ticks or y_tick_inc, not both
03152         }
03153         return TRUE;
03154     }
03155 
03159     function SetYTickPos($which_tp)
03160     {
03161         $this->y_tick_pos = $this->CheckOption($which_tp, 'plotleft, plotright, both, yaxis, none', __FUNCTION__);
03162         return (boolean)$this->y_tick_pos;
03163     }
03167     function SetXTickPos($which_tp)
03168     {
03169         $this->x_tick_pos = $this->CheckOption($which_tp, 'plotdown, plotup, both, xaxis, none', __FUNCTION__);
03170         return (boolean)$this->x_tick_pos;
03171     }
03172 
03176     function SetSkipTopTick($skip)
03177     {
03178         $this->skip_top_tick = (bool)$skip;
03179         return TRUE;
03180     }
03181 
03185     function SetSkipBottomTick($skip)
03186     {
03187         $this->skip_bottom_tick = (bool)$skip;
03188         return TRUE;
03189     }
03190 
03194     function SetSkipLeftTick($skip)
03195     {
03196         $this->skip_left_tick = (bool)$skip;
03197         return TRUE;
03198     }
03199 
03203     function SetSkipRightTick($skip)
03204     {
03205         $this->skip_right_tick = (bool)$skip;
03206         return TRUE;
03207     }
03208 
03209     function SetXTickLength($which_xln)
03210     {
03211         $this->x_tick_length = $which_xln;
03212         return TRUE;
03213     }
03214 
03215     function SetYTickLength($which_yln)
03216     {
03217         $this->y_tick_length = $which_yln;
03218         return TRUE;
03219     }
03220 
03221     function SetXTickCrossing($which_xc)
03222     {
03223         $this->x_tick_cross = $which_xc;
03224         return TRUE;
03225     }
03226 
03227     function SetYTickCrossing($which_yc)
03228     {
03229         $this->y_tick_cross = $which_yc;
03230         return TRUE;
03231     }
03232 
03233 
03237 
03241     function DrawBackground()
03242     {
03243         // Don't draw this twice if drawing two plots on one image
03244         if (! $this->background_done) {
03245             if (isset($this->bgimg)) {    // If bgimg is defined, use it
03246                 $this->tile_img($this->bgimg, 0, 0, $this->image_width, $this->image_height, $this->bgmode);
03247             } else {                        // Else use solid color
03248                 ImageFilledRectangle($this->img, 0, 0, $this->image_width, $this->image_height,
03249                                      $this->ndx_bg_color);
03250             }
03251             $this->background_done = TRUE;
03252         }
03253         return TRUE;
03254     }
03255 
03256 
03260     function DrawPlotAreaBackground()
03261     {
03262         if (isset($this->plotbgimg)) {
03263             $this->tile_img($this->plotbgimg, $this->plot_area[0], $this->plot_area[1],
03264                             $this->plot_area_width, $this->plot_area_height, $this->plotbgmode);
03265         }
03266         else {
03267             if ($this->draw_plot_area_background) {
03268                 ImageFilledRectangle($this->img, $this->plot_area[0], $this->plot_area[1],
03269                                      $this->plot_area[2], $this->plot_area[3], $this->ndx_plot_bg_color);
03270             }
03271         }
03272 
03273         return TRUE;
03274     }
03275 
03276 
03287     function tile_img($file, $xorig, $yorig, $width, $height, $mode)
03288     {
03289         $im = $this->GetImage($file, $tile_width, $tile_height);
03290         if (!$im)
03291             return FALSE;  // GetImage already produced an error message.
03292 
03293         if ($mode == 'scale') {
03294             imagecopyresized($this->img, $im, $xorig, $yorig, 0, 0, $width, $height, $tile_width, $tile_height);
03295             return TRUE;
03296         } else if ($mode == 'centeredtile') {
03297             $x0 = - floor($tile_width/2);   // Make the tile look better
03298             $y0 = - floor($tile_height/2);
03299         } else if ($mode = 'tile') {
03300             $x0 = 0;
03301             $y0 = 0;
03302         }
03303 
03304         // Actually draw the tile
03305 
03306         // But first on a temporal image.
03307         $tmp = ImageCreate($width, $height);
03308         if (! $tmp)
03309             return $this->PrintError('tile_img(): Could not create image resource.');
03310 
03311         for ($x = $x0; $x < $width; $x += $tile_width)
03312             for ($y = $y0; $y < $height; $y += $tile_height)
03313                 imagecopy($tmp, $im, $x, $y, 0, 0, $tile_width, $tile_height);
03314 
03315         // Copy the temporal image onto the final one.
03316         imagecopy($this->img, $tmp, $xorig, $yorig, 0,0, $width, $height);
03317 
03318         // Free resources
03319         imagedestroy($tmp);
03320         imagedestroy($im);
03321 
03322         return TRUE;
03323     }  // function tile_img
03324 
03325 
03329     function DrawImageBorder()
03330     {
03331         switch ($this->image_border_type) {
03332         case 'raised':
03333             ImageLine($this->img, 0, 0, $this->image_width-1, 0, $this->ndx_i_border);
03334             ImageLine($this->img, 1, 1, $this->image_width-2, 1, $this->ndx_i_border);
03335             ImageLine($this->img, 0, 0, 0, $this->image_height-1, $this->ndx_i_border);
03336             ImageLine($this->img, 1, 1, 1, $this->image_height-2, $this->ndx_i_border);
03337             ImageLine($this->img, $this->image_width-1, 0, $this->image_width-1,
03338                       $this->image_height-1, $this->ndx_i_border_dark);
03339             ImageLine($this->img, 0, $this->image_height-1, $this->image_width-1,
03340                       $this->image_height-1, $this->ndx_i_border_dark);
03341             ImageLine($this->img, $this->image_width-2, 1, $this->image_width-2,
03342                       $this->image_height-2, $this->ndx_i_border_dark);
03343             ImageLine($this->img, 1, $this->image_height-2, $this->image_width-2,
03344                       $this->image_height-2, $this->ndx_i_border_dark);
03345             break;
03346         case 'plain':
03347             ImageLine($this->img, 0, 0, $this->image_width-1, 0, $this->ndx_i_border_dark);
03348             ImageLine($this->img, $this->image_width-1, 0, $this->image_width-1,
03349                       $this->image_height-1, $this->ndx_i_border_dark);
03350             ImageLine($this->img, $this->image_width-1, $this->image_height-1, 0, $this->image_height-1,
03351                       $this->ndx_i_border_dark);
03352             ImageLine($this->img, 0, 0, 0, $this->image_height-1, $this->ndx_i_border_dark);
03353             break;
03354         case 'none':
03355             break;
03356         default:
03357             return $this->PrintError("DrawImageBorder(): unknown image_border_type: '$this->image_border_type'");
03358         }
03359         return TRUE;
03360     }
03361 
03362 
03366     function DrawTitle()
03367     {
03368         // Center of the plot area
03369         //$xpos = ($this->plot_area[0] + $this->plot_area_width )/ 2;
03370 
03371         // Center of the image:
03372         $xpos = $this->image_width / 2;
03373 
03374         // Place it at almost at the top
03375         $ypos = $this->safe_margin;
03376 
03377         $this->DrawText($this->title_font, 0, $xpos, $ypos,
03378                         $this->ndx_title_color, $this->title_txt, 'center', 'top');
03379 
03380         return TRUE;
03381 
03382     }
03383 
03384 
03388     function DrawXTitle()
03389     {
03390         if ($this->x_title_pos == 'none')
03391             return TRUE;
03392 
03393         // Center of the plot
03394         $xpos = ($this->plot_area[2] + $this->plot_area[0]) / 2;
03395 
03396         // Upper title
03397         if ($this->x_title_pos == 'plotup' || $this->x_title_pos == 'both') {
03398             $ypos = $this->plot_area[1] - $this->x_title_top_offset;
03399             $this->DrawText($this->x_title_font, 0, $xpos, $ypos, $this->ndx_title_color,
03400                             $this->x_title_txt, 'center', 'bottom');
03401         }
03402         // Lower title
03403         if ($this->x_title_pos == 'plotdown' || $this->x_title_pos == 'both') {
03404             $ypos = $this->plot_area[3] + $this->x_title_bot_offset;
03405             $this->DrawText($this->x_title_font, 0, $xpos, $ypos, $this->ndx_title_color,
03406                             $this->x_title_txt, 'center', 'top');
03407         }
03408         return TRUE;
03409     }
03410 
03414     function DrawYTitle()
03415     {
03416         if ($this->y_title_pos == 'none')
03417             return TRUE;
03418 
03419         // Center the title vertically to the plot area
03420         $ypos = ($this->plot_area[3] + $this->plot_area[1]) / 2;
03421 
03422         if ($this->y_title_pos == 'plotleft' || $this->y_title_pos == 'both') {
03423             $xpos = $this->plot_area[0] - $this->y_title_left_offset;
03424             $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color,
03425                             $this->y_title_txt, 'right', 'center');
03426         }
03427         if ($this->y_title_pos == 'plotright' || $this->y_title_pos == 'both') {
03428             $xpos = $this->plot_area[2] + $this->y_title_right_offset;
03429             $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color,
03430                             $this->y_title_txt, 'left', 'center');
03431         }
03432 
03433         return TRUE;
03434     }
03435 
03436 
03437     /*
03438      * \note Horizontal grid lines overwrite horizontal axis with y=0, so call this first, then DrawXAxis()
03439      */
03440     function DrawYAxis()
03441     {
03442         // Draw ticks, labels and grid, if any
03443         $this->DrawYTicks();
03444 
03445         // Draw Y axis at X = y_axis_x_pixels
03446         ImageLine($this->img, $this->y_axis_x_pixels, $this->plot_area[1],
03447                   $this->y_axis_x_pixels, $this->plot_area[3], $this->ndx_grid_color);
03448 
03449         return TRUE;
03450     }
03451 
03452     /*
03453      *
03454      */
03455     function DrawXAxis()
03456     {
03457         // Draw ticks, labels and grid
03458         $this->DrawXTicks();
03459 
03460         /* This tick and label tend to overlap with regular Y Axis labels,
03461          * as Mike Pullen pointed out.
03462          *
03463         //Draw Tick and Label for X axis
03464         if (! $this->skip_bottom_tick) {
03465             $ylab =$this->FormatLabel('y', $this->x_axis_position);
03466             $this->DrawYTick($ylab, $this->x_axis_y_pixels);
03467         }
03468         */
03469         //Draw X Axis at Y = x_axis_y_pixels
03470         ImageLine($this->img, $this->plot_area[0]+1, $this->x_axis_y_pixels,
03471                   $this->plot_area[2]-1, $this->x_axis_y_pixels, $this->ndx_grid_color);
03472 
03473         return TRUE;
03474     }
03475 
03479     function DrawYTick($which_ylab, $which_ypix)
03480     {
03481         // Ticks on Y axis
03482         if ($this->y_tick_pos == 'yaxis') {
03483             ImageLine($this->img, $this->y_axis_x_pixels - $this->y_tick_length, $which_ypix,
03484                       $this->y_axis_x_pixels + $this->y_tick_cross, $which_ypix, $this->ndx_tick_color);
03485         }
03486 
03487         // Ticks to the left of the Plot Area
03488         if (($this->y_tick_pos == 'plotleft') || ($this->y_tick_pos == 'both') ) {
03489             ImageLine($this->img, $this->plot_area[0] - $this->y_tick_length, $which_ypix,
03490                       $this->plot_area[0] + $this->y_tick_cross, $which_ypix, $this->ndx_tick_color);
03491         }
03492 
03493         // Ticks to the right of the Plot Area
03494         if (($this->y_tick_pos == 'plotright') || ($this->y_tick_pos == 'both') ) {
03495             ImageLine($this->img, $this->plot_area[2] + $this->y_tick_length, $which_ypix,
03496                       $this->plot_area[2] - $this->y_tick_cross, $which_ypix, $this->ndx_tick_color);
03497         }
03498 
03499         // Labels on Y axis
03500         if ($this->y_tick_label_pos == 'yaxis') {
03501             $this->DrawText($this->y_label_font, $this->y_label_angle,
03502                             $this->y_axis_x_pixels - $this->y_label_axis_offset, $which_ypix,
03503                             $this->ndx_text_color, $which_ylab, 'right', 'center');
03504         }
03505 
03506         // Labels to the left of the plot area
03507         if ($this->y_tick_label_pos == 'plotleft' || $this->y_tick_label_pos == 'both') {
03508             $this->DrawText($this->y_label_font, $this->y_label_angle,
03509                             $this->plot_area[0] - $this->y_label_left_offset, $which_ypix,
03510                             $this->ndx_text_color, $which_ylab, 'right', 'center');
03511         }
03512         // Labels to the right of the plot area
03513         if ($this->y_tick_label_pos == 'plotright' || $this->y_tick_label_pos == 'both') {
03514             $this->DrawText($this->y_label_font, $this->y_label_angle,
03515                             $this->plot_area[2] + $this->y_label_right_offset, $which_ypix,
03516                             $this->ndx_text_color, $which_ylab, 'left', 'center');
03517         }
03518         return TRUE;
03519     } // Function DrawYTick()
03520 
03521 
03528     function DrawYTicks()
03529     {
03530         // Sets the line style for IMG_COLOR_STYLED lines (grid)
03531         if ($this->dashed_grid) {
03532             $this->SetDashedStyle($this->ndx_light_grid_color);
03533             $style = IMG_COLOR_STYLED;
03534         } else {
03535             $style = $this->ndx_light_grid_color;
03536         }
03537 
03538         // Calculate the tick start, end, and step:
03539         list($y_tmp, $y_end, $delta_y) = $this->CalcTicks('y');
03540 
03541         for (;$y_tmp <= $y_end; $y_tmp += $delta_y) {
03542             $ylab = $this->FormatLabel('y', $y_tmp);
03543             $y_pixels = $this->ytr($y_tmp);
03544 
03545             // Horizontal grid line
03546             if ($this->draw_y_grid) {
03547                 ImageLine($this->img, $this->plot_area[0]+1, $y_pixels, $this->plot_area[2]-1, $y_pixels, $style);
03548             }
03549 
03550             // Draw tick mark(s)
03551             $this->DrawYTick($ylab, $y_pixels);
03552         }
03553         return TRUE;
03554     } // function DrawYTicks
03555 
03559     function DrawXTick($which_xlab, $which_xpix)
03560     {
03561         // Ticks on X axis
03562         if ($this->x_tick_pos == 'xaxis') {
03563             ImageLine($this->img, $which_xpix, $this->x_axis_y_pixels - $this->x_tick_cross,
03564                       $which_xpix, $this->x_axis_y_pixels + $this->x_tick_length, $this->ndx_tick_color);
03565         }
03566 
03567         // Ticks on top of the Plot Area
03568         if ($this->x_tick_pos == 'plotup' || $this->x_tick_pos == 'both') {
03569             ImageLine($this->img, $which_xpix, $this->plot_area[1] - $this->x_tick_length,
03570                       $which_xpix, $this->plot_area[1] + $this->x_tick_cross, $this->ndx_tick_color);
03571         }
03572 
03573         // Ticks on bottom of Plot Area
03574         if ($this->x_tick_pos == 'plotdown' || $this->x_tick_pos == 'both') {
03575             ImageLine($this->img, $which_xpix, $this->plot_area[3] + $this->x_tick_length,
03576                       $which_xpix, $this->plot_area[3] - $this->x_tick_cross, $this->ndx_tick_color);
03577         }
03578 
03579         // Label on X axis
03580         if ($this->x_tick_label_pos == 'xaxis') {
03581             $this->DrawText($this->x_label_font, $this->x_label_angle,
03582                             $which_xpix, $this->x_axis_y_pixels + $this->x_label_axis_offset,
03583                             $this->ndx_text_color, $which_xlab, 'center', 'top');
03584         }
03585 
03586         // Label on top of the Plot Area
03587         if ($this->x_tick_label_pos == 'plotup' || $this->x_tick_label_pos == 'both') {
03588             $this->DrawText($this->x_label_font, $this->x_label_angle,
03589                             $which_xpix, $this->plot_area[1] - $this->x_label_top_offset,
03590                             $this->ndx_text_color, $which_xlab, 'center', 'bottom');
03591         }
03592 
03593         // Label on bottom of the Plot Area
03594         if ($this->x_tick_label_pos == 'plotdown' || $this->x_tick_label_pos == 'both') {
03595             $this->DrawText($this->x_label_font, $this->x_label_angle,
03596                             $which_xpix, $this->plot_area[3] + $this->x_label_bot_offset,
03597                             $this->ndx_text_color, $which_xlab, 'center', 'top');
03598         }
03599         return TRUE;
03600     }
03601 
03609     function DrawXTicks()
03610     {
03611         // Sets the line style for IMG_COLOR_STYLED lines (grid)
03612         if ($this->dashed_grid) {
03613             $this->SetDashedStyle($this->ndx_light_grid_color);
03614             $style = IMG_COLOR_STYLED;
03615         } else {
03616             $style = $this->ndx_light_grid_color;
03617         }
03618 
03619         // Calculate the tick start, end, and step:
03620         list($x_tmp, $x_end, $delta_x) = $this->CalcTicks('x');
03621 
03622         for (;$x_tmp <= $x_end; $x_tmp += $delta_x) {
03623             $xlab = $this->FormatLabel('x', $x_tmp);
03624             $x_pixels = $this->xtr($x_tmp);
03625 
03626             // Vertical grid lines
03627             if ($this->draw_x_grid) {
03628                 ImageLine($this->img, $x_pixels, $this->plot_area[1], $x_pixels, $this->plot_area[3], $style);
03629             }
03630 
03631             // Draw tick mark(s)
03632             $this->DrawXTick($xlab, $x_pixels);
03633         }
03634         return TRUE;
03635     } // function DrawXTicks
03636 
03637 
03641     function DrawPlotBorder()
03642     {
03643         switch ($this->plot_border_type) {
03644         case 'left':    // for past compatibility
03645         case 'plotleft':
03646             ImageLine($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y),
03647                       $this->plot_area[0], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
03648             break;
03649         case 'right':
03650         case 'plotright':
03651             ImageLine($this->img, $this->plot_area[2], $this->ytr($this->plot_min_y),
03652                       $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
03653             break;
03654         case 'both':
03655         case 'sides':
03656              ImageLine($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y),
03657                       $this->plot_area[0], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
03658             ImageLine($this->img, $this->plot_area[2], $this->ytr($this->plot_min_y),
03659                       $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
03660             break;
03661         case 'none':
03662             //Draw No Border
03663             break;
03664         case 'full':
03665         default:
03666             ImageRectangle($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y),
03667                            $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
03668             break;
03669         }
03670         return TRUE;
03671     }
03672 
03673 
03678     function DrawDataLabel($which_font, $which_angle, $x_world, $y_world, $which_color, $which_text,
03679                       $which_halign = 'center', $which_valign = 'bottom', $x_adjustment=0, $y_adjustment=0) 
03680     {
03681         $data_label = $this->FormatLabel('y', $which_text);
03682         //since DrawDataLabel is going to be called alot - perhaps for speed it is better to 
03683         //not use this if statement and just always assume which_font is x_label_font (ditto for color).
03684         if ( empty($which_font) ) 
03685             $which_font = $this->x_label_font;
03686 
03687         $which_angle = empty($which_angle)?'0':$this->x_label_angle;
03688 
03689         if ( empty($which_color) ) 
03690             $which_color = $this->ndx_title_color;
03691 
03692         $x_pixels = $this->xtr($x_world) + $x_adjustment;
03693         $y_pixels = $this->ytr($y_world) + $y_adjustment;
03694 
03695         $this->DrawText($which_font, $which_angle, $x_pixels, $y_pixels,
03696                         $which_color, $data_label, $which_halign, $which_valign);
03697 
03698         return TRUE;
03699 
03700     }
03709     function DrawXDataLabel($xlab, $xpos, $row=FALSE)
03710     {
03711         // FIXME!! not working...
03712         // if (($this->_x_label_cnt++ % $this->x_label_inc) != 0)
03713         //    return;
03714 
03715         $xlab = $this->FormatLabel('x', $xlab);
03716 
03717         // Labels below the plot area
03718         if ($this->x_data_label_pos == 'plotdown' || $this->x_data_label_pos == 'both')
03719             $this->DrawText($this->x_label_font, $this->x_label_angle,
03720                             $xpos, $this->plot_area[3] + $this->x_label_bot_offset,
03721                             $this->ndx_text_color, $xlab, 'center', 'top');
03722 
03723         // Labels above the plot area
03724         if ($this->x_data_label_pos == 'plotup' || $this->x_data_label_pos == 'both')
03725             $this->DrawText($this->x_label_font, $this->x_label_angle,
03726                             $xpos, $this->plot_area[1] - $this->x_label_top_offset,
03727                             $this->ndx_text_color, $xlab, 'center', 'bottom');
03728 
03729         // $row=0 means this is the first row. $row=FALSE means don't do any rows.
03730         if ($row !== FALSE && $this->draw_x_data_label_lines)
03731             $this->DrawXDataLine($xpos, $row);
03732         return TRUE;
03733     }
03734 
03743     function DrawXDataLine($xpos, $row)
03744     {
03745         // Sets the line style for IMG_COLOR_STYLED lines (grid)
03746         if($this->dashed_grid) {
03747             $this->SetDashedStyle($this->ndx_light_grid_color);
03748             $style = IMG_COLOR_STYLED;
03749         } else {
03750             $style = $this->ndx_light_grid_color;
03751         }
03752 
03753         // Lines from the bottom up
03754         if ($this->x_data_label_pos == 'both') {
03755             ImageLine($this->img, $xpos, $this->plot_area[3], $xpos, $this->plot_area[1], $style);
03756         }
03757         // Lines from the bottom of the plot up to the max Y value at this X:
03758         else if ($this->x_data_label_pos == 'plotdown') {
03759             $ypos = $this->ytr($this->data_maxy[$row]);
03760             ImageLine($this->img, $xpos, $ypos, $xpos, $this->plot_area[3], $style);
03761         }
03762         // Lines from the top of the plot down to the min Y value at this X:
03763         else if ($this->x_data_label_pos == 'plotup') {
03764             $ypos = $this->ytr($this->data_miny[$row]);
03765             ImageLine($this->img, $xpos, $this->plot_area[1], $xpos, $ypos, $style);
03766         }
03767         return TRUE;
03768     }
03769 
03770 
03776     function DrawLegend()
03777     {
03778         // Find maximum legend label line width.
03779         $max_width = 0;
03780         foreach ($this->legend as $line) {
03781             list($width, $unused) = $this->SizeText($this->legend_font, 0, $line);
03782             if ($width > $max_width) $max_width = $width;
03783         }
03784 
03785         // For the color box and line spacing, use a typical font character: 8.
03786         list($char_w, $char_h) = $this->SizeText($this->legend_font, 0, '8');
03787 
03788         // Normalize text alignment and colorbox alignment variables:
03789         $text_align = isset($this->legend_text_align) ? $this->legend_text_align : 'right';
03790         $colorbox_align = isset($this->legend_colorbox_align) ? $this->legend_colorbox_align : 'right';
03791 
03792         // Sizing parameters:
03793         $v_margin = $char_h/2;                         // Between vertical borders and labels
03794         $dot_height = $char_h + $this->line_spacing;   // Height of the small colored boxes
03795         // Overall legend box width e.g.: | space colorbox space text space |
03796         // where colorbox and each space are 1 char width.
03797         if ($colorbox_align != 'none') {
03798             $width = $max_width + 4 * $char_w;
03799             $draw_colorbox = True;
03800         } else {
03801             $width = $max_width + 2 * $char_w;
03802             $draw_colorbox = False;
03803         }
03804 
03806         // User-defined position specified?
03807         if ( !isset($this->legend_x_pos) || !isset($this->legend_y_pos)) {
03808             // No, use default
03809             $box_start_x = $this->plot_area[2] - $width - $this->safe_margin;
03810             $box_start_y = $this->plot_area[1] + $this->safe_margin;
03811         } elseif (isset($this->legend_xy_world)) {
03812             // User-defined position in world-coordinates (See SetLegendWorld).
03813             $box_start_x = $this->xtr($this->legend_x_pos);
03814             $box_start_y = $this->ytr($this->legend_y_pos);
03815             unset($this->legend_xy_world);
03816         } else {
03817             // User-defined position in pixel coordinates.
03818             $box_start_x = $this->legend_x_pos;
03819             $box_start_y = $this->legend_y_pos;
03820         }
03821 
03822         // Lower right corner
03823         $box_end_y = $box_start_y + $dot_height*(count($this->legend)) + 2*$v_margin;
03824         $box_end_x = $box_start_x + $width;
03825 
03826         // Draw outer box
03827         ImageFilledRectangle($this->img, $box_start_x, $box_start_y, $box_end_x, $box_end_y, $this->ndx_bg_color);
03828         ImageRectangle($this->img, $box_start_x, $box_start_y, $box_end_x, $box_end_y, $this->ndx_grid_color);
03829 
03830         $color_index = 0;
03831         $max_color_index = count($this->ndx_data_colors) - 1;
03832 
03833         // Calculate color box and text horizontal positions.
03834         if (!$draw_colorbox) {
03835             if ($text_align == 'left')
03836                 $x_pos = $box_start_x + $char_w;
03837             else
03838                 $x_pos = $box_end_x - $char_w;
03839         } elseif ($colorbox_align == 'left') {
03840             $dot_left_x = $box_start_x + $char_w;
03841             $dot_right_x = $dot_left_x + $char_w;
03842             if ($text_align == 'left')
03843                 $x_pos = $dot_left_x + 2 * $char_w;
03844             else
03845                 $x_pos = $box_end_x - $char_w;
03846         } else {
03847             $dot_left_x = $box_end_x - 2 * $char_w;
03848             $dot_right_x = $dot_left_x + $char_w;
03849             if ($text_align == 'left')
03850                 $x_pos = $box_start_x + $char_w;
03851             else
03852                 $x_pos = $dot_left_x - $char_w;
03853         }
03854 
03855         // Calculate starting position of first text line.  The bottom of each color box
03856         // lines up with the bottom (baseline) of its text line.
03857         $y_pos = $box_start_y + $v_margin + $dot_height;
03858 
03859         foreach ($this->legend as $leg) {
03860             // Draw text with requested alignment:
03861             $this->DrawText($this->legend_font, 0, $x_pos, $y_pos,
03862                             $this->ndx_text_color, $leg, $text_align, 'bottom');
03863             if ($draw_colorbox) {
03864                 // Draw a box in the data color
03865                 $y1 = $y_pos - $dot_height + 1;
03866                 $y2 = $y_pos - 1;
03867                 ImageFilledRectangle($this->img, $dot_left_x, $y1, $dot_right_x, $y2,
03868                                      $this->ndx_data_colors[$color_index]);
03869                 // Draw a rectangle around the box
03870                 ImageRectangle($this->img, $dot_left_x, $y1, $dot_right_x, $y2,
03871                                $this->ndx_text_color);
03872             }
03873             $y_pos += $dot_height;
03874 
03875             $color_index++;
03876             if ($color_index > $max_color_index)
03877                 $color_index = 0;
03878         }
03879         return TRUE;
03880     } // Function DrawLegend()
03881 
03882 
03886     function DrawAxisLegend()
03887     {
03888         // Calculate available room
03889         // Calculate length of all items (boxes included)
03890         // Calculate number of lines and room it would take. FIXME: this should be known in CalcMargins()
03891         // Draw.
03892     }
03893 
03897 
03898 
03909     function DrawPieChart()
03910     {
03911         $xpos = $this->plot_area[0] + $this->plot_area_width/2;
03912         $ypos = $this->plot_area[1] + $this->plot_area_height/2;
03913         $diameter = min($this->plot_area_width, $this->plot_area_height);
03914         $radius = $diameter/2;
03915 
03916         // Get sum of each column? One pie slice per column
03917         if ($this->data_type === 'text-data') {
03918             for ($i = 0; $i < $this->num_data_rows; $i++) {
03919                 for ($j = 1; $j < $this->num_recs[$i]; $j++) {      // Label ($row[0]) unused in these pie charts
03920                     @ $sumarr[$j] += abs($this->data[$i][$j]);      // NOTE!  sum > 0 to make pie charts
03921                 }
03922             }
03923         }
03924         // Or only one column per row, one pie slice per row?
03925         else if ($this->data_type == 'text-data-single') {
03926             for ($i = 0; $i < $this->num_data_rows; $i++) {
03927                 $legend[$i] = $this->data[$i][0];                   // Set the legend to column labels
03928                 $sumarr[$i] = $this->data[$i][1];
03929             }
03930         }
03931         else if ($this->data_type == 'data-data') {
03932             for ($i = 0; $i < $this->num_data_rows; $i++) {
03933                 for ($j = 2; $j < $this->num_recs[$i]; $j++) {
03934                     @ $sumarr[$j] += abs($this->data[$i][$j]);
03935                 }
03936             }
03937         }
03938         else {
03939             return $this->PrintError("DrawPieChart(): Data type '$this->data_type' not supported.");
03940         }
03941 
03942         $total = array_sum($sumarr);
03943 
03944         if ($total == 0) {
03945             return $this->PrintError('DrawPieChart(): Empty data set');
03946         }
03947 
03948         if ($this->shading) {
03949             $diam2 = $diameter / 2;
03950         } else {
03951             $diam2 = $diameter;
03952         }
03953         $max_data_colors = count ($this->data_colors);
03954 
03955         for ($h = $this->shading; $h >= 0; $h--) {
03956             $color_index = 0;
03957             $start_angle = 0;
03958             $end_angle = 0;
03959             foreach ($sumarr as $val) {
03960                 // For shaded pies: the last one (at the top of the "stack") has a brighter color:
03961                 if ($h == 0)
03962                     $slicecol = $this->ndx_data_colors[$color_index];
03963                 else
03964                     $slicecol = $this->ndx_data_dark_colors[$color_index];
03965 
03966                 $label_txt = $this->number_format(($val / $total * 100), $this->y_precision) . '%';
03967                 $val = 360 * ($val / $total);
03968 
03969                 // NOTE that imagefilledarc measures angles CLOCKWISE (go figure why),
03970                 // so the pie chart would start clockwise from 3 o'clock, would it not be
03971                 // for the reversal of start and end angles in imagefilledarc()
03972                 // Also note ImageFilledArc only takes angles in integer degrees, and if the
03973                 // the start and end angles match then you get a full circle not a zero-width
03974                 // pie. This is bad. So skip any zero-size wedge. On the other hand, we cannot
03975                 // let cumulative error from rounding to integer result in missing wedges. So
03976                 // keep the running total as a float, and round the angles. It should not
03977                 // be necessary to check that the last wedge ends at 360 degrees.
03978                 $start_angle = $end_angle;
03979                 $end_angle += $val;
03980                 // This method of conversion to integer - truncate after reversing it - was
03981                 // chosen to match the implicit method of PHPlot<=5.0.4 to get the same slices.
03982                 $arc_start_angle = (int)(360 - $start_angle);
03983                 $arc_end_angle = (int)(360 - $end_angle);
03984 
03985                 if ($arc_start_angle > $arc_end_angle) {
03986                     $mid_angle = deg2rad($end_angle - ($val / 2));
03987 
03988                     // Draw the slice
03989                     ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2,
03990                                    $arc_end_angle, $arc_start_angle,
03991                                    $slicecol, IMG_ARC_PIE);
03992 
03993                     // Draw the labels only once
03994                     if ($h == 0) {
03995                         // Draw the outline
03996                         if (! $this->shading)
03997                             ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2,
03998                                            $arc_end_angle, $arc_start_angle,
03999                                            $this->ndx_grid_color, IMG_ARC_PIE | IMG_ARC_EDGED |IMG_ARC_NOFILL);
04000 
04001 
04002                         // The '* 1.2' trick is to get labels out of the pie chart so there are more
04003                         // chances they can be seen in small sectors.
04004                         $label_x = $xpos + ($diameter * 1.2 * cos($mid_angle)) * $this->label_scale_position;
04005                         $label_y = $ypos+$h - ($diam2 * 1.2 * sin($mid_angle)) * $this->label_scale_position;
04006 
04007                         $this->DrawText($this->generic_font, 0, $label_x, $label_y, $this->ndx_grid_color,
04008                                         $label_txt, 'center', 'center');
04009                     }
04010                 }
04011                 if (++$color_index >= $max_data_colors)
04012                     $color_index = 0;
04013             }   // end for
04014         }   // end for
04015         return TRUE;
04016     }
04017 
04018 
04023     function DrawDotsError()
04024     {
04025         if ($this->data_type != 'data-data-error') {
04026             return $this->PrintError("DrawDotsError(): Data type '$this->data_type' not supported.");
04027         }
04028 
04029         // Suppress duplicate X data labels in linepoints mode; let DrawLinesError() do them.
04030         $do_labels = ($this->plot_type != 'linepoints');
04031 
04032         for($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
04033             $record = 1;                                // Skip record #0 (title)
04034 
04035             $x_now = $this->data[$row][$record++];  // Read it, advance record index
04036 
04037             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates.
04038 
04039             // Draw X Data labels?
04040             if ($this->x_data_label_pos != 'none' && $do_labels)
04041                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
04042 
04043             // Now go for Y, E+, E-
04044             for ($idx = 0; $record < $this->num_recs[$row]; $idx++) {
04045                     // Y:
04046                     $y_now = $this->data[$row][$record++];
04047                     $this->DrawDot($x_now, $y_now, $idx, $this->ndx_data_colors[$idx]);
04048 
04049                     // Error +
04050                     $val = $this->data[$row][$record++];
04051                     $this->DrawYErrorBar($x_now, $y_now, $val, $this->error_bar_shape,
04052                                          $this->ndx_error_bar_colors[$idx]);
04053                     // Error -
04054                     $val = $this->data[$row][$record++];
04055                     $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape,
04056                                          $this->ndx_error_bar_colors[$idx]);
04057             }
04058         }
04059         return TRUE;
04060     } // function DrawDotsError()
04061 
04062 
04063     /*
04064      * Supported data types:
04065      *  - data-data ("title", x, y1, y2, y3, ...)
04066      *  - text-data ("title", y1, y2, y3, ...)
04067      */
04068     function DrawDots()
04069     {
04070         if (!$this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__))
04071             return FALSE;
04072 
04073         // Suppress duplicate X data labels in linepoints mode; let DrawLines() do them.
04074         $do_labels = ($this->plot_type != 'linepoints');
04075 
04076         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
04077             $rec = 1;                    // Skip record #0 (data label)
04078 
04079             // Do we have a value for X?
04080             if ($this->data_type == 'data-data')
04081                 $x_now = $this->data[$row][$rec++];  // Read it, advance record index
04082             else
04083                 $x_now = 0.5 + $cnt++;       // Place text-data at X = 0.5, 1.5, 2.5, etc...
04084 
04085             $x_now_pixels = $this->xtr($x_now);
04086 
04087             // Draw X Data labels?
04088             if ($this->x_data_label_pos != 'none' && $do_labels)
04089                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
04090 
04091             // Proceed with Y values
04092             for($idx = 0;$rec < $this->num_recs[$row]; $rec++, $idx++) {
04093                 if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data
04094                     $this->DrawDot($x_now, $this->data[$row][$rec],
04095                                    $idx, $this->ndx_data_colors[$idx]);
04096                 }
04097             }
04098         }
04099         return TRUE;
04100     } //function DrawDots
04101 
04102 
04106     function DrawThinBarLines()
04107     {
04108         if (!$this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__))
04109             return FALSE;
04110 
04111         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
04112             $rec = 1;                    // Skip record #0 (data label)
04113 
04114             // Do we have a value for X?
04115             if ($this->data_type == 'data-data')
04116                 $x_now = $this->data[$row][$rec++];  // Read it, advance record index
04117             else
04118                 $x_now = 0.5 + $cnt++;       // Place text-data at X = 0.5, 1.5, 2.5, etc...
04119 
04120             $x_now_pixels = $this->xtr($x_now);
04121 
04122             // Draw X Data labels?
04123             if ($this->x_data_label_pos != 'none')
04124                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
04125 
04126             // Proceed with Y values
04127             for($idx = 0;$rec < $this->num_recs[$row]; $rec++, $idx++) {
04128                 if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data
04129                     ImageSetThickness($this->img, $this->line_widths[$idx]);
04130                     // Draws a line from user defined x axis position up to ytr($val)
04131                     ImageLine($this->img, $x_now_pixels, $this->x_axis_y_pixels, $x_now_pixels,
04132                               $this->ytr($this->data[$row][$rec]), $this->ndx_data_colors[$idx]);
04133                 }
04134             }
04135         }
04136 
04137         ImageSetThickness($this->img, 1);
04138         return TRUE;
04139     }  //function DrawThinBarLines
04140 
04144     function DrawYErrorBar($x_world, $y_world, $error_height, $error_bar_type, $color)
04145     {
04146         /*
04147         // TODO: add a parameter to show datalabels next to error bars?
04148         // something like this:
04149         if ($this->x_data_label_pos == 'plot')
04150             $this->DrawText($this->error_font, 90, $x1, $y2,
04151                             $color, $label, 'center', 'bottom');
04152         */
04153 
04154         $x1 = $this->xtr($x_world);
04155         $y1 = $this->ytr($y_world);
04156         $y2 = $this->ytr($y_world+$error_height) ;
04157 
04158         ImageSetThickness($this->img, $this->error_bar_line_width);
04159         ImageLine($this->img, $x1, $y1 , $x1, $y2, $color);
04160 
04161         switch ($error_bar_type) {
04162         case 'line':
04163             break;
04164         case 'tee':
04165             ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color);
04166             break;
04167         default:
04168             ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color);
04169             break;
04170         }
04171 
04172         ImageSetThickness($this->img, 1);
04173         return TRUE;
04174     }
04175 
04181     function DrawDot($x_world, $y_world, $record, $color)
04182     {
04183         // TODO: optimize, avoid counting every time we are called.
04184         $record = $record % count ($this->point_shapes);
04185 
04186         $half_point = $this->point_sizes[$record] / 2;
04187 
04188         $x_mid = $this->xtr($x_world);
04189         $y_mid = $this->ytr($y_world);
04190 
04191         $x1 = $x_mid - $half_point;
04192         $x2 = $x_mid + $half_point;
04193         $y1 = $y_mid - $half_point;
04194         $y2 = $y_mid + $half_point;
04195 
04196         switch ($this->point_shapes[$record]) {
04197         case 'halfline':
04198             ImageLine($this->img, $x1, $y_mid, $x_mid, $y_mid, $color);
04199             break;
04200         case 'line':
04201             ImageLine($this->img, $x1, $y_mid, $x2, $y_mid, $color);
04202             break;
04203         case 'plus':
04204             ImageLine($this->img, $x1, $y_mid, $x2, $y_mid, $color);
04205             ImageLine($this->img, $x_mid, $y1, $x_mid, $y2, $color);
04206             break;
04207         case 'cross':
04208             ImageLine($this->img, $x1, $y1, $x2, $y2, $color);
04209             ImageLine($this->img, $x1, $y2, $x2, $y1, $color);
04210             break;
04211         case 'rect':
04212             ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color);
04213             break;
04214         case 'circle':
04215             ImageArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record], $this->point_sizes[$record],
04216                      0, 360, $color);
04217             break;
04218         case 'dot':
04219             ImageFilledArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record],
04220                            $this->point_sizes[$record], 0, 360, $color, IMG_ARC_PIE);
04221             break;
04222         case 'diamond':
04223             $arrpoints = array( $x1, $y_mid, $x_mid, $y1, $x2, $y_mid, $x_mid, $y2);
04224             ImageFilledPolygon($this->img, $arrpoints, 4, $color);
04225             break;
04226         case 'triangle':
04227             $arrpoints = array( $x1, $y_mid, $x2, $y_mid, $x_mid, $y2);
04228             ImageFilledPolygon($this->img, $arrpoints, 3, $color);
04229             break;
04230         case 'trianglemid':
04231             $arrpoints = array( $x1, $y1, $x2, $y1, $x_mid, $y_mid);
04232             ImageFilledPolygon($this->img, $arrpoints, 3, $color);
04233             break;
04234         case 'none':
04235             break;
04236         default:
04237             ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color);
04238             break;
04239         }
04240         return TRUE;
04241     }
04242 
04254     function DrawArea()
04255     {
04256         $incomplete_data_defaults_to_x_axis = FALSE;        // TODO: make this configurable
04257 
04258         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
04259             $rec = 1;                                       // Skip record #0 (data label)
04260 
04261             if ($this->data_type == 'data-data')            // Do we have a value for X?
04262                 $x_now = $this->data[$row][$rec++];         // Read it, advance record index
04263             else
04264                 $x_now = 0.5 + $cnt++;                      // Place text-data at X = 0.5, 1.5, 2.5, etc...
04265 
04266             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates
04267 
04268 
04269             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
04270                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
04271 
04272             // Proceed with Y values
04273             // Create array of points for imagefilledpolygon()
04274             for($idx = 0; $rec < $this->num_recs[$row]; $rec++, $idx++) {
04275                 if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data
04276                     $y_now_pixels = $this->ytr($this->data[$row][$rec]);
04277 
04278                     $posarr[$idx][] = $x_now_pixels;
04279                     $posarr[$idx][] = $y_now_pixels;
04280 
04281                     $num_points[$idx] = isset($num_points[$idx]) ? $num_points[$idx]+1 : 1;
04282                 }
04283                 // If there's missing data...
04284                 else {
04285                     if (isset ($incomplete_data_defaults_to_x_axis)) {
04286                         $posarr[$idx][] = $x_now_pixels;
04287                         $posarr[$idx][] = $this->x_axis_y_pixels;
04288                         $num_points[$idx] = isset($num_points[$idx]) ? $num_points[$idx]+1 : 1;
04289                     }
04290                 }
04291             }
04292         }   // end for
04293 
04294         $end = count($posarr);
04295         for ($i = 0; $i < $end; $i++) {
04296             // Prepend initial points. X = first point's X, Y = x_axis_y_pixels
04297             $x = $posarr[$i][0];
04298             array_unshift($posarr[$i], $x, $this->x_axis_y_pixels);
04299 
04300             // Append final points. X = last point's X, Y = x_axis_y_pixels
04301             $x = $posarr[$i][count($posarr[$i])-2];
04302             array_push($posarr[$i], $x, $this->x_axis_y_pixels);
04303 
04304             $num_points[$i] += 2;
04305 
04306             // Draw the poligon
04307             ImageFilledPolygon($this->img, $posarr[$i], $num_points[$i], $this->ndx_data_colors[$i]);
04308         }
04309         return TRUE;
04310     } // function DrawArea()
04311 
04312 
04319     function DrawLines()
04320     {
04321         // This will tell us if lines have already begun to be drawn.
04322         // It is an array to keep separate information for every line, with a single
04323         // variable we would sometimes get "undefined offset" errors and no plot...
04324         $start_lines = array_fill(0, $this->records_per_group, FALSE);
04325 
04326         if ($this->data_type == 'text-data') {
04327             $lastx[0] = $this->xtr(0);
04328             $lasty[0] = $this->xtr(0);
04329         }
04330 
04331         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
04332             $record = 1;                                    // Skip record #0 (data label)
04333 
04334             if ($this->data_type == 'data-data')            // Do we have a value for X?
04335                 $x_now = $this->data[$row][$record++];      // Read it, advance record index
04336             else
04337                 $x_now = 0.5 + $cnt++;                      // Place text-data at X = 0.5, 1.5, 2.5, etc...
04338 
04339             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates
04340 
04341             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
04342                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
04343 
04344             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
04345                 if (($line_style = $this->line_styles[$idx]) == 'none')
04346                     continue; //Allow suppressing entire line, useful with linepoints
04347                 if (is_numeric($this->data[$row][$record])) {           //Allow for missing Y data
04348                     $y_now_pixels = $this->ytr($this->data[$row][$record]);
04349 
04350                     if ($start_lines[$idx] == TRUE) {
04351                         // Set line width, revert it to normal at the end
04352                         ImageSetThickness($this->img, $this->line_widths[$idx]);
04353 
04354                         if ($line_style == 'dashed') {
04355                             $this->SetDashedStyle($this->ndx_data_colors[$idx]);
04356                             ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
04357                                       IMG_COLOR_STYLED);
04358                         } else {
04359                             ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
04360                                       $this->ndx_data_colors[$idx]);
04361                         }
04362 
04363                     }
04364                     $lasty[$idx] = $y_now_pixels;
04365                     $lastx[$idx] = $x_now_pixels;
04366                     $start_lines[$idx] = TRUE;
04367                 }
04368                 // Y data missing... should we leave a blank or not?
04369                 else if ($this->draw_broken_lines) {
04370                     $start_lines[$idx] = FALSE;
04371                 }
04372             }   // end for
04373         }   // end for
04374 
04375         ImageSetThickness($this->img, 1);       // Revert to original state for lines to be drawn later.
04376         return TRUE;
04377     } // function DrawLines()
04378 
04379 
04384     function DrawLinesError()
04385     {
04386         if ($this->data_type != 'data-data-error') {
04387             return $this->PrintError("DrawLinesError(): Data type '$this->data_type' not supported.");
04388         }
04389 
04390         $start_lines = array_fill(0, $this->records_per_group, FALSE);
04391 
04392         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
04393             $record = 1;                                    // Skip record #0 (data label)
04394 
04395             $x_now = $this->data[$row][$record++];          // Read X value, advance record index
04396 
04397             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates.
04398 
04399 
04400             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
04401                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
04402 
04403             // Now go for Y, E+, E-
04404             for ($idx = 0; $record < $this->num_recs[$row]; $idx++) {
04405                 if (($line_style = $this->line_styles[$idx]) == 'none')
04406                     continue; //Allow suppressing entire line, useful with linepoints
04407                 // Y
04408                 $y_now = $this->data[$row][$record++];
04409                 $y_now_pixels = $this->ytr($y_now);
04410 
04411                 if ($start_lines[$idx] == TRUE) {
04412                     ImageSetThickness($this->img, $this->line_widths[$idx]);
04413 
04414                     if ($line_style == 'dashed') {
04415                         $this->SetDashedStyle($this->ndx_data_colors[$idx]);
04416                         ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
04417                                   IMG_COLOR_STYLED);
04418                     } else {
04419                         ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
04420                                   $this->ndx_data_colors[$idx]);
04421                     }
04422                 }
04423 
04424                 // Error+
04425                 $val = $this->data[$row][$record++];
04426                 $this->DrawYErrorBar($x_now, $y_now, $val, $this->error_bar_shape,
04427                                      $this->ndx_error_bar_colors[$idx]);
04428 
04429                 // Error-
04430                 $val = $this->data[$row][$record++];
04431                 $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape,
04432                                      $this->ndx_error_bar_colors[$idx]);
04433 
04434                 // Update indexes:
04435                 $start_lines[$idx] = TRUE;   // Tells us if we already drew the first column of points,
04436                                              // thus having $lastx and $lasty ready for the next column.
04437                 $lastx[$idx] = $x_now_pixels;
04438                 $lasty[$idx] = $y_now_pixels;
04439             }   // end while
04440         }   // end for
04441 
04442         ImageSetThickness($this->img, 1);   // Revert to original state for lines to be drawn later.
04443         return TRUE;
04444     }   // function DrawLinesError()
04445 
04446 
04447 
04451     function DrawSquared()
04452     {
04453         // This will tell us if lines have already begun to be drawn.
04454         // It is an array to keep separate information for every line, for with a single
04455         // variable we could sometimes get "undefined offset" errors and no plot...
04456         $start_lines = array_fill(0, $this->records_per_group, FALSE);
04457 
04458         if ($this->data_type == 'text-data') {
04459             $lastx[0] = $this->xtr(0);
04460             $lasty[0] = $this->xtr(0);
04461         }
04462 
04463         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
04464             $record = 1;                                    // Skip record #0 (data label)
04465 
04466             if ($this->data_type == 'data-data')            // Do we have a value for X?
04467                 $x_now = $this->data[$row][$record++];      // Read it, advance record index
04468             else
04469                 $x_now = 0.5 + $cnt++;                      // Place text-data at X = 0.5, 1.5, 2.5, etc...
04470 
04471             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates
04472 
04473             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
04474                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels); // notice there is no last param.
04475 
04476             // Draw Lines
04477             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
04478                 if (is_numeric($this->data[$row][$record])) {               // Allow for missing Y data
04479                     $y_now_pixels = $this->ytr($this->data[$row][$record]);
04480 
04481                     if ($start_lines[$idx] == TRUE) {
04482                         // Set line width, revert it to normal at the end
04483                         ImageSetThickness($this->img, $this->line_widths[$idx]);
04484 
04485                         if ($this->line_styles[$idx] == 'dashed') {
04486                             $this->SetDashedStyle($this->ndx_data_colors[$idx]);
04487                             ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx],
04488                                       IMG_COLOR_STYLED);
04489                             ImageLine($this->img, $x_now_pixels, $lasty[$idx], $x_now_pixels, $y_now_pixels,
04490                                       IMG_COLOR_STYLED);
04491                         } else {
04492                             ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx],
04493                                       $this->ndx_data_colors[$idx]);
04494                             ImageLine($this->img, $x_now_pixels, $lasty[$idx], $x_now_pixels, $y_now_pixels,
04495                                       $this->ndx_data_colors[$idx]);
04496                         }
04497                     }
04498                     $lastx[$idx] = $x_now_pixels;
04499                     $lasty[$idx] = $y_now_pixels;
04500                     $start_lines[$idx] = TRUE;
04501                 }
04502                 // Y data missing... should we leave a blank or not?
04503                 else if ($this->draw_broken_lines) {
04504                     $start_lines[$idx] = FALSE;
04505                 }
04506             }
04507         }   // end while
04508 
04509         ImageSetThickness($this->img, 1);
04510         return TRUE;
04511     } // function DrawSquared()
04512 
04513 
04517     function DrawBars()
04518     {
04519         if ($this->data_type != 'text-data') {
04520             return $this->PrintError('DrawBars(): Bar plots must be text-data: use function SetDataType("text-data")');
04521         }
04522 
04523         // This is the X offset from the bar group's label center point to the left side of the first bar
04524         // in the group. See also CalcBarWidths above.
04525         $x_first_bar = (($this->records_per_group - 1) * $this->record_bar_width) / 2 - $this->bar_adjust_gap;
04526 
04527         for ($row = 0; $row < $this->num_data_rows; $row++) {
04528             $record = 1;                                    // Skip record #0 (data label)
04529 
04530             $x_now_pixels = $this->xtr(0.5 + $row);         // Place text-data at X = 0.5, 1.5, 2.5, etc...
04531 
04532             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
04533                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
04534 
04535             // Lower left X of first bar in the group:
04536             $x1 = $x_now_pixels - $x_first_bar;
04537 
04538             // Draw the bars in the group:
04539             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
04540                 if (is_numeric($this->data[$row][$record])) {       // Allow for missing Y data
04541                     $x2 = $x1 + $this->actual_bar_width;
04542 
04543                     if ($this->data[$row][$record] < $this->x_axis_position) {
04544                         $y1 = $this->x_axis_y_pixels;
04545                         $y2 = $this->ytr($this->data[$row][$record]);
04546                         $upgoing_bar = False;
04547                     } else {
04548                         $y1 = $this->ytr($this->data[$row][$record]);
04549                         $y2 = $this->x_axis_y_pixels;
04550                         $upgoing_bar = True;
04551                     }
04552 
04553                     // Draw the bar
04554                     ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]);
04555 
04556                     if ($this->shading) {                           // Draw the shade?
04557                         ImageFilledPolygon($this->img, array($x1, $y1,
04558                                                        $x1 + $this->shading, $y1 - $this->shading,
04559                                                        $x2 + $this->shading, $y1 - $this->shading,
04560                                                        $x2 + $this->shading, $y2 - $this->shading,
04561                                                        $x2, $y2,
04562                                                        $x2, $y1),
04563                                            6, $this->ndx_data_dark_colors[$idx]);
04564                     }
04565                     // Or draw a border?
04566                     else {
04567                         ImageRectangle($this->img, $x1, $y1, $x2,$y2, $this->ndx_data_border_colors[$idx]);
04568                     }
04569 
04570                     // Draw optional data labels above the bars (or below, for negative values).
04571                     if ( $this->y_data_label_pos == 'plotin') {
04572                         if ($upgoing_bar) {
04573                           $v_align = 'bottom';
04574                           $y_offset = -5 - $this->shading;
04575                         } else {
04576                           $v_align = 'top';
04577                           $y_offset = 2;
04578                         }
04579                         $this->DrawDataLabel($this->y_label_font, NULL, $row+0.5, $this->data[$row][$record], '',
04580                                 $this->data[$row][$record], 'center', $v_align,
04581                                 ($idx + 0.5) * $this->record_bar_width - $x_first_bar, $y_offset);
04582                     }
04583 
04584                 }
04585                 // Step to next bar in group:
04586                 $x1 += $this->record_bar_width;
04587             }   // end for
04588         }   // end for
04589         return TRUE;
04590     } //function DrawBars
04591 
04592 
04597     function DrawStackedBars()
04598     {
04599         if ($this->data_type != 'text-data') {
04600             return $this->PrintError('DrawStackedBars(): Bar plots must be text-data: use SetDataType("text-data")');
04601         }
04602 
04603         // This is the X offset from the bar's label center point to the left side of the bar.
04604         $x_first_bar = $this->record_bar_width / 2 - $this->bar_adjust_gap;
04605 
04606         for ($row = 0; $row < $this->num_data_rows; $row++) {
04607             $record = 1;                                    // Skip record #0 (data label)
04608 
04609             $x_now_pixels = $this->xtr(0.5 + $row);         // Place text-data at X = 0.5, 1.5, 2.5, etc...
04610 
04611             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
04612                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
04613 
04614             // Lower left and lower right X of the bars in this group:
04615             $x1 = $x_now_pixels - $x_first_bar;
04616             $x2 = $x1 + $this->actual_bar_width;
04617 
04618             // Draw the bars
04619             $oldv = 0;
04620             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
04621                 if (is_numeric($this->data[$row][$record])) {       // Allow for missing Y data
04622 
04623                     $y1 = $this->ytr(abs($this->data[$row][$record]) + $oldv);
04624                     $y2 = $this->ytr($this->x_axis_position + $oldv);
04625                     $oldv += abs($this->data[$row][$record]);
04626 
04627                     // Draw the bar
04628                     ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]);
04629 
04630                     if ($this->shading) {                           // Draw the shade?
04631                         ImageFilledPolygon($this->img, array($x1, $y1,
04632                                                        $x1 + $this->shading, $y1 - $this->shading,
04633                                                        $x2 + $this->shading, $y1 - $this->shading,
04634                                                        $x2 + $this->shading, $y2 - $this->shading,
04635                                                        $x2, $y2,
04636                                                        $x2, $y1),
04637                                            6, $this->ndx_data_dark_colors[$idx]);
04638                     }
04639                     // Or draw a border?
04640                     else {
04641                         ImageRectangle($this->img, $x1, $y1, $x2,$y2, $this->ndx_data_border_colors[$idx]);
04642                     }
04643                 }
04644             }   // end for
04645         }   // end for
04646         return TRUE;
04647     } //function DrawStackedBars
04648 
04649 
04653     function DrawGraph()
04654     {
04655         // Test for missing image, missing data, empty data:
04656         if (! $this->img) {
04657             return $this->PrintError('DrawGraph(): No image resource allocated');
04658         }
04659         if (empty($this->data) || ! is_array($this->data)) {
04660             return $this->PrintError("DrawGraph(): No data array");
04661         }
04662         if ($this->total_records == 0) {
04663             return $this->PrintError('DrawGraph(): Empty data set');
04664         }
04665 
04666         // For pie charts: don't draw grid or border or axes, and maximize area usage.
04667         // These controls can be split up in the future if needed.
04668         $draw_axes = ($this->plot_type != 'pie');
04669 
04670         // Get maxima and minima for scaling:
04671         if (!$this->FindDataLimits())
04672             return FALSE;
04673 
04674         // Set plot area world values (plot_max_x, etc.):
04675         if (!$this->CalcPlotAreaWorld())
04676             return FALSE;
04677 
04678         // Calculate X and Y axis positions in World Coordinates:
04679         $this->CalcAxisPositions();
04680 
04681         // Calculate the plot margins, if needed.
04682         // For pie charts, set the $maximize argument to maximize space usage.
04683         $this->CalcMargins(!$draw_axes);
04684 
04685         // Calculate the actual plot area in device coordinates:
04686         $this->CalcPlotAreaPixels();
04687 
04688         // Calculate the mapping between world and device coordinates:
04689         $this->CalcTranslation();
04690 
04691         // Pad color and style arrays to fit records per group:
04692         $this->PadArrays();
04693         $this->DoCallback('draw_setup');
04694 
04695         $this->DrawBackground();
04696         $this->DrawImageBorder();
04697         $this->DoCallback('draw_image_background');
04698 
04699         $this->DrawPlotAreaBackground();
04700         $this->DoCallback('draw_plotarea_background');
04701 
04702         $this->DrawTitle();
04703         $this->DrawXTitle();
04704         $this->DrawYTitle();
04705         $this->DoCallback('draw_titles');
04706 
04707         if ($draw_axes && ! $this->grid_at_foreground) {   // Usually one wants grids to go back, but...
04708             $this->DrawYAxis();     // Y axis must be drawn before X axis (see DrawYAxis())
04709             $this->DrawXAxis();
04710             $this->DoCallback('draw_axes');
04711         }
04712 
04713         switch ($this->plot_type) {
04714         case 'thinbarline':
04715             $this->DrawThinBarLines();
04716             break;
04717         case 'area':
04718             $this->DrawArea();
04719             break;
04720         case 'squared':
04721             $this->DrawSquared();
04722             break;
04723         case 'lines':
04724             if ( $this->data_type == 'data-data-error') {
04725                 $this->DrawLinesError();
04726             } else {
04727                 $this->DrawLines();
04728             }
04729             break;
04730         case 'linepoints':
04731             if ( $this->data_type == 'data-data-error') {
04732                 $this->DrawLinesError();
04733                 $this->DrawDotsError();
04734             } else {
04735                 $this->DrawLines();
04736                 $this->DrawDots();
04737             }
04738             break;
04739         case 'points';
04740             if ( $this->data_type == 'data-data-error') {
04741                 $this->DrawDotsError();
04742             } else {
04743                 $this->DrawDots();
04744             }
04745             break;
04746         case 'pie':
04747             $this->DrawPieChart();
04748             break;
04749         case 'stackedbars':
04750             $this->CalcBarWidths();
04751             $this->DrawStackedBars();
04752             break;
04753         case 'bars':
04754         default:
04755             $this->plot_type = 'bars';  // Set it if it wasn't already set. (necessary?)
04756             $this->CalcBarWidths();
04757             $this->DrawBars();
04758             break;
04759         }   // end switch
04760         $this->DoCallback('draw_graph');
04761 
04762         if ($draw_axes && $this->grid_at_foreground) {   // Usually one wants grids to go back, but...
04763             $this->DrawYAxis();     // Y axis must be drawn before X axis (see DrawYAxis())
04764             $this->DrawXAxis();
04765             $this->DoCallback('draw_axes');
04766         }
04767 
04768         if ($draw_axes) {
04769             $this->DrawPlotBorder();
04770             $this->DoCallback('draw_border');
04771         }
04772 
04773         if ($this->legend) {
04774             $this->DrawLegend();
04775             $this->DoCallback('draw_legend');
04776         }
04777 
04778         if ($this->print_image && !$this->PrintImage())
04779             return FALSE;
04780 
04781         return TRUE;
04782     } //function DrawGraph()
04783 
04787 
04791     function SetDrawVertTicks($which_dvt)
04792     {
04793         if ($which_dvt != 1)
04794             $this->SetYTickPos('none');
04795         return TRUE;
04796     }
04797 
04801     function SetDrawHorizTicks($which_dht)
04802     {
04803         if ($which_dht != 1)
04804            $this->SetXTickPos('none');
04805         return TRUE;
04806     }
04807 
04811     function SetNumHorizTicks($n)
04812     {
04813         return $this->SetNumXTicks($n);
04814     }
04815 
04819     function SetNumVertTicks($n)
04820     {
04821         return $this->SetNumYTicks($n);
04822     }
04823 
04827     function SetHorizTickIncrement($inc)
04828     {
04829         return $this->SetXTickIncrement($inc);
04830     }
04831 
04832 
04836     function SetVertTickIncrement($inc)
04837     {
04838         return $this->SetYTickIncrement($inc);
04839     }
04840 
04844     function SetVertTickPosition($which_tp)
04845     {
04846         return $this->SetYTickPos($which_tp);
04847     }
04848 
04852     function SetHorizTickPosition($which_tp)
04853     {
04854         return $this->SetXTickPos($which_tp);
04855     }
04856 
04860     function SetTitleFontSize($which_size)
04861     {
04862         return $this->SetFont('title', $which_size);
04863     }
04864 
04868     function SetAxisFontSize($which_size)
04869     {
04870         $this->SetFont('x_label', $which_size);
04871         $this->SetFont('y_label', $which_size);
04872     }
04873 
04877     function SetSmallFontSize($which_size)
04878     {
04879         return $this->SetFont('generic', $which_size);
04880     }
04881 
04885     function SetXLabelFontSize($which_size)
04886     {
04887         return $this->SetFont('x_title', $which_size);
04888     }
04889 
04893     function SetYLabelFontSize($which_size)
04894     {
04895         return $this->SetFont('y_title', $which_size);
04896     }
04897 
04901     function SetXLabel($which_xlab)
04902     {
04903         return $this->SetXTitle($which_xlab);
04904     }
04905 
04909     function SetYLabel($which_ylab)
04910     {
04911         return $this->SetYTitle($which_ylab);
04912     }
04913 
04917     function SetTickLength($which_tl)
04918     {
04919         $this->SetXTickLength($which_tl);
04920         $this->SetYTickLength($which_tl);
04921         return TRUE;
04922     }
04923 
04927     function SetYGridLabelType($which_yglt)
04928     {
04929         return $this->SetYLabelType($which_yglt);
04930     }
04931 
04935     function SetXGridLabelType($which_xglt)
04936     {
04937         return $this->SetXLabelType($which_xglt);
04938     }
04942     function SetYGridLabelPos($which_yglp)
04943     {
04944         return $this->SetYTickLabelPos($which_yglp);
04945     }
04949     function SetXGridLabelPos($which_xglp)
04950     {
04951         return $this->SetXTickLabelPos($which_xglp);
04952     }
04953 
04954 
04958     function SetXTitlePos($xpos)
04959     {
04960         $this->x_title_pos = $xpos;
04961         return TRUE;
04962     }
04963 
04967     function SetYTitlePos($xpos)
04968     {
04969         $this->y_title_pos = $xpos;
04970         return TRUE;
04971     }
04972 
04976     function SetXDataLabelAngle($which_xdla)
04977     {
04978         return $this->SetXLabelAngle($which_xdla);
04979     }
04980 
04987     function SetDrawXDataLabels($which_dxdl)
04988     {
04989         if ($which_dxdl == '1' )
04990             $this->SetXDataLabelPos('plotdown');
04991         else
04992             $this->SetXDataLabelPos('none');
04993     }
04994 
04998     function SetNewPlotAreaPixels($x1, $y1, $x2, $y2)
04999     {
05000         //Like in GD 0, 0 is upper left set via pixel Coordinates
05001         $this->plot_area = array($x1, $y1, $x2, $y2);
05002         $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0];
05003         $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1];
05004         $this->y_top_margin = $this->plot_area[1];
05005 
05006         if (isset($this->plot_max_x))
05007             $this->CalcTranslation();
05008 
05009         return TRUE;
05010     }
05011 
05015     function SetColor($which_color)
05016     {
05017         $this->SetRGBColor($which_color);
05018         return TRUE;
05019     }
05020 
05021     /*
05022      * \deprecated Use SetLineWidths().
05023      */
05024     function SetLineWidth($which_lw)
05025     {
05026 
05027         $this->SetLineWidths($which_lw);
05028 
05029         if (!$this->error_bar_line_width) {
05030             $this->SetErrorBarLineWidth($which_lw);
05031         }
05032         return TRUE;
05033     }
05034 
05035     /*
05036      * \deprecated Use SetPointShapes().
05037      */
05038     function SetPointShape($which_pt)
05039     {
05040         $this->SetPointShapes($which_pt);
05041         return TRUE;
05042     }
05043 
05044     /*
05045      * \deprecated Use SetPointSizes().
05046      */
05047     function SetPointSize($which_ps)
05048     {
05049         $this->SetPointSizes($which_ps);
05050         return TRUE;
05051     }
05052 }  // class PHPlot

Generated on Fri Dec 13 2013 17:56:53 for ILIAS Release_3_9_x_branch .rev 46835 by  doxygen 1.7.1