| 1 | <?php |
|---|
| 2 | /* |
|---|
| 3 | Graph Class. PHP Class to draw line, point, bar, and area graphs, including numeric x-axis and double y-axis. |
|---|
| 4 | Version: 1.6.4 |
|---|
| 5 | Copyright (C) 2000 Herman Veluwenkamp |
|---|
| 6 | |
|---|
| 7 | This library is free software; you can redistribute it and/or |
|---|
| 8 | modify it under the terms of the GNU Lesser General Public |
|---|
| 9 | License as published by the Free Software Foundation; either |
|---|
| 10 | version 2.1 of the License, or (at your option) any later version. |
|---|
| 11 | |
|---|
| 12 | This library is distributed in the hope that it will be useful, |
|---|
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 15 | Lesser General Public License for more details. |
|---|
| 16 | |
|---|
| 17 | You should have received a copy of the GNU Lesser General Public |
|---|
| 18 | License along with this library; if not, write to the Free Software |
|---|
| 19 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 20 | |
|---|
| 21 | Copy of GNU Lesser General Public License at: http://www.gnu.org/copyleft/lesser.txt |
|---|
| 22 | Contact author at: hermanV@subdimension.com |
|---|
| 23 | */ |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | class graph { |
|---|
| 27 | var $image; |
|---|
| 28 | var $debug = FALSE; // be careful!! |
|---|
| 29 | var $calculated = array(); // array of computed values for chart |
|---|
| 30 | var $parameter = array( // input parameters |
|---|
| 31 | 'width' => 320, // default width of image |
|---|
| 32 | 'height' => 240, // default height of image |
|---|
| 33 | 'file_name' => 'none', // name of file for file to be saved as. |
|---|
| 34 | // NOTE: no suffix required. this is determined from output_format below. |
|---|
| 35 | 'output_format' => 'PNG', // image output format. 'GIF', 'PNG', 'JPEG'. default 'PNG'. |
|---|
| 36 | |
|---|
| 37 | 'seconds_to_live' => 0, // expiry time in seconds (for HTTP header) |
|---|
| 38 | 'hours_to_live' => 0, // expiry time in hours (for HTTP header) |
|---|
| 39 | 'path_to_fonts' => 'fonts/', // path to fonts folder. don't forget *trailing* slash!! |
|---|
| 40 | // for WINDOZE this may need to be the full path, not relative. |
|---|
| 41 | |
|---|
| 42 | 'title' => 'Graph Title', // text for graph title |
|---|
| 43 | 'title_font' => 'ARIALBD.TTF', // title text font. don't forget to set 'path_to_fonts' above. |
|---|
| 44 | 'title_size' => 14, // title text point size |
|---|
| 45 | 'title_colour' => 'black', // colour for title text |
|---|
| 46 | |
|---|
| 47 | 'x_label' => '', // if this is set then this text is printed on bottom axis of graph. |
|---|
| 48 | 'y_label_left' => '', // if this is set then this text is printed on left axis of graph. |
|---|
| 49 | 'y_label_right' => '', // if this is set then this text is printed on right axis of graph. |
|---|
| 50 | |
|---|
| 51 | 'label_size' => 10, // label text point size |
|---|
| 52 | 'label_font' => 'ARIALBD.TTF', // label text font. don't forget to set 'path_to_fonts' above. |
|---|
| 53 | 'label_colour' => 'gray33', // label text colour |
|---|
| 54 | 'y_label_angle' => 90, // rotation of y axis label |
|---|
| 55 | |
|---|
| 56 | 'x_label_angle' => 0, // rotation of y axis label |
|---|
| 57 | |
|---|
| 58 | 'outer_padding' => 8, // padding around outer text. i.e. title, y label, and x label. |
|---|
| 59 | 'inner_padding' => 6, // padding beteen axis text and graph. |
|---|
| 60 | 'outer_border' => 'none', // colour of border aound image, or 'none'. |
|---|
| 61 | 'inner_border' => 'black', // colour of border around actual graph, or 'none'. |
|---|
| 62 | 'inner_border_type' => 'box', // 'box' for all four sides, 'axis' for x/y axis only, |
|---|
| 63 | // 'y' or 'y-left' for y axis only, 'y-right' for right y axis only, |
|---|
| 64 | // 'x' for x axis only, 'u' for both left and right y axis and x axis. |
|---|
| 65 | 'outer_background' => 'none', // background colour of entire image. |
|---|
| 66 | 'inner_background' => 'none', // background colour of plot area. |
|---|
| 67 | |
|---|
| 68 | 'y_min_left' => 0, // this will be reset to minimum value if there is a value lower than this. |
|---|
| 69 | 'y_max_left' => 0, // this will be reset to maximum value if there is a value higher than this. |
|---|
| 70 | 'y_min_right' => 0, // this will be reset to minimum value if there is a value lower than this. |
|---|
| 71 | 'y_max_right' => 0, // this will be reset to maximum value if there is a value higher than this. |
|---|
| 72 | 'x_min' => 0, // only used if x axis is numeric. |
|---|
| 73 | 'x_max' => 0, // only used if x axis is numeric. |
|---|
| 74 | |
|---|
| 75 | 'y_resolution_left' => 2, // scaling for rounding of y axis max value. |
|---|
| 76 | // if max y value is 8645 then |
|---|
| 77 | // if y_resolution is 0, then y_max becomes 9000. |
|---|
| 78 | // if y_resolution is 1, then y_max becomes 8700. |
|---|
| 79 | // if y_resolution is 2, then y_max becomes 8650. |
|---|
| 80 | // if y_resolution is 3, then y_max becomes 8645. |
|---|
| 81 | // get it? |
|---|
| 82 | 'y_decimal_left' => 0, // number of decimal places for y_axis text. |
|---|
| 83 | 'y_resolution_right' => 2, // ... same for right hand side |
|---|
| 84 | 'y_decimal_right' => 0, // ... same for right hand side |
|---|
| 85 | 'x_resolution' => 2, // only used if x axis is numeric. |
|---|
| 86 | 'x_decimal' => 0, // only used if x axis is numeric. |
|---|
| 87 | |
|---|
| 88 | 'point_size' => 4, // default point size. use even number for diamond or triangle to get nice look. |
|---|
| 89 | 'brush_size' => 4, // default brush size for brush line. |
|---|
| 90 | 'brush_type' => 'circle', // type of brush to use to draw line. choose from the following |
|---|
| 91 | // 'circle', 'square', 'horizontal', 'vertical', 'slash', 'backslash' |
|---|
| 92 | 'bar_size' => 0.8, // size of bar to draw. <1 bars won't touch |
|---|
| 93 | // 1 is full width - i.e. bars will touch. |
|---|
| 94 | // >1 means bars will overlap. |
|---|
| 95 | 'bar_spacing' => 10, // space in pixels between group of bars for each x value. |
|---|
| 96 | 'shadow_offset' => 3, // draw shadow at this offset, unless overidden by data parameter. |
|---|
| 97 | 'shadow' => 'grayCC', // 'none' or colour of shadow. |
|---|
| 98 | 'shadow_below_axis' => FALSE, // whether to draw shadows of bars and areas below the x/zero axis. |
|---|
| 99 | |
|---|
| 100 | |
|---|
| 101 | 'x_axis_gridlines' => 'auto', // if set to a number then x axis is treated as numeric. |
|---|
| 102 | 'y_axis_gridlines' => 6, // number of gridlines on y axis. |
|---|
| 103 | 'zero_axis' => 'none', // colour to draw zero-axis, or 'none'. |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | 'axis_font' => 'ARIAL.TTF', // axis text font. don't forget to set 'path_to_fonts' above. |
|---|
| 107 | 'axis_size' => 9, // axis text font size in points |
|---|
| 108 | 'axis_colour' => 'gray33', // colour of axis text. |
|---|
| 109 | 'y_axis_angle' => 0, // rotation of axis text. |
|---|
| 110 | 'x_axis_angle' => 90, // rotation of axis text. |
|---|
| 111 | |
|---|
| 112 | 'y_axis_text_left' => 1, // whether to print left hand y axis text. if 0 no text, if 1 all ticks have text, |
|---|
| 113 | 'x_axis_text' => 1, // if 4 then print every 4th tick and text, etc... |
|---|
| 114 | 'y_axis_text_right' => 0, // behaviour same as above for right hand y axis. |
|---|
| 115 | |
|---|
| 116 | 'x_offset' => 0.5, // x axis tick offset from y axis as fraction of tick spacing. |
|---|
| 117 | 'y_ticks_colour' => 'black', // colour to draw y ticks, or 'none'. |
|---|
| 118 | 'x_ticks_colour' => 'black', // colour to draw x ticks, or 'none'. |
|---|
| 119 | 'y_grid' => 'line', // grid lines. set to 'line' or 'dash'... |
|---|
| 120 | 'x_grid' => 'line', // or if set to 'none' print nothing. |
|---|
| 121 | 'grid_colour' => 'grayEE', // default grid colour. |
|---|
| 122 | 'tick_length' => 4, // length of ticks in pixels. can be negative. i.e. outside data drawing area. |
|---|
| 123 | |
|---|
| 124 | |
|---|
| 125 | 'legend' => 'none', // default. no legend. |
|---|
| 126 | // otherwise: 'top-left', 'top-right', 'bottom-left', 'bottom-right', |
|---|
| 127 | // 'outside-top', 'outside-bottom', 'outside-left', or 'outside-right'. |
|---|
| 128 | 'legend_offset' => 10, // offset in pixels from graph or outside border. |
|---|
| 129 | 'legend_padding' => 5, // padding around legend text. |
|---|
| 130 | 'legend_font' => 'ARIAL.TTF', // legend text font. don't forget to set 'path_to_fonts' above. |
|---|
| 131 | 'legend_size' => 9, // legend text point size. |
|---|
| 132 | 'legend_colour' => 'black', // legend text colour. |
|---|
| 133 | 'legend_border' => 'none', // legend border colour, or 'none'. |
|---|
| 134 | |
|---|
| 135 | 'decimal_point' => '.', // symbol for decimal separation '.' or ',' *european support. |
|---|
| 136 | 'thousand_sep' => ',', // symbol for thousand separation ',' or '' |
|---|
| 137 | |
|---|
| 138 | ); |
|---|
| 139 | |
|---|
| 140 | |
|---|
| 141 | function graph() { |
|---|
| 142 | if (func_num_args() == 2) { |
|---|
| 143 | $this->parameter['width'] = func_get_arg(0); |
|---|
| 144 | $this->parameter['height'] = func_get_arg(1); |
|---|
| 145 | } |
|---|
| 146 | //$this->boundaryBox = array( |
|---|
| 147 | $this->calculated['boundary_box'] = array( |
|---|
| 148 | 'left' => 0, |
|---|
| 149 | 'top' => 0, |
|---|
| 150 | 'right' => $this->parameter['width'] - 1, |
|---|
| 151 | 'bottom' => $this->parameter['height'] - 1); |
|---|
| 152 | |
|---|
| 153 | $this->init_colours(); |
|---|
| 154 | |
|---|
| 155 | //ImageColorTransparent($this->image, $this->colour['white']); // colour for transparency |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | // init all text - title, labels, and axis text. |
|---|
| 159 | function init() { |
|---|
| 160 | $this->calculated['outer_border'] = $this->calculated['boundary_box']; |
|---|
| 161 | |
|---|
| 162 | // outer padding |
|---|
| 163 | $this->calculated['boundary_box']['left'] += $this->parameter['outer_padding']; |
|---|
| 164 | $this->calculated['boundary_box']['top'] += $this->parameter['outer_padding']; |
|---|
| 165 | $this->calculated['boundary_box']['right'] -= $this->parameter['outer_padding']; |
|---|
| 166 | $this->calculated['boundary_box']['bottom'] -= $this->parameter['outer_padding']; |
|---|
| 167 | |
|---|
| 168 | $this->init_x_axis(); |
|---|
| 169 | $this->init_y_axis(); |
|---|
| 170 | $this->init_legend(); |
|---|
| 171 | $this->init_labels(); |
|---|
| 172 | |
|---|
| 173 | // take into account tick lengths |
|---|
| 174 | $this->calculated['bottom_inner_padding'] = $this->parameter['inner_padding']; |
|---|
| 175 | if (($this->parameter['x_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) |
|---|
| 176 | $this->calculated['bottom_inner_padding'] -= $this->parameter['tick_length']; |
|---|
| 177 | $this->calculated['boundary_box']['bottom'] -= $this->calculated['bottom_inner_padding']; |
|---|
| 178 | |
|---|
| 179 | $this->calculated['left_inner_padding'] = $this->parameter['inner_padding']; |
|---|
| 180 | if ($this->parameter['y_axis_text_left']) { |
|---|
| 181 | if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) |
|---|
| 182 | $this->calculated['left_inner_padding'] -= $this->parameter['tick_length']; |
|---|
| 183 | } |
|---|
| 184 | $this->calculated['boundary_box']['left'] += $this->calculated['left_inner_padding']; |
|---|
| 185 | |
|---|
| 186 | $this->calculated['right_inner_padding'] = $this->parameter['inner_padding']; |
|---|
| 187 | if ($this->parameter['y_axis_text_right']) { |
|---|
| 188 | if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) |
|---|
| 189 | $this->calculated['right_inner_padding'] -= $this->parameter['tick_length']; |
|---|
| 190 | } |
|---|
| 191 | $this->calculated['boundary_box']['right'] -= $this->calculated['right_inner_padding']; |
|---|
| 192 | |
|---|
| 193 | // boundaryBox now has coords for plotting area. |
|---|
| 194 | $this->calculated['inner_border'] = $this->calculated['boundary_box']; |
|---|
| 195 | |
|---|
| 196 | $this->init_data(); |
|---|
| 197 | $this->init_x_ticks(); |
|---|
| 198 | $this->init_y_ticks(); |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | |
|---|
| 202 | function draw_text() { |
|---|
| 203 | $colour = $this->parameter['outer_background']; |
|---|
| 204 | if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'fill'); // graph background |
|---|
| 205 | |
|---|
| 206 | // draw border around image |
|---|
| 207 | $colour = $this->parameter['outer_border']; |
|---|
| 208 | if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'box'); // graph border |
|---|
| 209 | |
|---|
| 210 | $this->draw_title(); |
|---|
| 211 | $this->draw_x_label(); |
|---|
| 212 | $this->draw_y_label_left(); |
|---|
| 213 | $this->draw_y_label_right(); |
|---|
| 214 | $this->draw_x_axis(); |
|---|
| 215 | $this->draw_y_axis(); |
|---|
| 216 | if ($this->calculated['y_axis_left']['has_data']) $this->draw_zero_axis_left(); // either draw zero axis on left |
|---|
| 217 | else if ($this->calculated['y_axis_right']['has_data']) $this->draw_zero_axis_right(); // ... or right. |
|---|
| 218 | $this->draw_legend(); |
|---|
| 219 | |
|---|
| 220 | // draw border around plot area |
|---|
| 221 | $colour = $this->parameter['inner_background']; |
|---|
| 222 | if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, 'fill'); // graph background |
|---|
| 223 | |
|---|
| 224 | // draw border around image |
|---|
| 225 | $colour = $this->parameter['inner_border']; |
|---|
| 226 | if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, $this->parameter['inner_border_type']); // graph border |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | function draw_stack() { |
|---|
| 230 | $this->init(); |
|---|
| 231 | $this->draw_text(); |
|---|
| 232 | |
|---|
| 233 | $yOrder = $this->y_order; // save y_order data. |
|---|
| 234 | // iterate over each data set. order is very important if you want to see data correctly. remember shadows!! |
|---|
| 235 | foreach ($yOrder as $set) { |
|---|
| 236 | $this->y_order = array($set); |
|---|
| 237 | $this->init_data(); |
|---|
| 238 | $this->draw_data(); |
|---|
| 239 | } |
|---|
| 240 | $this->y_order = $yOrder; // revert y_order data. |
|---|
| 241 | |
|---|
| 242 | $this->output(); |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | function draw() { |
|---|
| 246 | $this->init(); |
|---|
| 247 | $this->draw_text(); |
|---|
| 248 | $this->draw_data(); |
|---|
| 249 | $this->output(); |
|---|
| 250 | } |
|---|
| 251 | |
|---|
| 252 | // draw a data set |
|---|
| 253 | function draw_set($order, $set, $offset) { |
|---|
| 254 | // defaults |
|---|
| 255 | |
|---|
| 256 | // |
|---|
| 257 | if ($offset) { |
|---|
| 258 | if (isset($this->y_format[$set]['shadow'])) $colour = $this->y_format[$set]['shadow']; |
|---|
| 259 | else $colour = $this->parameter['shadow']; |
|---|
| 260 | } else { |
|---|
| 261 | $colour = $this->y_format[$set]['colour']; |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | $point = isset($this->y_format[$set]['point']) ? $this->y_format[$set]['point'] : 'none'; |
|---|
| 265 | $pointSize = isset($this->y_format[$set]['point_size']) ? $this->y_format[$set]['point_size'] : $this->parameter['point_size']; |
|---|
| 266 | $line = isset($this->y_format[$set]['line']) ? $this->y_format[$set]['line'] : 'none'; |
|---|
| 267 | $brushType = isset($this->y_format[$set]['brush_type']) ? $this->y_format[$set]['brush_type'] : $this->parameter['brush_type']; |
|---|
| 268 | $brushSize = isset($this->y_format[$set]['brush_size']) ? $this->y_format[$set]['brush_size'] : $this->parameter['brush_size']; |
|---|
| 269 | $bar = isset($this->y_format[$set]['bar']) ? $this->y_format[$set]['bar'] : 'none'; |
|---|
| 270 | $barSize = isset($this->y_format[$set]['bar_size']) ? $this->y_format[$set]['bar_size'] : $this->parameter['bar_size']; |
|---|
| 271 | $area = isset($this->y_format[$set]['area']) ? $this->y_format[$set]['area'] : 'none'; |
|---|
| 272 | |
|---|
| 273 | $lastX = 0; |
|---|
| 274 | $lastY = 'none'; |
|---|
| 275 | $fromX = 0; |
|---|
| 276 | $fromY = 'none'; |
|---|
| 277 | |
|---|
| 278 | //print "set $set<BR>"; |
|---|
| 279 | //expand_pre($this->calculated['y_plot']); |
|---|
| 280 | $index = -1; |
|---|
| 281 | foreach ($this->x_data as $x) { |
|---|
| 282 | $index++; |
|---|
| 283 | |
|---|
| 284 | //print "index $index<BR>"; |
|---|
| 285 | $thisY = $this->calculated['y_plot'][$set][$index]; |
|---|
| 286 | $thisX = $this->calculated['x_plot'][$index]; |
|---|
| 287 | |
|---|
| 288 | //print "$thisX, $thisY <BR>"; |
|---|
| 289 | //_p("thisX=$thisX, thisY=$thisY, bar=$bar, barSize=$barSize, colour=$colour, offset=$offset, set=$set"); |
|---|
| 290 | |
|---|
| 291 | /* */ |
|---|
| 292 | |
|---|
| 293 | |
|---|
| 294 | if (($bar!='none') && (string)$thisY != 'none') $this->bar($thisX, $thisY, $bar, $barSize, $colour, $offset, $set); |
|---|
| 295 | |
|---|
| 296 | if (($area!='none') && (((string)$lastY != 'none') && ((string)$thisY != 'none'))) |
|---|
| 297 | $this->area($lastX, $lastY, $thisX, $thisY, $area, $colour, $offset); |
|---|
| 298 | |
|---|
| 299 | if (($point!='none') && (string)$thisY != 'none') $this->plot($thisX, $thisY, $point, $pointSize, $colour, $offset); |
|---|
| 300 | |
|---|
| 301 | if (($line!='none') && ((string)$thisY != 'none')) { |
|---|
| 302 | if ((string)$fromY != 'none') |
|---|
| 303 | $this->line($fromX, $fromY, $thisX, $thisY, $line, $brushType, $brushSize, $colour, $offset); |
|---|
| 304 | |
|---|
| 305 | $fromY = $thisY; // start next line from here |
|---|
| 306 | $fromX = $thisX; // ... |
|---|
| 307 | } else { |
|---|
| 308 | $fromY = 'none'; |
|---|
| 309 | $fromX = 'none'; |
|---|
| 310 | } |
|---|
| 311 | |
|---|
| 312 | $lastX = $thisX; |
|---|
| 313 | $lastY = $thisY; |
|---|
| 314 | |
|---|
| 315 | } |
|---|
| 316 | } |
|---|
| 317 | |
|---|
| 318 | function draw_data() { |
|---|
| 319 | // cycle thru y data to be plotted |
|---|
| 320 | // first check for drop shadows... |
|---|
| 321 | foreach ($this->y_order as $order => $set) { |
|---|
| 322 | |
|---|
| 323 | $offset = $this->parameter['shadow_offset']; |
|---|
| 324 | if (isset($this->y_format[$set]['shadow_offset'])) $offset = $this->y_format[$set]['shadow_offset']; |
|---|
| 325 | |
|---|
| 326 | $colour = $this->parameter['shadow']; |
|---|
| 327 | if (isset($this->y_format[$set]['shadow'])) $colour = $this->y_format[$set]['shadow']; |
|---|
| 328 | |
|---|
| 329 | if (isset($colour)) if ($colour != 'none') $this->draw_set($order, $set, $offset); |
|---|
| 330 | } |
|---|
| 331 | |
|---|
| 332 | // then draw data |
|---|
| 333 | foreach ($this->y_order as $order => $set) { |
|---|
| 334 | $this->draw_set($order, $set, 0); |
|---|
| 335 | } |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | function draw_legend() { |
|---|
| 339 | $position = $this->parameter['legend']; |
|---|
| 340 | if ($position == 'none') return; // abort if no border |
|---|
| 341 | |
|---|
| 342 | $borderColour = $this->parameter['legend_border']; |
|---|
| 343 | $offset = $this->parameter['legend_offset']; |
|---|
| 344 | $padding = $this->parameter['legend_padding']; |
|---|
| 345 | $height = $this->calculated['legend']['boundary_box_all']['height']; |
|---|
| 346 | $width = $this->calculated['legend']['boundary_box_all']['width']; |
|---|
| 347 | $graphTop = $this->calculated['boundary_box']['top']; |
|---|
| 348 | $graphBottom = $this->calculated['boundary_box']['bottom']; |
|---|
| 349 | $graphLeft = $this->calculated['boundary_box']['left']; |
|---|
| 350 | $graphRight = $this->calculated['boundary_box']['right']; |
|---|
| 351 | $outsideRight = $this->calculated['outer_border']['right']; |
|---|
| 352 | $outsideBottom = $this->calculated['outer_border']['bottom']; |
|---|
| 353 | switch ($position) { |
|---|
| 354 | case 'top-left': |
|---|
| 355 | $top = $graphTop + $offset; |
|---|
| 356 | $bottom = $graphTop + $height + $offset; |
|---|
| 357 | $left = $graphLeft + $offset; |
|---|
| 358 | $right = $graphLeft + $width + $offset; |
|---|
| 359 | |
|---|
| 360 | break; |
|---|
| 361 | case 'top-right': |
|---|
| 362 | $top = $graphTop + $offset; |
|---|
| 363 | $bottom = $graphTop + $height + $offset; |
|---|
| 364 | $left = $graphRight - $width - $offset; |
|---|
| 365 | $right = $graphRight - $offset; |
|---|
| 366 | |
|---|
| 367 | break; |
|---|
| 368 | case 'bottom-left': |
|---|
| 369 | $top = $graphBottom - $height - $offset; |
|---|
| 370 | $bottom = $graphBottom - $offset; |
|---|
| 371 | $left = $graphLeft + $offset; |
|---|
| 372 | $right = $graphLeft + $width + $offset; |
|---|
| 373 | |
|---|
| 374 | break; |
|---|
| 375 | case 'bottom-right': |
|---|
| 376 | $top = $graphBottom - $height - $offset; |
|---|
| 377 | $bottom = $graphBottom - $offset; |
|---|
| 378 | $left = $graphRight - $width - $offset; |
|---|
| 379 | $right = $graphRight - $offset; |
|---|
| 380 | break; |
|---|
| 381 | |
|---|
| 382 | case 'outside-top' : |
|---|
| 383 | $top = $graphTop; |
|---|
| 384 | $bottom = $graphTop + $height; |
|---|
| 385 | $left = $outsideRight - $width - $offset; |
|---|
| 386 | $right = $outsideRight - $offset; |
|---|
| 387 | break; |
|---|
| 388 | |
|---|
| 389 | case 'outside-bottom' : |
|---|
| 390 | $top = $graphBottom - $height; |
|---|
| 391 | $bottom = $graphBottom; |
|---|
| 392 | $left = $outsideRight - $width - $offset; |
|---|
| 393 | $right = $outsideRight - $offset; |
|---|
| 394 | break; |
|---|
| 395 | |
|---|
| 396 | case 'outside-left' : |
|---|
| 397 | $top = $outsideBottom - $height - $offset; |
|---|
| 398 | $bottom = $outsideBottom - $offset; |
|---|
| 399 | $left = $graphLeft; |
|---|
| 400 | $right = $graphLeft + $width; |
|---|
| 401 | break; |
|---|
| 402 | |
|---|
| 403 | case 'outside-right' : |
|---|
| 404 | $top = $outsideBottom - $height - $offset; |
|---|
| 405 | $bottom = $outsideBottom - $offset; |
|---|
| 406 | $left = $graphRight - $width; |
|---|
| 407 | $right = $graphRight; |
|---|
| 408 | break; |
|---|
| 409 | default: // default is top left. no particular reason. |
|---|
| 410 | $top = $this->calculated['boundary_box']['top']; |
|---|
| 411 | $bottom = $this->calculated['boundary_box']['top'] + $this->calculated['legend']['boundary_box_all']['height']; |
|---|
| 412 | $left = $this->calculated['boundary_box']['left']; |
|---|
| 413 | $right = $this->calculated['boundary_box']['right'] + $this->calculated['legend']['boundary_box_all']['width']; |
|---|
| 414 | |
|---|
| 415 | } |
|---|
| 416 | // legend border |
|---|
| 417 | if($borderColour!='none') $this->draw_rectangle(array('top' => $top, |
|---|
| 418 | 'left' => $left, |
|---|
| 419 | 'bottom' => $bottom, |
|---|
| 420 | 'right' => $right), $this->parameter['legend_border'], 'box'); |
|---|
| 421 | |
|---|
| 422 | // legend text |
|---|
| 423 | $legendText = array('points' => $this->parameter['legend_size'], |
|---|
| 424 | 'angle' => 0, |
|---|
| 425 | 'font' => $this->parameter['legend_font'], |
|---|
| 426 | 'colour' => $this->parameter['legend_colour']); |
|---|
| 427 | |
|---|
| 428 | $box = $this->calculated['legend']['boundary_box_max']['height']; // use max height for legend square size. |
|---|
| 429 | $x = $left + $padding; |
|---|
| 430 | $x_text = $x + $box * 2; |
|---|
| 431 | $y = $top + $padding; |
|---|
| 432 | |
|---|
| 433 | foreach ($this->y_order as $set) { |
|---|
| 434 | $legendText['text'] = $this->calculated['legend']['text'][$set]; |
|---|
| 435 | if ($legendText['text'] != 'none') { |
|---|
| 436 | // if text exists then draw box and text |
|---|
| 437 | $boxColour = $this->colour[$this->y_format[$set]['colour']]; |
|---|
| 438 | |
|---|
| 439 | // draw box |
|---|
| 440 | ImageFilledRectangle($this->image, $x, $y, $x + $box, $y + $box, $boxColour); |
|---|
| 441 | |
|---|
| 442 | // draw text |
|---|
| 443 | $coords = array('x' => $x + $box * 2, 'y' => $y, 'reference' => 'top-left'); |
|---|
| 444 | $legendText['boundary_box'] = $this->calculated['legend']['boundary_box'][$set]; |
|---|
| 445 | $this->update_boundaryBox($legendText['boundary_box'], $coords); |
|---|
| 446 | $this->print_TTF($legendText); |
|---|
| 447 | $y += $padding + $box; |
|---|
| 448 | } |
|---|
| 449 | } |
|---|
| 450 | |
|---|
| 451 | } |
|---|
| 452 | |
|---|
| 453 | function draw_y_label_right() { |
|---|
| 454 | if (!$this->parameter['y_label_right']) return; |
|---|
| 455 | $x = $this->calculated['boundary_box']['right'] + $this->parameter['inner_padding']; |
|---|
| 456 | if ($this->parameter['y_axis_text_right']) $x += $this->calculated['y_axis_right']['boundary_box_max']['width'] |
|---|
| 457 | + $this->calculated['right_inner_padding']; |
|---|
| 458 | $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2; |
|---|
| 459 | |
|---|
| 460 | $label = $this->calculated['y_label_right']; |
|---|
| 461 | $coords = array('x' => $x, 'y' => $y, 'reference' => 'left-center'); |
|---|
| 462 | $this->update_boundaryBox($label['boundary_box'], $coords); |
|---|
| 463 | $this->print_TTF($label); |
|---|
| 464 | } |
|---|
| 465 | |
|---|
| 466 | |
|---|
| 467 | function draw_y_label_left() { |
|---|
| 468 | if (!$this->parameter['y_label_left']) return; |
|---|
| 469 | $x = $this->calculated['boundary_box']['left'] - $this->parameter['inner_padding']; |
|---|
| 470 | if ($this->parameter['y_axis_text_left']) $x -= $this->calculated['y_axis_left']['boundary_box_max']['width'] |
|---|
| 471 | + $this->calculated['left_inner_padding']; |
|---|
| 472 | $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2; |
|---|
| 473 | |
|---|
| 474 | $label = $this->calculated['y_label_left']; |
|---|
| 475 | $coords = array('x' => $x, 'y' => $y, 'reference' => 'right-center'); |
|---|
| 476 | $this->update_boundaryBox($label['boundary_box'], $coords); |
|---|
| 477 | $this->print_TTF($label); |
|---|
| 478 | } |
|---|
| 479 | |
|---|
| 480 | function draw_title() { |
|---|
| 481 | if (!$this->parameter['title']) return; |
|---|
| 482 | //$y = $this->calculated['outside_border']['top'] + $this->parameter['outer_padding']; |
|---|
| 483 | $y = $this->calculated['boundary_box']['top'] - $this->parameter['outer_padding']; |
|---|
| 484 | $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2; |
|---|
| 485 | $label = $this->calculated['title']; |
|---|
| 486 | $coords = array('x' => $x, 'y' => $y, 'reference' => 'bottom-center'); |
|---|
| 487 | $this->update_boundaryBox($label['boundary_box'], $coords); |
|---|
| 488 | $this->print_TTF($label); |
|---|
| 489 | } |
|---|
| 490 | |
|---|
| 491 | function draw_x_label() { |
|---|
| 492 | if (!$this->parameter['x_label']) return; |
|---|
| 493 | $y = $this->calculated['boundary_box']['bottom'] + $this->parameter['inner_padding']; |
|---|
| 494 | if ($this->parameter['x_axis_text']) $y += $this->calculated['x_axis']['boundary_box_max']['height'] |
|---|
| 495 | + $this->calculated['bottom_inner_padding']; |
|---|
| 496 | $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2; |
|---|
| 497 | $label = $this->calculated['x_label']; |
|---|
| 498 | $coords = array('x' => $x, 'y' => $y, 'reference' => 'top-center'); |
|---|
| 499 | $this->update_boundaryBox($label['boundary_box'], $coords); |
|---|
| 500 | $this->print_TTF($label); |
|---|
| 501 | } |
|---|
| 502 | |
|---|
| 503 | function draw_zero_axis_left() { |
|---|
| 504 | $colour = $this->parameter['zero_axis']; |
|---|
| 505 | if ($colour == 'none') return; |
|---|
| 506 | // draw zero axis on left hand side |
|---|
| 507 | $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top'] + ($this->calculated['y_axis_left']['max'] * $this->calculated['y_axis_left']['factor'])); |
|---|
| 508 | ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]); |
|---|
| 509 | } |
|---|
| 510 | |
|---|
| 511 | function draw_zero_axis_right() { |
|---|
| 512 | $colour = $this->parameter['zero_axis']; |
|---|
| 513 | if ($colour == 'none') return; |
|---|
| 514 | // draw zero axis on right hand side |
|---|
| 515 | $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top'] + ($this->calculated['y_axis_right']['max'] * $this->calculated['y_axis_right']['factor'])); |
|---|
| 516 | ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]); |
|---|
| 517 | } |
|---|
| 518 | |
|---|
| 519 | function draw_x_axis() { |
|---|
| 520 | $gridColour = $this->colour[$this->parameter['grid_colour']]; |
|---|
| 521 | $tickColour = $this->colour[$this->parameter['x_ticks_colour']]; |
|---|
| 522 | $axis_colour = $this->parameter['axis_colour']; |
|---|
| 523 | $xGrid = $this->parameter['x_grid']; |
|---|
| 524 | $gridTop = $this->calculated['boundary_box']['top']; |
|---|
| 525 | $gridBottom = $this->calculated['boundary_box']['bottom']; |
|---|
| 526 | |
|---|
| 527 | if ($this->parameter['tick_length'] >= 0) { |
|---|
| 528 | $tickTop = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length']; |
|---|
| 529 | $tickBottom = $this->calculated['boundary_box']['bottom']; |
|---|
| 530 | $textBottom = $tickBottom + $this->calculated['bottom_inner_padding']; |
|---|
| 531 | } else { |
|---|
| 532 | $tickTop = $this->calculated['boundary_box']['bottom']; |
|---|
| 533 | $tickBottom = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length']; |
|---|
| 534 | $textBottom = $tickBottom + $this->calculated['bottom_inner_padding']; |
|---|
| 535 | } |
|---|
| 536 | |
|---|
| 537 | $axis_font = $this->parameter['axis_font']; |
|---|
| 538 | $axis_size = $this->parameter['axis_size']; |
|---|
| 539 | $axis_angle = $this->parameter['x_axis_angle']; |
|---|
| 540 | |
|---|
| 541 | if ($axis_angle == 0) $reference = 'top-center'; |
|---|
| 542 | if ($axis_angle > 0) $reference = 'top-right'; |
|---|
| 543 | if ($axis_angle < 0) $reference = 'top-left'; |
|---|
| 544 | if ($axis_angle == 90) $reference = 'top-center'; |
|---|
| 545 | |
|---|
| 546 | //generic tag information. applies to all axis text. |
|---|
| 547 | $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour); |
|---|
| 548 | |
|---|
| 549 | foreach ($this->calculated['x_axis']['tick_x'] as $set => $tickX) { |
|---|
| 550 | // draw x grid if colour specified |
|---|
| 551 | if ($xGrid != 'none') { |
|---|
| 552 | switch ($xGrid) { |
|---|
| 553 | case 'line': |
|---|
| 554 | ImageLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour); |
|---|
| 555 | break; |
|---|
| 556 | case 'dash': |
|---|
| 557 | ImageDashedLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour); |
|---|
| 558 | break; |
|---|
| 559 | } |
|---|
| 560 | } |
|---|
| 561 | |
|---|
| 562 | if ($this->parameter['x_axis_text'] && !($set % $this->parameter['x_axis_text'])) { // test if tick should be displayed |
|---|
| 563 | // draw tick |
|---|
| 564 | if ($tickColour != 'none') |
|---|
| 565 | ImageLine($this->image, round($tickX), round($tickTop), round($tickX), round($tickBottom), $tickColour); |
|---|
| 566 | |
|---|
| 567 | // draw axis text |
|---|
| 568 | $coords = array('x' => $tickX, 'y' => $textBottom, 'reference' => $reference); |
|---|
| 569 | $axisTag['text'] = $this->calculated['x_axis']['text'][$set]; |
|---|
| 570 | $axisTag['boundary_box'] = $this->calculated['x_axis']['boundary_box'][$set]; |
|---|
| 571 | $this->update_boundaryBox($axisTag['boundary_box'], $coords); |
|---|
| 572 | $this->print_TTF($axisTag); |
|---|
| 573 | } |
|---|
| 574 | } |
|---|
| 575 | } |
|---|
| 576 | |
|---|
| 577 | function draw_y_axis() { |
|---|
| 578 | $gridColour = $this->colour[$this->parameter['grid_colour']]; |
|---|
| 579 | $tickColour = $this->colour[$this->parameter['y_ticks_colour']]; |
|---|
| 580 | $axis_colour = $this->parameter['axis_colour']; |
|---|
| 581 | $yGrid = $this->parameter['y_grid']; |
|---|
| 582 | $gridLeft = $this->calculated['boundary_box']['left']; |
|---|
| 583 | $gridRight = $this->calculated['boundary_box']['right']; |
|---|
| 584 | |
|---|
| 585 | // axis font information |
|---|
| 586 | $axis_font = $this->parameter['axis_font']; |
|---|
| 587 | $axis_size = $this->parameter['axis_size']; |
|---|
| 588 | $axis_angle = $this->parameter['y_axis_angle']; |
|---|
| 589 | $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour); |
|---|
| 590 | |
|---|
| 591 | |
|---|
| 592 | if ($this->calculated['y_axis_left']['has_data']) { |
|---|
| 593 | // LEFT HAND SIDE |
|---|
| 594 | // left and right coords for ticks |
|---|
| 595 | if ($this->parameter['tick_length'] >= 0) { |
|---|
| 596 | $tickLeft = $this->calculated['boundary_box']['left']; |
|---|
| 597 | $tickRight = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length']; |
|---|
| 598 | } else { |
|---|
| 599 | $tickLeft = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length']; |
|---|
| 600 | $tickRight = $this->calculated['boundary_box']['left']; |
|---|
| 601 | } |
|---|
| 602 | $textRight = $tickLeft - $this->calculated['left_inner_padding']; |
|---|
| 603 | |
|---|
| 604 | if ($axis_angle == 0) $reference = 'right-center'; |
|---|
| 605 | if ($axis_angle > 0) $reference = 'right-top'; |
|---|
| 606 | if ($axis_angle < 0) $reference = 'right-bottom'; |
|---|
| 607 | if ($axis_angle == 90) $reference = 'right-center'; |
|---|
| 608 | |
|---|
| 609 | foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) { |
|---|
| 610 | // draw y grid if colour specified |
|---|
| 611 | if ($yGrid != 'none') { |
|---|
| 612 | switch ($yGrid) { |
|---|
| 613 | case 'line': |
|---|
| 614 | ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); |
|---|
| 615 | break; |
|---|
| 616 | case 'dash': |
|---|
| 617 | ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); |
|---|
| 618 | break; |
|---|
| 619 | } |
|---|
| 620 | } |
|---|
| 621 | |
|---|
| 622 | // y axis text |
|---|
| 623 | if ($this->parameter['y_axis_text_left'] && !($set % $this->parameter['y_axis_text_left'])) { // test if tick should be displayed |
|---|
| 624 | // draw tick |
|---|
| 625 | if ($tickColour != 'none') |
|---|
| 626 | ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour); |
|---|
| 627 | |
|---|
| 628 | // draw axis text... |
|---|
| 629 | $coords = array('x' => $textRight, 'y' => $tickY, 'reference' => $reference); |
|---|
| 630 | $axisTag['text'] = $this->calculated['y_axis_left']['text'][$set]; |
|---|
| 631 | $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set]; |
|---|
| 632 | $this->update_boundaryBox($axisTag['boundary_box'], $coords); |
|---|
| 633 | $this->print_TTF($axisTag); |
|---|
| 634 | } |
|---|
| 635 | } |
|---|
| 636 | } |
|---|
| 637 | |
|---|
| 638 | if ($this->calculated['y_axis_right']['has_data']) { |
|---|
| 639 | // RIGHT HAND SIDE |
|---|
| 640 | // left and right coords for ticks |
|---|
| 641 | if ($this->parameter['tick_length'] >= 0) { |
|---|
| 642 | $tickLeft = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length']; |
|---|
| 643 | $tickRight = $this->calculated['boundary_box']['right']; |
|---|
| 644 | } else { |
|---|
| 645 | $tickLeft = $this->calculated['boundary_box']['right']; |
|---|
| 646 | $tickRight = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length']; |
|---|
| 647 | } |
|---|
| 648 | $textLeft = $tickRight+ $this->calculated['left_inner_padding']; |
|---|
| 649 | |
|---|
| 650 | if ($axis_angle == 0) $reference = 'left-center'; |
|---|
| 651 | if ($axis_angle > 0) $reference = 'left-bottom'; |
|---|
| 652 | if ($axis_angle < 0) $reference = 'left-top'; |
|---|
| 653 | if ($axis_angle == 90) $reference = 'left-center'; |
|---|
| 654 | |
|---|
| 655 | foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) { |
|---|
| 656 | if (!$this->calculated['y_axis_left']['has_data'] && $yGrid != 'none') { // draw grid if not drawn already (above) |
|---|
| 657 | switch ($yGrid) { |
|---|
| 658 | case 'line': |
|---|
| 659 | ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); |
|---|
| 660 | break; |
|---|
| 661 | case 'dash': |
|---|
| 662 | ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); |
|---|
| 663 | break; |
|---|
| 664 | } |
|---|
| 665 | } |
|---|
| 666 | |
|---|
| 667 | if ($this->parameter['y_axis_text_right'] && !($set % $this->parameter['y_axis_text_right'])) { // test if tick should be displayed |
|---|
| 668 | // draw tick |
|---|
| 669 | if ($tickColour != 'none') |
|---|
| 670 | ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour); |
|---|
| 671 | |
|---|
| 672 | // draw axis text... |
|---|
| 673 | $coords = array('x' => $textLeft, 'y' => $tickY, 'reference' => $reference); |
|---|
| 674 | $axisTag['text'] = $this->calculated['y_axis_right']['text'][$set]; |
|---|
| 675 | $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set]; |
|---|
| 676 | $this->update_boundaryBox($axisTag['boundary_box'], $coords); |
|---|
| 677 | $this->print_TTF($axisTag); |
|---|
| 678 | } |
|---|
| 679 | } |
|---|
| 680 | } |
|---|
| 681 | } |
|---|
| 682 | |
|---|
| 683 | function init_data() { |
|---|
| 684 | $this->calculated['y_plot'] = array(); // array to hold pixel plotting coords for y axis |
|---|
| 685 | $height = $this->calculated['boundary_box']['bottom'] - $this->calculated['boundary_box']['top']; |
|---|
| 686 | $width = $this->calculated['boundary_box']['right'] - $this->calculated['boundary_box']['left']; |
|---|
| 687 | |
|---|
| 688 | // calculate pixel steps between axis ticks. |
|---|
| 689 | $this->calculated['y_axis']['step'] = $height / ($this->parameter['y_axis_gridlines'] - 1); |
|---|
| 690 | |
|---|
| 691 | // calculate x ticks spacing taking into account x offset for ticks. |
|---|
| 692 | $extraTick = 2 * $this->parameter['x_offset']; // extra tick to account for padding |
|---|
| 693 | $numTicks = $this->calculated['x_axis']['num_ticks'] - 1; // number of x ticks |
|---|
| 694 | |
|---|
| 695 | $this->calculated['x_axis']['step'] = $width / ($numTicks + $extraTick); |
|---|
| 696 | $widthPlot = $width - ($this->calculated['x_axis']['step'] * $extraTick); |
|---|
| 697 | $this->calculated['x_axis']['step'] = $widthPlot / $numTicks; |
|---|
| 698 | |
|---|
| 699 | //calculate factor for transforming x,y physical coords to logical coords for right hand y_axis. |
|---|
| 700 | $y_range = $this->calculated['y_axis_right']['max'] - $this->calculated['y_axis_right']['min']; |
|---|
| 701 | $y_range = ($y_range ? $y_range : 1); |
|---|
| 702 | $this->calculated['y_axis_right']['factor'] = $height / $y_range; |
|---|
| 703 | |
|---|
| 704 | //calculate factor for transforming x,y physical coords to logical coords for left hand axis. |
|---|
| 705 | $yRange = $this->calculated['y_axis_left']['max'] - $this->calculated['y_axis_left']['min']; |
|---|
| 706 | $yRange = ($yRange ? $yRange : 1); |
|---|
| 707 | $this->calculated['y_axis_left']['factor'] = $height / $yRange; |
|---|
| 708 | if ($this->parameter['x_axis_gridlines'] != 'auto') { |
|---|
| 709 | $xRange = $this->calculated['x_axis']['max'] - $this->calculated['x_axis']['min']; |
|---|
| 710 | $xRange = ($xRange ? $xRange : 1); |
|---|
| 711 | $this->calculated['x_axis']['factor'] = $widthPlot / $xRange; |
|---|
| 712 | } |
|---|
| 713 | |
|---|
| 714 | // cycle thru all data sets... |
|---|
| 715 | $this->calculated['num_bars'] = 0; |
|---|
| 716 | foreach ($this->y_order as $order => $set) { |
|---|
| 717 | // determine how many bars there are |
|---|
| 718 | if (isset($this->y_format[$set]['bar']) && ($this->y_format[$set]['bar'] != 'none')) { |
|---|
| 719 | $this->calculated['bar_offset_index'][$set] = $this->calculated['num_bars']; // index to relate bar with data set. |
|---|
| 720 | $this->calculated['num_bars']++; |
|---|
| 721 | } |
|---|
| 722 | |
|---|
| 723 | // calculate y coords for plotting data |
|---|
| 724 | $index = -1; |
|---|
| 725 | foreach ($this->x_data as $x) { |
|---|
| 726 | $index++; |
|---|
| 727 | $this->calculated['y_plot'][$set][$index] = $this->y_data[$set][$index]; |
|---|
| 728 | |
|---|
| 729 | if ((string)$this->y_data[$set][$index] != 'none') { |
|---|
| 730 | |
|---|
| 731 | if (isset($this->y_format[$set]['y_axis']) && $this->y_format[$set]['y_axis'] == 'right') { |
|---|
| 732 | $this->calculated['y_plot'][$set][$index] = |
|---|
| 733 | round(($this->y_data[$set][$index] - $this->calculated['y_axis_right']['min']) |
|---|
| 734 | * $this->calculated['y_axis_right']['factor']); |
|---|
| 735 | } else { |
|---|
| 736 | //print "$set $index<BR>"; |
|---|
| 737 | $this->calculated['y_plot'][$set][$index] = |
|---|
| 738 | round(($this->y_data[$set][$index] - $this->calculated['y_axis_left']['min']) |
|---|
| 739 | * $this->calculated['y_axis_left']['factor']); |
|---|
| 740 | } |
|---|
| 741 | |
|---|
| 742 | } |
|---|
| 743 | } |
|---|
| 744 | } |
|---|
| 745 | |
|---|
| 746 | // calculate bar parameters if bars are to be drawn. |
|---|
| 747 | if ($this->calculated['num_bars']) { |
|---|
| 748 | $xStep = $this->calculated['x_axis']['step']; |
|---|
| 749 | $totalWidth = $this->calculated['x_axis']['step'] - $this->parameter['bar_spacing']; |
|---|
| 750 | $barWidth = $totalWidth / $this->calculated['num_bars']; |
|---|
| 751 | |
|---|
| 752 | $barX = ($barWidth - $totalWidth) / 2; // starting x offset |
|---|
| 753 | for ($i=0; $i < $this->calculated['num_bars']; $i++) { |
|---|
| 754 | $this->calculated['bar_offset_x'][$i] = $barX; |
|---|
| 755 | $barX += $barWidth; // add width of bar to x offset. |
|---|
| 756 | } |
|---|
| 757 | $this->calculated['bar_width'] = $barWidth; |
|---|
| 758 | } |
|---|
| 759 | |
|---|
| 760 | |
|---|
| 761 | } |
|---|
| 762 | |
|---|
| 763 | function init_x_ticks() { |
|---|
| 764 | // get coords for x axis ticks and data plots |
|---|
| 765 | //$xGrid = $this->parameter['x_grid']; |
|---|
| 766 | $xStep = $this->calculated['x_axis']['step']; |
|---|
| 767 | $ticksOffset = $this->parameter['x_offset']; // where to start drawing ticks relative to y axis. |
|---|
| 768 | $gridLeft = $this->calculated['boundary_box']['left'] + ($xStep * $ticksOffset); // grid x start |
|---|
| 769 | $tickX = $gridLeft; // tick x coord |
|---|
| 770 | |
|---|
| 771 | foreach ($this->calculated['x_axis']['text'] as $set => $value) { |
|---|
| 772 | //print "index: $set<BR>"; |
|---|
| 773 | // x tick value |
|---|
| 774 | $this->calculated['x_axis']['tick_x'][$set] = $tickX; |
|---|
| 775 | // if num ticks is auto then x plot value is same as x tick |
|---|
| 776 | if ($this->parameter['x_axis_gridlines'] == 'auto') $this->calculated['x_plot'][$set] = round($tickX); |
|---|
| 777 | //print $this->calculated['x_plot'][$set].'<BR>'; |
|---|
| 778 | $tickX += $xStep; |
|---|
| 779 | } |
|---|
| 780 | |
|---|
| 781 | //print "xStep: $xStep <BR>"; |
|---|
| 782 | // if numeric x axis then calculate x coords for each data point. this is seperate from x ticks. |
|---|
| 783 | if ($this->parameter['x_axis_gridlines'] != 'auto') { |
|---|
| 784 | $gridX = $gridLeft; |
|---|
| 785 | $factor = $this->calculated['x_axis']['factor']; |
|---|
| 786 | $min = $this->calculated['x_axis']['min']; |
|---|
| 787 | |
|---|
| 788 | foreach ($this->x_data as $index => $x) { |
|---|
| 789 | //print "index: $index, x: $x<BR>"; |
|---|
| 790 | $offset = $x - $this->calculated['x_axis']['min']; |
|---|
| 791 | |
|---|
| 792 | //$gridX = ($offset * $this->calculated['x_axis']['factor']); |
|---|
| 793 | //print "offset: $offset <BR>"; |
|---|
| 794 | //$this->calculated['x_plot'][$set] = $gridLeft + ($offset * $this->calculated['x_axis']['factor']); |
|---|
| 795 | |
|---|
| 796 | $this->calculated['x_plot'][$index] = $gridLeft + ($x - $min) * $factor; |
|---|
| 797 | |
|---|
| 798 | //print $this->calculated['x_plot'][$set].'<BR>'; |
|---|
| 799 | } |
|---|
| 800 | } |
|---|
| 801 | //expand_pre($this->calculated['boundary_box']); |
|---|
| 802 | //print "factor ".$this->calculated['x_axis']['factor']."<BR>"; |
|---|
| 803 | //expand_pre($this->calculated['x_plot']); |
|---|
| 804 | } |
|---|
| 805 | |
|---|
| 806 | function init_y_ticks() { |
|---|
| 807 | // get coords for y axis ticks |
|---|
| 808 | |
|---|
| 809 | $yStep = $this->calculated['y_axis']['step']; |
|---|
| 810 | $gridBottom = $this->calculated['boundary_box']['bottom']; |
|---|
| 811 | $tickY = $gridBottom; // tick y coord |
|---|
| 812 | |
|---|
| 813 | for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { |
|---|
| 814 | $this->calculated['y_axis']['tick_y'][$i] = $tickY; |
|---|
| 815 | $tickY -= $yStep; |
|---|
| 816 | } |
|---|
| 817 | |
|---|
| 818 | } |
|---|
| 819 | |
|---|
| 820 | function init_labels() { |
|---|
| 821 | if ($this->parameter['title']) { |
|---|
| 822 | $size = $this->get_boundaryBox( |
|---|
| 823 | array('points' => $this->parameter['title_size'], |
|---|
| 824 | 'angle' => 0, |
|---|
| 825 | 'font' => $this->parameter['title_font'], |
|---|
| 826 | 'text' => $this->parameter['title'])); |
|---|
| 827 | $this->calculated['title']['boundary_box'] = $size; |
|---|
| 828 | $this->calculated['title']['text'] = $this->parameter['title']; |
|---|
| 829 | $this->calculated['title']['font'] = $this->parameter['title_font']; |
|---|
| 830 | $this->calculated['title']['points'] = $this->parameter['title_size']; |
|---|
| 831 | $this->calculated['title']['colour'] = $this->parameter['title_colour']; |
|---|
| 832 | $this->calculated['title']['angle'] = 0; |
|---|
| 833 | |
|---|
| 834 | $this->calculated['boundary_box']['top'] += $size['height'] + $this->parameter['outer_padding']; |
|---|
| 835 | //$this->calculated['boundary_box']['top'] += $size['height']; |
|---|
| 836 | |
|---|
| 837 | } else $this->calculated['title']['boundary_box'] = $this->get_null_size(); |
|---|
| 838 | |
|---|
| 839 | if ($this->parameter['y_label_left']) { |
|---|
| 840 | $this->calculated['y_label_left']['text'] = $this->parameter['y_label_left']; |
|---|
| 841 | $this->calculated['y_label_left']['angle'] = $this->parameter['y_label_angle']; |
|---|
| 842 | $this->calculated['y_label_left']['font'] = $this->parameter['label_font']; |
|---|
| 843 | $this->calculated['y_label_left']['points'] = $this->parameter['label_size']; |
|---|
| 844 | $this->calculated['y_label_left']['colour'] = $this->parameter['label_colour']; |
|---|
| 845 | |
|---|
| 846 | $size = $this->get_boundaryBox($this->calculated['y_label_left']); |
|---|
| 847 | $this->calculated['y_label_left']['boundary_box'] = $size; |
|---|
| 848 | //$this->calculated['boundary_box']['left'] += $size['width'] + $this->parameter['inner_padding']; |
|---|
| 849 | $this->calculated['boundary_box']['left'] += $size['width']; |
|---|
| 850 | |
|---|
| 851 | } else $this->calculated['y_label_left']['boundary_box'] = $this->get_null_size(); |
|---|
| 852 | |
|---|
| 853 | if ($this->parameter['y_label_right']) { |
|---|
| 854 | $this->calculated['y_label_right']['text'] = $this->parameter['y_label_right']; |
|---|
| 855 | $this->calculated['y_label_right']['angle'] = $this->parameter['y_label_angle']; |
|---|
| 856 | $this->calculated['y_label_right']['font'] = $this->parameter['label_font']; |
|---|
| 857 | $this->calculated['y_label_right']['points'] = $this->parameter['label_size']; |
|---|
| 858 | $this->calculated['y_label_right']['colour'] = $this->parameter['label_colour']; |
|---|
| 859 | |
|---|
| 860 | $size = $this->get_boundaryBox($this->calculated['y_label_right']); |
|---|
| 861 | $this->calculated['y_label_right']['boundary_box'] = $size; |
|---|
| 862 | //$this->calculated['boundary_box']['right'] -= $size['width'] + $this->parameter['inner_padding']; |
|---|
| 863 | $this->calculated['boundary_box']['right'] -= $size['width']; |
|---|
| 864 | |
|---|
| 865 | } else $this->calculated['y_label_right']['boundary_box'] = $this->get_null_size(); |
|---|
| 866 | |
|---|
| 867 | if ($this->parameter['x_label']) { |
|---|
| 868 | $this->calculated['x_label']['text'] = $this->parameter['x_label']; |
|---|
| 869 | $this->calculated['x_label']['angle'] = $this->parameter['x_label_angle']; |
|---|
| 870 | $this->calculated['x_label']['font'] = $this->parameter['label_font']; |
|---|
| 871 | $this->calculated['x_label']['points'] = $this->parameter['label_size']; |
|---|
| 872 | $this->calculated['x_label']['colour'] = $this->parameter['label_colour']; |
|---|
| 873 | |
|---|
| 874 | $size = $this->get_boundaryBox($this->calculated['x_label']); |
|---|
| 875 | $this->calculated['x_label']['boundary_box'] = $size; |
|---|
| 876 | //$this->calculated['boundary_box']['bottom'] -= $size['height'] + $this->parameter['inner_padding']; |
|---|
| 877 | $this->calculated['boundary_box']['bottom'] -= $size['height']; |
|---|
| 878 | |
|---|
| 879 | } else $this->calculated['x_label']['boundary_box'] = $this->get_null_size(); |
|---|
| 880 | |
|---|
| 881 | } |
|---|
| 882 | |
|---|
| 883 | |
|---|
| 884 | function init_legend() { |
|---|
| 885 | $this->calculated['legend'] = array(); // array to hold calculated values for legend. |
|---|
| 886 | //$this->calculated['legend']['boundary_box_max'] = array('height' => 0, 'width' => 0); |
|---|
| 887 | $this->calculated['legend']['boundary_box_max'] = $this->get_null_size(); |
|---|
| 888 | if ($this->parameter['legend'] == 'none') return; |
|---|
| 889 | |
|---|
| 890 | $position = $this->parameter['legend']; |
|---|
| 891 | $numSets = 0; // number of data sets with legends. |
|---|
| 892 | $sumTextHeight = 0; // total of height of all legend text items. |
|---|
| 893 | $width = 0; |
|---|
| 894 | $height = 0; |
|---|
| 895 | |
|---|
| 896 | foreach ($this->y_order as $set) { |
|---|
| 897 | $text = isset($this->y_format[$set]['legend']) ? $this->y_format[$set]['legend'] : 'none'; |
|---|
| 898 | $size = $this->get_boundaryBox( |
|---|
| 899 | array('points' => $this->parameter['legend_size'], |
|---|
| 900 | 'angle' => 0, |
|---|
| 901 | 'font' => $this->parameter['legend_font'], |
|---|
| 902 | 'text' => $text)); |
|---|
| 903 | |
|---|
| 904 | $this->calculated['legend']['boundary_box'][$set] = $size; |
|---|
| 905 | $this->calculated['legend']['text'][$set] = $text; |
|---|
| 906 | //$this->calculated['legend']['font'][$set] = $this->parameter['legend_font']; |
|---|
| 907 | //$this->calculated['legend']['points'][$set] = $this->parameter['legend_size']; |
|---|
| 908 | //$this->calculated['legend']['angle'][$set] = 0; |
|---|
| 909 | |
|---|
| 910 | if ($text && $text!='none') { |
|---|
| 911 | $numSets++; |
|---|
| 912 | $sumTextHeight += $size['height']; |
|---|
| 913 | } |
|---|
| 914 | |
|---|
| 915 | if ($size['width'] > $this->calculated['legend']['boundary_box_max']['width']) |
|---|
| 916 | $this->calculated['legend']['boundary_box_max'] = $size; |
|---|
| 917 | } |
|---|
| 918 | |
|---|
| 919 | $offset = $this->parameter['legend_offset']; // offset in pixels of legend box from graph border. |
|---|
| 920 | $padding = $this->parameter['legend_padding']; // padding in pixels around legend text. |
|---|
| 921 | $textWidth = $this->calculated['legend']['boundary_box_max']['width']; // width of largest legend item. |
|---|
| 922 | $textHeight = $this->calculated['legend']['boundary_box_max']['height']; // use height as size to use for colour square in legend. |
|---|
| 923 | $width = $padding * 2 + $textWidth + $textHeight * 2; // left and right padding + maximum text width + space for square |
|---|
| 924 | $height = $padding * ($numSets + 1) + $sumTextHeight; // top and bottom padding + padding between text + text. |
|---|
| 925 | |
|---|
| 926 | |
|---|
| 927 | $this->calculated['legend']['boundary_box_all'] = array('width' => $width, |
|---|
| 928 | 'height' => $height, |
|---|
| 929 | 'offset' => $offset, |
|---|
| 930 | 'reference' => $position); |
|---|
| 931 | |
|---|
| 932 | switch ($position) { // move in right or bottom if legend is outside data plotting area. |
|---|
| 933 | case 'outside-top' : |
|---|
| 934 | $this->calculated['boundary_box']['right'] -= $offset + $width; // move in right hand side |
|---|
| 935 | break; |
|---|
| 936 | |
|---|
| 937 | case 'outside-bottom' : |
|---|
| 938 | $this->calculated['boundary_box']['right'] -= $offset + $width; // move in right hand side |
|---|
| 939 | break; |
|---|
| 940 | |
|---|
| 941 | case 'outside-left' : |
|---|
| 942 | $this->calculated['boundary_box']['bottom'] -= $offset + $height; // move in right hand side |
|---|
| 943 | break; |
|---|
| 944 | |
|---|
| 945 | case 'outside-right' : |
|---|
| 946 | $this->calculated['boundary_box']['bottom'] -= $offset + $height; // move in right hand side |
|---|
| 947 | break; |
|---|
| 948 | } |
|---|
| 949 | } |
|---|
| 950 | |
|---|
| 951 | function init_y_axis() { |
|---|
| 952 | $this->calculated['y_axis_left'] = array(); // array to hold calculated values for y_axis on left. |
|---|
| 953 | $this->calculated['y_axis_left']['boundary_box_max'] = $this->get_null_size(); |
|---|
| 954 | $this->calculated['y_axis_right'] = array(); // array to hold calculated values for y_axis on right. |
|---|
| 955 | $this->calculated['y_axis_right']['boundary_box_max'] = $this->get_null_size(); |
|---|
| 956 | |
|---|
| 957 | $axis_font = $this->parameter['axis_font']; |
|---|
| 958 | $axis_size = $this->parameter['axis_size']; |
|---|
| 959 | $axis_colour = $this->parameter['axis_colour']; |
|---|
| 960 | $axis_angle = $this->parameter['y_axis_angle']; |
|---|
| 961 | |
|---|
| 962 | $this->calculated['y_axis_left']['has_data'] = FALSE; |
|---|
| 963 | $this->calculated['y_axis_right']['has_data'] = FALSE; |
|---|
| 964 | |
|---|
| 965 | // find min and max y values. |
|---|
| 966 | $minLeft = $this->parameter['y_min_left']; |
|---|
| 967 | $maxLeft = $this->parameter['y_max_left']; |
|---|
| 968 | $minRight = $this->parameter['y_min_right']; |
|---|
| 969 | $maxRight = $this->parameter['y_max_right']; |
|---|
| 970 | $dataLeft = array(); |
|---|
| 971 | $dataRight = array(); |
|---|
| 972 | foreach ($this->y_order as $order => $set) { |
|---|
| 973 | if (isset($this->y_format[$set]['y_axis']) && $this->y_format[$set]['y_axis'] == 'right') { |
|---|
| 974 | $this->calculated['y_axis_right']['has_data'] = TRUE; |
|---|
| 975 | $dataRight = array_merge($dataRight, $this->y_data[$set]); |
|---|
| 976 | } else { |
|---|
| 977 | $this->calculated['y_axis_left']['has_data'] = TRUE; |
|---|
| 978 | $dataLeft = array_merge($dataLeft, $this->y_data[$set]); |
|---|
| 979 | } |
|---|
| 980 | } |
|---|
| 981 | $dataLeftRange = $this->find_range($dataLeft, $minLeft, $maxLeft, $this->parameter['y_resolution_left']); |
|---|
| 982 | $dataRightRange = $this->find_range($dataRight, $minRight, $maxRight, $this->parameter['y_resolution_right']); |
|---|
| 983 | $minLeft = $dataLeftRange['min']; |
|---|
| 984 | $maxLeft = $dataLeftRange['max']; |
|---|
| 985 | $minRight = $dataRightRange['min']; |
|---|
| 986 | $maxRight = $dataRightRange['max']; |
|---|
| 987 | |
|---|
| 988 | $this->calculated['y_axis_left']['min'] = $minLeft; |
|---|
| 989 | $this->calculated['y_axis_left']['max'] = $maxLeft; |
|---|
| 990 | $this->calculated['y_axis_right']['min'] = $minRight; |
|---|
| 991 | $this->calculated['y_axis_right']['max'] = $maxRight; |
|---|
| 992 | |
|---|
| 993 | $stepLeft = ($maxLeft - $minLeft) / ($this->parameter['y_axis_gridlines'] - 1); |
|---|
| 994 | $startLeft = $minLeft; |
|---|
| 995 | $step_right = ($maxRight - $minRight) / ($this->parameter['y_axis_gridlines'] - 1); |
|---|
| 996 | $start_right = $minRight; |
|---|
| 997 | |
|---|
| 998 | if ($this->parameter['y_axis_text_left']) { |
|---|
| 999 | for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes |
|---|
| 1000 | // left y axis |
|---|
| 1001 | $value = number_format($startLeft, $this->parameter['y_decimal_left'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); |
|---|
| 1002 | $this->calculated['y_axis_left']['data'][$i] = $startLeft; |
|---|
| 1003 | $this->calculated['y_axis_left']['text'][$i] = $value; // text is formatted raw data |
|---|
| 1004 | |
|---|
| 1005 | $size = $this->get_boundaryBox( |
|---|
| 1006 | array('points' => $axis_size, |
|---|
| 1007 | 'font' => $axis_font, |
|---|
| 1008 | 'angle' => $axis_angle, |
|---|
| 1009 | 'colour' => $axis_colour, |
|---|
| 1010 | 'text' => $value)); |
|---|
| 1011 | $this->calculated['y_axis_left']['boundary_box'][$i] = $size; |
|---|
| 1012 | |
|---|
| 1013 | if ($size['height'] > $this->calculated['y_axis_left']['boundary_box_max']['height']) |
|---|
| 1014 | $this->calculated['y_axis_left']['boundary_box_max']['height'] = $size['height']; |
|---|
| 1015 | if ($size['width'] > $this->calculated['y_axis_left']['boundary_box_max']['width']) |
|---|
| 1016 | $this->calculated['y_axis_left']['boundary_box_max']['width'] = $size['width']; |
|---|
| 1017 | |
|---|
| 1018 | $startLeft += $stepLeft; |
|---|
| 1019 | } |
|---|
| 1020 | $this->calculated['boundary_box']['left'] += $this->calculated['y_axis_left']['boundary_box_max']['width'] |
|---|
| 1021 | + $this->parameter['inner_padding']; |
|---|
| 1022 | } |
|---|
| 1023 | |
|---|
| 1024 | if ($this->parameter['y_axis_text_right']) { |
|---|
| 1025 | for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes |
|---|
| 1026 | // right y axis |
|---|
| 1027 | $value = number_format($start_right, $this->parameter['y_decimal_right'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); |
|---|
| 1028 | $this->calculated['y_axis_right']['data'][$i] = $start_right; |
|---|
| 1029 | $this->calculated['y_axis_right']['text'][$i] = $value; // text is formatted raw data |
|---|
| 1030 | $size = $this->get_boundaryBox( |
|---|
| 1031 | array('points' => $axis_size, |
|---|
| 1032 | 'font' => $axis_font, |
|---|
| 1033 | 'angle' => $axis_angle, |
|---|
| 1034 | 'colour' => $axis_colour, |
|---|
| 1035 | 'text' => $value)); |
|---|
| 1036 | $this->calculated['y_axis_right']['boundary_box'][$i] = $size; |
|---|
| 1037 | |
|---|
| 1038 | if ($size['height'] > $this->calculated['y_axis_right']['boundary_box_max']['height']) |
|---|
| 1039 | $this->calculated['y_axis_right']['boundary_box_max'] = $size; |
|---|
| 1040 | if ($size['width'] > $this->calculated['y_axis_right']['boundary_box_max']['width']) |
|---|
| 1041 | $this->calculated['y_axis_right']['boundary_box_max']['width'] = $size['width']; |
|---|
| 1042 | |
|---|
| 1043 | $start_right += $step_right; |
|---|
| 1044 | } |
|---|
| 1045 | $this->calculated['boundary_box']['right'] -= $this->calculated['y_axis_right']['boundary_box_max']['width'] |
|---|
| 1046 | + $this->parameter['inner_padding']; |
|---|
| 1047 | } |
|---|
| 1048 | } |
|---|
| 1049 | |
|---|
| 1050 | function init_x_axis() { |
|---|
| 1051 | $this->calculated['x_axis'] = array(); // array to hold calculated values for x_axis. |
|---|
| 1052 | $this->calculated['x_axis']['boundary_box_max'] = array('height' => 0, 'width' => 0); |
|---|
| 1053 | |
|---|
| 1054 | $axis_font = $this->parameter['axis_font']; |
|---|
| 1055 | $axis_size = $this->parameter['axis_size']; |
|---|
| 1056 | $axis_colour = $this->parameter['axis_colour']; |
|---|
| 1057 | $axis_angle = $this->parameter['x_axis_angle']; |
|---|
| 1058 | |
|---|
| 1059 | // check whether to treat x axis as numeric |
|---|
| 1060 | if ($this->parameter['x_axis_gridlines'] == 'auto') { // auto means text based x_axis, not numeric... |
|---|
| 1061 | $this->calculated['x_axis']['num_ticks'] = sizeof($this->x_data); |
|---|
| 1062 | $data = $this->x_data; |
|---|
| 1063 | for ($i=0; $i < $this->calculated['x_axis']['num_ticks']; $i++) { |
|---|
| 1064 | $key = key($data); |
|---|
| 1065 | $value = array_shift($data); // grab value from begin of array |
|---|
| 1066 | if (is_numeric($key)) $key = $value; |
|---|
| 1067 | $this->calculated['x_axis']['data'][$i] = $value; |
|---|
| 1068 | $this->calculated['x_axis']['text'][$i] = $key; // raw data and text are both the same in this case |
|---|
| 1069 | $size = $this->get_boundaryBox( |
|---|
| 1070 | array('points' => $axis_size, |
|---|
| 1071 | 'font' => $axis_font, |
|---|
| 1072 | 'angle' => $axis_angle, |
|---|
| 1073 | 'colour' => $axis_colour, |
|---|
| 1074 | 'text' => $key)); |
|---|
| 1075 | $this->calculated['x_axis']['boundary_box'][$i] = $size; |
|---|
| 1076 | if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height']) |
|---|
| 1077 | $this->calculated['x_axis']['boundary_box_max'] = $size; |
|---|
| 1078 | } |
|---|
| 1079 | |
|---|
| 1080 | } else { // x axis is numeric so find max min values... |
|---|
| 1081 | $this->calculated['x_axis']['num_ticks'] = $this->parameter['x_axis_gridlines']; |
|---|
| 1082 | |
|---|
| 1083 | $min = $this->parameter['x_min']; |
|---|
| 1084 | $max = $this->parameter['x_max']; |
|---|
| 1085 | $data = array(); |
|---|
| 1086 | $data = $this->find_range($this->x_data, $min, $max, $this->parameter['x_resolution']); |
|---|
| 1087 | $min = $data['min']; |
|---|
| 1088 | $max = $data['max']; |
|---|
| 1089 | $this->calculated['x_axis']['min'] = $min; |
|---|
| 1090 | $this->calculated['x_axis']['max'] = $max; |
|---|
| 1091 | |
|---|
| 1092 | $step = ($max - $min) / ($this->calculated['x_axis']['num_ticks'] - 1); |
|---|
| 1093 | $start = $min; |
|---|
| 1094 | |
|---|
| 1095 | for ($i = 0; $i < $this->calculated['x_axis']['num_ticks']; $i++) { // calculate x axis text sizes |
|---|
| 1096 | $value = number_format($start, $this->parameter['x_decimal'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); |
|---|
| 1097 | $this->calculated['x_axis']['data'][$i] = $start; |
|---|
| 1098 | $this->calculated['x_axis']['text'][$i] = $value; // text is formatted raw data |
|---|
| 1099 | |
|---|
| 1100 | $size = $this->get_boundaryBox( |
|---|
| 1101 | array('points' => $axis_size, |
|---|
| 1102 | 'font' => $axis_font, |
|---|
| 1103 | 'angle' => $axis_angle, |
|---|
| 1104 | 'colour' => $axis_colour, |
|---|
| 1105 | 'text' => $value)); |
|---|
| 1106 | $this->calculated['x_axis']['boundary_box'][$i] = $size; |
|---|
| 1107 | |
|---|
| 1108 | if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height']) |
|---|
| 1109 | $this->calculated['x_axis']['boundary_box_max'] = $size; |
|---|
| 1110 | |
|---|
| 1111 | $start += $step; |
|---|
| 1112 | } |
|---|
| 1113 | } |
|---|
| 1114 | if ($this->parameter['x_axis_text']) |
|---|
| 1115 | $this->calculated['boundary_box']['bottom'] -= $this->calculated['x_axis']['boundary_box_max']['height'] |
|---|
| 1116 | + $this->parameter['inner_padding']; |
|---|
| 1117 | } |
|---|
| 1118 | |
|---|
| 1119 | // find max and min values for a data array given the resolution. |
|---|
| 1120 | function find_range($data, $min, $max, $resolution) { |
|---|
| 1121 | if (sizeof($data) == 0 ) return array('min' => 0, 'max' => 0); |
|---|
| 1122 | foreach ($data as $key => $value) { |
|---|
| 1123 | if ($value=='none') continue; |
|---|
| 1124 | if ($value > $max) $max = $value; |
|---|
| 1125 | if ($value < $min) $min = $value; |
|---|
| 1126 | } |
|---|
| 1127 | |
|---|
| 1128 | if ($max == 0) { |
|---|
| 1129 | $factor = 1; |
|---|
| 1130 | } else { |
|---|
| 1131 | if ($max < 0) $factor = - pow(10, (floor(log10(abs($max))) + $resolution) ); |
|---|
| 1132 | else $factor = pow(10, (floor(log10(abs($max))) - $resolution) ); |
|---|
| 1133 | } |
|---|
| 1134 | |
|---|
| 1135 | $max = $factor * @ceil($max / $factor); |
|---|
| 1136 | $min = $factor * @floor($min / $factor); |
|---|
| 1137 | |
|---|
| 1138 | //print "max=$max, min=$min<BR>"; |
|---|
| 1139 | |
|---|
| 1140 | return array('min' => $min, 'max' => $max); |
|---|
| 1141 | } |
|---|
| 1142 | |
|---|
| 1143 | |
|---|
| 1144 | function print_TTF($message) { |
|---|
| 1145 | $points = $message['points']; |
|---|
| 1146 | $angle = $message['angle']; |
|---|
| 1147 | $text = $message['text']; |
|---|
| 1148 | $colour = $this->colour[$message['colour']]; |
|---|
| 1149 | $font = $this->parameter['path_to_fonts'].$message['font']; |
|---|
| 1150 | |
|---|
| 1151 | $x = $message['boundary_box']['x']; |
|---|
| 1152 | $y = $message['boundary_box']['y']; |
|---|
| 1153 | $offsetX = $message['boundary_box']['offsetX']; |
|---|
| 1154 | $offsetY = $message['boundary_box']['offsetY']; |
|---|
| 1155 | $height = $message['boundary_box']['height']; |
|---|
| 1156 | $width = $message['boundary_box']['width']; |
|---|
| 1157 | $reference = $message['boundary_box']['reference']; |
|---|
| 1158 | |
|---|
| 1159 | switch ($reference) { |
|---|
| 1160 | case 'top-left': |
|---|
| 1161 | case 'left-top': |
|---|
| 1162 | $y += $height - $offsetY; |
|---|
| 1163 | //$y += $offsetY; |
|---|
| 1164 | $x += $offsetX; |
|---|
| 1165 | break; |
|---|
| 1166 | case 'left-center': |
|---|
| 1167 | $y += ($height / 2) - $offsetY; |
|---|
| 1168 | $x += $offsetX; |
|---|
| 1169 | break; |
|---|
| 1170 | case 'left-bottom': |
|---|
| 1171 | $y -= $offsetY; |
|---|
| 1172 | $x += $offsetX; |
|---|
| 1173 | break; |
|---|
| 1174 | case 'top-center': |
|---|
| 1175 | $y += $height - $offsetY; |
|---|
| 1176 | $x -= ($width / 2) - $offsetX; |
|---|
| 1177 | break; |
|---|
| 1178 | case 'top-right': |
|---|
| 1179 | case 'right-top': |
|---|
| 1180 | $y += $height - $offsetY; |
|---|
| 1181 | $x -= $width - $offsetX; |
|---|
| 1182 | break; |
|---|
| 1183 | case 'right-center': |
|---|
| 1184 | $y += ($height / 2) - $offsetY; |
|---|
| 1185 | $x -= $width - $offsetX; |
|---|
| 1186 | break; |
|---|
| 1187 | case 'right-bottom': |
|---|
| 1188 | $y -= $offsetY; |
|---|
| 1189 | $x -= $width - $offsetX; |
|---|
| 1190 | break; |
|---|
| 1191 | case 'bottom-center': |
|---|
| 1192 | $y -= $offsetY; |
|---|
| 1193 | $x -= ($width / 2) - $offsetX; |
|---|
| 1194 | break; |
|---|
| 1195 | default: |
|---|
| 1196 | $y = 0; |
|---|
| 1197 | $x = 0; |
|---|
| 1198 | break; |
|---|
| 1199 | } |
|---|
| 1200 | ImageTTFText($this->image, $points, $angle, $x, $y, $colour, $font, $text); |
|---|
| 1201 | } |
|---|
| 1202 | |
|---|
| 1203 | // move boundaryBox to coordinates specified |
|---|
| 1204 | function update_boundaryBox(&$boundaryBox, $coords) { |
|---|
| 1205 | $width = $boundaryBox['width']; |
|---|
| 1206 | $height = $boundaryBox['height']; |
|---|
| 1207 | $x = $coords['x']; |
|---|
| 1208 | $y = $coords['y']; |
|---|
| 1209 | $reference = $coords['reference']; |
|---|
| 1210 | switch ($reference) { |
|---|
| 1211 | case 'top-left': |
|---|
| 1212 | case 'left-top': |
|---|
| 1213 | $top = $y; |
|---|
| 1214 | $bottom = $y + $height; |
|---|
| 1215 | $left = $x; |
|---|
| 1216 | $right = $x + $width; |
|---|
| 1217 | break; |
|---|
| 1218 | case 'left-center': |
|---|
| 1219 | $top = $y - ($height / 2); |
|---|
| 1220 | $bottom = $y + ($height / 2); |
|---|
| 1221 | $left = $x; |
|---|
| 1222 | $right = $x + $width; |
|---|
| 1223 | break; |
|---|
| 1224 | case 'left-bottom': |
|---|
| 1225 | $top = $y - $height; |
|---|
| 1226 | $bottom = $y; |
|---|
| 1227 | $left = $x; |
|---|
| 1228 | $right = $x + $width; |
|---|
| 1229 | break; |
|---|
| 1230 | case 'top-center': |
|---|
| 1231 | $top = $y; |
|---|
| 1232 | $bottom = $y + $height; |
|---|
| 1233 | $left = $x - ($width / 2); |
|---|
| 1234 | $right = $x + ($width / 2); |
|---|
| 1235 | break; |
|---|
| 1236 | case 'right-top': |
|---|
| 1237 | case 'top-right': |
|---|
| 1238 | $top = $y; |
|---|
| 1239 | $bottom = $y + $height; |
|---|
| 1240 | $left = $x - $width; |
|---|
| 1241 | $right = $x; |
|---|
| 1242 | break; |
|---|
| 1243 | case 'right-center': |
|---|
| 1244 | $top = $y - ($height / 2); |
|---|
| 1245 | $bottom = $y + ($height / 2); |
|---|
| 1246 | $left = $x - $width; |
|---|
| 1247 | $right = $x; |
|---|
| 1248 | break; |
|---|
| 1249 | case 'bottom=right': |
|---|
| 1250 | case 'right-bottom': |
|---|
| 1251 | $top = $y - $height; |
|---|
| 1252 | $bottom = $y; |
|---|
| 1253 | $left = $x - $width; |
|---|
| 1254 | $right = $x; |
|---|
| 1255 | break; |
|---|
| 1256 | default: |
|---|
| 1257 | $top = 0; |
|---|
| 1258 | $bottom = $height; |
|---|
| 1259 | $left = 0; |
|---|
| 1260 | $right = $width; |
|---|
| 1261 | break; |
|---|
| 1262 | } |
|---|
| 1263 | |
|---|
| 1264 | $boundaryBox = array_merge($boundaryBox, array('top' => $top, |
|---|
| 1265 | 'bottom' => $bottom, |
|---|
| 1266 | 'left' => $left, |
|---|
| 1267 | 'right' => $right, |
|---|
| 1268 | 'x' => $x, |
|---|
| 1269 | 'y' => $y, |
|---|
| 1270 | 'reference' => $reference)); |
|---|
| 1271 | } |
|---|
| 1272 | |
|---|
| 1273 | function get_null_size() { |
|---|
| 1274 | return array('width' => 0, |
|---|
| 1275 | 'height' => 0, |
|---|
| 1276 | 'offsetX' => 0, |
|---|
| 1277 | 'offsetY' => 0, |
|---|
| 1278 | //'fontHeight' => 0 |
|---|
| 1279 | ); |
|---|
| 1280 | } |
|---|
| 1281 | |
|---|
| 1282 | function get_boundaryBox($message) { |
|---|
| 1283 | $points = $message['points']; |
|---|
| 1284 | $angle = $message['angle']; |
|---|
| 1285 | $font = $this->parameter['path_to_fonts'].$message['font']; |
|---|
| 1286 | $text = $message['text']; |
|---|
| 1287 | |
|---|
| 1288 | //print ('get_boundaryBox'); |
|---|
| 1289 | //expandPre($message); |
|---|
| 1290 | |
|---|
| 1291 | // get font size |
|---|
| 1292 | $bounds = ImageTTFBBox($points, $angle, $font, "W"); |
|---|
| 1293 | if ($angle < 0) { |
|---|
| 1294 | $fontHeight = abs($bounds[7]-$bounds[1]); |
|---|
| 1295 | } else if ($angle > 0) { |
|---|
| 1296 | $fontHeight = abs($bounds[1]-$bounds[7]); |
|---|
| 1297 | } else { |
|---|
| 1298 | $fontHeight = abs($bounds[7]-$bounds[1]); |
|---|
| 1299 | } |
|---|
| 1300 | |
|---|
| 1301 | // get boundary box and offsets for printing at an angle |
|---|
| 1302 | $bounds = ImageTTFBBox($points, $angle, $font, $text); |
|---|
| 1303 | |
|---|
| 1304 | if ($angle < 0) { |
|---|
| 1305 | $width = abs($bounds[4]-$bounds[0]); |
|---|
| 1306 | $height = abs($bounds[3]-$bounds[7]); |
|---|
| 1307 | $offsetY = abs($bounds[3]-$bounds[1]); |
|---|
| 1308 | $offsetX = 0; |
|---|
| 1309 | |
|---|
| 1310 | } else if ($angle > 0) { |
|---|
| 1311 | $width = abs($bounds[2]-$bounds[6]); |
|---|
| 1312 | $height = abs($bounds[1]-$bounds[5]); |
|---|
| 1313 | $offsetY = 0; |
|---|
| 1314 | $offsetX = abs($bounds[0]-$bounds[6]); |
|---|
| 1315 | |
|---|
| 1316 | } else { |
|---|
| 1317 | $width = abs($bounds[4]-$bounds[6]); |
|---|
| 1318 | $height = abs($bounds[7]-$bounds[1]); |
|---|
| 1319 | $offsetY = 0; |
|---|
| 1320 | $offsetX = 0; |
|---|
| 1321 | } |
|---|
| 1322 | |
|---|
| 1323 | //return values |
|---|
| 1324 | return array('width' => $width, |
|---|
| 1325 | 'height' => $height, |
|---|
| 1326 | 'offsetX' => $offsetX, |
|---|
| 1327 | 'offsetY' => $offsetY, |
|---|
| 1328 | //'fontHeight' => $fontHeight |
|---|
| 1329 | ); |
|---|
| 1330 | } |
|---|
| 1331 | |
|---|
| 1332 | function draw_rectangle($border, $colour, $type) { |
|---|
| 1333 | $colour = $this->colour[$colour]; |
|---|
| 1334 | switch ($type) { |
|---|
| 1335 | case 'fill': // fill the rectangle |
|---|
| 1336 | ImageFilledRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour); |
|---|
| 1337 | break; |
|---|
| 1338 | case 'box': // all sides |
|---|
| 1339 | ImageRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour); |
|---|
| 1340 | break; |
|---|
| 1341 | case 'axis': // bottom x axis and left y axis |
|---|
| 1342 | ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); |
|---|
| 1343 | ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); |
|---|
| 1344 | break; |
|---|
| 1345 | case 'y': // left y axis only |
|---|
| 1346 | case 'y-left': |
|---|
| 1347 | ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); |
|---|
| 1348 | break; |
|---|
| 1349 | case 'y-right': // right y axis only |
|---|
| 1350 | ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour); |
|---|
| 1351 | break; |
|---|
| 1352 | case 'x': // bottom x axis only |
|---|
| 1353 | ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); |
|---|
| 1354 | break; |
|---|
| 1355 | case 'u': // u shaped. bottom x axis and both left and right y axis. |
|---|
| 1356 | ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); |
|---|
| 1357 | ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour); |
|---|
| 1358 | ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); |
|---|
| 1359 | break; |
|---|
| 1360 | |
|---|
| 1361 | } |
|---|
| 1362 | } |
|---|
| 1363 | |
|---|
| 1364 | function init_colours() { |
|---|
| 1365 | $this->image = ImageCreate($this->parameter['width'], $this->parameter['height']); |
|---|
| 1366 | // standard colours |
|---|
| 1367 | $this->colour['white'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF); // first colour is background colour. |
|---|
| 1368 | $this->colour['black'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0x00); |
|---|
| 1369 | $this->colour['maroon'] = ImageColorAllocate ($this->image, 0x80, 0x00, 0x00); |
|---|
| 1370 | $this->colour['green'] = ImageColorAllocate ($this->image, 0x00, 0x80, 0x00); |
|---|
| 1371 | $this->colour['olive'] = ImageColorAllocate ($this->image, 0x80, 0x80, 0x00); |
|---|
| 1372 | $this->colour['navy'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0x80); |
|---|
| 1373 | $this->colour['purple'] = ImageColorAllocate ($this->image, 0x80, 0x00, 0x80); |
|---|
| 1374 | $this->colour['gray'] = ImageColorAllocate ($this->image, 0x80, 0x80, 0x80); |
|---|
| 1375 | $this->colour['red'] = ImageColorAllocate ($this->image, 0xFF, 0x00, 0x00); |
|---|
| 1376 | $this->colour['lime'] = ImageColorAllocate ($this->image, 0x00, 0xFF, 0x00); |
|---|
| 1377 | $this->colour['yellow'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0x00); |
|---|
| 1378 | $this->colour['blue'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0xFF); |
|---|
| 1379 | $this->colour['fuchsia'] = ImageColorAllocate ($this->image, 0xFF, 0x00, 0xFF); |
|---|
| 1380 | $this->colour['aqua'] = ImageColorAllocate ($this->image, 0x00, 0xFF, 0xFF); |
|---|
| 1381 | //$this->colour['white'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF); |
|---|
| 1382 | // shades of gray |
|---|
| 1383 | $this->colour['grayF0'] = ImageColorAllocate ($this->image, 0xF0, 0xF0, 0xF0); |
|---|
| 1384 | $this->colour['grayEE'] = ImageColorAllocate ($this->image, 0xEE, 0xEE, 0xEE); |
|---|
| 1385 | $this->colour['grayDD'] = ImageColorAllocate ($this->image, 0xDD, 0xDD, 0xDD); |
|---|
| 1386 | $this->colour['grayCC'] = ImageColorAllocate ($this->image, 0xCC, 0xCC, 0xCC); |
|---|
| 1387 | $this->colour['grayBB'] = ImageColorAllocate ($this->image, 0xBB, 0xBB, 0xBB); |
|---|
| 1388 | $this->colour['grayAA'] = ImageColorAllocate ($this->image, 0xAA, 0xAA, 0xAA); |
|---|
| 1389 | $this->colour['gray33'] = ImageColorAllocate ($this->image, 0x33, 0x33, 0x33); |
|---|
| 1390 | $this->colour['gray66'] = ImageColorAllocate ($this->image, 0x66, 0x66, 0x66); |
|---|
| 1391 | $this->colour['gray99'] = ImageColorAllocate ($this->image, 0x99, 0x99, 0x99); |
|---|
| 1392 | |
|---|
| 1393 | $this->colour['none'] = 'none'; |
|---|
| 1394 | return true; |
|---|
| 1395 | } |
|---|
| 1396 | |
|---|
| 1397 | function output() { |
|---|
| 1398 | if ($this->debug) { // for debugging purposes. |
|---|
| 1399 | //expandPre($this->graph); |
|---|
| 1400 | //expandPre($this->y_data); |
|---|
| 1401 | //expandPre($this->x_data); |
|---|
| 1402 | //expandPre($this->parameter); |
|---|
| 1403 | } else { |
|---|
| 1404 | |
|---|
| 1405 | $expiresSeconds = $this->parameter['seconds_to_live']; |
|---|
| 1406 | $expiresHours = $this->parameter['hours_to_live']; |
|---|
| 1407 | |
|---|
| 1408 | if ($expiresHours || $expiresSeconds) { |
|---|
| 1409 | $now = mktime (date("H"),date("i"),date("s"),date("m"),date("d"),date("Y")); |
|---|
| 1410 | $expires = mktime (date("H")+$expiresHours,date("i"),date("s")+$expiresSeconds,date("m"),date("d"),date("Y")); |
|---|
| 1411 | $expiresGMT = gmdate('D, d M Y H:i:s', $expires).' GMT'; |
|---|
| 1412 | $lastModifiedGMT = gmdate('D, d M Y H:i:s', $now).' GMT'; |
|---|
| 1413 | |
|---|
| 1414 | Header('Last-modified: '.$lastModifiedGMT); |
|---|
| 1415 | Header('Expires: '.$expiresGMT); |
|---|
| 1416 | } |
|---|
| 1417 | |
|---|
| 1418 | if ($this->parameter['file_name'] == 'none' || empty($this->parameter['file_name'] )) { |
|---|
| 1419 | switch ($this->parameter['output_format']) { |
|---|
| 1420 | case 'GIF': |
|---|
| 1421 | Header("Content-type: image/gif"); // GIF??. switch to PNG guys!! |
|---|
| 1422 | ImageGIF($this->image); |
|---|
| 1423 | break; |
|---|
| 1424 | case 'JPEG': |
|---|
| 1425 | Header("Content-type: image/jpeg"); // JPEG for line art??. included for completeness. |
|---|
| 1426 | ImageJPEG($this->image); |
|---|
| 1427 | break; |
|---|
| 1428 | default: |
|---|
| 1429 | Header("Content-type: image/png"); // preferred output format |
|---|
| 1430 | ImagePNG($this->image); |
|---|
| 1431 | break; |
|---|
| 1432 | } |
|---|
| 1433 | } else { |
|---|
| 1434 | switch ($this->parameter['output_format']) { |
|---|
| 1435 | case 'GIF': |
|---|
| 1436 | ImageGIF($this->image, $this->parameter['file_name'].'.gif'); |
|---|
| 1437 | break; |
|---|
| 1438 | case 'JPEG': |
|---|
| 1439 | ImageJPEG($this->image, $this->parameter['file_name'].'.jpg'); |
|---|
| 1440 | break; |
|---|
| 1441 | default: |
|---|
| 1442 | ImagePNG($this->image, $this->parameter['file_name'].'.png'); |
|---|
| 1443 | break; |
|---|
| 1444 | } |
|---|
| 1445 | } |
|---|
| 1446 | |
|---|
| 1447 | ImageDestroy($this->image); |
|---|
| 1448 | } |
|---|
| 1449 | } // function output |
|---|
| 1450 | |
|---|
| 1451 | /* |
|---|
| 1452 | function init_variable(&$variable, $value, $default) { |
|---|
| 1453 | if (!empty($value)) $variable = $value; |
|---|
| 1454 | else if (isset($default)) $variable = $default; |
|---|
| 1455 | else unset($variable); |
|---|
| 1456 | } |
|---|
| 1457 | */ |
|---|
| 1458 | |
|---|
| 1459 | // plot a point. options include square, circle, diamond, triangle, and dot. offset is used for drawing shadows. |
|---|
| 1460 | // for diamonds and triangles the size should be an even number to get nice look. if odd the points are crooked. |
|---|
| 1461 | function plot($x, $y, $type, $size, $colour, $offset) { |
|---|
| 1462 | //print("drawing point of type: $type, at offset: $offset"); |
|---|
| 1463 | $u = $x + $offset; |
|---|
| 1464 | $v = $this->calculated['inner_border']['bottom'] - $y + $offset; |
|---|
| 1465 | $half = $size / 2; |
|---|
| 1466 | |
|---|
| 1467 | switch ($type) { |
|---|
| 1468 | case 'square': |
|---|
| 1469 | ImageFilledRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]); |
|---|
| 1470 | break; |
|---|
| 1471 | case 'square-open': |
|---|
| 1472 | ImageRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]); |
|---|
| 1473 | break; |
|---|
| 1474 | case 'circle': |
|---|
| 1475 | ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]); |
|---|
| 1476 | ImageFillToBorder($this->image, $u, $v, $this->colour[$colour], $this->colour[$colour]); |
|---|
| 1477 | break; |
|---|
| 1478 | case 'circle-open': |
|---|
| 1479 | ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]); |
|---|
| 1480 | break; |
|---|
| 1481 | case 'diamond': |
|---|
| 1482 | ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]); |
|---|
| 1483 | break; |
|---|
| 1484 | case 'diamond-open': |
|---|
| 1485 | ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]); |
|---|
| 1486 | break; |
|---|
| 1487 | case 'triangle': |
|---|
| 1488 | ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]); |
|---|
| 1489 | break; |
|---|
| 1490 | case 'triangle-open': |
|---|
| 1491 | ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]); |
|---|
| 1492 | break; |
|---|
| 1493 | case 'dot': |
|---|
| 1494 | ImageSetPixel($this->image, $u, $v, $this->colour[$colour]); |
|---|
| 1495 | break; |
|---|
| 1496 | } |
|---|
| 1497 | } |
|---|
| 1498 | |
|---|
| 1499 | function bar($x, $y, $type, $size, $colour, $offset, $index) { |
|---|
| 1500 | |
|---|
| 1501 | //_p($index); |
|---|
| 1502 | |
|---|
| 1503 | $index_offset = $this->calculated['bar_offset_index'][$index]; |
|---|
| 1504 | $bar_offset = $this->calculated['bar_offset_x'][$index_offset]; |
|---|
| 1505 | //$this->dbug("drawing bar at offset = $offset : index = $index: bar_offset = $bar_offset"); |
|---|
| 1506 | |
|---|
| 1507 | $span = ($this->calculated['bar_width'] * $size) / 2; |
|---|
| 1508 | $x_left = $x + $bar_offset - $span; |
|---|
| 1509 | $x_right = $x + $bar_offset + $span; |
|---|
| 1510 | |
|---|
| 1511 | if ($this->parameter['zero_axis'] != 'none') { |
|---|
| 1512 | $zero = $this->calculated['zero_axis']; |
|---|
| 1513 | if ($this->parameter['shadow_below_axis'] ) $zero += $offset; |
|---|
| 1514 | $u_left = $x_left + $offset; |
|---|
| 1515 | $u_right = $x_right + $offset - 1; |
|---|
| 1516 | $v = $this->calculated['boundary_box']['bottom'] - $y + $offset; |
|---|
| 1517 | |
|---|
| 1518 | if ($v > $zero) { |
|---|
| 1519 | $top = $zero +1; |
|---|
| 1520 | $bottom = $v; |
|---|
| 1521 | } else { |
|---|
| 1522 | $top = $v; |
|---|
| 1523 | $bottom = $zero - 1; |
|---|
| 1524 | } |
|---|
| 1525 | |
|---|
| 1526 | switch ($type) { |
|---|
| 1527 | case 'open': |
|---|
| 1528 | //ImageRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]); |
|---|
| 1529 | if ($v > $zero) |
|---|
| 1530 | ImageRectangle($this->image, round($u_left), $bottom, round($u_right), $bottom, $this->colour[$colour]); |
|---|
| 1531 | else |
|---|
| 1532 | ImageRectangle($this->image, round($u_left), $top, round($u_right), $top, $this->colour[$colour]); |
|---|
| 1533 | ImageRectangle($this->image, round($u_left), $top, round($u_left), $bottom, $this->colour[$colour]); |
|---|
| 1534 | ImageRectangle($this->image, round($u_right), $top, round($u_right), $bottom, $this->colour[$colour]); |
|---|
| 1535 | break; |
|---|
| 1536 | case 'fill': |
|---|
| 1537 | ImageFilledRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]); |
|---|
| 1538 | break; |
|---|
| 1539 | } |
|---|
| 1540 | |
|---|
| 1541 | } else { |
|---|
| 1542 | |
|---|
| 1543 | $bottom = $this->calculated['boundary_box']['bottom']; |
|---|
| 1544 | if ($this->parameter['shadow_below_axis'] ) $bottom += $offset; |
|---|
| 1545 | if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn. |
|---|
| 1546 | $u_left = $x_left + $offset; |
|---|
| 1547 | $u_right = $x_right + $offset - 1; |
|---|
| 1548 | $v = $this->calculated['boundary_box']['bottom'] - $y + $offset; |
|---|
| 1549 | |
|---|
| 1550 | switch ($type) { |
|---|
| 1551 | case 'open': |
|---|
| 1552 | ImageRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]); |
|---|
| 1553 | break; |
|---|
| 1554 | case 'fill': |
|---|
| 1555 | ImageFilledRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]); |
|---|
| 1556 | break; |
|---|
| 1557 | } |
|---|
| 1558 | } |
|---|
| 1559 | } |
|---|
| 1560 | |
|---|
| 1561 | function area($x_start, $y_start, $x_end, $y_end, $type, $colour, $offset) { |
|---|
| 1562 | //dbug("drawing area type: $type, at offset: $offset"); |
|---|
| 1563 | if ($this->parameter['zero_axis'] != 'none') { |
|---|
| 1564 | $bottom = $this->calculated['boundary_box']['bottom']; |
|---|
| 1565 | $zero = $this->calculated['zero_axis']; |
|---|
| 1566 | if ($this->parameter['shadow_below_axis'] ) $zero += $offset; |
|---|
| 1567 | $u_start = $x_start + $offset; |
|---|
| 1568 | $u_end = $x_end + $offset; |
|---|
| 1569 | $v_start = $bottom - $y_start + $offset; |
|---|
| 1570 | $v_end = $bottom - $y_end + $offset; |
|---|
| 1571 | switch ($type) { |
|---|
| 1572 | case 'fill': |
|---|
| 1573 | // draw it this way 'cos the FilledPolygon routine seems a bit buggy. |
|---|
| 1574 | ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); |
|---|
| 1575 | ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); |
|---|
| 1576 | break; |
|---|
| 1577 | case 'open': |
|---|
| 1578 | //ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); |
|---|
| 1579 | ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); |
|---|
| 1580 | ImageLine($this->image, $u_start, $v_start, $u_start, $zero, $this->colour[$colour]); |
|---|
| 1581 | ImageLine($this->image, $u_end, $v_end, $u_end, $zero, $this->colour[$colour]); |
|---|
| 1582 | break; |
|---|
| 1583 | } |
|---|
| 1584 | } else { |
|---|
| 1585 | $bottom = $this->calculated['boundary_box']['bottom']; |
|---|
| 1586 | $u_start = $x_start + $offset; |
|---|
| 1587 | $u_end = $x_end + $offset; |
|---|
| 1588 | $v_start = $bottom - $y_start + $offset; |
|---|
| 1589 | $v_end = $bottom - $y_end + $offset; |
|---|
| 1590 | |
|---|
| 1591 | if ($this->parameter['shadow_below_axis'] ) $bottom += $offset; |
|---|
| 1592 | if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn. |
|---|
| 1593 | switch ($type) { |
|---|
| 1594 | case 'fill': |
|---|
| 1595 | ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]); |
|---|
| 1596 | break; |
|---|
| 1597 | case 'open': |
|---|
| 1598 | ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]); |
|---|
| 1599 | break; |
|---|
| 1600 | } |
|---|
| 1601 | } |
|---|
| 1602 | } |
|---|
| 1603 | |
|---|
| 1604 | function line($x_start, $y_start, $x_end, $y_end, $type, $brush_type, $brush_size, $colour, $offset) { |
|---|
| 1605 | //dbug("drawing line of type: $type, at offset: $offset"); |
|---|
| 1606 | $u_start = $x_start + $offset; |
|---|
| 1607 | $v_start = $this->calculated['boundary_box']['bottom'] - $y_start + $offset; |
|---|
| 1608 | $u_end = $x_end + $offset; |
|---|
| 1609 | $v_end = $this->calculated['boundary_box']['bottom'] - $y_end + $offset; |
|---|
| 1610 | |
|---|
| 1611 | switch ($type) { |
|---|
| 1612 | case 'brush': |
|---|
| 1613 | $this->draw_brush_line($u_start, $v_start, $u_end, $v_end, $brush_size, $brush_type, $colour); |
|---|
| 1614 | break; |
|---|
| 1615 | case 'line' : |
|---|
| 1616 | ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); |
|---|
| 1617 | break; |
|---|
| 1618 | case 'dash': |
|---|
| 1619 | ImageDashedLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); |
|---|
| 1620 | break; |
|---|
| 1621 | } |
|---|
| 1622 | } |
|---|
| 1623 | |
|---|
| 1624 | // function to draw line. would prefer to use gdBrush but this is not supported yet. |
|---|
| 1625 | function draw_brush_line($x0, $y0, $x1, $y1, $size, $type, $colour) { |
|---|
| 1626 | //$this->dbug("line: $x0, $y0, $x1, $y1"); |
|---|
| 1627 | $dy = $y1 - $y0; |
|---|
| 1628 | $dx = $x1 - $x0; |
|---|
| 1629 | $t = 0; |
|---|
| 1630 | $watchdog = 1024; // precaution to prevent infinite loops. |
|---|
| 1631 | |
|---|
| 1632 | $this->draw_brush($x0, $y0, $size, $type, $colour); |
|---|
| 1633 | if (abs($dx) > abs($dy)) { // slope < 1 |
|---|
| 1634 | //$this->dbug("slope < 1"); |
|---|
| 1635 | $m = $dy / $dx; // compute slope |
|---|
| 1636 | $t += $y0; |
|---|
| 1637 | $dx = ($dx < 0) ? -1 : 1; |
|---|
| 1638 | $m *= $dx; |
|---|
| 1639 | while (round($x0) != round($x1)) { |
|---|
| 1640 | if (!$watchdog--) break; |
|---|
| 1641 | $x0 += $dx; // step to next x value |
|---|
| 1642 | $t += $m; // add slope to y value |
|---|
| 1643 | $y = round($t); |
|---|
| 1644 | //$this->dbug("x0=$x0, x1=$x1, y=$y watchdog=$watchdog"); |
|---|
| 1645 | $this->draw_brush($x0, $y, $size, $type, $colour); |
|---|
| 1646 | |
|---|
| 1647 | } |
|---|
| 1648 | } else { // slope >= 1 |
|---|
| 1649 | //$this->dbug("slope >= 1"); |
|---|
| 1650 | $m = $dx / $dy; // compute slope |
|---|
| 1651 | $t += $x0; |
|---|
| 1652 | $dy = ($dy < 0) ? -1 : 1; |
|---|
| 1653 | $m *= $dy; |
|---|
| 1654 | while (round($y0) != round($y1)) { |
|---|
| 1655 | if (!$watchdog--) break; |
|---|
| 1656 | $y0 += $dy; // step to next y value |
|---|
| 1657 | $t += $m; // add slope to x value |
|---|
| 1658 | $x = round($t); |
|---|
| 1659 | //$this->dbug("x=$x, y0=$y0, y1=$y1 watchdog=$watchdog"); |
|---|
| 1660 | $this->draw_brush($x, $y0, $size, $type, $colour); |
|---|
| 1661 | |
|---|
| 1662 | } |
|---|
| 1663 | } |
|---|
| 1664 | } |
|---|
| 1665 | |
|---|
| 1666 | function draw_brush($x, $y, $size, $type, $colour) { |
|---|
| 1667 | $x = round($x); |
|---|
| 1668 | $y = round($y); |
|---|
| 1669 | $half = round($size / 2); |
|---|
| 1670 | switch ($type) { |
|---|
| 1671 | case 'circle': |
|---|
| 1672 | ImageArc($this->image, $x, $y, $size, $size, 0, 360, $this->colour[$colour]); |
|---|
| 1673 | ImageFillToBorder($this->image, $x, $y, $this->colour[$colour], $this->colour[$colour]); |
|---|
| 1674 | break; |
|---|
| 1675 | case 'square': |
|---|
| 1676 | ImageFilledRectangle($this->image, $x-$half, $y-$half, $x+$half, $y+$half, $this->colour[$colour]); |
|---|
| 1677 | break; |
|---|
| 1678 | case 'vertical': |
|---|
| 1679 | ImageFilledRectangle($this->image, $x, $y-$half, $x+1, $y+$half, $this->colour[$colour]); |
|---|
| 1680 | break; |
|---|
| 1681 | case 'horizontal': |
|---|
| 1682 | ImageFilledRectangle($this->image, $x-$half, $y, $x+$half, $y+1, $this->colour[$colour]); |
|---|
| 1683 | break; |
|---|
| 1684 | case 'slash': |
|---|
| 1685 | ImageFilledPolygon($this->image, array($x+$half, $y-$half, |
|---|
| 1686 | $x+$half+1, $y-$half, |
|---|
| 1687 | $x-$half+1, $y+$half, |
|---|
| 1688 | $x-$half, $y+$half |
|---|
| 1689 | ), 4, $this->colour[$colour]); |
|---|
| 1690 | break; |
|---|
| 1691 | case 'backslash': |
|---|
| 1692 | ImageFilledPolygon($this->image, array($x-$half, $y-$half, |
|---|
| 1693 | $x-$half+1, $y-$half, |
|---|
| 1694 | $x+$half+1, $y+$half, |
|---|
| 1695 | $x+$half, $y+$half |
|---|
| 1696 | ), 4, $this->colour[$colour]); |
|---|
| 1697 | break; |
|---|
| 1698 | default: |
|---|
| 1699 | @eval($type); // user can create own brush script. |
|---|
| 1700 | } |
|---|
| 1701 | } |
|---|
| 1702 | |
|---|
| 1703 | } // class graph |
|---|
| 1704 | |
|---|
| 1705 | |
|---|
| 1706 | ?> |
|---|