/[drupal]/contributions/modules/graphstat/phplot.php
ViewVC logotype

Contents of /contributions/modules/graphstat/phplot.php

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Wed Nov 14 22:29:56 2007 UTC (2 years ago) by profix898
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
Changes since 1.1: +1 -1 lines
File MIME type: text/x-php
- Initial version for Drupal 6
1 <?php
2
3 /* $Id: phplot.php,v 1.131 2007/10/19 02:57:56 lbayuk Exp $ */
4
5 /*
6 * PHPLOT Version 5.0.4
7 * Copyright (C) 1998-2007 Afan Ottenheimer. Released under
8 * the GPL and PHP licenses as stated in the README file which should
9 * have been included with this document.
10 *
11 * Co-author and maintainer (2003-2005)
12 * Miguel de Benito Delgado <nonick AT vodafone DOT es>
13 *
14 * Maintainer (2006-present)
15 * <lbayuk AT users DOT sourceforge DOT net>
16 *
17 * Visit http://sourceforge.net/projects/phplot/
18 * for PHPlot documentation, downloads, and discussions.
19 *
20 * Requires PHP 4.3.0 or later. PHP 5.2.x or later is recommended.
21 */
22
23 class PHPlot {
24
25 /* I have removed internal variable declarations, some isset() checking was required,
26 * but now the variables left are those which can be tweaked by the user. This is intended to
27 * be the first step towards moving most of the Set...() methods into a subclass which will be
28 * used only when strictly necessary. Many users will be able to put default values here in the
29 * class and thus avoid memory overhead and reduce parsing times.
30 */
31 //////////////// CONFIG PARAMETERS //////////////////////
32
33 var $is_inline = FALSE; // FALSE = Sends headers, TRUE = sends just raw image data
34 var $browser_cache = FALSE; // FALSE = Sends headers for browser to not cache the image,
35 // (only if is_inline = FALSE also)
36
37 var $safe_margin = 5; // Extra margin used in several places. In pixels
38
39 var $x_axis_position = ''; // Where to draw both axis (world coordinates),
40 var $y_axis_position = ''; // leave blank for X axis at 0 and Y axis at left of plot.
41
42 var $xscale_type = 'linear'; // linear, log
43 var $yscale_type = 'linear';
44
45 //Fonts
46 var $use_ttf = FALSE; // Use True Type Fonts?
47 var $ttf_path = '.'; // Default path to look in for TT Fonts.
48 var $default_ttfont = 'benjamingothic.ttf';
49 var $line_spacing = 4; // Pixels between lines.
50
51 // Font angles: 0 or 90 degrees for fixed fonts, any for TTF
52 var $x_label_angle = 0; // For labels on X axis (tick and data)
53 var $y_label_angle = 0; // For labels on Y axis (tick and data)
54 var $x_title_angle = 0; // Don't change this if you don't want to screw things up!
55 var $y_title_angle = 90; // Nor this.
56 var $title_angle = 0; // Or this.
57
58 //Formats
59 var $file_format = 'png';
60 var $output_file = ''; // For output to a file instead of stdout
61
62 //Data
63 var $data_type = 'text-data'; // text-data, data-data-error, data-data, text-data-single
64 var $plot_type= 'linepoints'; // bars, lines, linepoints, area, points, pie, thinbarline, squared
65
66 var $label_scale_position = 0.5; // Shifts data labes in pie charts. 1 = top, 0 = bottom
67 var $group_frac_width = 0.7; // Bars use this fraction (0 to 1) of a group's space
68 var $bar_extra_space = 0.5; // Number of extra bar's worth of space in a group
69 var $bar_width_adjust = 1; // 1 = bars of normal width, must be > 0
70
71 var $y_precision = 1;
72 var $x_precision = 1;
73
74 var $data_units_text = ''; // Units text for 'data' labels (i.e: 'ยค', '$', etc.)
75
76 // Titles
77 var $title_txt = '';
78
79 var $x_title_txt = '';
80 var $x_title_pos = 'plotdown'; // plotdown, plotup, both, none
81
82 var $y_title_txt = '';
83 var $y_title_pos = 'plotleft'; // plotleft, plotright, both, none
84
85
86 //Labels
87 // There are two types of labels in PHPlot:
88 // Tick labels: they follow the grid, next to ticks in axis. (DONE)
89 // they are drawn at grid drawing time, by DrawXTicks() and DrawYTicks()
90 // Data labels: they follow the data points, and can be placed on the axis or the plot (x/y) (TODO)
91 // they are drawn at graph plotting time, by Draw*DataLabel(), called by DrawLines(), etc.
92 // Draw*DataLabel() also draws H/V lines to datapoints depending on draw_*_data_label_lines
93
94 // Tick Labels
95 var $x_tick_label_pos = 'plotdown'; // plotdown, plotup, both, xaxis, none
96 var $y_tick_label_pos = 'plotleft'; // plotleft, plotright, both, yaxis, none
97
98 // Data Labels:
99 var $x_data_label_pos = 'plotdown'; // plotdown, plotup, both, plot, all, none
100 var $y_data_label_pos = 'plotleft'; // plotleft, plotright, both, plot, all, plotin, none
101
102 var $draw_x_data_label_lines = FALSE; // Draw a line from the data point to the axis?
103 var $draw_y_data_label_lines = FALSE; // TODO
104
105 // Label types: (for tick, data and plot labels)
106 var $x_label_type = ''; // data, time. Leave blank for no formatting.
107 var $y_label_type = ''; // data, time. Leave blank for no formatting.
108 var $x_time_format = '%H:%M:%S'; // See http://www.php.net/manual/html/function.strftime.html
109 var $y_time_format = '%H:%M:%S'; // SetYTimeFormat() too...
110
111 // Skipping labels
112 var $x_label_inc = 1; // Draw a label every this many (1 = all) (TODO)
113 var $y_label_inc = 1;
114 var $_x_label_cnt = 0; // internal count FIXME: work in progress
115
116 // Legend
117 var $legend = ''; // An array with legend titles
118 // These variables are unset to take default values:
119 // var $legend_x_pos; // User-specified upper left coordinates of legend box
120 // var $legend_y_pos;
121 // var $legend_xy_world; // If set, legend_x/y_pos are world coords, else pixel coords
122 // var $legend_text_align; // left or right, Unset means right
123 // var $legend_colorbox_align; // left, right, or none; Unset means same as text_align
124
125 //Ticks
126 var $x_tick_length = 5; // tick length in pixels for upper/lower axis
127 var $y_tick_length = 5; // tick length in pixels for left/right axis
128
129 var $x_tick_cross = 3; // ticks cross x axis this many pixels
130 var $y_tick_cross = 3; // ticks cross y axis this many pixels
131
132 var $x_tick_pos = 'plotdown'; // plotdown, plotup, both, xaxis, none
133 var $y_tick_pos = 'plotleft'; // plotright, plotleft, both, yaxis, none
134
135 var $num_x_ticks = '';
136 var $num_y_ticks = '';
137
138 var $x_tick_inc = ''; // Set num_x_ticks or x_tick_inc, not both.
139 var $y_tick_inc = ''; // Set num_y_ticks or y_tick_inc, not both.
140
141 var $skip_top_tick = FALSE;
142 var $skip_bottom_tick = FALSE;
143 var $skip_left_tick = FALSE;
144 var $skip_right_tick = FALSE;
145
146 //Grid Formatting
147 var $draw_x_grid = FALSE;
148 var $draw_y_grid = TRUE;
149
150 var $dashed_grid = TRUE;
151 var $grid_at_foreground = FALSE; // Chooses whether to draw the grid below or above the graph
152
153 //Colors and styles (all colors can be array (R,G,B) or named color)
154 var $color_array = 'small'; // 'small', 'large' or array (define your own colors)
155 // See rgb.inc.php and SetRGBArray()
156 var $i_border = array(194, 194, 194);
157 var $plot_bg_color = 'white';
158 var $bg_color = 'white';
159 var $label_color = 'black';
160 var $text_color = 'black';
161 var $grid_color = 'black';
162 var $light_grid_color = 'gray';
163 var $tick_color = 'black';
164 var $title_color = 'black';
165 var $data_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1');
166 var $error_bar_colors = array('SkyBlue', 'green', 'orange', 'blue', 'orange', 'red', 'violet', 'azure1');
167 var $data_border_colors = array('black');
168
169 var $line_widths = 1; // single value or array
170 var $line_styles = array('solid', 'solid', 'dashed'); // single value or array
171 var $dashed_style = '2-4'; // colored dots-transparent dots
172
173 var $point_sizes = array(5,5,3); // single value or array
174 var $point_shapes = array('diamond'); // rect, circle, diamond, triangle, dot, line, halfline, cross
175
176 var $error_bar_size = 5; // right and left size of tee
177 var $error_bar_shape = 'tee'; // 'tee' or 'line'
178 var $error_bar_line_width = 1; // single value (or array TODO)
179
180 var $plot_border_type = 'sides'; // left, sides, none, full
181 var $image_border_type = 'none'; // 'raised', 'plain', 'none'
182
183 var $shading = 5; // 0 for no shading, > 0 is size of shadows in pixels
184
185 var $draw_plot_area_background = FALSE;
186 var $draw_broken_lines = FALSE; // Tells not to draw lines for missing Y data.
187
188 //Miscellaneous
189 var $callbacks = array( // Valid callback reasons (see SetCallBack)
190 'draw_setup' => NULL,
191 'draw_image_background' => NULL,
192 'draw_plotarea_background' => NULL,
193 'draw_titles' => NULL,
194 'draw_axes' => NULL,
195 'draw_graph' => NULL,
196 'draw_border' => NULL,
197 'draw_legend' => NULL,
198 );
199
200
201 //////////////////////////////////////////////////////
202 //BEGIN CODE
203 //////////////////////////////////////////////////////
204
205 /*!
206 * Constructor: Setup img resource, colors and size of the image, and font sizes.
207 *
208 * \param which_width int Image width in pixels.
209 * \param which_height int Image height in pixels.
210 * \param which_output_file string Filename for output.
211 * \param which_input_fule string Path to a file to be used as background.
212 */
213 function PHPlot($which_width=600, $which_height=400, $which_output_file=NULL, $which_input_file=NULL)
214 {
215 $this->SetRGBArray($this->color_array);
216
217 $this->background_done = FALSE; // Set to TRUE after background image is drawn once
218
219 if ($which_output_file)
220 $this->SetOutputFile($which_output_file);
221
222 if ($which_input_file)
223 $this->SetInputFile($which_input_file);
224 else {
225 $this->image_width = $which_width;
226 $this->image_height = $which_height;
227
228 $this->img = ImageCreate($this->image_width, $this->image_height);
229 if (! $this->img)
230 $this->PrintError('PHPlot(): Could not create image resource.');
231
232 }
233
234 $this->SetDefaultStyles();
235 $this->SetDefaultFonts();
236
237 $this->SetTitle('');
238 $this->SetXTitle('');
239 $this->SetYTitle('');
240
241 $this->print_image = TRUE; // Use for multiple plots per image (TODO: automatic)
242 }
243
244 /*!
245 * Reads an image file. Stores width and height, and returns the image
246 * resource. On error, calls PrintError and returns False.
247 * This is used by the constructor via SetInputFile, and by tile_img().
248 */
249 function GetImage($image_filename, &$width, &$height)
250 {
251 $error = '';
252 $size = getimagesize($image_filename);
253 if (!$size) {
254 $error = "Unable to query image file $image_filename";
255 } else {
256 $image_type = $size[2];
257 switch($image_type) {
258 case IMAGETYPE_GIF:
259 $img = @ ImageCreateFromGIF ($image_filename);
260 break;
261 case IMAGETYPE_PNG:
262 $img = @ ImageCreateFromPNG ($image_filename);
263 break;
264 case IMAGETYPE_JPEG:
265 $img = @ ImageCreateFromJPEG ($image_filename);
266 break;
267 default:
268 $error = "Unknown image type ($image_type) for image file $image_filename";
269 break;
270 }
271 }
272 if (empty($error) && !$img) {
273 # getimagesize is OK, but GD won't read it. Maybe unsupported format.
274 $error = "Failed to read image file $image_filename";
275 }
276 if (!empty($error)) {
277 $this->PrintError($error);
278 }
279 $width = $size[0];
280 $height = $size[1];
281 return $img;
282 }
283
284 /*!
285 * Selects an input file to be used as background for the whole graph.
286 * This resets the graph size to the image's size.
287 * Note: This is used by the constructor. It is deprecated for direct use.
288 */
289 function SetInputFile($which_input_file)
290 {
291 $im = $this->GetImage($which_input_file, $this->image_width, $this->image_height);
292 if (!$im)
293 return FALSE; // GetImage already produced an error message.
294
295 // Deallocate any resources previously allocated
296 if (isset($this->img))
297 imagedestroy($this->img);
298
299 $this->img = $im;
300
301 // Do not overwrite the input file with the background color.
302 $this->background_done = TRUE;
303
304 return TRUE;
305 }
306
307 /////////////////////////////////////////////
308 ////////////// COLORS
309 /////////////////////////////////////////////
310
311 /*!
312 * Returns an index to a color passed in as anything (string, hex, rgb)
313 *
314 * \param which_color * Color (can be '#AABBCC', 'Colorname', or array(r,g,b))
315 */
316 function SetIndexColor($which_color)
317 {
318 list ($r, $g, $b) = $this->SetRGBColor($which_color); //Translate to RGB
319 return ImageColorResolve($this->img, $r, $g, $b);
320 }
321
322
323 /*!
324 * Returns an index to a slightly darker color than the one requested.
325 */
326 function SetIndexDarkColor($which_color)
327 {
328 list ($r, $g, $b) = $this->SetRGBColor($which_color);
329 $r = max(0, $r - 0x30);
330 $g = max(0, $g - 0x30);
331 $b = max(0, $b - 0x30);
332 return ImageColorResolve($this->img, $r, $g, $b);
333 }
334
335 /*!
336 * Sets/reverts all colors and styles to their defaults. If session is set, then only updates indices,
337 * as they are lost with every script execution, else, sets the default colors by name or value and
338 * then updates indices too.
339 *
340 * FIXME Isn't this too slow?
341 *
342 */
343 function SetDefaultStyles()
344 {
345 /* Some of the Set*() functions use default values when they get no parameters. */
346
347 if (! isset($this->session_set)) {
348 // If sessions are enabled, this variable will be preserved, so upon future executions, we
349 // will have it set, as well as color names (though not color indices, that's why we
350 // need to rebuild them)
351 $this->session_set = TRUE;
352
353 // These only need to be set once
354 $this->SetLineWidths();
355 $this->SetLineStyles();
356 $this->SetDefaultDashedStyle($this->dashed_style);
357 $this->SetPointSizes($this->point_sizes);
358 }
359
360 $this->SetImageBorderColor($this->i_border);
361 $this->SetPlotBgColor($this->plot_bg_color);
362 $this->SetBackgroundColor($this->bg_color);
363 $this->SetLabelColor($this->label_color);
364 $this->SetTextColor($this->text_color);
365 $this->SetGridColor($this->grid_color);
366 $this->SetLightGridColor($this->light_grid_color);
367 $this->SetTickColor($this->tick_color);
368 $this->SetTitleColor($this->title_color);
369 $this->SetDataColors();
370 $this->SetErrorBarColors();
371 $this->SetDataBorderColors();
372 }
373
374
375 /*
376 *
377 */
378 function SetBackgroundColor($which_color)
379 {
380 $this->bg_color= $which_color;
381 $this->ndx_bg_color= $this->SetIndexColor($this->bg_color);
382 return TRUE;
383 }
384
385 /*
386 *
387 */
388 function SetPlotBgColor($which_color)
389 {
390 $this->plot_bg_color= $which_color;
391 $this->ndx_plot_bg_color= $this->SetIndexColor($this->plot_bg_color);
392 return TRUE;
393 }
394
395 /*
396 *
397 */
398 function SetTitleColor($which_color)
399 {
400 $this->title_color= $which_color;
401 $this->ndx_title_color= $this->SetIndexColor($this->title_color);
402 return TRUE;
403 }
404
405 /*
406 *
407 */
408 function SetTickColor ($which_color)
409 {
410 $this->tick_color= $which_color;
411 $this->ndx_tick_color= $this->SetIndexColor($this->tick_color);
412 return TRUE;
413 }
414
415
416 /*
417 *
418 */
419 function SetLabelColor ($which_color)
420 {
421 $this->label_color = $which_color;
422 $this->ndx_title_color= $this->SetIndexColor($this->label_color);
423 return TRUE;
424 }
425
426
427 /*
428 *
429 */
430 function SetTextColor ($which_color)
431 {
432 $this->text_color= $which_color;
433 $this->ndx_text_color= $this->SetIndexColor($this->text_color);
434 return TRUE;
435 }
436
437
438 /*
439 *
440 */
441 function SetLightGridColor ($which_color)
442 {
443 $this->light_grid_color= $which_color;
444 $this->ndx_light_grid_color= $this->SetIndexColor($this->light_grid_color);
445 return TRUE;
446 }
447
448
449 /*
450 *
451 */
452 function SetGridColor ($which_color)
453 {
454 $this->grid_color = $which_color;
455 $this->ndx_grid_color= $this->SetIndexColor($this->grid_color);
456 return TRUE;
457 }
458
459
460 /*
461 *
462 */
463 function SetImageBorderColor($which_color)
464 {
465 $this->i_border = $which_color;
466 $this->ndx_i_border = $this->SetIndexColor($this->i_border);
467 $this->ndx_i_border_dark = $this->SetIndexDarkColor($this->i_border);
468 return TRUE;
469 }
470
471
472 /*
473 *
474 */
475 function SetTransparentColor($which_color)
476 {
477 ImageColorTransparent($this->img, $this->SetIndexColor($which_color));
478 return TRUE;
479 }
480
481
482 /*!
483 * Sets the array of colors to be used. It can be user defined, a small predefined one
484 * or a large one included from 'rgb.inc.php'.
485 *
486 * \param which_color_array If an array, the used as color array. If a string can
487 * be one of 'small' or 'large'.
488 */
489 function SetRGBArray ($which_color_array)
490 {
491 if ( is_array($which_color_array) ) { // User defined array
492 $this->rgb_array = $which_color_array;
493 return TRUE;
494 } elseif ($which_color_array == 'small') { // Small predefined color array
495 $this->rgb_array = array(
496 'white' => array(255, 255, 255),
497 'snow' => array(255, 250, 250),
498 'PeachPuff' => array(255, 218, 185),
499 'ivory' => array(255, 255, 240),
500 'lavender' => array(230, 230, 250),
501 'black' => array( 0, 0, 0),
502 'DimGrey' => array(105, 105, 105),
503 'gray' => array(190, 190, 190),
504 'grey' => array(190, 190, 190),
505 'navy' => array( 0, 0, 128),
506 'SlateBlue' => array(106, 90, 205),
507 'blue' => array( 0, 0, 255),
508 'SkyBlue' => array(135, 206, 235),
509 'cyan' => array( 0, 255, 255),
510 'DarkGreen' => array( 0, 100, 0),
511 'green' => array( 0, 255, 0),
512 'YellowGreen' => array(154, 205, 50),
513 'yellow' => array(255, 255, 0),
514 'orange' => array(255, 165, 0),
515 'gold' => array(255, 215, 0),
516 'peru' => array(205, 133, 63),
517 'beige' => array(245, 245, 220),
518 'wheat' => array(245, 222, 179),
519 'tan' => array(210, 180, 140),
520 'brown' => array(165, 42, 42),
521 'salmon' => array(250, 128, 114),
522 'red' => array(255, 0, 0),
523 'pink' => array(255, 192, 203),
524 'maroon' => array(176, 48, 96),
525 'magenta' => array(255, 0, 255),
526 'violet' => array(238, 130, 238),
527 'plum' => array(221, 160, 221),
528 'orchid' => array(218, 112, 214),
529 'purple' => array(160, 32, 240),
530 'azure1' => array(240, 255, 255),
531 'aquamarine1' => array(127, 255, 212)
532 );
533 return TRUE;
534 } elseif ($which_color_array === 'large') { // Large color array
535 include("./rgb.inc.php");
536 $this->rgb_array = $RGBArray;
537 } else { // Default to black and white only.
538 $this->rgb_array = array('white' => array(255, 255, 255), 'black' => array(0, 0, 0));
539 }
540
541 return TRUE;
542 }
543
544 /*!
545 * Returns an array in R, G, B format 0-255
546 *
547 * \param color_asked array(R,G,B) or string (named color or '#AABBCC')
548 */
549 function SetRGBColor($color_asked)
550 {
551 if (empty($color_asked)) {
552 $ret_val = array(0, 0, 0);
553 } elseif (count($color_asked) == 3 ) { // already array of 3 rgb
554 $ret_val = $color_asked;
555 } elseif ($color_asked[0] == '#') { // Hex RGB notation #RRGGBB
556 $ret_val = array(hexdec(substr($color_asked, 1, 2)),
557 hexdec(substr($color_asked, 3, 2)),
558 hexdec(substr($color_asked, 5, 2)));
559
560 } elseif (isset($this->rgb_array[$color_asked])) { // Color by name
561 $ret_val = $this->rgb_array[$color_asked];
562 } else {
563 $this->DrawError("SetRGBColor(): Color '$color_asked' is not valid.");
564 }
565 return $ret_val;
566 }
567
568
569 /*!
570 * Sets the colors for the data.
571 */
572 function SetDataColors($which_data = NULL, $which_border = NULL)
573 {
574 if (is_null($which_data) && is_array($this->data_colors)) {
575 // use already set data_colors
576 } else if (! is_array($which_data)) {
577 $this->data_colors = ($which_data) ? array($which_data) : array('blue', 'red', 'green', 'orange');
578 } else {
579 $this->data_colors = $which_data;
580 }
581
582 $i = 0;
583 foreach ($this->data_colors as $col) {
584 $this->ndx_data_colors[$i] = $this->SetIndexColor($col);
585 $this->ndx_data_dark_colors[$i] = $this->SetIndexDarkColor($col);
586 $i++;
587 }
588
589 // For past compatibility:
590 $this->SetDataBorderColors($which_border);
591 } // function SetDataColors()
592
593
594 /*!
595 *
596 */
597 function SetDataBorderColors($which_br = NULL)
598 {
599 if (is_null($which_br) && is_array($this->data_border_colors)) {
600 // use already set data_border_colors
601 } else if (! is_array($which_br)) {
602 // Create new array with specified color
603 $this->data_border_colors = ($which_br) ? array($which_br) : array('black');
604 } else {
605 $this->data_border_colors = $which_br;
606 }
607
608 $i = 0;
609 foreach($this->data_border_colors as $col) {
610 $this->ndx_data_border_colors[$i] = $this->SetIndexColor($col);
611 $i++;
612 }
613 } // function SetDataBorderColors()
614
615
616 /*!
617 * Sets the colors for the data error bars.
618 */
619 function SetErrorBarColors($which_err = NULL)
620 {
621 if (is_null($which_err) && is_array($this->error_bar_colors)) {
622 // use already set error_bar_colors
623 } else if (! is_array($which_err)) {
624 $this->error_bar_colors = ($which_err) ? array($which_err) : array('black');
625 } else {
626 $this->error_bar_colors = $which_err;
627 }
628
629 $i = 0;
630 foreach($this->error_bar_colors as $col) {
631 $this->ndx_error_bar_colors[$i] = $this->SetIndexColor($col);
632 $i++;
633 }
634 return TRUE;
635
636 } // function SetErrorBarColors()
637
638
639 /*!
640 * Sets the default dashed style.
641 * \param which_style A string specifying order of colored and transparent dots,
642 * i.e: '4-3' means 4 colored, 3 transparent;
643 * '2-3-1-2' means 2 colored, 3 transparent, 1 colored, 2 transparent.
644 */
645 function SetDefaultDashedStyle($which_style)
646 {
647 // String: "numcol-numtrans-numcol-numtrans..."
648 $asked = explode('-', $which_style);
649
650 if (count($asked) < 2) {
651 $this->DrawError("SetDefaultDashedStyle(): Wrong parameter '$which_style'.");
652 return FALSE;
653 }
654
655 // Build the string to be eval()uated later by SetDashedStyle()
656 $this->default_dashed_style = 'array( ';
657
658 $t = 0;
659 foreach($asked as $s) {
660 if ($t % 2 == 0) {
661 $this->default_dashed_style .= str_repeat('$which_ndxcol,', $s);
662 } else {
663 $this->default_dashed_style .= str_repeat('IMG_COLOR_TRANSPARENT,', $s);
664 }
665 $t++;
666 }
667 // Remove trailing comma and add closing parenthesis
668 $this->default_dashed_style = substr($this->default_dashed_style, 0, -1);
669 $this->default_dashed_style .= ')';
670
671 return TRUE;
672 }
673
674
675 /*!
676 * Sets the style before drawing a dashed line. Defaults to $this->default_dashed_style
677 * \param which_ndxcol Color index to be used.
678 */
679 function SetDashedStyle($which_ndxcol)
680 {
681 // See SetDefaultDashedStyle() to understand this.
682 eval ("\$style = $this->default_dashed_style;");
683 return imagesetstyle($this->img, $style);
684 }
685
686
687 /*!
688 * Sets line widths on a per-line basis.
689 */
690 function SetLineWidths($which_lw=NULL)
691 {
692 if (is_null($which_lw)) {
693 // Do nothing, use default value.
694 } else if (is_array($which_lw)) {
695 // Did we get an array with line widths?
696 $this->line_widths = $which_lw;
697 } else {
698 $this->line_widths = array($which_lw);
699 }
700 return TRUE;
701 }
702
703 /*!
704 *
705 */
706 function SetLineStyles($which_ls=NULL)
707 {
708 if (is_null($which_ls)) {
709 // Do nothing, use default value.
710 } else if ( is_array($which_ls)) {
711 // Did we get an array with line styles?
712 $this->line_styles = $which_ls;
713 } else {
714 $this->line_styles = ($which_ls) ? array($which_ls) : array('solid');
715 }
716 return TRUE;
717 }
718
719
720 /////////////////////////////////////////////
721 ////////////// FONTS
722 /////////////////////////////////////////////
723
724
725 /*!
726 * Sets number of pixels between lines of the same text.
727 */
728 function SetLineSpacing($which_spc)
729 {
730 $this->line_spacing = $which_spc;
731 }
732
733
734 /*!
735 * Enables use of TrueType fonts in the graph. Font initialisation methods
736 * depend on this setting, so when called, SetUseTTF() resets the font
737 * settings
738 */
739 function SetUseTTF($which_ttf)
740 {
741 $this->use_ttf = $which_ttf;
742 $this->SetDefaultFonts();
743 return TRUE;
744 }
745
746 /*!
747 * Sets the directory name to look into for TrueType fonts.
748 */
749 function SetTTFPath($which_path)
750 {
751 // Maybe someone needs really dynamic config. He'll need this:
752 // clearstatcache();
753
754 if (is_dir($which_path) && is_readable($which_path)) {
755 $this->ttf_path = $which_path;
756 return TRUE;
757 } else {
758 $this->PrintError("SetTTFPath(): $which_path is not a valid path.");
759 return FALSE;
760 }
761 }
762
763 /*!
764 * Sets the default TrueType font and updates all fonts to that.
765 * The default font might be a full path, or relative to the TTFPath,
766 * so let SetFont check that it exists.
767 * Side effect: enable use of TrueType fonts.
768 */
769 function SetDefaultTTFont($which_font)
770 {
771 $this->default_ttfont = $which_font;
772 $this->SetUseTTF(TRUE);
773 return TRUE;
774 }
775
776 /*!
777 * Sets fonts to their defaults
778 */
779 function SetDefaultFonts()
780 {
781 // TTF:
782 if ($this->use_ttf) {
783 $this->SetFont('generic', '', 8);
784 $this->SetFont('title', '', 14);
785 $this->SetFont('legend', '', 8);
786 $this->SetFont('x_label', '', 6);
787 $this->SetFont('y_label', '', 6);
788 $this->SetFont('x_title', '', 10);
789 $this->SetFont('y_title', '', 10);
790 }
791 // Fixed:
792 else {
793 $this->SetFont('generic', 2);
794 $this->SetFont('title', 5);
795 $this->SetFont('legend', 2);
796 $this->SetFont('x_label', 1);
797 $this->SetFont('y_label', 1);
798 $this->SetFont('x_title', 3);
799 $this->SetFont('y_title', 3);
800 }
801
802 return TRUE;
803 }
804
805 /*!
806 * Sets Fixed/Truetype font parameters.
807 * \param $which_elem Is the element whose font is to be changed.
808 * It can be one of 'title', 'legend', 'generic',
809 * 'x_label', 'y_label', x_title' or 'y_title'
810 * \param $which_font Can be a number (for fixed font sizes) or
811 * a string with the font pathname or filename when using TTFonts.
812 * For TTFonts, an empty string means use the default font.
813 * \param $which_size Point size (TTF only)
814 * Calculates and updates internal height and width variables.
815 */
816 function SetFont($which_elem, $which_font, $which_size = 12)
817 {
818 // TTF:
819 if ($this->use_ttf) {
820 // Empty font name means use the default font.
821 if (empty($which_font))
822 $which_font = $this->default_ttfont;
823 $path = $which_font;
824
825 // First try the font name directly, if not then try with path.
826 if (!is_file($path) || !is_readable($path)) {
827 $path = $this->ttf_path . '/' . $which_font;
828 if (!is_file($path) || !is_readable($path)) {
829 $this->DrawError("SetFont(): Can't find TrueType font $which_font");
830 return FALSE;
831 }
832 }
833
834 switch ($which_elem) {
835 case 'generic':
836 $this->generic_font['font'] = $path;
837 $this->generic_font['size'] = $which_size;
838 break;
839 case 'title':
840 $this->title_font['font'] = $path;
841 $this->title_font['size'] = $which_size;
842 break;
843 case 'legend':
844 $this->legend_font['font'] = $path;
845 $this->legend_font['size'] = $which_size;
846 break;
847 case 'x_label':
848 $this->x_label_font['font'] = $path;
849 $this->x_label_font['size'] = $which_size;
850 break;
851 case 'y_label':
852 $this->y_label_font['font'] = $path;
853 $this->y_label_font['size'] = $which_size;
854 break;
855 case 'x_title':
856 $this->x_title_font['font'] = $path;
857 $this->x_title_font['size'] = $which_size;
858 break;
859 case 'y_title':
860 $this->y_title_font['font'] = $path;
861 $this->y_title_font['size'] = $which_size;
862 break;
863 default:
864 $this->DrawError("SetFont(): Unknown element '$which_elem' specified.");
865 return FALSE;
866 }
867 return TRUE;
868
869 }
870
871 // Fixed fonts:
872 if ($which_font > 5 || $which_font < 0) {
873 $this->DrawError('SetFont(): Non-TTF font size must be 1, 2, 3, 4 or 5');
874 return FALSE;
875 }
876
877 switch ($which_elem) {
878 case 'generic':
879 $this->generic_font['font'] = $which_font;
880 $this->generic_font['height'] = ImageFontHeight($which_font);
881 $this->generic_font['width'] = ImageFontWidth($which_font);
882 break;
883 case 'title':
884 $this->title_font['font'] = $which_font;
885 $this->title_font['height'] = ImageFontHeight($which_font);
886 $this->title_font['width'] = ImageFontWidth($which_font);
887 break;
888 case 'legend':
889 $this->legend_font['font'] = $which_font;
890 $this->legend_font['height'] = ImageFontHeight($which_font);
891 $this->legend_font['width'] = ImageFontWidth($which_font);
892 break;
893 case 'x_label':
894 $this->x_label_font['font'] = $which_font;
895 $this->x_label_font['height'] = ImageFontHeight($which_font);
896 $this->x_label_font['width'] = ImageFontWidth($which_font);
897 break;
898 case 'y_label':
899 $this->y_label_font['font'] = $which_font;
900 $this->y_label_font['height'] = ImageFontHeight($which_font);
901 $this->y_label_font['width'] = ImageFontWidth($which_font);
902 break;
903 case 'x_title':
904 $this->x_title_font['font'] = $which_font;
905 $this->x_title_font['height'] = ImageFontHeight($which_font);
906 $this->x_title_font['width'] = ImageFontWidth($which_font);
907 break;
908 case 'y_title':
909 $this->y_title_font['font'] = $which_font;
910 $this->y_title_font['height'] = ImageFontHeight($which_font);
911 $this->y_title_font['width'] = ImageFontWidth($which_font);
912 break;
913 default:
914 $this->DrawError("SetFont(): Unknown element '$which_elem' specified.");
915 return FALSE;
916 }
917 return TRUE;
918 }
919
920
921 /*!
922 * Returns an array with the size of the bounding box of an
923 * arbitrarily placed (rotated) TrueType text string.
924 */
925 function TTFBBoxSize($size, $angle, $font, $string)
926 {
927 // First, assume angle < 90
928 $arr = ImageTTFBBox($size, 0, $font, $string);
929 $flat_width = $arr[2] - $arr[0];
930 $flat_height = abs($arr[3] - $arr[5]);
931
932 // Now the bounding box
933 $angle = deg2rad($angle);
934 $width = ceil(abs($flat_width*cos($angle) + $flat_height*sin($angle))); //Must be integer
935 $height = ceil(abs($flat_width*sin($angle) + $flat_height*cos($angle))); //Must be integer
936
937 return array($width, $height);
938 }
939
940
941 /*!
942 * Draws a string of text. Horizontal and vertical alignment are relative to
943 * to the drawing. That is: vertical text (90 deg) gets centered along y-axis
944 * with v_align = 'center', and adjusted to the left of x-axis with h_align = 'right',
945 *
946 * \note Original multiple lines code submitted by Remi Ricard.
947 * \note Original vertical code submitted by Marlin Viss.
948 */
949 function DrawText($which_font, $which_angle, $which_xpos, $which_ypos, $which_color, $which_text,
950 $which_halign = 'left', $which_valign = 'bottom')
951 {
952 // TTF:
953 if ($this->use_ttf) {
954 $size = $this->TTFBBoxSize($which_font['size'], $which_angle, $which_font['font'], $which_text);
955 $rads = deg2rad($which_angle);
956
957 if ($which_valign == 'center')
958 $which_ypos += $size[1]/2;
959 elseif ($which_valign == 'bottom')
960 $which_ypos += $size[1];
961
962 if ($which_halign == 'center')
963 $which_xpos -= ($size[0]/2) * cos($rads);
964 elseif ($which_halign == 'left')
965 $which_xpos += $size[0] * sin($rads);
966 elseif ($which_halign == 'right')
967 $which_xpos -= $size[0] * cos($rads);
968
969 ImageTTFText($this->img, $which_font['size'], $which_angle,
970 $which_xpos, $which_ypos, $which_color, $which_font['font'], $which_text);
971 }
972 // Fixed fonts:
973 else {
974 // Split the text by its lines, and count them
975 $which_text = ereg_replace("\r", "", $which_text);
976 $str = split("\n", $which_text);
977 $nlines = count($str);
978 $spacing = $this->line_spacing * ($nlines - 1);
979
980 // Vertical text:
981 // (Remember the alignment convention with vertical text)
982 if ($which_angle == 90) {
983 // The text goes around $which_xpos.
984 if ($which_halign == 'center')
985 $which_xpos -= ($nlines * ($which_font['height'] + $spacing))/2;
986
987 // Left alignment requires no modification to $xpos...
988 // Right-align it. $which_xpos designated the rightmost x coordinate.
989 elseif ($which_halign == 'right') {
990 $which_xpos -= ($nlines * ($which_font['height'] + $spacing));
991 }
992
993 $ypos = $which_ypos;
994 for($i = 0; $i < $nlines; $i++) {
995 // Center the text vertically around $which_ypos (each line)
996 if ($which_valign == 'center')
997 $ypos = $which_ypos + (strlen($str[$i]) * $which_font['width']) / 2;
998 // Make the text finish (vertically) at $which_ypos
999 if ($which_valign == 'bottom')
1000 $ypos = $which_ypos + strlen($str[$i]) * $which_font['width'];
1001
1002 ImageStringUp($this->img, $which_font['font'],
1003 $i * ($which_font['height'] + $spacing) + $which_xpos,
1004 $ypos, $str[$i], $which_color);
1005 }
1006 }
1007 // Horizontal text:
1008 else {
1009 // The text goes above $which_ypos
1010 if ($which_valign == 'top')
1011 $which_ypos -= $nlines * ($which_font['height'] + $spacing);
1012 // The text is centered around $which_ypos
1013 if ($which_valign == 'center')
1014 $which_ypos -= ($nlines * ($which_font['height'] + $spacing))/2;
1015 // valign = 'bottom' requires no modification
1016
1017 $xpos = $which_xpos;
1018 for($i = 0; $i < $nlines; $i++) {
1019 // center the text around $which_xpos
1020 if ($which_halign == 'center')
1021 $xpos = $which_xpos - (strlen($str[$i]) * $which_font['width'])/2;
1022 // make the text finish at $which_xpos
1023 if ($which_halign == 'right')
1024 $xpos = $which_xpos - strlen($str[$i]) * $which_font['width'];
1025
1026 ImageString($this->img, $which_font['font'], $xpos,
1027 $i * ($which_font['height'] + $spacing) + $which_ypos,
1028 $str[$i], $which_color);
1029 }
1030 }
1031 }
1032 return TRUE;
1033 } // function DrawText()
1034
1035
1036 /////////////////////////////////////////////
1037 /////////// INPUT / OUTPUT CONTROL
1038 /////////////////////////////////////////////
1039
1040 /*!
1041 * Sets output file format.
1042 */
1043 function SetFileFormat($format)
1044 {
1045 $asked = $this->CheckOption($format, 'jpg, png, gif, wbmp', __FUNCTION__);
1046
1047 switch ($asked) {
1048 case 'jpg':
1049 if (imagetypes() & IMG_JPG)
1050 $this->file_format = 'jpg';
1051 return TRUE;
1052 break;
1053 case 'png':
1054 if (imagetypes() & IMG_PNG)
1055 $this->file_format = 'png';
1056 return TRUE;
1057 break;
1058 case 'gif':
1059 if (imagetypes() & IMG_GIF)
1060 $this->file_format = 'gif';
1061 return TRUE;
1062 break;
1063 case 'wbmp':
1064 if (imagetypes() & IMG_WBMP)
1065 $this->file_format = 'wbmp';
1066 return TRUE;
1067 break;
1068 default:
1069 $this->PrintError("SetFileFormat():File format '$format' not supported");
1070 return FALSE;
1071 }
1072 }
1073
1074
1075 /*!
1076 * Selects an input file to be used as graph background and scales or tiles this image
1077 * to fit the sizes.
1078 * \param input_file string Path to the file to be used (jpeg, png and gif accepted)
1079 * \param mode string 'centeredtile', 'tile', 'scale' (the image to the graph's size)
1080 */
1081 function SetBgImage($input_file, $mode='centeredtile')
1082 {
1083 $this->bgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
1084 $this->bgimg = $input_file;
1085 }
1086
1087 /*!
1088 * Selects an input file to be used as plot area background and scales or tiles this image
1089 * to fit the sizes.
1090 * \param input_file string Path to the file to be used (jpeg, png and gif accepted)
1091 * \param mode string 'centeredtile', 'tile', 'scale' (the image to the graph's size)
1092 */
1093 function SetPlotAreaBgImage($input_file, $mode='tile')
1094 {
1095 $this->plotbgmode = $this->CheckOption($mode, 'tile, centeredtile, scale', __FUNCTION__);
1096 $this->plotbgimg = $input_file;
1097 }
1098
1099
1100 /*!
1101 * Sets the name of the file to be used as output file.
1102 */
1103 function SetOutputFile($which_output_file)
1104 {
1105 $this->output_file = $which_output_file;
1106 return TRUE;
1107 }
1108
1109 /*!
1110 * Sets the output image as 'inline', that is: no Content-Type headers are sent
1111 * to the browser. Needed if you want to embed the images.
1112 */
1113 function SetIsInline($which_ii)
1114 {
1115 $this->is_inline = (bool)$which_ii;
1116 return TRUE;
1117 }
1118
1119
1120 /*!
1121 * Performs the actual outputting of the generated graph.
1122 */
1123 function PrintImage()
1124 {
1125 // Browser cache stuff submitted by Thiemo Nagel
1126 if ( (! $this->browser_cache) && (! $this->is_inline)) {
1127 header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
1128 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT');
1129 header('Cache-Control: no-cache, must-revalidate');
1130 header('Pragma: no-cache');
1131 }
1132
1133 switch($this->file_format) {
1134 case 'png':
1135 if (! $this->is_inline) {
1136 Header('Content-type: image/png');
1137 }
1138 if ($this->is_inline && $this->output_file != '') {
1139 ImagePng($this->img, $this->output_file);
1140 } else {
1141 ImagePng($this->img);
1142 }
1143 break;
1144 case 'jpg':
1145 if (! $this->is_inline) {
1146 Header('Content-type: image/jpeg');
1147 }
1148 if ($this->is_inline && $this->output_file != '') {
1149 ImageJPEG($this->img, $this->output_file);
1150 } else {
1151 ImageJPEG($this->img);
1152 }
1153 break;
1154 case 'gif':
1155 if (! $this->is_inline) {
1156 Header('Content-type: image/gif');
1157 }
1158 if ($this->is_inline && $this->output_file != '') {
1159 ImageGIF($this->img, $this->output_file);
1160 } else {
1161 ImageGIF($this->img);
1162 }
1163
1164 break;
1165 case 'wbmp': // wireless bitmap, 2 bit.
1166 if (! $this->is_inline) {
1167 Header('Content-type: image/wbmp');
1168 }
1169 if ($this->is_inline && $this->output_file != '') {
1170 ImageWBMP($this->img, $this->output_file);
1171 } else {
1172 ImageWBMP($this->img);
1173 }
1174
1175 break;
1176 default:
1177 $this->PrintError('PrintImage(): Please select an image type!');
1178 break;
1179 }
1180 return TRUE;
1181 }
1182