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