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

survey/phplot/phplot.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /* $Id: phplot.php 6558 2005-01-26 16:20:31Z smeyer $ */
00004 
00005 /*
00006  * PHPLOT Version 5.0.rc1
00007  * Copyright (C) 1998, 1999, 2000, 2001 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  * Recent (2003-2004) work by Miguel de Benito Delgado <nonick AT vodafone DOT es>
00012  *
00013  * Requires PHP 4.2.0 or later (CHECK THIS)
00014  */
00015 
00016 if (! defined(__FUNCTION__))
00017     define(__FUNCTION__, '__FUNCTION__ Requires at least PHP 4.3.0.');
00018 
00019 define ('MINY', -1);        // Indexes in $data (for DrawXDataLine())
00020 define ('MAXY', -2);
00021 define ('TOTY', -3);
00022 
00023 error_reporting(E_ALL);
00024 
00025 class PHPlot {
00026 
00027     /* I have removed internal variable declarations, some isset() checking was required,
00028      * but now the variables left are those which can be tweaked by the user. This is intended to
00029      * be the first step towards moving most of the Set...() methods into a subclass which will be
00030      * used only when strictly necessary. Many users will be able to put default values here in the
00031      * class and thus avoid memory overhead and reduce parsing times.
00032      */
00034 
00035     var $is_inline = FALSE;             // FALSE = Sends headers, TRUE = sends just raw image data
00036     var $browser_cache = FALSE;         // FALSE = Sends headers for browser to not cache the image,
00037                                         // (only if is_inline = FALSE also)
00038 
00039     var $safe_margin = 5;               // Extra margin used in several places. In pixels
00040 
00041     var $x_axis_position = '';          // Where to draw both axis (world coordinates),
00042     var $y_axis_position = '';          // leave blank for X axis at 0 and Y axis at left of plot.
00043 
00044     var $xscale_type = 'linear';        // linear, log
00045     var $yscale_type = 'linear';
00046 
00047 //Fonts
00048     var $use_ttf  = FALSE;                  // Use True Type Fonts?
00049     var $ttf_path = '.';                    // Default path to look in for TT Fonts.
00050     var $default_ttfont = 'benjamingothic.ttf';
00051     var $line_spacing = 4;                  // Pixels between lines.
00052 
00053     // Font angles: 0 or 90 degrees for fixed fonts, any for TTF
00054     var $x_label_angle = 0;                 // For labels on X axis (tick and data)
00055     var $y_label_angle = 0;                 // For labels on Y axis (tick and data)
00056     var $x_title_angle = 0;                 // Don't change this if you don't want to screw things up!
00057     var $y_title_angle = 90;                // Nor this.
00058     var $title_angle = 0;                   // Or this.
00059 
00060 //Formats
00061     var $file_format = 'png';
00062     var $output_file = '';                  // For output to a file instead of stdout
00063 
00064 //Data
00065     var $data_type = 'text-data';           // text-data, data-data-error, data-data, text-data-single
00066     var $plot_type= 'linepoints';           // bars, lines, linepoints, area, points, pie, thinbarline, squared
00067 
00068     var $label_scale_position = 0.5;        // Shifts data labes in pie charts. 1 = top, 0 = bottom
00069     var $group_frac_width = 0.7;            // value from 0 to 1 = width of bar groups
00070     var $bar_width_adjust = 1;              // 1 = bars of normal width, must be > 0
00071 
00072     var $y_precision = 1;
00073     var $x_precision = 1;
00074 
00075     var $data_units_text = '';              // Units text for 'data' labels (i.e: '¤', '$', etc.)
00076 
00077 // Titles
00078     var $title_txt = '';
00079 
00080     var $x_title_txt = '';
00081     var $x_title_pos = 'plotdown';          // plotdown, plotup, both, none
00082 
00083     var $y_title_txt = '';
00084     var $y_title_pos = 'plotleft';          // plotleft, plotright, both, none
00085 
00086 
00087 //Labels
00088     // There are two types of labels in PHPlot:
00089     //    Tick labels: they follow the grid, next to ticks in axis.   (DONE)
00090     //                 they are drawn at grid drawing time, by DrawXTicks() and DrawYTicks()
00091     //    Data labels: they follow the data points, and can be placed on the axis or the plot (x/y)  (TODO)
00092     //                 they are drawn at graph plotting time, by Draw*DataLabel(), called by DrawLines(), etc.
00093     //                 Draw*DataLabel() also draws H/V lines to datapoints depending on draw_*_data_label_lines
00094 
00095     // Tick Labels
00096     var $x_tick_label_pos = 'plotdown';     // plotdown, plotup, both, xaxis, none
00097     var $y_tick_label_pos = 'plotleft';     // plotleft, plotright, both, yaxis, none
00098 
00099     // Data Labels:
00100     var $x_data_label_pos = 'plotdown';     // plotdown, plotup, both, plot, all, none
00101     var $y_data_label_pos = 'plotleft';     // plotleft, plotright, both, plot, all, none
00102 
00103     var $draw_x_data_label_lines = FALSE;   // Draw a line from the data point to the axis?
00104     var $draw_y_data_label_lines = FALSE;   // TODO
00105 
00106     // Label types: (for tick, data and plot labels)
00107     var $x_label_type = '';                 // data, time. Leave blank for no formatting.
00108     var $y_label_type = '';                 // data, time. Leave blank for no formatting.
00109     var $x_time_format = '%H:%m:%s';        // See http://www.php.net/manual/html/function.strftime.html
00110     var $y_time_format = '%H:%m:%s';        // SetYTimeFormat() too...
00111 
00112     // Skipping labels
00113     var $x_label_inc = 1;                   // Draw a label every this many (1 = all) (TODO)
00114     var $y_label_inc = 1;
00115     var $_x_label_cnt = 0;                  // internal count FIXME: work in progress
00116 
00117     // Legend
00118     var $legend = '';                       // An array with legend titles
00119     var $legend_x_pos = '';
00120     var $legend_y_pos = '';
00121 
00122 
00123 //Ticks
00124     var $x_tick_length = 5;                 // tick length in pixels for upper/lower axis
00125     var $y_tick_length = 5;                 // tick length in pixels for left/right axis
00126 
00127     var $x_tick_cross = 3;                  // ticks cross x axis this many pixels
00128     var $y_tick_cross = 3;                  // ticks cross y axis this many pixels
00129 
00130     var $x_tick_pos = 'plotdown';           // plotdown, plotup, both, xaxis, none
00131     var $y_tick_pos = 'plotleft';           // plotright, plotleft, both, yaxis, none
00132 
00133     var $num_x_ticks = '';
00134     var $num_y_ticks = '';
00135 
00136     var $x_tick_inc = '';                   // Set num_x_ticks or x_tick_inc, not both.
00137     var $y_tick_inc = '';                   // Set num_y_ticks or y_tick_inc, not both.
00138 
00139     var $skip_top_tick = FALSE;
00140     var $skip_bottom_tick = FALSE;
00141     var $skip_left_tick = FALSE;
00142     var $skip_right_tick = FALSE;
00143 
00144 //Grid Formatting
00145     var $draw_x_grid = FALSE;
00146     var $draw_y_grid = TRUE;
00147 
00148     var $dashed_grid = TRUE;
00149     var $grid_at_foreground = FALSE;        // Chooses whether to draw the grid below or above the graph
00150 
00151 //Colors and styles       (all colors can be array (R,G,B) or named color)
00152     var $color_array = 'small';             // 'small', 'large' or array (define your own colors)
00153                                             // See rgb.inc.php and SetRGBArray()
00154     var $i_border = array(194, 194, 194);
00155     var $plot_bg_color = 'white';
00156     var $bg_color = 'white';
00157     var $label_color = 'black';
00158     var $text_color = 'black';
00159     var $grid_color = 'black';
00160     var $light_grid_color = 'gray';
00161     var $tick_color = 'black';
00162     var $title_color = 'black';
00163     var $data_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1');
00164     var $error_bar_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1');
00165     var $data_border_colors = array('black');
00166 
00167     var $line_widths = 1;                  // single value or array
00168     var $line_styles = array('solid', 'solid', 'dashed');   // single value or array
00169     var $dashed_style = '2-4';              // colored dots-transparent dots
00170 
00171     var $point_sizes = array(5,5,3);         // single value or array
00172     var $point_shapes = array('diamond');   // rect, circle, diamond, triangle, dot, line, halfline, cross
00173 
00174     var $error_bar_size = 5;                // right and left size of tee
00175     var $error_bar_shape = 'tee';           // 'tee' or 'line'
00176     var $error_bar_line_width = 1;          // single value (or array TODO)
00177 
00178     var $plot_border_type = 'sides';        // left, sides, none, full
00179     var $image_border_type = 'none';        // 'raised', 'plain', 'none'
00180 
00181     var $shading = 5;                       // 0 for no shading, > 0 is size of shadows in pixels
00182 
00183     var $draw_plot_area_background = FALSE;
00184     var $draw_broken_lines = FALSE;          // Tells not to draw lines for missing Y data.
00185 
00186 
00188 //BEGIN CODE
00190 
00199     function PHPlot($which_width=600, $which_height=400, $which_output_file=NULL, $which_input_file=NULL)
00200     {
00201         /*
00202          * Please see http://www.php.net/register_shutdown_function
00203          * PLEASE NOTE: register_shutdown_function() will take a copy of the object rather than a reference
00204          * so we put an ampersand. However, the function registered will work on the object as it
00205          * was upon registration. To solve this, one of two methods can be used:
00206          *      $obj = new object();
00207          *      register_shutdown_function(array(&$obj,'shutdown'));
00208          * OR
00209          *      $obj = &new object();
00210          * HOWEVER, as the second statement assigns $obj a reference to the current object, it might be that
00211          * several instances mess things up... (CHECK THIS)
00212          *
00213          * AND
00214          *    as $this->img is set upon construction of the object, problems will not arise for us (for the
00215          *    moment maybe, so I put all this here just in case)
00216          */
00217         register_shutdown_function(array(&$this, '_PHPlot'));
00218 
00219         $this->SetRGBArray($this->color_array);
00220 
00221         $this->background_done = FALSE;     // Set to TRUE after background image is drawn once
00222 
00223         if ($which_output_file)
00224             $this->SetOutputFile($which_output_file);
00225 
00226         if ($which_input_file)
00227             $this->SetInputFile($which_input_file);
00228         else {
00229             $this->image_width = $which_width;
00230             $this->image_height = $which_height;
00231 
00232             $this->img = ImageCreate($this->image_width, $this->image_height);
00233             if (! $this->img)
00234                 $this->PrintError('PHPlot(): Could not create image resource.');
00235 
00236         }
00237 
00238         $this->SetDefaultStyles();
00239         $this->SetDefaultFonts();
00240 
00241         $this->SetTitle('');
00242         $this->SetXTitle('');
00243         $this->SetYTitle('');
00244 
00245         $this->print_image = TRUE;      // Use for multiple plots per image (TODO: automatic)
00246     }
00247 
00254     function _PHPlot ()
00255     {
00256         ImageDestroy($this->img);
00257         return;
00258     }
00259 
00260 
00264 
00270     function SetIndexColor($which_color)
00271     {
00272         list ($r, $g, $b) = $this->SetRGBColor($which_color);  //Translate to RGB
00273         $index = ImageColorExact($this->img, $r, $g, $b);
00274         if ($index == -1) {
00275             return ImageColorResolve($this->img, $r, $g, $b);
00276         } else {
00277             return $index;
00278         }
00279     }
00280 
00281 
00285     function SetIndexDarkColor($which_color)
00286     {
00287         list ($r, $g, $b) = $this->SetRGBColor($which_color);
00288 
00289         $r -= 0x30;     $r = ($r < 0) ? 0 : $r;
00290         $g -= 0x30;     $g = ($g < 0) ? 0 : $g;
00291         $b -= 0x30;     $b = ($b < 0) ? 0 : $b;
00292 
00293         $index = ImageColorExact($this->img, $r, $g, $b);
00294         if ($index == -1) {
00295             return ImageColorResolve($this->img, $r, $g, $b);
00296         } else {
00297             return $index;
00298         }
00299     }
00300 
00309     function SetDefaultStyles()
00310     {
00311         /* Some of the Set*() functions use default values when they get no parameters. */
00312 
00313         if (! isset($this->session_set)) {
00314             // If sessions are enabled, this variable will be preserved, so upon future executions, we
00315             // will have it set, as well as color names (though not color indices, that's why we
00316             // need to rebuild them)
00317             $this->session_set = TRUE;
00318 
00319             // These only need to be set once
00320             $this->SetLineWidths();
00321             $this->SetLineStyles();
00322             $this->SetDefaultDashedStyle($this->dashed_style);
00323             $this->SetPointSizes($this->point_sizes);
00324         }
00325 
00326         $this->SetImageBorderColor($this->i_border);
00327         $this->SetPlotBgColor($this->plot_bg_color);
00328         $this->SetBackgroundColor($this->bg_color);
00329         $this->SetLabelColor($this->label_color);
00330         $this->SetTextColor($this->text_color);
00331         $this->SetGridColor($this->grid_color);
00332         $this->SetLightGridColor($this->light_grid_color);
00333         $this->SetTickColor($this->tick_color);
00334         $this->SetTitleColor($this->title_color);
00335         $this->SetDataColors();
00336         $this->SetErrorBarColors();
00337         $this->SetDataBorderColors();
00338     }
00339 
00340 
00341     /*
00342      *
00343      */
00344     function SetBackgroundColor($which_color)
00345     {
00346         $this->bg_color= $which_color;
00347         $this->ndx_bg_color= $this->SetIndexColor($this->bg_color);
00348         return TRUE;
00349     }
00350 
00351     /*
00352      *
00353      */
00354     function SetPlotBgColor($which_color)
00355     {
00356         $this->plot_bg_color= $which_color;
00357         $this->ndx_plot_bg_color= $this->SetIndexColor($this->plot_bg_color);
00358         return TRUE;
00359     }
00360 
00361    /*
00362     *
00363     */
00364     function SetTitleColor($which_color)
00365     {
00366         $this->title_color= $which_color;
00367         $this->ndx_title_color= $this->SetIndexColor($this->title_color);
00368         return TRUE;
00369     }
00370 
00371     /*
00372      *
00373      */
00374     function SetTickColor ($which_color)
00375     {
00376         $this->tick_color= $which_color;
00377         $this->ndx_tick_color= $this->SetIndexColor($this->tick_color);
00378         return TRUE;
00379     }
00380 
00381 
00382     /*
00383      *
00384      */
00385     function SetLabelColor ($which_color)
00386     {
00387         $this->label_color = $which_color;
00388         $this->ndx_title_color= $this->SetIndexColor($this->label_color);
00389         return TRUE;
00390     }
00391 
00392 
00393     /*
00394      *
00395      */
00396     function SetTextColor ($which_color)
00397     {
00398         $this->text_color= $which_color;
00399         $this->ndx_text_color= $this->SetIndexColor($this->text_color);
00400         return TRUE;
00401     }
00402 
00403 
00404     /*
00405      *
00406      */
00407     function SetLightGridColor ($which_color)
00408     {
00409         $this->light_grid_color= $which_color;
00410         $this->ndx_light_grid_color= $this->SetIndexColor($this->light_grid_color);
00411         return TRUE;
00412     }
00413 
00414 
00415     /*
00416      *
00417      */
00418     function SetGridColor ($which_color)
00419     {
00420         $this->grid_color = $which_color;
00421         $this->ndx_grid_color= $this->SetIndexColor($this->grid_color);
00422         return TRUE;
00423     }
00424 
00425 
00426     /*
00427      *
00428      */
00429     function SetImageBorderColor($which_color)
00430     {
00431         $this->i_border = $which_color;
00432         $this->ndx_i_border = $this->SetIndexColor($this->i_border);
00433         $this->ndx_i_border_dark = $this->SetIndexDarkColor($this->i_border);
00434         return TRUE;
00435     }
00436 
00437 
00438     /*
00439      *
00440      */
00441     function SetTransparentColor($which_color)
00442     {
00443         ImageColorTransparent($this->img, $this->SetIndexColor($which_color));
00444         return TRUE;
00445     }
00446 
00447 
00455     function SetRGBArray ($which_color_array)
00456     {
00457         if ( is_array($which_color_array) ) {           // User defined array
00458             $this->rgb_array = $which_color_array;
00459             return TRUE;
00460         } elseif ($which_color_array == 'small') {      // Small predefined color array
00461             $this->rgb_array = array(
00462                 'white'          => array(255, 255, 255),
00463                 'snow'           => array(255, 250, 250),
00464                 'PeachPuff'      => array(255, 218, 185),
00465                 'ivory'          => array(255, 255, 240),
00466                 'lavender'       => array(230, 230, 250),
00467                 'black'          => array(  0,   0,   0),
00468                 'DimGrey'        => array(105, 105, 105),
00469                 'gray'           => array(190, 190, 190),
00470                 'grey'           => array(190, 190, 190),
00471                 'navy'           => array(  0,   0, 128),
00472                 'SlateBlue'      => array(106,  90, 205),
00473                 'blue'           => array(  0,   0, 255),
00474                 'SkyBlue'        => array(135, 206, 235),
00475                 'cyan'           => array(  0, 255, 255),
00476                 'DarkGreen'      => array(  0, 100,   0),
00477                 'green'          => array(  0, 255,   0),
00478                 'YellowGreen'    => array(154, 205,  50),
00479                 'yellow'         => array(255, 255,   0),
00480                 'orange'         => array(255, 165,   0),
00481                 'gold'           => array(255, 215,   0),
00482                 'peru'           => array(205, 133,  63),
00483                 'beige'          => array(245, 245, 220),
00484                 'wheat'          => array(245, 222, 179),
00485                 'tan'            => array(210, 180, 140),
00486                 'brown'          => array(165,  42,  42),
00487                 'salmon'         => array(250, 128, 114),
00488                 'red'            => array(255,   0,   0),
00489                 'pink'           => array(255, 192, 203),
00490                 'maroon'         => array(176,  48,  96),
00491                 'magenta'        => array(255,   0, 255),
00492                 'violet'         => array(238, 130, 238),
00493                 'plum'           => array(221, 160, 221),
00494                 'orchid'         => array(218, 112, 214),
00495                 'purple'         => array(160,  32, 240),
00496                 'azure1'         => array(240, 255, 255),
00497                 'aquamarine1'    => array(127, 255, 212)
00498                 );
00499             return TRUE;
00500         } elseif ($which_color_array === 'large')  {    // Large color array
00501             include("./rgb.inc.php");
00502             $this->rgb_array = $RGBArray;
00503         } else {                                        // Default to black and white only.
00504             $this->rgb_array = array('white' => array(255, 255, 255), 'black' => array(0, 0, 0));
00505         }
00506 
00507         return TRUE;
00508     }
00509 
00515     function SetRGBColor($color_asked)
00516     {
00517         if ($color_asked == '') { $color_asked = array(0, 0, 0); };
00518 
00519         if ( count($color_asked) == 3 ) {    // already array of 3 rgb
00520                $ret_val =  $color_asked;
00521         } else {                             // asking for a color by string
00522             if(substr($color_asked, 0, 1) == '#') {         // asking in #FFFFFF format.
00523                 $ret_val = array(hexdec(substr($color_asked, 1, 2)), hexdec(substr($color_asked, 3, 2)),
00524                                   hexdec(substr($color_asked, 5, 2)));
00525             } else {                                        // asking by color name
00526                 $ret_val = $this->rgb_array[$color_asked];
00527             }
00528         }
00529         return $ret_val;
00530     }
00531 
00532 
00536     function SetDataColors($which_data = NULL, $which_border = NULL)
00537     {
00538         if (is_null($which_data) && is_array($this->data_colors)) {
00539             // use already set data_colors
00540         } else if (! is_array($which_data)) {
00541             $this->data_colors = ($which_data) ? array($which_data) : array('blue', 'red', 'green', 'orange');
00542         } else {
00543             $this->data_colors = $which_data;
00544         }
00545 
00546         $i = 0;
00547         foreach ($this->data_colors as $col) {
00548             $this->ndx_data_colors[$i] = $this->SetIndexColor($col);
00549             $this->ndx_data_dark_colors[$i] = $this->SetIndexDarkColor($col);
00550             $i++;
00551         }
00552 
00553         // For past compatibility:
00554         $this->SetDataBorderColors($which_border);
00555     } // function SetDataColors()
00556 
00557 
00561     function SetDataBorderColors($which_br = NULL)
00562     {
00563         if (is_null($which_br) && is_array($this->data_border_colors)) {
00564             // use already set data_border_colors
00565         } else if (! is_array($which_br)) {
00566             // Create new array with specified color
00567             $this->data_border_colors = ($which_br) ? array($which_br) : array('black');
00568         } else {
00569             $this->data_border_colors = $which_br;
00570         }
00571 
00572         $i = 0;
00573         foreach($this->data_border_colors as $col) {
00574             $this->ndx_data_border_colors[$i] = $this->SetIndexColor($col);
00575             $i++;
00576         }
00577     } // function SetDataBorderColors()
00578 
00579 
00583     function SetErrorBarColors($which_err = NULL)
00584     {
00585         if (is_null($which_err) && is_array($this->error_bar_colors)) {
00586             // use already set error_bar_colors
00587         } else if (! is_array($which_err)) {
00588             $this->error_bar_colors = ($which_err) ? array($which_err) : array('black');
00589         } else {
00590             $this->error_bar_colors = $which_err;
00591         }
00592 
00593         $i = 0;
00594         foreach($this->error_bar_colors as $col) {
00595             $this->ndx_error_bar_colors[$i] = $this->SetIndexColor($col);
00596             $i++;
00597         }
00598         return TRUE;
00599 
00600     } // function SetErrorBarColors()
00601 
00602 
00609     function SetDefaultDashedStyle($which_style)
00610     {
00611         // String: "numcol-numtrans-numcol-numtrans..."
00612         $asked = explode('-', $which_style);
00613 
00614         if (count($asked) < 2) {
00615             $this->DrawError("SetDefaultDashedStyle(): Wrong parameter '$which_style'.");
00616             return FALSE;
00617         }
00618 
00619         // Build the string to be eval()uated later by SetDashedStyle()
00620         $this->default_dashed_style = 'array( ';
00621 
00622         $t = 0;
00623         foreach($asked as $s) {
00624             if ($t % 2 == 0) {
00625                 $this->default_dashed_style .= str_repeat('$which_ndxcol,', $s);
00626             } else {
00627                 $this->default_dashed_style .= str_repeat('IMG_COLOR_TRANSPARENT,', $s);
00628             }
00629             $t++;
00630         }
00631         // Remove trailing comma and add closing parenthesis
00632         $this->default_dashed_style = substr($this->default_dashed_style, 0, -1);
00633         $this->default_dashed_style .= ')';
00634 
00635         return TRUE;
00636     }
00637 
00638 
00643     function SetDashedStyle($which_ndxcol)
00644     {
00645         // See SetDefaultDashedStyle() to understand this.
00646         eval ("\$style = $this->default_dashed_style;");
00647         return imagesetstyle($this->img, $style);
00648     }
00649 
00650 
00654     function SetLineWidths($which_lw=NULL)
00655     {
00656         if (is_null($which_lw)) {
00657             // Do nothing, use default value.
00658         } else if (is_array($which_lw)) {
00659             // Did we get an array with line widths?
00660             $this->line_widths = $which_lw;
00661         } else {
00662             $this->line_widths = array($which_lw);
00663         }
00664         return TRUE;
00665     }
00666 
00670     function SetLineStyles($which_ls=NULL)
00671     {
00672         if (is_null($which_ls)) {
00673             // Do nothing, use default value.
00674         } else if (! is_array($which_ls)) {
00675             // Did we get an array with line styles?
00676             $this->line_styles = $which_ls;
00677         } else {
00678             $this->line_styles = ($which_ls) ? array($which_ls) : array('solid');
00679         }
00680         return TRUE;
00681     }
00682 
00683 
00687 
00688 
00692     function SetLineSpacing($which_spc)
00693     {
00694         $this->line_spacing = $which_spc;
00695     }
00696 
00697 
00703     function SetUseTTF($which_ttf)
00704     {
00705         $this->use_ttf = $which_ttf;
00706         if ($which_ttf)
00707             $this->SetDefaultFonts();
00708         return TRUE;
00709     }
00710 
00714     function SetTTFPath($which_path)
00715     {
00716         // Maybe someone needs really dynamic config. He'll need this:
00717         // clearstatcache();
00718 
00719         if (is_dir($which_path) && is_readable($which_path)) {
00720             $this->ttf_path = $which_path;
00721             return TRUE;
00722         } else {
00723             $this->PrintError("SetTTFPath(): $which_path is not a valid path.");
00724             return FALSE;
00725         }
00726     }
00727 
00731     function SetDefaultTTFont($which_font)
00732     {
00733         if (is_file($which_font) && is_readable($which_font)) {
00734             $this->default_ttfont = $which_font;
00735             return $this->SetDefaultFonts();
00736         } else {
00737             $this->PrintError("SetDefaultTTFont(): $which_font is not a valid font file.");
00738             return FALSE;
00739         }
00740     }
00741 
00745     function SetDefaultFonts()
00746     {
00747         // TTF:
00748         if ($this->use_ttf) {
00749             //$this->SetTTFPath(dirname($_SERVER['PHP_SELF']));
00750             $this->SetTTFPath(getcwd());
00751             $this->SetFont('generic', $this->default_ttfont, 8);
00752             $this->SetFont('title', $this->default_ttfont, 14);
00753             $this->SetFont('legend', $this->default_ttfont, 8);
00754             $this->SetFont('x_label', $this->default_ttfont, 6);
00755             $this->SetFont('y_label', $this->default_ttfont, 6);
00756             $this->SetFont('x_title', $this->default_ttfont, 10);
00757             $this->SetFont('y_title', $this->default_ttfont, 10);
00758         }
00759         // Fixed:
00760         else {
00761             $this->SetFont('generic', 2);
00762             $this->SetFont('title', 5);
00763             $this->SetFont('legend', 2);
00764             $this->SetFont('x_label', 1);
00765             $this->SetFont('y_label', 1);
00766             $this->SetFont('x_title', 3);
00767             $this->SetFont('y_title', 3);
00768         }
00769 
00770         return TRUE;
00771     }
00772 
00783     function SetFont($which_elem, $which_font, $which_size = 12)
00784     {
00785         // TTF:
00786         if ($this->use_ttf) {
00787             $path = $this->ttf_path.'/'.$which_font;
00788 
00789             if (! is_file($path) || ! is_readable($path) ) {
00790                 $this->DrawError("SetFont(): True Type font $path doesn't exist");
00791                 return FALSE;
00792             }
00793 
00794             switch ($which_elem) {
00795             case 'generic':
00796                 $this->generic_font['font'] = $path;
00797                 $this->generic_font['size'] = $which_size;
00798                 break;
00799             case 'title':
00800                 $this->title_font['font'] = $path;
00801                 $this->title_font['size'] = $which_size;
00802                 break;
00803             case 'legend':
00804                 $this->legend_font['font'] = $path;
00805                 $this->legend_font['size'] = $which_size;
00806                 break;
00807             case 'x_label':
00808                 $this->x_label_font['font'] = $path;
00809                 $this->x_label_font['size'] = $which_size;
00810                 break;
00811             case 'y_label':
00812                 $this->y_label_font['font'] = $path;
00813                 $this->y_label_font['size'] = $which_size;
00814                 break;
00815             case 'x_title':
00816                 $this->x_title_font['font'] = $path;
00817                 $this->x_title_font['size'] = $which_size;
00818                 break;
00819             case 'y_title':
00820                 $this->y_title_font['font'] = $path;
00821                 $this->y_title_font['size'] = $which_size;
00822                 break;
00823             default:
00824                 $this->DrawError("SetFont(): Unknown element '$which_elem' specified.");
00825                 return FALSE;
00826             }
00827             return TRUE;
00828 
00829         }
00830 
00831         // Fixed fonts:
00832         if ($which_font > 5 || $which_font < 0) {
00833             $this->DrawError('SetFont(): Non-TTF font size must be 1, 2, 3, 4 or 5');
00834             return FALSE;
00835         }
00836 
00837         switch ($which_elem) {
00838         case 'generic':
00839             $this->generic_font['font'] = $which_font;
00840             $this->generic_font['height'] = ImageFontHeight($which_font);
00841             $this->generic_font['width'] = ImageFontWidth($which_font);
00842             break;
00843         case 'title':
00844            $this->title_font['font'] = $which_font;
00845            $this->title_font['height'] = ImageFontHeight($which_font);
00846            $this->title_font['width'] = ImageFontWidth($which_font);
00847            break;
00848         case 'legend':
00849             $this->legend_font['font'] = $which_font;
00850             $this->legend_font['height'] = ImageFontHeight($which_font);
00851             $this->legend_font['width'] = ImageFontWidth($which_font);
00852             break;
00853         case 'x_label':
00854             $this->x_label_font['font'] = $which_font;
00855             $this->x_label_font['height'] = ImageFontHeight($which_font);
00856             $this->x_label_font['width'] = ImageFontWidth($which_font);
00857             break;
00858         case 'y_label':
00859             $this->y_label_font['font'] = $which_font;
00860             $this->y_label_font['height'] = ImageFontHeight($which_font);
00861             $this->y_label_font['width'] = ImageFontWidth($which_font);
00862             break;
00863         case 'x_title':
00864             $this->x_title_font['font'] = $which_font;
00865             $this->x_title_font['height'] = ImageFontHeight($which_font);
00866             $this->x_title_font['width'] = ImageFontWidth($which_font);
00867             break;
00868         case 'y_title':
00869             $this->y_title_font['font'] = $which_font;
00870             $this->y_title_font['height'] = ImageFontHeight($which_font);
00871             $this->y_title_font['width'] = ImageFontWidth($which_font);
00872             break;
00873         default:
00874             $this->DrawError("SetFont(): Unknown element '$which_elem' specified.");
00875             return FALSE;
00876         }
00877         return TRUE;
00878     }
00879 
00880 
00885     function TTFBBoxSize($size, $angle, $font, $string)
00886     {
00887         // First, assume angle < 90
00888         $arr = ImageTTFBBox($size, 0, $font, $string);
00889         $flat_width  = $arr[2] - $arr[0];
00890         $flat_height = abs($arr[3] - $arr[5]);
00891 
00892         // Now the bounding box
00893         $angle = deg2rad($angle);
00894         $width  = ceil(abs($flat_width*cos($angle) + $flat_height*sin($angle))); //Must be integer
00895         $height = ceil(abs($flat_width*sin($angle) + $flat_height*cos($angle))); //Must be integer
00896 
00897         return array($width, $height);
00898     }
00899 
00900 
00909     function DrawText($which_font, $which_angle, $which_xpos, $which_ypos, $which_color, $which_text,
00910                       $which_halign = 'left', $which_valign = 'bottom')
00911     {
00912         // TTF:
00913         if ($this->use_ttf) {
00914             $size = $this->TTFBBoxSize($which_font['size'], $which_angle, $which_font['font'], $which_text);
00915             $rads = deg2rad($which_angle);
00916 
00917             if ($which_valign == 'center')
00918                 $which_ypos += $size[1]/2;
00919 
00920             if ($which_valign == 'bottom')
00921                 $which_ypos += $size[1];
00922 
00923             if ($which_halign == 'center')
00924                 $which_xpos -= ($size[0]/2) * cos($rads);
00925 
00926             if ($which_halign == 'left')
00927                 $which_xpos += $size[0] * sin($rads);
00928 
00929             if ($which_halign == 'right')
00930                 $which_xpos -= $size[0] * cos($rads);
00931 
00932             ImageTTFText($this->img, $which_font['size'], $which_angle,
00933                          $which_xpos, $which_ypos, $which_color, $which_font['font'], $which_text);
00934         }
00935         // Fixed fonts:
00936         else {
00937             // Split the text by its lines, and count them
00938             $which_text = ereg_replace("\r", "", $which_text);
00939             $str = split("\n", $which_text);
00940             $nlines = count($str);
00941             $spacing = $this->line_spacing * ($nlines - 1);
00942 
00943             // Vertical text:
00944             // (Remember the alignment convention with vertical text)
00945             if ($which_angle == 90) {
00946                 // The text goes around $which_xpos.
00947                 if ($which_halign == 'center')
00948                     $which_xpos -= ($nlines * ($which_font['height'] + $spacing))/2;
00949 
00950                 // Left alignment requires no modification to $xpos...
00951                 // Right-align it. $which_xpos designated the rightmost x coordinate.
00952                 else if ($which_halign == 'right')
00953                     $which_xpos += ($nlines * ($which_font['height'] + $spacing));
00954 
00955                 $ypos = $which_ypos;
00956                 for($i = 0; $i < $nlines; $i++) {
00957                     // Center the text vertically around $which_ypos (each line)
00958                     if ($which_valign == 'center')
00959                         $ypos = $which_ypos + (strlen($str[$i]) * $which_font['width']) / 2;
00960                     // Make the text finish (vertically) at $which_ypos
00961                     if ($which_valign == 'bottom')
00962                         $ypos = $which_ypos + strlen($str[$i]) * $which_font['width'];
00963 
00964                     ImageStringUp($this->img, $which_font['font'],
00965                                   $i * ($which_font['height'] + $spacing) + $which_xpos,
00966                                   $ypos, $str[$i], $which_color);
00967                 }
00968             }
00969             // Horizontal text:
00970             else {
00971                 // The text goes above $which_ypos
00972                 if ($which_valign == 'top')
00973                     $which_ypos -= $nlines * ($which_font['height'] + $spacing);
00974                 // The text is centered around $which_ypos
00975                 if ($which_valign == 'center')
00976                     $which_ypos -= ($nlines * ($which_font['height'] + $spacing))/2;
00977                 // valign = 'bottom' requires no modification
00978 
00979                 $xpos = $which_xpos;
00980                 for($i = 0; $i < $nlines; $i++) {
00981                     // center the text around $which_xpos
00982                     if ($which_halign == 'center')
00983                         $xpos = $which_xpos - (strlen($str[$i]) * $which_font['width'])/2;
00984                     // make the text finish at $which_xpos
00985                     if ($which_halign == 'right')
00986                         $xpos = $which_xpos - strlen($str[$i]) * $which_font['width'];
00987 
00988                     ImageString($this->img, $which_font['font'], $xpos,
00989                                 $i * ($which_font['height'] + $spacing) + $which_ypos,
00990                                 $str[$i], $which_color);
00991                 }
00992             }
00993         }
00994         return TRUE;
00995     } // function DrawText()
00996 
00997 
01001 
01005     function SetFileFormat($format)
01006     {
01007         $asked = $this->CheckOption($format, 'jpg, png, gif, wbmp', __FUNCTION__);
01008 
01009         switch ($asked) {
01010         case 'jpg':
01011             if (imagetypes() & IMG_JPG)
01012                 $this->file_format = 'jpg';
01013                 return TRUE;
01014             break;
01015         case 'png':
01016             if (imagetypes() & IMG_PNG)
01017                 $this->file_format = 'png';
01018                 return TRUE;
01019             break;
01020         case 'gif':
01021             if (imagetypes() & IMG_GIF)
01022                 $this->file_format = 'gif';
01023                 return TRUE;
01024             break;
01025         case 'wbmp':
01026             if (imagetypes() & IMG_WBMP)
01027                 $this->file_format = 'wbmp';
01028                 return TRUE;
01029             break;
01030         default:
01031             $this->PrintError("SetFileFormat():File format '$format' not supported");
01032             return FALSE;
01033         }
01034     }
01035 
01036 
01043     function SetBgImage($input_file, $mode='centeredtile')
01044     {
01045         $this->bgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
01046         $this->bgimg  = $input_file;
01047     }
01048 
01055     function SetPlotAreaBgImage($input_file, $mode='tile')
01056     {
01057         $this->plotbgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
01058         $this->plotbgimg  = $input_file;
01059     }
01060 
01061 
01065     function SetOutputFile($which_output_file)
01066     {
01067         $this->output_file = $which_output_file;
01068         return TRUE;
01069     }
01070 
01075     function SetIsInline($which_ii)
01076     {
01077         $this->is_inline = (bool)$which_ii;
01078         return TRUE;
01079     }
01080 
01081 
01086     function PrintImage()
01087     {
01088         // Browser cache stuff submitted by Thiemo Nagel
01089         if ( (! $this->browser_cache) && (! $this->is_inline)) {
01090             header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
01091             header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');
01092             header('Cache-Control: no-cache, must-revalidate');
01093             header('Pragma: no-cache');
01094         }
01095 
01096         switch($this->file_format) {
01097         case 'png':
01098             if (! $this->is_inline) {
01099                 Header('Content-type: image/png');
01100             }
01101             if ($this->is_inline && $this->output_file != '') {
01102                 ImagePng($this->img, $this->output_file);
01103             } else {
01104                 ImagePng($this->img);
01105             }
01106             break;
01107         case 'jpg':
01108             if (! $this->is_inline) {
01109                 Header('Content-type: image/jpeg');
01110             }
01111             if ($this->is_inline && $this->output_file != '') {
01112                 ImageJPEG($this->img, $this->output_file);
01113             } else {
01114                 ImageJPEG($this->img);
01115             }
01116             break;
01117         case 'gif':
01118             if (! $this->is_inline) {
01119                 Header('Content-type: image/gif');
01120             }
01121             if ($this->is_inline && $this->output_file != '') {
01122                 ImageGIF($this->img, $this->output_file);
01123             } else {
01124                 ImageGIF($this->img);
01125             }
01126 
01127             break;
01128         case 'wbmp':        // wireless bitmap, 2 bit.
01129             if (! $this->is_inline) {
01130                 Header('Content-type: image/wbmp');
01131             }
01132             if ($this->is_inline && $this->output_file != '') {
01133                 ImageWBMP($this->img, $this->output_file);
01134             } else {
01135                 ImageWBMP($this->img);
01136             }
01137 
01138             break;
01139         default:
01140             $this->PrintError('PrintImage(): Please select an image type!');
01141             break;
01142         }
01143         return TRUE;
01144     }
01145 
01149     function PrintError($error_message)
01150     {
01151         echo "<p><b>Fatal error</b>: $error_message<p>";
01152         die;
01153     }
01154 
01162     function DrawError($error_message, $where_x = NULL, $where_y = NULL)
01163     {
01164         if (! $this->img)
01165             $this->PrintError('_DrawError(): Warning, no image resource allocated. '.
01166                               'The message to be written was: '.$error_message);
01167 
01168         $ypos = (! $where_y) ? $this->image_height/2 : $where_y;
01169         $xpos = (! $where_x) ? $this->image_width/2 : $where_x;
01170         ImageRectangle($this->img, 0, 0, $this->image_width, $this->image_height,
01171                        ImageColorAllocate($this->img, 255, 255, 255));
01172 
01173         $this->DrawText($this->generic_font, 0, $xpos, $ypos, ImageColorAllocate($this->img, 0, 0, 0),
01174                         $error_message, 'center', 'center');
01175 
01176         $this->PrintImage();
01177         exit;
01178 //        return TRUE;
01179     }
01180 
01184 
01185 
01189     function SetXDataLabelPos($which_xdlp)
01190     {
01191         $this->x_data_label_pos = $this->CheckOption($which_xdlp, 'plotdown, plotup, both, xaxis, all, none',
01192                                                       __FUNCTION__);
01193         if ($which_xdlp != 'none')
01194             $this->x_tick_label_pos = 'none';
01195 
01196         return TRUE;
01197     }
01198 
01202     function SetYDataLabelPos($which_ydlp)
01203     {
01204         $this->y_data_label_pos = $this->CheckOption($which_ydlp, 'plotleft, plotright, both, yaxis, all, none',
01205                                                       __FUNCTION__);
01206         if ($which_ydlp != 'none')
01207             $this->y_tick_label_pos = 'none';
01208 
01209         return TRUE;
01210     }
01211 
01212 
01216     function SetXTickLabelPos($which_xtlp)
01217     {
01218         $this->x_tick_label_pos = $this->CheckOption($which_xtlp, 'plotdown, plotup, both, xaxis, all, none',
01219                                                       __FUNCTION__);
01220         if ($which_xtlp != 'none')
01221             $this->x_data_label_pos = 'none';
01222 
01223         return TRUE;
01224     }
01225 
01229     function SetYTickLabelPos($which_ytlp)
01230     {
01231         $this->y_tick_label_pos = $this->CheckOption($which_ytlp, 'plotleft, plotright, both, yaxis, all, none',
01232                                                       __FUNCTION__);
01233         if ($which_ytlp != 'none')
01234             $this->y_data_label_pos = 'none';
01235 
01236         return TRUE;
01237     }
01238 
01243     function SetXLabelType($which_xlt)
01244     {
01245         $this->x_label_type = $this->CheckOption($which_xlt, 'data, time, title', __FUNCTION__);
01246         return TRUE;
01247     }
01248 
01252     function SetYLabelType($which_ylt)
01253     {
01254         $this->y_label_type = $this->CheckOption($which_ylt, 'data, time', __FUNCTION__);
01255         return TRUE;
01256     }
01257 
01258     function SetXTimeFormat($which_xtf)
01259     {
01260         $this->x_time_format = $which_xtf;
01261         return TRUE;
01262     }
01263     function SetYTimeFormat($which_ytf)
01264     {
01265         $this->y_time_format = $which_ytf;
01266         return TRUE;
01267     }
01268 
01269     function SetXLabelAngle($which_xla)
01270     {
01271         $this->x_label_angle = $which_xla;
01272         return TRUE;
01273     }
01274 
01275     function SetYLabelAngle($which_yla)
01276     {
01277         $this->y_label_angle = $which_yla;
01278         return TRUE;
01279     }
01280 
01284 
01294     function CheckOption($which_opt, $which_acc, $which_func)
01295     {
01296         $asked = trim($which_opt);
01297 
01298         // FIXME: this for backward compatibility, as eregi() fails with empty strings.
01299         if ($asked == '')
01300             return '';
01301 
01302         $asked = strtolower($asked);
01303         if (@ eregi($asked, $which_acc)) {
01304             return $asked;
01305         } else {
01306             $this->DrawError("$which_func(): '$which_opt' not in available choices: '$which_acc'.");
01307             return NULL;
01308         }
01309     }
01310 
01311 
01315     function SetBrowserCache($which_browser_cache)
01316     {
01317         $this->browser_cache = $which_browser_cache;
01318         return TRUE;
01319     }
01320 
01324     function SetPrintImage($which_pi)
01325     {
01326         $this->print_image = $which_pi;
01327         return TRUE;
01328     }
01329 
01333     function SetLegend($which_leg)
01334     {
01335         if (is_array($which_leg)) {             // use array
01336             $this->legend = $which_leg;
01337             return TRUE;
01338         } else if (! is_null($which_leg)) {     // append string
01339             $this->legend[] = $which_leg;
01340             return TRUE;
01341         } else {
01342             $this->DrawError("SetLegend(): argument must not be null.");
01343             return FALSE;
01344         }
01345     }
01346 
01352     function SetLegendPixels($which_x, $which_y, $which_type=NULL)
01353     {
01354         $this->legend_x_pos = $which_x;
01355         $this->legend_y_pos = $which_y;
01356 
01357         return TRUE;
01358     }
01359 
01365     function SetLegendWorld($which_x, $which_y, $which_type=NULL)
01366     {
01367         if (! isset($this->scale_is_set))
01368             $this->CalcTranslation();
01369 
01370         $this->legend_x_pos = $this->xtr($which_x);
01371         $this->legend_y_pos = $this->ytr($which_y);
01372 
01373         return TRUE;
01374     }
01375 
01379     function SetPlotBorderType($pbt)
01380     {
01381         $this->plot_border_type = $this->CheckOption($pbt, 'left, sides, none, full', __FUNCTION__);
01382     }
01383 
01387     function SetImageBorderType($sibt)
01388     {
01389         $this->image_border_type = $this->CheckOption($sibt, 'raised, plain', __FUNCTION__);
01390     }
01391 
01392 
01396     function SetDrawPlotAreaBackground($dpab)
01397     {
01398         $this->draw_plot_area_background = (bool)$dpab;
01399     }
01400 
01401 
01405     function SetDrawYGrid($dyg)
01406     {
01407         $this->draw_y_grid = (bool)$dyg;
01408         return TRUE;
01409     }
01410 
01411 
01415     function SetDrawXGrid($dxg)
01416     {
01417         $this->draw_x_grid = (bool)$dxg;
01418         return TRUE;
01419     }
01420 
01421 
01425     function SetDrawDashedGrid($ddg)
01426     {
01427         $this->dashed_grid = (bool)$ddg;
01428         return TRUE;
01429     }
01430 
01431 
01435     function SetDrawXDataLabelLines($dxdl)
01436     {
01437         $this->draw_x_data_label_lines = (bool)$dxdl;
01438         return TRUE;
01439     }
01440 
01441 
01446     function SetDrawYDataLabelLines($dydl)
01447     {
01448         $this->draw_y_data_label_lines = $dydl;
01449         return TRUE;
01450     }
01451 
01456     function SetTitle($which_title)
01457     {
01458         $this->title_txt = $which_title;
01459 
01460         if ($which_title == '') {
01461             $this->title_height = 0;
01462             return TRUE;
01463         }
01464 
01465         $str = split("\n", $which_title);
01466         $lines = count($str);
01467         $spacing = $this->line_spacing * ($lines - 1);
01468 
01469         if ($this->use_ttf) {
01470             $size = $this->TTFBBoxSize($this->title_font['size'], 0, $this->title_font['font'], $which_title);
01471             $this->title_height = $size[1] * $lines;
01472         } else {
01473             $this->title_height = ($this->title_font['height'] + $spacing) * $lines;
01474         }
01475         return TRUE;
01476     }
01477 
01481     function SetXTitle($which_xtitle, $which_xpos = 'plotdown')
01482     {
01483         if ($which_xtitle == '')
01484             $which_xpos = 'none';
01485 
01486         $this->x_title_pos = $this->CheckOption($which_xpos, 'plotdown, plotup, both, none', __FUNCTION__);
01487 
01488         $this->x_title_txt = $which_xtitle;
01489 
01490         $str = split("\n", $which_xtitle);
01491         $lines = count($str);
01492         $spacing = $this->line_spacing * ($lines - 1);
01493 
01494         if ($this->use_ttf) {
01495             $size = $this->TTFBBoxSize($this->x_title_font['size'], 0, $this->x_title_font['font'], $which_xtitle);
01496             $this->x_title_height = $size[1] * $lines;
01497         } else {
01498             $this->x_title_height = ($this->y_title_font['height'] + $spacing) * $lines;
01499         }
01500 
01501         return TRUE;
01502     }
01503 
01504 
01508     function SetYTitle($which_ytitle, $which_ypos = 'plotleft')
01509     {
01510         if ($which_ytitle == '')
01511             $which_ypos = 'none';
01512 
01513         $this->y_title_pos = $this->CheckOption($which_ypos, 'plotleft, plotright, both, none', __FUNCTION__);
01514 
01515         $this->y_title_txt = $which_ytitle;
01516 
01517         $str = split("\n", $which_ytitle);
01518         $lines = count($str);
01519         $spacing = $this->line_spacing * ($lines - 1);
01520 
01521         if ($this->use_ttf) {
01522             $size = $this->TTFBBoxSize($this->y_title_font['size'], 90, $this->y_title_font['font'],
01523                                        $which_ytitle);
01524             $this->y_title_width = $size[0] * $lines;
01525         } else {
01526             $this->y_title_width = ($this->y_title_font['height'] + $spacing) * $lines;
01527         }
01528 
01529         return TRUE;
01530     }
01531 
01536     function SetShading($which_s)
01537     {
01538         $this->shading = (int)$which_s;
01539         return TRUE;
01540     }
01541 
01542     function SetPlotType($which_pt)
01543     {
01544         $this->plot_type = $this->CheckOption($which_pt,
01545                            'bars, stackedbars, lines, linepoints, area, points, pie, thinbarline, squared',
01546                             __FUNCTION__);
01547     }
01548 
01553     function SetYAxisPosition($pos)
01554     {
01555         $this->y_axis_position = (int)$pos;
01556         if (isset($this->scale_is_set)) {
01557             $this->CalcTranslation();
01558         }
01559         return TRUE;
01560     }
01561 
01566     function SetXAxisPosition($pos)
01567     {
01568         $this->x_axis_position = (int)$pos;
01569         if (isset($this->scale_is_set)) {
01570             $this->CalcTranslation();
01571         }
01572         return TRUE;
01573     }
01574 
01575 
01576     function SetXScaleType($which_xst)
01577     {
01578         $this->xscale_type = $this->CheckOption($which_xst, 'linear, log', __FUNCTION__);
01579         return TRUE;
01580     }
01581 
01582     function SetYScaleType($which_yst)
01583     {
01584         $this->yscale_type = $this->CheckOption($which_yst, 'linear, log',  __FUNCTION__);
01585         return TRUE;
01586     }
01587 
01588     function SetPrecisionX($which_prec)
01589     {
01590         $this->x_precision = $which_prec;
01591         $this->SetXLabelType('data');
01592         return TRUE;
01593     }
01594 
01595     function SetPrecisionY($which_prec)
01596     {
01597         $this->y_precision = $which_prec;
01598         $this->SetYLabelType('data');
01599         return TRUE;
01600     }
01601 
01602     function SetErrorBarLineWidth($which_seblw)
01603     {
01604         $this->error_bar_line_width = $which_seblw;
01605         return TRUE;
01606     }
01607 
01608     function SetLabelScalePosition($which_blp)
01609     {
01610         //0 to 1
01611         $this->label_scale_position = $which_blp;
01612         return TRUE;
01613     }
01614 
01615     function SetErrorBarSize($which_ebs)
01616     {
01617         //in pixels
01618         $this->error_bar_size = $which_ebs;
01619         return TRUE;
01620     }
01621 
01625     function SetErrorBarShape($which_ebs)
01626     {
01627         $this->error_bar_shape = $this->CheckOption($which_ebs, 'tee, line', __FUNCTION__);
01628     }
01629 
01635     function SetPointShapes($which_pt)
01636     {
01637         if (is_null($which_pt)) {
01638             // Do nothing, use default value.
01639         } else if (is_array($which_pt)) {
01640             // Did we get an array with point shapes?
01641             $this->point_shapes = $which_pt;
01642         } else {
01643             // Single value into array
01644             $this->point_shapes = array($which_pt);
01645         }
01646 
01647         foreach ($this->point_shapes as $shape)
01648         {
01649             // TODO, better check, per element rectification
01650             $this->CheckOption($shape,
01651                'halfline, line, plus, cross, rect, circle, dot, diamond, triangle, trianglemid',
01652                 __FUNCTION__);
01653         }
01654 
01655         // Make both point_shapes and point_sizes same size.
01656         $ps = count($this->point_sizes);
01657         $pt = count($this->point_shapes);
01658 
01659         if ($ps < $pt) {
01660             array_pad_array($this->point_sizes, $pt);
01661         } else if ($pt > $ps) {
01662             array_pad_array($this->point_shapes, $ps);
01663         }
01664         return TRUE;
01665     }
01666 
01672     function SetPointSizes($which_ps)
01673     {
01674         if (is_null($which_ps)) {
01675             // Do nothing, use default value.
01676         } else if (is_array($which_ps)) {
01677             // Did we get an array with point sizes?
01678             $this->point_sizes = $which_ps;
01679         } else {
01680             // Single value into array
01681             $this->point_sizes = array($which_ps);
01682         }
01683 
01684         // Make both point_shapes and point_sizes same size.
01685         $ps = count($this->point_sizes);
01686         $pt = count($this->point_shapes);
01687 
01688         if ($ps < $pt) {
01689             array_pad_array($this->point_sizes, $pt);
01690         } else if ($pt > $ps) {
01691             array_pad_array($this->point_shapes, $ps);
01692         }
01693 
01694         // Fix odd point sizes for point shapes which need it
01695         for ($i = 0; $i < $pt; $i++) {
01696             if ($this->point_shapes[$i] == 'diamond' or $this->point_shapes[$i] == 'triangle') {
01697                 if ($this->point_sizes[$i] % 2 != 0) {
01698                     $this->point_sizes[$i]++;
01699                 }
01700             }
01701         }
01702         return TRUE;
01703     }
01704 
01705 
01710     function SetDrawBrokenLines($bl)
01711     {
01712         $this->draw_broken_lines = (bool)$bl;
01713     }
01714 
01715 
01722     function SetDataType($which_dt)
01723     {
01724         //The next four lines are for past compatibility.
01725         if ($which_dt == 'text-linear') { $which_dt = 'text-data'; };
01726         if ($which_dt == 'linear-linear') { $which_dt = 'data-data'; };
01727         if ($which_dt == 'linear-linear-error') { $which_dt = 'data-data-error'; };
01728         if ($which_dt == 'text-data-pie') { $which_dt = 'text-data-single'; }
01729 
01730 
01731         $this->data_type = $this->CheckOption($which_dt, 'text-data, text-data-single, '.
01732                                                          'data-data, data-data-error', __FUNCTION__);
01733         return TRUE;
01734     }
01735 
01741     function SetDataValues(&$which_dv)
01742     {
01743         unset ($this->data_limits_done);        // Reset this for every new data_set
01744         $this->num_data_rows = count($which_dv);
01745         $this->total_records = 0;               // Perform some useful calculations.
01746         $this->records_per_group = 1;
01747         for ($i = 0, $recs = 0; $i < $this->num_data_rows; $i++) {
01748             // Copy
01749             $this->data[$i] = array_values($which_dv[$i]);   // convert to numerical indices.
01750 
01751             // Compute some values
01752             $recs = count($this->data[$i]);
01753             $this->total_records += $recs;
01754 
01755             if ($recs > $this->records_per_group)
01756                 $this->records_per_group = $recs;
01757 
01758             $this->num_recs[$i] = $recs;
01759         }
01760     }
01761 
01767     function PadArrays()
01768     {
01769         array_pad_array($this->line_widths, $this->records_per_group);
01770         array_pad_array($this->line_styles, $this->records_per_group);
01771 
01772         array_pad_array($this->data_colors, $this->records_per_group);
01773         array_pad_array($this->data_border_colors, $this->records_per_group);
01774         array_pad_array($this->error_bar_colors, $this->records_per_group);
01775 
01776         $this->SetDataColors();
01777         $this->SetDataBorderColors();
01778         $this->SetErrorBarColors();
01779 
01780         return TRUE;
01781     }
01782 
01783 
01787 
01796     function FindDataLimits()
01797     {
01798         // Set some default min and max values before running through the data
01799         switch ($this->data_type) {
01800         case 'text-data':
01801             $minx = 0;
01802             $maxx = $this->num_data_rows - 1 ;
01803             $miny = $this->data[0][1];
01804             $maxy = $miny;
01805             break;
01806         default:  //Everything else: data-data, etc, take first value
01807             $minx = $this->data[0][1];
01808             $maxx = $minx;
01809             $miny = $this->data[0][2];
01810             $maxy = $miny;
01811             break;
01812         }
01813 
01814         $mine = 0;  // Maximum value for the -error bar (assume error bars always > 0)
01815         $maxe = 0;  // Maximum value for the +error bar (assume error bars always > 0)
01816         $maxt = 0;  // Maximum number of characters in text labels
01817 
01818         $minminy = $miny;
01819         $maxmaxy = $maxy;
01820 
01821         if ($this->plot_type == 'stackedbars') { $maxmaxy = $minminy = 0; }
01822 
01823         // Process each row of data
01824         for ($i=0; $i < $this->num_data_rows; $i++) {
01825             $j=0;
01826             // Extract maximum text label length
01827             $val = @ strlen($this->data[$i][$j++]);
01828             $maxt = ($val > $maxt) ? $val : $maxt;
01829 
01830 
01831             if ($this->plot_type == 'stackedbars') { $maxy = $miny = 0; }
01832 
01833             switch ($this->data_type) {
01834             case 'text-data':           // Data is passed in as (title, y1, y2, y3, ...)
01835             case 'text-data-single':    // This one is for some pie charts
01836                 // $numrecs = @ count($this->data[$i]);
01837                 $miny = $maxy = (double)$this->data[$i][$j];
01838                 for (; $j < $this->num_recs[$i]; $j++) {
01839                     $val = (double)$this->data[$i][$j];
01840                     if ($this->plot_type == 'stackedbars') {
01841                         $maxy += abs($val);      // only positive values for the moment
01842                     } else {
01843                         $maxy = ($val > $maxy) ? $val : $maxy;
01844                         $miny = ($val < $miny) ? $val : $miny;
01845                     }
01846                 }
01847                 break;
01848             case 'data-data':           // Data is passed in as (title, x, y, y2, y3, ...)
01849                 // X value:
01850                 $val = (double)$this->data[$i][$j++];
01851                 $maxx = ($val > $maxx) ? $val : $maxx;
01852                 $minx = ($val < $minx) ? $val : $minx;
01853 
01854                 $miny = $maxy = (double)$this->data[$i][$j];
01855                 // $numrecs = @ count($this->data[$i]);
01856                 for (; $j < $this->num_recs[$i]; $j++) {
01857                     $val = (double)$this->data[$i][$j];
01858                     $maxy = ($val > $maxy) ? $val : $maxy;
01859                     $miny = ($val < $miny) ? $val : $miny;
01860                 }
01861                 break;
01862             case 'data-data-error':     // Data is passed in as (title, x, y, err+, err-, y2, err2+, err2-,...)
01863                 // X value:
01864                 $val = (double)$this->data[$i][$j++];
01865                 $maxx = ($val > $maxx) ? $val : $maxx;
01866                 $minx = ($val < $minx) ? $val : $minx;
01867 
01868                 $miny = $maxy = (double)$this->data[$i][$j];
01869                 // $numrecs = @ count($this->data[$i]);
01870                 for (; $j < $this->num_recs[$i];) {
01871                     // Y value:
01872                     $val = (double)$this->data[$i][$j++];
01873                     $maxy = ($val > $maxy) ? $val : $maxy;
01874                     $miny = ($val < $miny) ? $val : $miny;
01875                     // Error +:
01876                     $val = (double)$this->data[$i][$j++];
01877                     $maxe = ($val > $maxe) ? $val : $maxe;
01878                     // Error -:
01879                     $val = (double)$this->data[$i][$j++];
01880                     $mine = ($val > $mine) ? $val : $mine;
01881                 }
01882                 $maxy = $maxy + $maxe;
01883                 $miny = $miny - $mine;      // assume error bars are always > 0
01884                 break;
01885             default:
01886                 $this->PrintError("FindDataLimits(): Unknown data type '$data_type'.");
01887             break;
01888             }
01889             $this->data[$i][MINY] = $miny;      // This row's min Y, for DrawXDataLine()
01890             $this->data[$i][MAXY] = $maxy;      // This row's max Y, for DrawXDataLine()
01891 
01892             $minminy = ($miny < $minminy) ? $miny : $minminy;   // global min
01893             $maxmaxy = ($maxy > $maxmaxy) ? $maxy : $maxmaxy;   // global max
01894         }
01895 
01896         $this->min_x = $minx;
01897         $this->max_x = $maxx;
01898         $this->min_y = $minminy;
01899         $this->max_y = $maxmaxy;
01900         $this->max_t = $maxt;
01901 
01902         $this->data_limits_done = TRUE;
01903 
01904         return TRUE;
01905     }
01906 
01907 
01920     function CalcMargins()
01921     {
01922         // Temporary variables for label size calculation
01923         $xlab = $this->FormatLabel('x', $this->max_x);
01924         $ylab = $this->FormatLabel('y', $this->max_y);
01925 
01926         // dirty fix:
01927         // max_t is the maximum data label length (from column 0 of each data row).
01928         if ($this->max_t > strlen ($xlab))
01929             $xlab = sprintf ("%{$this->max_t}s","_");
01930 
01932 
01933         // TTFonts:
01934         if ($this->use_ttf) {
01935             // Maximum X axis label height
01936             $size = $this->TTFBBoxSize($this->x_label_font['size'], $this->x_label_angle,
01937                                        $this->x_label_font['font'], $xlab);
01938             $this->x_tick_label_height = $size[1];
01939 
01940             // Maximum Y axis label width
01941             $size = $this->TTFBBoxSize($this->y_label_font['size'], $this->y_label_angle,
01942                                         $this->y_label_font['font'], $ylab);
01943             $this->y_tick_label_width = $size[0];
01944         }
01945         // Fixed fonts:
01946         else {
01947             // Maximum X axis label height
01948             if ($this->x_label_angle == 90)
01949                 $this->x_tick_label_height = strlen($xlab) * $this->x_label_font['width'];
01950             else
01951                 $this->x_tick_label_height = $this->x_label_font['height'];
01952 
01953             // Maximum Y axis label width
01954             $this->y_tick_label_width = strlen($ylab) * $this->y_label_font['width'];
01955         }
01956 
01957 
01959 
01960         // Upper title, ticks and tick labels, and data labels:
01961         $this->y_top_margin = $this->title_height + $this->safe_margin * 2;
01962 
01963         if ($this->x_title_pos == 'plotup' || $this->x_title_pos == 'both')
01964             $this->y_top_margin += $this->x_title_height + $this->safe_margin;
01965 
01966         if ($this->x_tick_label_pos == 'plotup' || $this->x_tick_label_pos == 'both')
01967             $this->y_top_margin += $this->x_tick_label_height;
01968 
01969         if ($this->x_tick_pos == 'plotup' || $this->x_tick_pos == 'both')
01970             $this->y_top_margin += $this->x_tick_length * 2;
01971 
01972         if ($this->x_data_label_pos == 'plotup' || $this->x_data_label_pos == 'both')
01973             $this->y_top_margin += $this->x_tick_label_height;
01974 
01975         // Lower title, ticks and tick labels, and data labels:
01976         $this->y_bot_margin = $this->safe_margin * 2;
01977 
01978         if ($this->x_title_pos == 'plotdown' || $this->x_title_pos == 'both')
01979             $this->y_bot_margin += $this->x_title_height;
01980 
01981         if ($this->x_tick_pos == 'plotdown' || $this->x_tick_pos == 'both')
01982             $this->y_bot_margin += $this->x_tick_length * 2;
01983 
01984         if ($this->x_tick_pos == 'xaxis' && ($this->x_axis_position == '' || $this->x_axis_position == 0))
01985             $this->y_bot_margin += $this->x_tick_length * 2;
01986 
01987         if ($this->x_tick_label_pos == 'plotdown' || $this->x_tick_label_pos == 'both')
01988             $this->y_bot_margin += $this->x_tick_label_height;
01989 
01990         if ($this->x_tick_label_pos == 'xaxis' && ($this->x_axis_position == '' || $this->x_axis_position == 0))
01991             $this->y_bot_margin += $this->x_tick_label_height;
01992 
01993         if ($this->x_data_label_pos == 'plotdown' || $this->x_data_label_pos == 'both')
01994             $this->y_bot_margin += $this->x_tick_label_height;
01995 
01996         // Left title, ticks and tick labels:
01997         $this->x_left_margin = $this->safe_margin * 2;
01998 
01999         if ($this->y_title_pos == 'plotleft' || $this->y_title_pos == 'both')
02000             $this->x_left_margin += $this->y_title_width + $this->safe_margin;
02001 
02002         if ($this->y_tick_label_pos == 'plotleft' || $this->y_tick_label_pos == 'both')
02003             $this->x_left_margin += $this->y_tick_label_width;
02004 
02005         if ($this->y_tick_pos == 'plotleft' || $this->y_tick_pos == 'both')
02006             $this->x_left_margin += $this->y_tick_length * 2 ;
02007 
02008         // Right title, ticks and tick labels:
02009         $this->x_right_margin = $this->safe_margin * 2;
02010 
02011         if ($this->y_title_pos == 'plotright' || $this->y_title_pos == 'both')
02012             $this->x_right_margin += $this->y_title_width + $this->safe_margin;
02013 
02014         if ($this->y_tick_label_pos == 'plotright' || $this->y_tick_label_pos == 'both')
02015             $this->x_right_margin += $this->y_tick_label_width;
02016 
02017         if ($this->y_tick_pos == 'plotright' || $this->y_tick_pos == 'both')
02018             $this->x_right_margin += $this->y_tick_length * 2;
02019 
02020 
02021         $this->x_tot_margin = $this->x_left_margin + $this->x_right_margin;
02022         $this->y_tot_margin = $this->y_top_margin + $this->y_bot_margin;
02023 
02024         return;
02025     }
02026 
02027 
02031     function SetMarginsPixels($which_lm, $which_rm, $which_tm, $which_bm)
02032     {
02033 
02034         $this->x_left_margin = $which_lm;
02035         $this->x_right_margin = $which_rm;
02036         $this->x_tot_margin = $which_lm + $which_rm;
02037 
02038         $this->y_top_margin = $which_tm;
02039         $this->y_bot_margin = $which_bm;
02040         $this->y_tot_margin = $which_tm + $which_bm;
02041 
02042         $this->SetPlotAreaPixels();
02043 
02044         return;
02045     }
02046 
02047 
02055     function SetPlotAreaPixels($x1=NULL, $y1=NULL, $x2=NULL, $y2=NULL)
02056     {
02057         if ($x2 && $y2) {
02058             $this->plot_area = array($x1, $y1, $x2, $y2);
02059         } else {
02060             if (! isset($this->x_tot_margin))
02061                 $this->CalcMargins();
02062 
02063             $this->plot_area = array($this->x_left_margin, $this->y_top_margin,
02064                                      $this->image_width - $this->x_right_margin,
02065                                      $this->image_height - $this->y_bot_margin);
02066         }
02067         $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0];
02068         $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1];
02069 
02070         // Reset the scale with the new plot area.
02071         if (isset($this->plot_max_x))
02072             $this->CalcTranslation();
02073 
02074         return TRUE;
02075 
02076     }
02077 
02078 
02085     function SetPlotAreaWorld($xmin=NULL, $ymin=NULL, $xmax=NULL, $ymax=NULL)
02086     {
02087         if (! isset($this->data_limits_done)) { // For automatic setting of data we need data limits
02088             $this->FindDataLimits() ;
02089         }
02090 
02091         if ($xmin === NULL || $xmin === '') {
02092             if ($this->data_type == 'text-data')  // Valid for data without X values only.
02093                 $xmin = 0;
02094             else
02095                 $xmin = $this->min_x;
02096         }
02097         if ($xmax === NULL || $xmax === '') {
02098             if ($this->data_type == 'text-data')  // Valid for data without X values only.
02099                 $xmax = $this->max_x + 1;
02100             else
02101                 $xmax = $this->max_x;
02102         }
02103 
02104         // Leave room above and below the highest and lowest data points.
02105 
02106         if ($ymin === NULL || $ymin === '') {
02107             if ($this->min_y < 0)
02108                 $ymin = ceil($this->min_y * 1.1);
02109             else
02110                 $ymin = floor($this->min_y * 0.9);
02111         }
02112         if ($ymax === NULL || $ymax === '') {
02113             if ($this->max_y < 0)
02114                 $ymax = floor($this->max_y * 0.9);
02115             else
02116                 $ymax = ceil($this->max_y * 1.1);
02117         }
02118 
02119         // Error checking
02120 
02121         if ($ymin == $ymax)     // Minimum height
02122             $ymax += 1;
02123 
02124         if ($this->yscale_type == 'log') {
02125             if ($ymin <= 0) {
02126                 $ymin = 1;
02127             }
02128             if ($ymax <= 0) {
02129                 $this->PrintError('SetPlotAreaWorld(): Log plots need data greater than 0');
02130                 return FALSE;
02131             }
02132         }
02133 
02134         if ($ymax <= $ymin) {
02135             $this->DrawError('SetPlotAreaWorld(): Error in data - max not greater than min');
02136             return FALSE;
02137         }
02138 
02139 
02140         // Reset (if it was already set) the scale with the new maxs and mins
02141 
02142         $this->plot_min_x = $xmin;
02143         $this->plot_max_x = $xmax;
02144         $this->plot_min_y = $ymin;
02145         $this->plot_max_y = $ymax;
02146 
02147         if (isset($this->plot_area_width)) {
02148             $this->CalcTranslation();
02149         }
02150 
02151         return TRUE;
02152     } //function SetPlotAreaWorld
02153 
02154 
02158     function CalcBarWidths()
02159     {
02160         $group_width = ($this->plot_area[2] - $this->plot_area[0]) /
02161                       $this->num_data_rows * $this->group_frac_width;
02162         if ($this->plot_type == 'bars') {
02163             $this->record_bar_width = $group_width / $this->records_per_group;
02164         } else if ($this->plot_type == 'stackedbars') {
02165             $this->record_bar_width = $group_width;
02166         }
02167         $this->data_group_space = $group_width / 2;
02168         return TRUE;
02169     }
02170 
02174     function CalcTranslation()
02175     {
02176         if ($this->plot_max_x - $this->plot_min_x == 0) { // Check for div by 0
02177             $this->xscale = 0;
02178         } else {
02179             if ($this->xscale_type == 'log') {
02180                 $this->xscale = ($this->plot_area_width)/(log10($this->plot_max_x) - log10($this->plot_min_x));
02181             } else {
02182                 $this->xscale = ($this->plot_area_width)/($this->plot_max_x - $this->plot_min_x);
02183             }
02184         }
02185 
02186         if ($this->plot_max_y - $this->plot_min_y == 0) { // Check for div by 0
02187             $this->yscale = 0;
02188         } else {
02189             if ($this->yscale_type == 'log') {
02190                 $this->yscale = ($this->plot_area_height)/(log10($this->plot_max_y) - log10($this->plot_min_y));
02191             } else {
02192                 $this->yscale = ($this->plot_area_height)/($this->plot_max_y - $this->plot_min_y);
02193             }
02194         }
02195         // GD defines x = 0 at left and y = 0 at TOP so -/+ respectively
02196         if ($this->xscale_type == 'log') {
02197             $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * log10($this->plot_min_x) );
02198         } else {
02199             $this->plot_origin_x = $this->plot_area[0] - ($this->xscale * $this->plot_min_x);
02200         }
02201         if ($this->yscale_type == 'log') {
02202             $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * log10($this->plot_min_y));
02203         } else {
02204             $this->plot_origin_y = $this->plot_area[3] + ($this->yscale * $this->plot_min_y);
02205         }
02206 
02207         $this->scale_is_set = TRUE;
02208 
02209         /************** FIXME?? *************/
02210         // There should be a better place for this.
02211 
02212         // User provided y axis position?
02213         if ($this->y_axis_position != '') {
02214             // Make sure we draw our axis inside the plot
02215             $this->y_axis_position = ($this->y_axis_position < $this->plot_min_x)
02216                                      ? $this->plot_min_x : $this->y_axis_position;
02217             $this->y_axis_position = ($this->y_axis_position > $this->plot_max_x)
02218                                      ? $this->plot_max_x : $this->y_axis_position;
02219             $this->y_axis_x_pixels = $this->xtr($this->y_axis_position);
02220         } else {
02221             // Default to left axis
02222             $this->y_axis_x_pixels = $this->xtr($this->plot_min_x);
02223         }
02224         // User provided x axis position?
02225         if ($this->x_axis_position != '') {
02226             // Make sure we draw our axis inside the plot
02227             $this->x_axis_position = ($this->x_axis_position < $this->plot_min_y)
02228                                      ? $this->plot_min_y : $this->x_axis_position;
02229             $this->x_axis_position = ($this->x_axis_position > $this->plot_max_y)
02230                                      ? $this->plot_max_y : $this->x_axis_position;
02231             $this->x_axis_y_pixels = $this->ytr($this->x_axis_position);
02232         } else {
02233             if ($this->yscale_type == 'log')
02234                 $this->x_axis_y_pixels = $this->ytr(1);
02235             else
02236                 // Default to axis at 0 or plot_min_y (should be 0 anyway, from SetPlotAreaWorld())
02237                 $this->x_axis_y_pixels = ($this->plot_min_y <= 0) && (0 <= $this->plot_max_y)
02238                                          ? $this->ytr(0) : $this->ytr($this->plot_min_y);
02239         }
02240 
02241     } // function CalcTranslation()
02242 
02243 
02248     function xtr($x_world)
02249     {
02250         //$x_pixels =  $this->x_left_margin + ($this->image_width - $this->x_tot_margin)*
02251         //      (($x_world - $this->plot_min_x) / ($this->plot_max_x - $this->plot_min_x)) ;
02252         //which with a little bit of math reduces to ...
02253         if ($this->xscale_type == 'log') {
02254             $x_pixels = $this->plot_origin_x + log10($x_world) * $this->xscale ;
02255         } else {
02256             $x_pixels = $this->plot_origin_x + $x_world * $this->xscale ;
02257         }
02258         return round($x_pixels);
02259     }
02260 
02261 
02266     function ytr($y_world)
02267     {
02268         if ($this->yscale_type == 'log') {
02269             //minus because GD defines y = 0 at top. doh!
02270             $y_pixels =  $this->plot_origin_y - log10($y_world) * $this->yscale ;
02271         } else {
02272             $y_pixels =  $this->plot_origin_y - $y_world * $this->yscale ;
02273         }
02274         return round($y_pixels);
02275     }
02276 
02282     function FormatLabel($which_pos, $which_lab)
02283     {
02284         switch ($which_pos) {
02285         case 'x':
02286         case 'plotx':
02287             switch ($this->x_label_type) {
02288             case 'title':
02289                 $lab = @ $this->data[$which_lab][0];
02290                 break;
02291             case 'data':
02292                 $lab = number_format($which_lab, $this->x_precision, '.', ',').$this->data_units_text;
02293                 break;
02294             case 'time':
02295                 $lab = strftime($this->x_time_format, $which_lab);
02296                 break;
02297             default:
02298                 // Unchanged from whatever format it is passed in
02299                 $lab = $which_lab;
02300             break;
02301             }
02302             break;
02303         case 'y':
02304         case 'ploty':
02305             switch ($this->y_label_type) {
02306             case 'data':
02307                 $lab = number_format($which_lab, $this->y_precision, '.', ',').$this->data_units_text;
02308                 break;
02309             case 'time':
02310                 $lab = strftime($this->y_time_format, $which_lab);
02311                 break;
02312             default:
02313                 // Unchanged from whatever format it is passed in
02314                 $lab = $which_lab;
02315                 break;
02316             }
02317             break;
02318         default:
02319             $this->PrintError("FormatLabel(): Unknown label type $which_type");
02320             return NULL;
02321         }
02322 
02323         return $lab;
02324     } //function FormatLabel
02325 
02326 
02327 
02331 
02335     function SetXTickIncrement($which_ti=NULL)
02336     {
02337         if ($which_ti) {
02338             $this->x_tick_inc = $which_ti;  //world coordinates
02339         } else {
02340             if (! isset($this->data_limits_done)) {
02341                 $this->FindDataLimits();  //Get maxima and minima for scaling
02342             }
02343             $this->x_tick_inc =  ($this->plot_max_x  - $this->plot_min_x  )/10;
02344         }
02345         $this->num_x_ticks = ''; //either use num_y_ticks or y_tick_inc, not both
02346         return TRUE;
02347     }
02348 
02352     function SetYTickIncrement($which_ti=NULL)
02353     {
02354         if ($which_ti) {
02355             $this->y_tick_inc = $which_ti;  //world coordinates
02356         } else {
02357             if (! isset($this->data_limits_done)) {
02358                 $this->FindDataLimits();  //Get maxima and minima for scaling
02359             }
02360             if (! isset($this->plot_max_y))
02361                 $this->SetPlotAreaWorld();
02362 
02363             $this->y_tick_inc =  ($this->plot_max_y  - $this->plot_min_y  )/10;
02364         }
02365         $this->num_y_ticks = ''; //either use num_y_ticks or y_tick_inc, not both
02366         return TRUE;
02367     }
02368 
02369 
02370     function SetNumXTicks($which_nt)
02371     {
02372         $this->num_x_ticks = $which_nt;
02373         $this->x_tick_inc = '';  //either use num_x_ticks or x_tick_inc, not both
02374         return TRUE;
02375     }
02376 
02377     function SetNumYTicks($which_nt)
02378     {
02379         $this->num_y_ticks = $which_nt;
02380         $this->y_tick_inc = '';  //either use num_y_ticks or y_tick_inc, not both
02381         return TRUE;
02382     }
02383 
02387     function SetYTickPos($which_tp)
02388     {
02389         $this->y_tick_pos = $this->CheckOption($which_tp, 'plotleft, plotright, both, yaxis, none', __FUNCTION__);
02390         return TRUE;
02391     }
02395     function SetXTickPos($which_tp)
02396     {
02397         $this->x_tick_pos = $this->CheckOption($which_tp, 'plotdown, plotup, both, xaxis, none', __FUNCTION__);
02398         return TRUE;
02399     }
02400 
02404     function SetSkipTopTick($skip)
02405     {
02406         $this->skip_top_tick = (bool)$skip;
02407         return TRUE;
02408     }
02409 
02413     function SetSkipBottomTick($skip)
02414     {
02415         $this->skip_bottom_tick = (bool)$skip;
02416         return TRUE;
02417     }
02418 
02422     function SetSkipLeftTick($skip)
02423     {
02424         $this->skip_left_tick = (bool)$skip;
02425         return TRUE;
02426     }
02427 
02431     function SetSkipRightTick($skip)
02432     {
02433         $this->skip_right_tick = (bool)$skip;
02434         return TRUE;
02435     }
02436 
02437     function SetXTickLength($which_xln)
02438     {
02439         $this->x_tick_length = $which_xln;
02440         return TRUE;
02441     }
02442 
02443     function SetYTickLength($which_yln)
02444     {
02445         $this->y_tick_length = $which_yln;
02446         return TRUE;
02447     }
02448 
02449     function SetXTickCrossing($which_xc)
02450     {
02451         $this->x_tick_cross = $which_xc;
02452         return TRUE;
02453     }
02454 
02455     function SetYTickCrossing($which_yc)
02456     {
02457         $this->y_tick_cross = $which_yc;
02458         return TRUE;
02459     }
02460 
02461 
02465 
02469     function DrawBackground()
02470     {
02471         // Don't draw this twice if drawing two plots on one image
02472         if (! $this->background_done) {
02473             if (isset($this->bgimg)) {    // If bgimg is defined, use it
02474                 $this->tile_img($this->bgimg, 0, 0, $this->image_width, $this->image_height, $this->bgmode);
02475             } else {                        // Else use solid color
02476                 ImageFilledRectangle($this->img, 0, 0, $this->image_width, $this->image_height,
02477                                      $this->ndx_bg_color);
02478             }
02479             $this->background_done = TRUE;
02480             return TRUE;        // Done
02481         }
02482         return FALSE;           // Nothing done
02483     }
02484 
02485 
02489     function DrawPlotAreaBackground()
02490     {
02491         if (isset($this->plotbgimg)) {
02492             $this->tile_img($this->plotbgimg, $this->plot_area[0], $this->plot_area[1],
02493                             $this->plot_area_width, $this->plot_area_height, $this->plotbgmode);
02494         }
02495         else {
02496             if ($this->draw_plot_area_background) {
02497                 ImageFilledRectangle($this->img, $this->plot_area[0], $this->plot_area[1],
02498                                      $this->plot_area[2], $this->plot_area[3], $this->ndx_plot_bg_color);
02499             }
02500         }
02501 
02502         return TRUE;
02503     }
02504 
02505 
02516     function tile_img($file, $xorig, $yorig, $width, $height, $mode)
02517     {
02518         $size = getimagesize($file);
02519         $input_format = $size[2];
02520 
02521         switch($input_format) {
02522         case 1:
02523             $im = @ imagecreatefromGIF ($file);
02524             if (! $im) {
02525                 $this->PrintError("tile_img:() Unable to open $file as a GIF.");
02526                 return FALSE;
02527             }
02528             break;
02529         case 2:
02530             $im = @ imagecreatefromJPEG ($file);
02531             if (! $im) {
02532                 $this->PrintError("tile_img(): Unable to open $file as a JPG.");
02533                 return FALSE;
02534             }
02535             break;
02536         case 3:
02537             $im = @ imagecreatefromPNG ($file);
02538             if (! $im) {
02539                 $this->PrintError("tile_img(): Unable to open $file as a PNG.");
02540                 return FALSE;
02541             }
02542             break;
02543         default:
02544             $this->PrintError('tile_img(): Please select a gif, jpg, or png image.');
02545             return FALSE;
02546             break;
02547         }
02548 
02549 
02550         if ($mode == 'scale') {
02551             imagecopyresized($this->img, $im, $xorig, $yorig, 0, 0, $width, $height, $size[0],$size[1]);
02552             return TRUE;
02553         } else if ($mode == 'centeredtile') {
02554             $x0 = - floor($size[0]/2);   // Make the tile look better
02555             $y0 = - floor($size[1]/2);
02556         } else if ($mode = 'tile') {
02557             $x0 = 0;
02558             $y0 = 0;
02559         }
02560 
02561         // Actually draw the tile
02562 
02563         // But first on a temporal image.
02564         $tmp = ImageCreate($width, $height);
02565         if (! $tmp)
02566             $this->PrintError('tile_img(): Could not create image resource.');
02567 
02568         for ($x = $x0; $x < $width; $x += $size[0])
02569             for ($y = $y0; $y < $height; $y += $size[1])
02570                 imagecopy($tmp, $im, $x, $y, 0, 0, $size[0], $size[1]);
02571 
02572         // Copy the temporal image onto the final one.
02573         imagecopy($this->img, $tmp, $xorig, $yorig, 0,0, $width, $height);
02574 
02575         // Free resources
02576         imagedestroy($tmp);
02577         imagedestroy($im);
02578 
02579         return TRUE;
02580     }  // function tile_img
02581 
02582 
02586     function DrawImageBorder()
02587     {
02588         switch ($this->image_border_type) {
02589         case 'raised':
02590             ImageLine($this->img, 0, 0, $this->image_width-1, 0, $this->ndx_i_border);
02591             ImageLine($this->img, 1, 1, $this->image_width-2, 1, $this->ndx_i_border);
02592             ImageLine($this->img, 0, 0, 0, $this->image_height-1, $this->ndx_i_border);
02593             ImageLine($this->img, 1, 1, 1, $this->image_height-2, $this->ndx_i_border);
02594             ImageLine($this->img, $this->image_width-1, 0, $this->image_width-1,
02595                       $this->image_height-1, $this->ndx_i_border_dark);
02596             ImageLine($this->img, 0, $this->image_height-1, $this->image_width-1,
02597                       $this->image_height-1, $this->ndx_i_border_dark);
02598             ImageLine($this->img, $this->image_width-2, 1, $this->image_width-2,
02599                       $this->image_height-2, $this->ndx_i_border_dark);
02600             ImageLine($this->img, 1, $this->image_height-2, $this->image_width-2,
02601                       $this->image_height-2, $this->ndx_i_border_dark);
02602             break;
02603         case 'plain':
02604             ImageLine($this->img, 0, 0, $this->image_width, 0, $this->ndx_i_border_dark);
02605             ImageLine($this->img, $this->image_width-1, 0, $this->image_width-1,
02606                       $this->image_height, $this->ndx_i_border_dark);
02607             ImageLine($this->img, $this->image_width-1, $this->image_height-1, 0, $this->image_height-1,
02608                       $this->ndx_i_border_dark);
02609             ImageLine($this->img, 0, 0, 0, $this->image_height, $this->ndx_i_border_dark);
02610             break;
02611         case 'none':
02612             break;
02613         default:
02614             $this->DrawError("DrawImageBorder(): unknown image_border_type: '$this->image_border_type'");
02615             return FALSE;
02616         }
02617         return TRUE;
02618     }
02619 
02620 
02624     function DrawTitle()
02625     {
02626         // Center of the plot area
02627         //$xpos = ($this->plot_area[0] + $this->plot_area_width )/ 2;
02628 
02629         // Center of the image:
02630         $xpos = $this->image_width / 2;
02631 
02632         // Place it at almost at the top
02633         $ypos = $this->safe_margin;
02634 
02635         $this->DrawText($this->title_font, $this->title_angle, $xpos, $ypos,
02636                         $this->ndx_title_color, $this->title_txt, 'center', 'bottom');
02637 
02638         return TRUE;
02639 
02640     }
02641 
02642 
02646     function DrawXTitle()
02647     {
02648         if ($this->x_title_pos == 'none')
02649             return;
02650 
02651         // Center of the plot
02652         $xpos = ($this->plot_area[2] + $this->plot_area[0]) / 2;
02653 
02654         // Upper title
02655         if ($this->x_title_pos == 'plotup' || $this->x_title_pos == 'both') {
02656             $ypos = $this->safe_margin + $this->title_height + $this->safe_margin;
02657             $this->DrawText($this->x_title_font, $this->x_title_angle,
02658                             $xpos, $ypos, $this->ndx_title_color, $this->x_title_txt, 'center');
02659         }
02660         // Lower title
02661         if ($this->x_title_pos == 'plotdown' || $this->x_title_pos == 'both') {
02662             $ypos = $this->image_height - $this->x_title_height - $this->safe_margin;
02663             $this->DrawText($this->x_title_font, $this->x_title_angle,
02664                             $xpos, $ypos, $this->ndx_title_color, $this->x_title_txt, 'center');
02665         }
02666         return TRUE;
02667     }
02668 
02672     function DrawYTitle()
02673     {
02674         if ($this->y_title_pos == 'none')
02675             return;
02676 
02677         // Center the title vertically to the plot
02678         $ypos = ($this->plot_area[3] + $this->plot_area[1]) / 2;
02679 
02680         if ($this->y_title_pos == 'plotleft' || $this->y_title_pos == 'both') {
02681             $xpos = $this->safe_margin;
02682             $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color,
02683                             $this->y_title_txt, 'left', 'center');
02684         }
02685         if ($this->y_title_pos == 'plotright' || $this->y_title_pos == 'both') {
02686             $xpos = $this->image_width - $this->safe_margin - $this->y_title_width - $this->safe_margin;
02687             $this->DrawText($this->y_title_font, 90, $xpos, $ypos, $this->ndx_title_color,
02688                             $this->y_title_txt, 'left', 'center');
02689         }
02690 
02691         return TRUE;
02692     }
02693 
02694 
02695     /*
02696      * \note Horizontal grid lines overwrite horizontal axis with y=0, so call this first, then DrawXAxis()
02697      */
02698     function DrawYAxis()
02699     {
02700         // Draw ticks, labels and grid, if any
02701         $this->DrawYTicks();
02702 
02703         // Draw Y axis at X = y_axis_x_pixels
02704         ImageLine($this->img, $this->y_axis_x_pixels, $this->plot_area[1],
02705                   $this->y_axis_x_pixels, $this->plot_area[3], $this->ndx_grid_color);
02706 
02707         return TRUE;
02708     }
02709 
02710     /*
02711      *
02712      */
02713     function DrawXAxis()
02714     {
02715         // Draw ticks, labels and grid
02716         $this->DrawXTicks();
02717 
02718         /* This tick and label tend to overlap with regular Y Axis labels,
02719          * as Mike Pullen pointed out.
02720          *
02721         //Draw Tick and Label for X axis
02722         if (! $this->skip_bottom_tick) {
02723             $ylab =$this->FormatLabel('y', $this->x_axis_position);
02724             $this->DrawYTick($ylab, $this->x_axis_y_pixels);
02725         }
02726         */
02727         //Draw X Axis at Y = x_axis_y_pixels
02728         ImageLine($this->img, $this->plot_area[0]+1, $this->x_axis_y_pixels,
02729                   $this->plot_area[2]-1, $this->x_axis_y_pixels, $this->ndx_grid_color);
02730 
02731         return TRUE;
02732     }
02733 
02738     function DrawYTick($which_ylab, $which_ypix)
02739     {
02740         // Ticks on Y axis
02741         if ($this->y_tick_pos == 'yaxis') {
02742             ImageLine($this->img, $this->y_axis_x_pixels - $this->y_tick_length, $which_ypix,
02743                       $this->y_axis_x_pixels + $this->y_tick_cross, $which_ypix,
02744                       $this->ndx_tick_color);
02745         }
02746 
02747         // Labels on Y axis
02748         if ($this->y_tick_label_pos == 'yaxis') {
02749             $this->DrawText($this->y_label_font, $this->y_label_angle,
02750                             $this->y_axis_x_pixels - $this->y_tick_length * 1.5, $which_ypix,
02751                             $this->ndx_text_color, $which_ylab, 'right', 'center');
02752         }
02753 
02754         // Ticks to the left of the Plot Area
02755         if (($this->y_tick_pos == 'plotleft') || ($this->y_tick_pos == 'both') ) {
02756             ImageLine($this->img, $this->plot_area[0] - $this->y_tick_length,
02757                       $which_ypix, $this->plot_area[0] + $this->y_tick_cross,
02758                       $which_ypix, $this->ndx_tick_color);
02759         }
02760 
02761         // Ticks to the right of the Plot Area
02762         if (($this->y_tick_pos == 'plotright') || ($this->y_tick_pos == 'both') ) {
02763             ImageLine($this->img, ($this->plot_area[2] + $this->y_tick_length),
02764                       $which_ypix, $this->plot_area[2] - $this->y_tick_cross,
02765                       $which_ypix, $this->ndx_tick_color);
02766         }
02767 
02768         // Labels to the left of the plot area
02769         if ($this->y_tick_label_pos == 'plotleft' || $this->y_tick_label_pos == 'both') {
02770             $this->DrawText($this->y_label_font, $this->y_label_angle,
02771                             $this->plot_area[0] - $this->y_tick_length * 1.5, $which_ypix,
02772                             $this->ndx_text_color, $which_ylab, 'right', 'center');
02773         }
02774         // Labels to the right of the plot area
02775         if ($this->y_tick_label_pos == 'plotright' || $this->y_tick_label_pos == 'both') {
02776             $this->DrawText($this->y_label_font, $this->y_label_angle,
02777                             $this->plot_area[2] + $this->y_tick_length * 1.5, $which_ypix,
02778                             $this->ndx_text_color, $which_ylab, 'left', 'center');
02779         }
02780    } // Function DrawYTick()
02781 
02782 
02789     function DrawYTicks()
02790     {
02791         // Sets the line style for IMG_COLOR_STYLED lines (grid)
02792         if ($this->dashed_grid) {
02793             $this->SetDashedStyle($this->ndx_light_grid_color);
02794             $style = IMG_COLOR_STYLED;
02795         } else {
02796             $style = $this->ndx_light_grid_color;
02797         }
02798 
02799         // maxy is always > miny so delta_y is always positive
02800         if ($this->y_tick_inc) {
02801             $delta_y = $this->y_tick_inc;
02802         } elseif ($this->num_y_ticks) {
02803             $delta_y = ($this->plot_max_y - $this->plot_min_y) / $this->num_y_ticks;
02804         } else {
02805             $delta_y = ($this->plot_max_y - $this->plot_min_y) / 10 ;
02806         }
02807 
02808         // NOTE: When working with floats, because of approximations when adding $delta_y,
02809         // $y_tmp never equals $y_end  at the for loop, so one spurious line would  get drawn where
02810         // not for the substraction to $y_end here.
02811         $y_tmp = (double)$this->plot_min_y;
02812         $y_end = (double)$this->plot_max_y - ($delta_y/2);
02813 
02814         if ($this->skip_bottom_tick)
02815             $y_tmp += $delta_y;
02816 
02817         if ($this->skip_top_tick)
02818             $y_end -= $delta_y;
02819 
02820         for (;$y_tmp < $y_end; $y_tmp += $delta_y) {
02821             $ylab = $this->FormatLabel('y', $y_tmp);
02822             $y_pixels = $this->ytr($y_tmp);
02823 
02824             // Horizontal grid line
02825             if ($this->draw_y_grid) {
02826                 ImageLine($this->img, $this->plot_area[0]+1, $y_pixels, $this->plot_area[2]-1, $y_pixels, $style);
02827             }
02828 
02829             // Draw ticks
02830             $this->DrawYTick($ylab, $y_pixels);
02831         }
02832         return TRUE;
02833     } // function DrawYTicks
02834 
02835 
02843     function DrawXTicks()
02844     {
02845         // Sets the line style for IMG_COLOR_STYLED lines (grid)
02846         if ($this->dashed_grid) {
02847             $this->SetDashedStyle($this->ndx_light_grid_color);
02848             $style = IMG_COLOR_STYLED;
02849         } else {
02850             $style = $this->ndx_light_grid_color;
02851         }
02852 
02853         // Calculate x increment between ticks
02854         if ($this->x_tick_inc) {
02855             $delta_x = $this->x_tick_inc;
02856         } elseif ($this->num_x_ticks) {
02857             $delta_x = ($this->plot_max_x - $this->plot_min_x) / $this->num_x_ticks;
02858         } else {
02859             $delta_x =($this->plot_max_x - $this->plot_min_x) / 10 ;
02860         }
02861 
02862         // NOTE: When working with decimals, because of approximations when adding $delta_x,
02863         // $x_tmp never equals $x_end  at the for loop, so one spurious line would  get drawn where
02864         // not for the substraction to $x_end here.
02865         $x_tmp = (double)$this->plot_min_x;
02866         $x_end = (double)$this->plot_max_x - ($delta_x/2);
02867 
02868         // Should the leftmost tick be drawn?
02869         if ($this->skip_left_tick)
02870             $x_tmp += $delta_x;
02871 
02872         // And the rightmost?
02873         if (! $this->skip_right_tick)
02874             $x_end += $delta_x;
02875 
02876         for (;$x_tmp < $x_end; $x_tmp += $delta_x) {
02877             $xlab = $this->FormatLabel('x', $x_tmp);
02878             $x_pixels = $this->xtr($x_tmp);
02879 
02880             // Vertical grid lines
02881             if ($this->draw_x_grid) {
02882                 ImageLine($this->img, $x_pixels, $this->plot_area[1], $x_pixels, $this->plot_area[3], $style);
02883             }
02884 
02885             // Tick on X Axis
02886             if ($this->x_tick_pos == 'xaxis') {
02887 
02888                 ImageLine($this->img, $x_pixels, $this->x_axis_y_pixels - $this->x_tick_cross,
02889                           $x_pixels, $this->x_axis_y_pixels + $this->x_tick_length, $this->ndx_tick_color);
02890             }
02891 
02892             // Label on X axis
02893             if ($this->x_tick_label_pos == 'xaxis') {
02894                  $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels,
02895                                 $this->x_axis_y_pixels + $this->x_tick_length*1.5, $this->ndx_text_color,
02896                                 $xlab, 'center', 'bottom');
02897             }
02898 
02899             // Top of the plot area tick
02900             if ($this->x_tick_pos == 'plotup' || $this->x_tick_pos == 'both') {
02901                 ImageLine($this->img, $x_pixels, $this->plot_area[1] - $this->x_tick_length,
02902                           $x_pixels, $this->plot_area[1] + $this->x_tick_cross, $this->ndx_tick_color);
02903             }
02904             // Bottom of the plot area tick
02905             if ($this->x_tick_pos == 'plotdown' || $this->x_tick_pos == 'both') {
02906                 ImageLine($this->img, $x_pixels, $this->plot_area[3] + $this->x_tick_length,
02907                           $x_pixels, $this->plot_area[3] - $this->x_tick_cross, $this->ndx_tick_color);
02908             }
02909 
02910             // Top of the plot area tick label
02911             if ($this->x_tick_label_pos == 'plotup' || $this->x_tick_label_pos == 'both') {
02912                 $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels,
02913                                 $this->plot_area[1] - $this->x_tick_length*1.5, $this->ndx_text_color,
02914                                 $xlab, 'center', 'top');
02915             }
02916 
02917             // Bottom of the plot area tick label
02918             if ($this->x_tick_label_pos == 'plotdown' || $this->x_tick_label_pos == 'both') {
02919                 $this->DrawText($this->x_label_font, $this->x_label_angle, $x_pixels,
02920                                 $this->plot_area[3] + $this->x_tick_length*1.5, $this->ndx_text_color,
02921                                 $xlab, 'center', 'bottom');
02922             }
02923         }
02924         return;
02925     } // function DrawXTicks
02926 
02927 
02931     function DrawPlotBorder()
02932     {
02933         switch ($this->plot_border_type) {
02934         case 'left':    // for past compatibility
02935         case 'plotleft':
02936             ImageLine($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y),
02937                       $this->plot_area[0], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
02938             break;
02939         case 'right':
02940         case 'plotright':
02941             ImageLine($this->img, $this->plot_area[2], $this->ytr($this->plot_min_y),
02942                       $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
02943             break;
02944         case 'both':
02945         case 'sides':
02946              ImageLine($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y),
02947                       $this->plot_area[0], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
02948             ImageLine($this->img, $this->plot_area[2], $this->ytr($this->plot_min_y),
02949                       $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
02950             break;
02951         case 'none':
02952             //Draw No Border
02953             break;
02954         case 'full':
02955         default:
02956             ImageRectangle($this->img, $this->plot_area[0], $this->ytr($this->plot_min_y),
02957                            $this->plot_area[2], $this->ytr($this->plot_max_y), $this->ndx_grid_color);
02958             break;
02959         }
02960         return TRUE;
02961     }
02962 
02963 
02972     function DrawXDataLabel($xlab, $xpos, $row=FALSE)
02973     {
02974         // FIXME!! not working...
02975         if (($this->_x_label_cnt++ % $this->x_label_inc) != 0)
02976             return;
02977 
02978         $xlab = $this->FormatLabel('x', $xlab);
02979 
02980         // Labels below the plot area
02981         if ($this->x_data_label_pos == 'plotdown' || $this->x_data_label_pos == 'both')
02982             $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos,
02983                             $this->plot_area[3] + $this->x_tick_length,
02984                             $this->ndx_text_color, $xlab, 'center', 'bottom');
02985 
02986         // Labels above the plot area
02987         if ($this->x_data_label_pos == 'plotup' || $this->x_data_label_pos == 'both')
02988             $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos,
02989                             $this->plot_area[1] - $this->x_tick_length ,
02990                             $this->ndx_text_color, $xlab, 'center', 'top');
02991 
02992         if ($row && $this->draw_x_data_label_lines)
02993             $this->DrawXDataLine($xpos, $row);
02994     }
02995 
03004     function DrawXDataLine($xpos, $row)
03005     {
03006         // Sets the line style for IMG_COLOR_STYLED lines (grid)
03007         if($this->dashed_grid) {
03008             $this->SetDashedStyle($this->ndx_light_grid_color);
03009             $style = IMG_COLOR_STYLED;
03010         } else {
03011             $style = $this->ndx_light_grid_color;
03012         }
03013 
03014         // Lines from the bottom up
03015         if ($this->x_data_label_pos == 'both') {
03016             ImageLine($this->img, $xpos, $this->plot_area[3], $xpos, $this->plot_area[1], $style);
03017         }
03018         // Lines coming from the bottom of the plot
03019         else if ($this->x_data_label_pos == 'plotdown') {
03020             // See FindDataLimits() to see why 'MAXY' index.
03021             $ypos = $this->ytr($this->data[$row][MAXY]);
03022             ImageLine($this->img, $xpos, $ypos, $xpos, $this->plot_area[3], $style);
03023         }
03024         // Lines coming from the top of the plot
03025         else if ($this->x_data_label_pos == 'plotup') {
03026             // See FindDataLimits() to see why 'MINY' index.
03027             $ypos = $this->ytr($this->data[$row][MINY]);
03028             ImageLine($this->img, $xpos, $this->plot_area[1], $xpos, $ypos, $style);
03029         }
03030     }
03031 
03032 /*
03033     function DrawPlotLabel($xlab, $xpos, $ypos)
03034     {
03035         $this->DrawText($this->x_label_font, $this->x_label_angle, $xpos, $this
03036 */
03037 
03045     function DrawLegend($which_x1, $which_y1, $which_boxtype)
03046     {
03047         // Find maximum legend label length
03048         $max_len = 0;
03049         foreach ($this->legend as $leg) {
03050             $len = strlen($leg);
03051             $max_len = ($len > $max_len) ? $len : $max_len;
03052         }
03053         $max_len += 5;          // Leave room for the boxes and margins
03054 
03056         // TTF:
03057         if ($this->use_ttf) {
03058             $size = $this->TTFBBoxSize($this->legend_font['size'], 0,
03059                                        $this->legend_font['font'], '_');
03060             $char_w = $size[0];
03061 
03062             $size = $this->TTFBBoxSize($this->legend_font['size'], 0,
03063                                        $this->legend_font['font'], '|');
03064             $char_h = $size[1];
03065         }
03066         // Fixed fonts:
03067         else {
03068             $char_w = $this->legend_font['width'];
03069             $char_h = $this->legend_font['height'];
03070         }
03071 
03072         $v_margin = $char_h/2;                         // Between vertical borders and labels
03073         $dot_height = $char_h + $this->line_spacing;   // Height of the small colored boxes
03074         $width = $char_w * $max_len;
03075 
03077         // upper Left
03078         if ( (! $which_x1) || (! $which_y1) ) {
03079             $box_start_x = $this->plot_area[2] - $width;
03080             $box_start_y = $this->plot_area[1] + 5;
03081         } else {
03082             $box_start_x = $which_x1;
03083             $box_start_y = $which_y1;
03084         }
03085 
03086         // Lower right corner
03087         $box_end_y = $box_start_y + $dot_height*(count($this->legend)) + 2*$v_margin;
03088         $box_end_x = $box_start_x + $width - 5;
03089 
03090 
03091         // Draw outer box
03092         ImageFilledRectangle($this->img, $box_start_x, $box_start_y, $box_end_x, $box_end_y, $this->ndx_bg_color);
03093         ImageRectangle($this->img, $box_start_x, $box_start_y, $box_end_x, $box_end_y, $this->ndx_grid_color);
03094 
03095         $color_index = 0;
03096         $max_color_index = count($this->ndx_data_colors) - 1;
03097 
03098         $dot_left_x = $box_end_x - $char_w * 2;
03099         $dot_right_x = $box_end_x - $char_w;
03100         $y_pos = $box_start_y + $v_margin;
03101 
03102         foreach ($this->legend as $leg) {
03103             // Text right aligned to the little box
03104             $this->DrawText($this->legend_font, 0, $dot_left_x - $char_w, $y_pos,
03105                             $this->ndx_text_color, $leg, 'right');
03106             // Draw a box in the data color
03107             ImageFilledRectangle($this->img, $dot_left_x, $y_pos + 1, $dot_right_x,
03108                                  $y_pos + $dot_height-1, $this->ndx_data_colors[$color_index]);
03109             // Draw a rectangle around the box
03110             ImageRectangle($this->img, $dot_left_x, $y_pos + 1, $dot_right_x,
03111                            $y_pos + $dot_height-1, $this->ndx_text_color);
03112 
03113             $y_pos += $char_h + $this->line_spacing;
03114 
03115             $color_index++;
03116             if ($color_index > $max_color_index)
03117                 $color_index = 0;
03118         }
03119     } // Function DrawLegend()
03120 
03121 
03125     function DrawAxisLegend()
03126     {
03127         // Calculate available room
03128         // Calculate length of all items (boxes included)
03129         // Calculate number of lines and room it would take. FIXME: this should be known in CalcMargins()
03130         // Draw.
03131     }
03132 
03136 
03137 
03148     function DrawPieChart()
03149     {
03150         $xpos = $this->plot_area[0] + $this->plot_area_width/2;
03151         $ypos = $this->plot_area[1] + $this->plot_area_height/2;
03152         $diameter = min($this->plot_area_width, $this->plot_area_height);
03153         $radius = $diameter/2;
03154 
03155         // Get sum of each column? One pie slice per column
03156         if ($this->data_type === 'text-data') {
03157             for ($i = 0; $i < $this->num_data_rows; $i++) {
03158                 for ($j = 1; $j < $this->num_recs[$i]; $j++) {      // Label ($row[0]) unused in these pie charts
03159                     @ $sumarr[$j] += abs($this->data[$i][$j]);      // NOTE!  sum > 0 to make pie charts
03160                 }
03161             }
03162         }
03163         // Or only one column per row, one pie slice per row?
03164         else if ($this->data_type == 'text-data-single') {
03165             for ($i = 0; $i < $this->num_data_rows; $i++) {
03166                 $legend[$i] = $this->data[$i][0];                   // Set the legend to column labels
03167                 $sumarr[$i] = $this->data[$i][1];
03168             }
03169         }
03170         else if ($this->data_type == 'data-data') {
03171             for ($i = 0; $i < $this->num_data_rows; $i++) {
03172                 for ($j = 2; $j < $this->num_recs[$i]; $j++) {
03173                     @ $sumarr[$j] += abs($this->data[$i][$j]);
03174                 }
03175             }
03176         }
03177         else {
03178             $this->DrawError("DrawPieChart(): Data type '$this->data_type' not supported.");
03179             return FALSE;
03180         }
03181 
03182         $total = array_sum($sumarr);
03183 
03184         if ($total == 0) {
03185             $this->DrawError('DrawPieChart(): Empty data set');
03186             return FALSE;
03187         }
03188 
03189         if ($this->shading) {
03190             $diam2 = $diameter / 2;
03191         } else {
03192             $diam2 = $diameter;
03193         }
03194         $max_data_colors = count ($this->data_colors);
03195 
03196         for ($h = $this->shading; $h >= 0; $h--) {
03197             $color_index = 0;
03198             $start_angle = 0;
03199             $end_angle = 0;
03200             foreach ($sumarr as $val) {
03201                 // For shaded pies: the last one (at the top of the "stack") has a brighter color:
03202                 if ($h == 0)
03203                     $slicecol = $this->ndx_data_colors[$color_index];
03204                 else
03205                     $slicecol = $this->ndx_data_dark_colors[$color_index];
03206 
03207                 $label_txt = number_format(($val / $total * 100), $this->y_precision, '.', ', ') . '%';
03208                 $val = 360 * ($val / $total);
03209 
03210                 // NOTE that imagefilledarc measures angles CLOCKWISE (go figure why),
03211                 // so the pie chart would start clockwise from 3 o'clock, would it not be
03212                 // for the reversal of start and end angles in imagefilledarc()
03213                 $start_angle = $end_angle;
03214                 $end_angle += $val;
03215                 $mid_angle = deg2rad($end_angle - ($val / 2));
03216 
03217                 // Draw the slice
03218                 ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2,
03219                                360-$end_angle, 360-$start_angle,
03220                                $slicecol, IMG_ARC_PIE);
03221 
03222                 // Draw the labels only once
03223                 if ($h == 0) {
03224                     // Draw the outline
03225                     if (! $this->shading)
03226                         ImageFilledArc($this->img, $xpos, $ypos+$h, $diameter, $diam2,
03227                                        360-$end_angle, 360-$start_angle,
03228                                        $this->ndx_grid_color, IMG_ARC_PIE | IMG_ARC_EDGED |IMG_ARC_NOFILL);
03229 
03230 
03231                     // The '* 1.2' trick is to get labels out of the pie chart so there are more
03232                     // chances they can be seen in small sectors.
03233                     $label_x = $xpos + ($diameter * 1.2 * cos($mid_angle)) * $this->label_scale_position;
03234                     $label_y = $ypos+$h - ($diam2 * 1.2 * sin($mid_angle)) * $this->label_scale_position;
03235 
03236                     $this->DrawText($this->generic_font, 0, $label_x, $label_y, $this->ndx_grid_color,
03237                                     $label_txt, 'center', 'center');
03238                 }
03239                 $color_index++;
03240                 $color_index = $color_index % $max_data_colors;
03241             }   // end for
03242         }   // end for
03243     }
03244 
03245 
03250     function DrawDotsError()
03251     {
03252         $this->CheckOption($this->data_type, 'data-data-error', __FUNCTION__);
03253 
03254         for($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
03255             $record = 1;                                // Skip record #0 (title)
03256 
03257             // Do we have a value for X?
03258             if ($this->data_type == 'data-data-error')
03259                 $x_now = $this->data[$row][$record++];  // Read it, advance record index
03260             else
03261                 $x_now = 0.5 + $cnt++;                  // Place text-data at X = 0.5, 1.5, 2.5, etc...
03262 
03263             // Draw X Data labels?
03264             if ($this->x_data_label_pos != 'none')
03265                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
03266 
03267             while ($record < $this->num_recs[$row]) {
03268                     // Y:
03269                     $y_now = $this->data[$row][$record];
03270                     $this->DrawDot($x_now, $y_now, $record, $this->ndx_data_colors[$record++]);
03271 
03272                     // Error +
03273                     $val = $this->data[$row][$record];
03274                     $this->DrawYErrorBar($x_now, $y_now, $val, $this->error_bar_shape,
03275                                          $this->ndx_error_bar_colors[$record++]);
03276                     // Error -
03277                     $val = $this->data[$row][$record];
03278                     $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape,
03279                                          $this->ndx_error_bar_colors[$record++]);
03280             }
03281         }
03282     } // function DrawDotsError()
03283 
03284 
03285     /*
03286      * Supported data types:
03287      *  - data-data ("title", x, y1, y2, y3, ...)
03288      *  - text-data ("title", y1, y2, y3, ...)
03289      */
03290     function DrawDots()
03291     {
03292         $this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__);
03293 
03294         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
03295             $rec = 1;                    // Skip record #0 (data label)
03296 
03297             // Do we have a value for X?
03298             if ($this->data_type == 'data-data')
03299                 $x_now = $this->data[$row][$rec++];  // Read it, advance record index
03300             else
03301                 $x_now = 0.5 + $cnt++;       // Place text-data at X = 0.5, 1.5, 2.5, etc...
03302 
03303             $x_now_pixels = $this->xtr($x_now);
03304 
03305             // Draw X Data labels?
03306             if ($this->x_data_label_pos != 'none')
03307                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
03308 
03309             // Proceed with Y values
03310             for($idx = 0;$rec < $this->num_recs[$row]; $rec++, $idx++) {
03311                 if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data
03312                     $this->DrawDot($x_now, $this->data[$row][$rec],
03313                                    $rec, $this->ndx_data_colors[$idx]);
03314                 }
03315             }
03316         }
03317     } //function DrawDots
03318 
03319 
03323     function DrawThinBarLines()
03324     {
03325         $this->CheckOption($this->data_type, 'text-data, data-data', __FUNCTION__);
03326 
03327         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
03328             $rec = 1;                    // Skip record #0 (data label)
03329 
03330             // Do we have a value for X?
03331             if ($this->data_type == 'data-data')
03332                 $x_now = $this->data[$row][$rec++];  // Read it, advance record index
03333             else
03334                 $x_now = 0.5 + $cnt++;       // Place text-data at X = 0.5, 1.5, 2.5, etc...
03335 
03336             $x_now_pixels = $this->xtr($x_now);
03337 
03338             // Draw X Data labels?
03339             if ($this->x_data_label_pos != 'none')
03340                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
03341 
03342             // Proceed with Y values
03343             for($idx = 0;$rec < $this->num_recs[$row]; $rec++, $idx++) {
03344                 if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data
03345                     ImageSetThickness($this->img, $this->line_widths[$idx]);
03346                     // Draws a line from user defined x axis position up to ytr($val)
03347                     ImageLine($this->img, $x_now_pixels, $this->x_axis_y_pixels, $x_now_pixels,
03348                               $this->ytr($this->data[$row][$rec]), $this->ndx_data_colors[$idx]);
03349                 }
03350             }
03351         }
03352 
03353         ImageSetThickness($this->img, 1);
03354     }  //function DrawThinBarLines
03355 
03359     function DrawYErrorBar($x_world, $y_world, $error_height, $error_bar_type, $color)
03360     {
03361         /*
03362         // TODO: add a parameter to show datalabels next to error bars?
03363         // something like this:
03364         if ($this->x_data_label_pos == 'plot') {
03365             $this->DrawText($this->error_font, 90, $x1, $y2,
03366                             $color, $label, 'center', 'top');
03367         */
03368 
03369         $x1 = $this->xtr($x_world);
03370         $y1 = $this->ytr($y_world);
03371         $y2 = $this->ytr($y_world+$error_height) ;
03372 
03373         ImageSetThickness($this->img, $this->error_bar_line_width);
03374         ImageLine($this->img, $x1, $y1 , $x1, $y2, $color);
03375 
03376         switch ($error_bar_type) {
03377         case 'line':
03378             break;
03379         case 'tee':
03380             ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color);
03381             break;
03382         default:
03383             ImageLine($this->img, $x1-$this->error_bar_size, $y2, $x1+$this->error_bar_size, $y2, $color);
03384             break;
03385         }
03386 
03387         ImageSetThickness($this->img, 1);
03388         return TRUE;
03389     }
03390 
03396     function DrawDot($x_world, $y_world, $record, $color)
03397     {
03398         // TODO: optimize, avoid counting every time we are called.
03399         $record = $record % count ($this->point_shapes);
03400 
03401         $half_point = $this->point_sizes[$record] / 2;
03402 
03403         $x_mid = $this->xtr($x_world);
03404         $y_mid = $this->ytr($y_world);
03405 
03406         $x1 = $x_mid - $half_point;
03407         $x2 = $x_mid + $half_point;
03408         $y1 = $y_mid - $half_point;
03409         $y2 = $y_mid + $half_point;
03410 
03411         switch ($this->point_shapes[$record]) {
03412         case 'halfline':
03413             ImageLine($this->img, $x1, $y_mid, $x_mid, $y_mid, $color);
03414             break;
03415         case 'line':
03416             ImageLine($this->img, $x1, $y_mid, $x2, $y_mid, $color);
03417             break;
03418         case 'plus':
03419             ImageLine($this->img, $x1, $y_mid, $x2, $y_mid, $color);
03420             ImageLine($this->img, $x_mid, $y1, $x_mid, $y2, $color);
03421             break;
03422         case 'cross':
03423             ImageLine($this->img, $x1, $y1, $x2, $y2, $color);
03424             ImageLine($this->img, $x1, $y2, $x2, $y1, $color);
03425             break;
03426         case 'rect':
03427             ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color);
03428             break;
03429         case 'circle':
03430             ImageArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record], $this->point_sizes[$record], 0, 360, $color);
03431             break;
03432         case 'dot':
03433             ImageFilledArc($this->img, $x_mid, $y_mid, $this->point_sizes[$record], $this->point_sizes[$record], 0, 360,
03434                            $color, IMG_ARC_PIE);
03435             break;
03436         case 'diamond':
03437             $arrpoints = array( $x1, $y_mid, $x_mid, $y1, $x2, $y_mid, $x_mid, $y2);
03438             ImageFilledPolygon($this->img, $arrpoints, 4, $color);
03439             break;
03440         case 'triangle':
03441             $arrpoints = array( $x1, $y_mid, $x2, $y_mid, $x_mid, $y2);
03442             ImageFilledPolygon($this->img, $arrpoints, 3, $color);
03443             break;
03444         case 'trianglemid':
03445             $arrpoints = array( $x1, $y1, $x2, $y1, $x_mid, $y_mid);
03446             ImageFilledPolygon($this->img, $arrpoints, 3, $color);
03447             break;
03448         default:
03449             ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $color);
03450             break;
03451         }
03452         return TRUE;
03453     }
03454 
03466     function DrawArea()
03467     {
03468         $incomplete_data_defaults_to_x_axis = FALSE;        // TODO: make this configurable
03469 
03470         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
03471             $rec = 1;                                       // Skip record #0 (data label)
03472 
03473             if ($this->data_type == 'data-data')            // Do we have a value for X?
03474                 $x_now = $this->data[$row][$rec++];         // Read it, advance record index
03475             else
03476                 $x_now = 0.5 + $cnt++;                      // Place text-data at X = 0.5, 1.5, 2.5, etc...
03477 
03478             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates
03479 
03480 
03481             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
03482                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
03483 
03484             // Proceed with Y values
03485             // Create array of points for imagefilledpolygon()
03486             for($idx = 0; $rec < $this->num_recs[$row]; $rec++, $idx++) {
03487                 if (is_numeric($this->data[$row][$rec])) {              // Allow for missing Y data
03488                     $y_now_pixels = $this->ytr($this->data[$row][$rec]);
03489 
03490                     $posarr[$idx][] = $x_now_pixels;
03491                     $posarr[$idx][] = $y_now_pixels;
03492 
03493                     $num_points[$idx] = isset($num_points[$idx]) ? $num_points[$idx]+1 : 1;
03494                 }
03495                 // If there's missing data...
03496                 else {
03497                     if (isset ($incomplete_data_defaults_to_x_axis)) {
03498                         $posarr[$idx][] = $x_now_pixels;
03499                         $posarr[$idx][] = $this->x_axis_y_pixels;
03500                         $num_points[$idx] = isset($num_points[$idx]) ? $num_points[$idx]+1 : 1;
03501                     }
03502                 }
03503             }
03504         }   // end for
03505 
03506         $end = count($posarr);
03507         for ($i = 0; $i < $end; $i++) {
03508             // Prepend initial points. X = first point's X, Y = x_axis_y_pixels
03509             $x = $posarr[$i][0];
03510             array_unshift($posarr[$i], $x, $this->x_axis_y_pixels);
03511 
03512             // Append final points. X = last point's X, Y = x_axis_y_pixels
03513             $x = $posarr[$i][count($posarr[$i])-2];
03514             array_push($posarr[$i], $x, $this->x_axis_y_pixels);
03515 
03516             $num_points[$i] += 2;
03517 
03518             // Draw the poligon
03519             ImageFilledPolygon($this->img, $posarr[$i], $num_points[$i], $this->ndx_data_colors[$i]);
03520         }
03521 
03522     } // function DrawArea()
03523 
03524 
03531     function DrawLines()
03532     {
03533         // This will tell us if lines have already begun to be drawn.
03534         // It is an array to keep separate information for every line, with a single
03535         // variable we would sometimes get "undefined offset" errors and no plot...
03536         $start_lines = array_fill(0, $this->records_per_group, FALSE);
03537 
03538         if ($this->data_type == 'text-data') {
03539             $lastx[0] = $this->xtr(0);
03540             $lasty[0] = $this->xtr(0);
03541         }
03542 
03543         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
03544             $record = 1;                                    // Skip record #0 (data label)
03545 
03546             if ($this->data_type == 'data-data')            // Do we have a value for X?
03547                 $x_now = $this->data[$row][$record++];      // Read it, advance record index
03548             else
03549                 $x_now = 0.5 + $cnt++;                      // Place text-data at X = 0.5, 1.5, 2.5, etc...
03550 
03551             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates
03552 
03553             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
03554                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
03555 
03556             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
03557                 if (is_numeric($this->data[$row][$record])) {           //Allow for missing Y data
03558                     $y_now_pixels = $this->ytr($this->data[$row][$record]);
03559 
03560                     if ($start_lines[$idx] == TRUE) {
03561                         // Set line width, revert it to normal at the end
03562                         ImageSetThickness($this->img, $this->line_widths[$idx]);
03563 
03564                         if ($this->line_styles[$idx] == 'dashed') {
03565                             $this->SetDashedStyle($this->ndx_data_colors[$idx]);
03566                             ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
03567                                       IMG_COLOR_STYLED);
03568                         } else {
03569                             ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
03570                                       $this->ndx_data_colors[$idx]);
03571                         }
03572 
03573                     }
03574                     $lasty[$idx] = $y_now_pixels;
03575                     $lastx[$idx] = $x_now_pixels;
03576                     $start_lines[$idx] = TRUE;
03577                 }
03578                 // Y data missing... should we leave a blank or not?
03579                 else if ($this->draw_broken_lines) {
03580                     $start_lines[$idx] = FALSE;
03581                 }
03582             }   // end for
03583         }   // end for
03584 
03585         ImageSetThickness($this->img, 1);       // Revert to original state for lines to be drawn later.
03586     } // function DrawLines()
03587 
03588 
03593     function DrawLinesError()
03594     {
03595         if ($this->data_type != 'data-data-error') {
03596             $this->DrawError("DrawLinesError(): Data type '$this->data_type' not supported.");
03597             return FALSE;
03598         }
03599 
03600         $start_lines = array_fill(0, $this->records_per_group, FALSE);
03601 
03602         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
03603             $record = 1;                                    // Skip record #0 (data label)
03604 
03605             $x_now = $this->data[$row][$record++];          // Read X value, advance record index
03606 
03607             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates.
03608 
03609 
03610             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
03611                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels, $row);
03612 
03613             // Now go for Y, E+, E-
03614             for ($idx = 0; $record < $this->num_recs[$row]; $idx++) {
03615                 // Y
03616                 $y_now = $this->data[$row][$record++];
03617                 $y_now_pixels = $this->ytr($y_now);
03618 
03619                 if ($start_lines[$idx] == TRUE) {
03620                     ImageSetThickness($this->img, $this->line_widths[$idx]);
03621 
03622                     if ($this->line_styles[$idx] == 'dashed') {
03623                         $this->SetDashedStyle($this->ndx_data_colors[$idx]);
03624                         ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
03625                                   IMG_COLOR_STYLED);
03626                     } else {
03627                         ImageLine($this->img, $x_now_pixels, $y_now_pixels, $lastx[$idx], $lasty[$idx],
03628                                   $this->ndx_data_colors[$idx]);
03629                     }
03630                 }
03631 
03632                 // Error+
03633                 $val = $this->data[$row][$record++];
03634                 $this->DrawYErrorBar($x_now, $y_now, $val, $this->error_bar_shape,
03635                                      $this->ndx_error_bar_colors[$idx]);
03636 
03637                 // Error-
03638                 $val = $this->data[$row][$record++];
03639                 $this->DrawYErrorBar($x_now, $y_now, -$val, $this->error_bar_shape,
03640                                      $this->ndx_error_bar_colors[$idx]);
03641 
03642                 // Update indexes:
03643                 $start_lines[$idx] = TRUE;   // Tells us if we already drew the first column of points,
03644                                              // thus having $lastx and $lasty ready for the next column.
03645                 $lastx[$idx] = $x_now_pixels;
03646                 $lasty[$idx] = $y_now_pixels;
03647             }   // end while
03648         }   // end for
03649 
03650         ImageSetThickness($this->img, 1);   // Revert to original state for lines to be drawn later.
03651     }   // function DrawLinesError()
03652 
03653 
03654 
03658     function DrawSquared()
03659     {
03660         // This will tell us if lines have already begun to be drawn.
03661         // It is an array to keep separate information for every line, for with a single
03662         // variable we could sometimes get "undefined offset" errors and no plot...
03663         $start_lines = array_fill(0, $this->records_per_group, FALSE);
03664 
03665         if ($this->data_type == 'text-data') {
03666             $lastx[0] = $this->xtr(0);
03667             $lasty[0] = $this->xtr(0);
03668         }
03669 
03670         for ($row = 0, $cnt = 0; $row < $this->num_data_rows; $row++) {
03671             $record = 1;                                    // Skip record #0 (data label)
03672 
03673             if ($this->data_type == 'data-data')            // Do we have a value for X?
03674                 $x_now = $this->data[$row][$record++];      // Read it, advance record index
03675             else
03676                 $x_now = 0.5 + $cnt++;                      // Place text-data at X = 0.5, 1.5, 2.5, etc...
03677 
03678             $x_now_pixels = $this->xtr($x_now);             // Absolute coordinates
03679 
03680             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
03681                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels); // notice there is no last param.
03682 
03683             // Draw Lines
03684             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
03685                 if (is_numeric($this->data[$row][$record])) {               // Allow for missing Y data
03686                     $y_now_pixels = $this->ytr($this->data[$row][$record]);
03687 
03688                     if ($start_lines[$idx] == TRUE) {
03689                         // Set line width, revert it to normal at the end
03690                         ImageSetThickness($this->img, $this->line_widths[$idx]);
03691 
03692                         if ($this->line_styles[$idx] == 'dashed') {
03693                             $this->SetDashedStyle($this->ndx_data_colors[$idx]);
03694                             ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx],
03695                                       IMG_COLOR_STYLED);
03696                             ImageLine($this->img, $x_now_pixels, $lasty[$idx], $x_now_pixels, $y_now_pixels,
03697                                       IMG_COLOR_STYLED);
03698                         } else {
03699                             ImageLine($this->img, $lastx[$idx], $lasty[$idx], $x_now_pixels, $lasty[$idx],
03700                                       $this->ndx_data_colors[$idx]);
03701                             ImageLine($this->img, $x_now_pixels, $lasty[$idx], $x_now_pixels, $y_now_pixels,
03702                                       $this->ndx_data_colors[$idx]);
03703                         }
03704                     }
03705                     $lastx[$idx] = $x_now_pixels;
03706                     $lasty[$idx] = $y_now_pixels;
03707                     $start_lines[$idx] = TRUE;
03708                 }
03709                 // Y data missing... should we leave a blank or not?
03710                 else if ($this->draw_broken_lines) {
03711                     $start_lines[$idx] = FALSE;
03712                 }
03713             }
03714         }   // end while
03715 
03716         ImageSetThickness($this->img, 1);
03717     } // function DrawSquared()
03718 
03719 
03723     function DrawBars()
03724     {
03725         if ($this->data_type != 'text-data') {
03726             $this->DrawError('DrawBars(): Bar plots must be text-data: use function SetDataType("text-data")');
03727             return FALSE;
03728         }
03729 
03730         for ($row = 0; $row < $this->num_data_rows; $row++) {
03731             $record = 1;                                    // Skip record #0 (data label)
03732 
03733             $x_now_pixels = $this->xtr(0.5 + $row);         // Place text-data at X = 0.5, 1.5, 2.5, etc...
03734 
03735             if ($this->x_data_label_pos != 'none')          // Draw X Data labels? TODO:labels on top of bars.
03736                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
03737 
03738             // Draw the bar
03739             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
03740                 if (is_numeric($this->data[$row][$record])) {       // Allow for missing Y data
03741                     $x1 = $x_now_pixels - $this->data_group_space + ($idx * $this->record_bar_width);
03742                     $x2 = $x1 + ($this->bar_width_adjust * $this->record_bar_width);
03743 
03744                     if ($this->data[$row][$record] < $this->x_axis_position) {
03745                         $y1 = $this->x_axis_y_pixels;
03746                         $y2 = $this->ytr($this->data[$row][$record]);
03747                     } else {
03748                         $y1 = $this->ytr($this->data[$row][$record]);
03749                         $y2 = $this->x_axis_y_pixels;
03750                     }
03751 
03752                     if ($this->shading) {                           // Draw the shade?
03753                         ImageFilledPolygon($this->img, array($x1, $y1,
03754                                                        $x1 + $this->shading, $y1 - $this->shading,
03755                                                        $x2 + $this->shading, $y1 - $this->shading,
03756                                                        $x2 + $this->shading, $y2 - $this->shading,
03757                                                        $x2, $y2,
03758                                                        $x2, $y1),
03759                                            6, $this->ndx_data_dark_colors[$idx]);
03760                     }
03761                     // Or draw a border?
03762                     else {
03763                         ImageRectangle($this->img, $x1, $y1, $x2,$y2, $this->ndx_data_border_colors[$idx]);
03764                     }
03765                     // Draw the bar
03766                     ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]);
03767                 }
03768             }   // end for
03769         }   // end for
03770     } //function DrawBars
03771 
03772 
03777     function DrawStackedBars()
03778     {
03779         if ($this->data_type != 'text-data') {
03780             $this->DrawError('DrawStackedBars(): Bar plots must be text-data: use SetDataType("text-data")');
03781             return FALSE;
03782         }
03783 
03784         for ($row = 0; $row < $this->num_data_rows; $row++) {
03785             $record = 1;                                    // Skip record #0 (data label)
03786 
03787             $x_now_pixels = $this->xtr(0.5 + $row);         // Place text-data at X = 0.5, 1.5, 2.5, etc...
03788 
03789             if ($this->x_data_label_pos != 'none')          // Draw X Data labels?
03790                 $this->DrawXDataLabel($this->data[$row][0], $x_now_pixels);
03791 
03792             // Draw the bars
03793             $oldv = 0;
03794             for ($idx = 0; $record < $this->num_recs[$row]; $record++, $idx++) {
03795                 if (is_numeric($this->data[$row][$record])) {       // Allow for missing Y data
03796                     $x1 = $x_now_pixels - $this->data_group_space;
03797                     $x2 = $x_now_pixels + $this->data_group_space;
03798 
03799                     $y1 = $this->ytr(abs($this->data[$row][$record]) + $oldv);
03800                     $y2 = $this->ytr($this->x_axis_position + $oldv);
03801                     $oldv += abs($this->data[$row][$record]);
03802 
03803                     if ($this->shading) {                           // Draw the shade?
03804                         ImageFilledPolygon($this->img, array($x1, $y1,
03805                                                        $x1 + $this->shading, $y1 - $this->shading,
03806                                                        $x2 + $this->shading, $y1 - $this->shading,
03807                                                        $x2 + $this->shading, $y2 - $this->shading,
03808                                                        $x2, $y2,
03809                                                        $x2, $y1),
03810                                            6, $this->ndx_data_dark_colors[$idx]);
03811                     }
03812                     // Or draw a border?
03813                     else {
03814                         ImageRectangle($this->img, $x1, $y1, $x2,$y2, $this->ndx_data_border_colors[$idx]);
03815                     }
03816                     // Draw the bar
03817                     ImageFilledRectangle($this->img, $x1, $y1, $x2, $y2, $this->ndx_data_colors[$idx]);
03818 
03819                 }
03820             }   // end for
03821         }   // end for
03822     } //function DrawStackedBars
03823 
03824 
03828     function DrawGraph()
03829     {
03830         if (! $this->img) {
03831             $this->DrawError('DrawGraph(): No image resource allocated');
03832             return FALSE;
03833         }
03834 
03835         if (! is_array($this->data)) {
03836             $this->DrawError("DrawGraph(): No array of data in \$data");
03837             return FALSE;
03838         }
03839 
03840         if (! isset($this->data_limits_done))
03841             $this->FindDataLimits();                // Get maxima and minima for scaling
03842 
03843         if ($this->total_records == 0) {            // Check for empty data sets
03844             $this->DrawError('Empty data set');
03845             return FALSE;
03846         }
03847 
03848         $this->CalcMargins();                       // Calculate margins
03849 
03850         if (! isset($this->plot_area_width))        // Set plot area pixel values (plot_area[])
03851             $this->SetPlotAreaPixels();
03852 
03853         if (! isset($this->plot_max_y))             // Set plot area world values (plot_max_x, etc.)
03854             $this->SetPlotAreaWorld();
03855 
03856         if ($this->plot_type == 'bars' || $this->plot_type == 'stackedbars') // Calculate bar widths
03857             $this->CalcBarWidths();
03858 /* FIXME!!  this sort of thing should not be done without user's consent
03859         if ($this->x_data_label_pos != 'none') {    // Default: do not draw tick stuff if
03860             $this->x_tick_label_pos = 'none';       // there are data labels.
03861             $this->x_tick_pos = 'none';
03862         }
03863 */
03864         $this->PadArrays();                         // Pad color and style arrays to fit records per group.
03865 
03866         $this->DrawBackground();
03867 
03868         $this->DrawImageBorder();
03869 
03870         $this->DrawPlotAreaBackground();
03871 
03872         $this->DrawTitle();
03873         $this->DrawXTitle();
03874         $this->DrawYTitle();
03875 
03876         // Pie charts are drawn differently, handle them first
03877         if ($this->plot_type == 'pie') {
03878             // Pie charts can maximize image space usage.
03879             $this->SetPlotAreaPixels($this->safe_margin, $this->title_height,
03880                                      $this->image_width - $this->safe_margin,
03881                                      $this->image_height - $this->safe_margin);
03882             $this->DrawPieChart();
03883 
03884             if ($this->legend)
03885                 $this->DrawLegend($this->legend_x_pos, $this->legend_y_pos, '');
03886 
03887             if ($this->print_image)
03888                 $this->PrintImage();
03889 
03890             return;
03891         }
03892 
03894 
03895         if (! $this->grid_at_foreground) {         // Usually one wants grids to go back, but...
03896             $this->DrawYAxis();     // Y axis must be drawn before X axis (see DrawYAxis())
03897             $this->DrawXAxis();
03898         }
03899 
03900         switch ($this->plot_type) {
03901         case 'thinbarline':
03902             $this->DrawThinBarLines();
03903             break;
03904         case 'area':
03905             $this->DrawArea();
03906             break;
03907         case 'squared':
03908             $this->DrawSquared();
03909             break;
03910         case 'lines':
03911             if ( $this->data_type == 'data-data-error') {
03912                 $this->DrawLinesError();
03913             } else {
03914                 $this->DrawLines();
03915             }
03916             break;
03917         case 'linepoints':          // FIXME !!! DrawXDataLabel gets called in DrawLines() and DrawDots()
03918             if ( $this->data_type == 'data-data-error') {
03919                 $this->DrawLinesError();
03920                 $this->DrawDotsError();
03921             } else {
03922                 $this->DrawLines();
03923                 $this->DrawDots();
03924             }
03925             break;
03926         case 'points';
03927             if ( $this->data_type == 'data-data-error') {
03928                 $this->DrawDotsError();
03929             } else {
03930                 $this->DrawDots();
03931             }
03932             break;
03933         case 'stackedbars':
03934             $this->DrawStackedBars();
03935             break;
03936         case 'bars':
03937             $this->DrawBars();
03938             break;
03939         default:
03940             $this->plot_type = 'bars';  // Set it if it wasn't already set.
03941             $this->DrawBars();
03942             break;
03943         }   // end switch
03944 
03945         if ($this->grid_at_foreground) {         // Usually one wants grids to go back, but...
03946             $this->DrawYAxis();     // Y axis must be drawn before X axis (see DrawYAxis())
03947             $this->DrawXAxis();
03948         }
03949 
03950         $this->DrawPlotBorder();
03951 
03952         if ($this->legend)
03953             $this->DrawLegend($this->legend_x_pos, $this->legend_y_pos, '');
03954 
03955         if ($this->print_image)
03956             $this->PrintImage();
03957 
03958     } //function DrawGraph()
03959 
03963 
03967     function SetDrawVertTicks($which_dvt)
03968     {
03969         if ($which_dvt != 1)
03970             $this->SetYTickPos('none');
03971         return TRUE;
03972     }
03973 
03977     function SetDrawHorizTicks($which_dht)
03978     {
03979         if ($which_dht != 1)
03980            $this->SetXTickPos('none');
03981         return TRUE;
03982     }
03983 
03987     function SetNumHorizTicks($n)
03988     {
03989         return $this->SetNumXTicks($n);
03990     }
03991 
03995     function SetNumVertTicks($n)
03996     {
03997         return $this->SetNumYTicks($n);
03998     }
03999 
04003     function SetHorizTickIncrement($inc)
04004     {
04005         return $this->SetXTickIncrement($inc);
04006     }
04007 
04008 
04012     function SetVertTickIncrement($inc)
04013     {
04014         return $this->SetYTickIncrement($inc);
04015     }
04016 
04020     function SetVertTickPosition($which_tp)
04021     {
04022         return $this->SetYTickPos($which_tp);
04023     }
04024 
04028     function SetHorizTickPosition($which_tp)
04029     {
04030         return $this->SetXTickPos($which_tp);
04031     }
04032 
04036     function SetTitleFontSize($which_size)
04037     {
04038         return $this->SetFont('title', $which_size);
04039     }
04040 
04044     function SetAxisFontSize($which_size)
04045     {
04046         $this->SetFont('x_label', $which_size);
04047         $this->SetFont('y_label', $whic_size);
04048     }
04049 
04053     function SetSmallFontSize($which_size)
04054     {
04055         return $this->SetFont('generic', $which_size);
04056     }
04057 
04061     function SetXLabelFontSize($which_size)
04062     {
04063         return $this->SetFont('x_title', $which_size);
04064     }
04065 
04069     function SetYLabelFontSize($which_size)
04070     {
04071         return $this->SetFont('y_title', $which_size);
04072     }
04073 
04077     function SetXLabel($which_xlab)
04078     {
04079         return $this->SetXTitle($which_xlab);
04080     }
04081 
04085     function SetYLabel($which_ylab)
04086     {
04087         return $this->SetYTitle($which_ylab);
04088     }
04089 
04094     function SetImageArea($which_iw, $which_ih)
04095     {
04096         $this->image_width = $which_iw;
04097         $this->image_height = $which_ih;
04098 
04099         return TRUE;
04100     }
04101 
04105     function SetTickLength($which_tl)
04106     {
04107         $this->SetXTickLength($which_tl);
04108         $this->SetYTickLength($which_tl);
04109         return TRUE;
04110     }
04111 
04115     function SetYGridLabelType($which_yglt)
04116     {
04117         return $this->SetYLabelType($which_yglt);
04118     }
04119 
04123     function SetXGridLabelType($which_xglt)
04124     {
04125         return $this->SetXLabelType($which_xglt);
04126     }
04130     function SetYGridLabelPos($which_yglp)
04131     {
04132         return $this->SetYTickLabelPos($which_yglp);
04133     }
04137     function SetXGridLabelPos($which_xglp)
04138     {
04139         return $this->SetXTickLabelPos($which_xglp);
04140     }
04141 
04142 
04146     function SetXTitlePos($xpos)
04147     {
04148         $this->x_title_pos = $xpos;
04149         return TRUE;
04150     }
04151 
04155     function SetYTitlePos($xpos)
04156     {
04157         $this->y_title_pos = $xpos;
04158         return TRUE;
04159     }
04160 
04164     function DrawDotSeries()
04165     {
04166         $this->DrawDots();
04167     }
04168 
04172     function SetXDataLabelAngle($which_xdla)
04173     {
04174         return $this->SetXLabelAngle($which_xdla);
04175     }
04176 
04183     function SetDrawXDataLabels($which_dxdl)
04184     {
04185         if ($which_dxdl == '1' )
04186             $this->SetXDataLabelPos('plotdown');
04187         else
04188             $this->SetXDataLabelPos('none');
04189     }
04190 
04195     function DrawLineSeries()
04196     {
04197         return $this->DrawLines();
04198     }
04199 
04203     function CalcXHeights()
04204     {
04205         // TTF
04206         if ($this->use_ttf) {
04207             $xstr = str_repeat('.', $this->max_t);
04208             $size = $this->TTFBBoxSize($this->x_label_font['size'], $this->x_label_angle,
04209                                        $this->x_label_font['font'], $xstr);
04210             $this->x_tick_label_height = $size[1];
04211         }
04212         // Fixed font
04213         else { // For Non-TTF fonts we can have only angles 0 or 90
04214             if ($this->x_label_angle == 90)
04215                 $this->x_tick_label_height = $this->max_t * $this->x_label_font['width'];
04216             else
04217                 $this->x_tick_label_height = $this->x_label_font['height'];
04218         }
04219 
04220         return TRUE;
04221     }
04222 
04223 
04227     function CalcYWidths()
04228     {
04229         //the "." is for space. It isn't actually printed
04230         $ylab = number_format($this->max_y, $this->y_precision, '.', ', ') . $this->data_units_text . '.';
04231 
04232         // TTF
04233         if ($this->use_ttf) {
04234             // Maximum Y tick label width
04235             $size = $this->TTFBBoxSize($this->y_label_font['size'], 0, $this->y_label_font['font'], $ylab);
04236             $this->y_tick_label_width = $size[0];
04237 
04238         }
04239         // Fixed font
04240         else {
04241             // Y axis title width
04242             $this->y_tick_label_width = strlen($ylab) * $this->y_label_font['width'];
04243         }
04244 
04245         return TRUE;
04246     }
04247 
04251     function DrawLabels()
04252     {
04253         $this->DrawTitle();
04254         $this->DrawXTitle();
04255         $this->DrawYTitle();
04256     }
04257 
04262     function InitImage()
04263     {
04264         $this->img = ImageCreate($this->image_width, $this->image_height);
04265 
04266         if (! $this->img)
04267             $this->PrintError('InitImage(): Could not create image resource');
04268         return TRUE;
04269     }
04270 
04274     function SetNewPlotAreaPixels($x1, $y1, $x2, $y2)
04275     {
04276         //Like in GD 0, 0 is upper left set via pixel Coordinates
04277         $this->plot_area = array($x1, $y1, $x2, $y2);
04278         $this->plot_area_width = $this->plot_area[2] - $this->plot_area[0];
04279         $this->plot_area_height = $this->plot_area[3] - $this->plot_area[1];
04280         $this->y_top_margin = $this->plot_area[1];
04281 
04282         if (isset($this->plot_max_x))
04283             $this->CalcTranslation();
04284 
04285         return TRUE;
04286     }
04287 
04291     function SetColor($which_color)
04292     {
04293         $this->SetRGBColor($which_color);
04294         return TRUE;
04295     }
04296 
04297     /*
04298      * \deprecated Use SetLineWidths().
04299      */
04300     function SetLineWidth($which_lw)
04301     {
04302 
04303         $this->SetLineWidths($which_lw);
04304 
04305         if (!$this->error_bar_line_width) {
04306             $this->SetErrorBarLineWidth($which_lw);
04307         }
04308         return TRUE;
04309     }
04310 
04314     function DrawDashedLine($x1, $y1, $x2, $y2 , $dash_length, $dash_space, $color)
04315     {
04316         if ($dash_length)
04317             $dashes = array_fill(0, $dash_length, $color);
04318         else
04319             $dashes = array();
04320         if ($dash_space)
04321             $spaces = array_fill(0, $dash_space, IMG_COLOR_TRANSPARENT);
04322         else
04323             $spaces = array();
04324 
04325         $style = array_merge($dashes, $spaces);
04326         ImageSetStyle($this->img, $style);
04327         ImageLine($this->img, $x1, $y1, $x2, $y2, IMG_COLOR_STYLED);
04328     }
04329 
04334     function SetInputFile($which_input_file)
04335     {
04336         $size = GetImageSize($which_input_file);
04337         $input_type = $size[2];
04338 
04339         switch($input_type) {
04340         case 1:
04341             $im = @ ImageCreateFromGIF ($which_input_file);
04342             if (!$im) { // See if it failed
04343                 $this->PrintError("Unable to open $which_input_file as a GIF");
04344                 return FALSE;
04345             }
04346         break;
04347         case 3:
04348             $im = @ ImageCreateFromPNG ($which_input_file);
04349             if (!$im) { // See if it failed
04350                 $this->PrintError("Unable to open $which_input_file as a PNG");
04351                 return FALSE;
04352             }
04353         break;
04354         case 2:
04355             $im = @ ImageCreateFromJPEG ($which_input_file);
04356             if (!$im) { // See if it failed
04357                 $this->PrintError("Unable to open $which_input_file as a JPG");
04358                 return FALSE;
04359             }
04360         break;
04361         default:
04362             $this->PrintError('SetInputFile(): Please select gif, jpg, or png for image type!');
04363             return FALSE;
04364         break;
04365         }
04366 
04367         // Set Width and Height of Image
04368         $this->image_width = $size[0];
04369         $this->image_height = $size[1];
04370 
04371         // Deallocate any resources previously allocated
04372         if ($this->img)
04373             imagedestroy($this->img);
04374 
04375         $this->img = $im;
04376 
04377         return TRUE;
04378 
04379     }
04380 
04381 
04382     /*
04383      * \deprecated Use SetPointShapes().
04384      */
04385     function SetPointShape($which_pt)
04386     {
04387         $this->SetPointShapes($which_pt);
04388         return TRUE;
04389     }
04390 
04391     /*
04392      * \deprecated Use SetPointSizes().
04393      */
04394     function SetPointSize($which_ps)
04395     {
04396         $this->SetPointSizes($which_ps);
04397         return TRUE;
04398     }
04399 }  // class PHPlot
04400 
04401 
04402 
04404 
04405 
04412 function array_pad_array(&$arr, $size, $arr2=NULL)
04413 {
04414     if (! is_array($arr2)) {
04415         $arr2 = $arr;                           // copy the original array
04416     }
04417     while (count($arr) < $size)
04418         $arr = array_merge_php4($arr, $arr2);        // append until done
04419 }
04420 
04426 function array_merge_php4($array1,$array2)
04427 {
04428     $return=array();
04429 
04430     foreach(func_get_args() as $arg){
04431         if(!is_array($arg)){
04432         $arg=array($arg);
04433         }
04434         foreach($arg as $key=>$val){
04435             if(!is_int($key)){
04436                 $return[$key]=$val;
04437             }else{
04438                 $return[]=$val;
04439             }
04440         }
04441     }
04442     return $return;
04443  }
04444 
04445 
04446 
04447 
04448 ?>

Generated on Fri Dec 13 2013 13:52:15 for ILIAS Release_3_7_x_branch .rev 46817 by  doxygen 1.7.1