From b9b17c8a30c086f721b6b75185e2c68e7cf38a8f Mon Sep 17 00:00:00 2001 From: nicolasconnault Date: Mon, 19 May 2008 05:20:48 +0000 Subject: [PATCH] Indenting the code properly --- lib/graphlib.php | 3094 +++++++++++++++++++++++----------------------- 1 file changed, 1547 insertions(+), 1547 deletions(-) diff --git a/lib/graphlib.php b/lib/graphlib.php index 6c79f3478a..230d910102 100644 --- a/lib/graphlib.php +++ b/lib/graphlib.php @@ -146,1620 +146,1620 @@ class graph { -// init all text - title, labels, and axis text. -function init() { - - /// Moodle mods: overrides the font path and encodings - - global $CFG; - - /// A default.ttf is searched for in this order: - /// dataroot/lang/xx_local/fonts - /// dataroot/lang/xx/fonts - /// dirroot/lang/xx/fonts - /// dataroot/lang - /// lib/ - - $currlang = current_language(); - if (file_exists("$CFG->dataroot/lang/".$currlang."_local/fonts/default.ttf")) { - $fontpath = "$CFG->dataroot/lang/".$currlang."_local/fonts/"; - } else if (file_exists("$CFG->dataroot/lang/$currlang/fonts/default.ttf")) { - $fontpath = "$CFG->dataroot/lang/$currlang/fonts/"; - } else if (file_exists("$CFG->dirroot/lang/$currlang/fonts/default.ttf")) { - $fontpath = "$CFG->dirroot/lang/$currlang/fonts/"; - } else if (file_exists("$CFG->dataroot/lang/default.ttf")) { - $fontpath = "$CFG->dataroot/lang/"; - } else { - $fontpath = "$CFG->libdir/"; - } - - $this->parameter['path_to_fonts'] = $fontpath; - - /// End Moodle mods - - - - $this->calculated['outer_border'] = $this->calculated['boundary_box']; - - // outer padding - $this->calculated['boundary_box']['left'] += $this->parameter['outer_padding']; - $this->calculated['boundary_box']['top'] += $this->parameter['outer_padding']; - $this->calculated['boundary_box']['right'] -= $this->parameter['outer_padding']; - $this->calculated['boundary_box']['bottom'] -= $this->parameter['outer_padding']; - - $this->init_x_axis(); - $this->init_y_axis(); - $this->init_legend(); - $this->init_labels(); - - // take into account tick lengths - $this->calculated['bottom_inner_padding'] = $this->parameter['x_inner_padding']; - if (($this->parameter['x_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) - $this->calculated['bottom_inner_padding'] -= $this->parameter['tick_length']; - $this->calculated['boundary_box']['bottom'] -= $this->calculated['bottom_inner_padding']; - - $this->calculated['left_inner_padding'] = $this->parameter['y_inner_padding']; - if ($this->parameter['y_axis_text_left']) { - if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) - $this->calculated['left_inner_padding'] -= $this->parameter['tick_length']; - } - $this->calculated['boundary_box']['left'] += $this->calculated['left_inner_padding']; - - $this->calculated['right_inner_padding'] = $this->parameter['y_inner_padding']; - if ($this->parameter['y_axis_text_right']) { - if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) - $this->calculated['right_inner_padding'] -= $this->parameter['tick_length']; - } - $this->calculated['boundary_box']['right'] -= $this->calculated['right_inner_padding']; - - // boundaryBox now has coords for plotting area. - $this->calculated['inner_border'] = $this->calculated['boundary_box']; - - $this->init_data(); - $this->init_x_ticks(); - $this->init_y_ticks(); -} - -function draw_text() { - $colour = $this->parameter['outer_background']; - if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'fill'); // graph background - - // draw border around image - $colour = $this->parameter['outer_border']; - if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'box'); // graph border - - $this->draw_title(); - $this->draw_x_label(); - $this->draw_y_label_left(); - $this->draw_y_label_right(); - $this->draw_x_axis(); - $this->draw_y_axis(); - if ($this->calculated['y_axis_left']['has_data']) $this->draw_zero_axis_left(); // either draw zero axis on left - else if ($this->calculated['y_axis_right']['has_data']) $this->draw_zero_axis_right(); // ... or right. - $this->draw_legend(); - - // draw border around plot area - $colour = $this->parameter['inner_background']; - if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, 'fill'); // graph background - - // draw border around image - $colour = $this->parameter['inner_border']; - if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, $this->parameter['inner_border_type']); // graph border -} - -function draw_stack() { - $this->init(); - $this->draw_text(); - - $yOrder = $this->y_order; // save y_order data. - // iterate over each data set. order is very important if you want to see data correctly. remember shadows!! - foreach ($yOrder as $set) { - $this->y_order = array($set); - $this->init_data(); - $this->draw_data(); - } - $this->y_order = $yOrder; // revert y_order data. - - $this->output(); -} - -function draw() { - $this->init(); - $this->draw_text(); - $this->draw_data(); - $this->output(); -} - -// draw a data set -function draw_set($order, $set, $offset) { - if ($offset) @$this->init_variable($colour, $this->y_format[$set]['shadow'], $this->parameter['shadow']); - else $colour = $this->y_format[$set]['colour']; - @$this->init_variable($point, $this->y_format[$set]['point'], 'none'); - @$this->init_variable($pointSize, $this->y_format[$set]['point_size'], $this->parameter['point_size']); - @$this->init_variable($line, $this->y_format[$set]['line'], 'none'); - @$this->init_variable($brushType, $this->y_format[$set]['brush_type'], $this->parameter['brush_type']); - @$this->init_variable($brushSize, $this->y_format[$set]['brush_size'], $this->parameter['brush_size']); - @$this->init_variable($bar, $this->y_format[$set]['bar'], 'none'); - @$this->init_variable($barSize, $this->y_format[$set]['bar_size'], $this->parameter['bar_size']); - @$this->init_variable($area, $this->y_format[$set]['area'], 'none'); - - $lastX = 0; - $lastY = 'none'; - $fromX = 0; - $fromY = 'none'; - - //print "set $set
"; - //expand_pre($this->calculated['y_plot']); - - foreach ($this->x_data as $index => $x) { - //print "index $index
"; - $thisY = $this->calculated['y_plot'][$set][$index]; - $thisX = $this->calculated['x_plot'][$index]; - - //print "$thisX, $thisY
"; - - if (($bar!='none') && (string)$thisY != 'none') { - if ($relatedset = $this->offset_relation[$set]) { // Moodle - $yoffset = $this->calculated['y_plot'][$relatedset][$index]; // Moodle - } else { // Moodle - $yoffset = 0; // Moodle - } // Moodle - //$this->bar($thisX, $thisY, $bar, $barSize, $colour, $offset, $set); // Moodle - $this->bar($thisX, $thisY, $bar, $barSize, $colour, $offset, $set, $yoffset); // Moodle + // init all text - title, labels, and axis text. + function init() { + + /// Moodle mods: overrides the font path and encodings + + global $CFG; + + /// A default.ttf is searched for in this order: + /// dataroot/lang/xx_local/fonts + /// dataroot/lang/xx/fonts + /// dirroot/lang/xx/fonts + /// dataroot/lang + /// lib/ + + $currlang = current_language(); + if (file_exists("$CFG->dataroot/lang/".$currlang."_local/fonts/default.ttf")) { + $fontpath = "$CFG->dataroot/lang/".$currlang."_local/fonts/"; + } else if (file_exists("$CFG->dataroot/lang/$currlang/fonts/default.ttf")) { + $fontpath = "$CFG->dataroot/lang/$currlang/fonts/"; + } else if (file_exists("$CFG->dirroot/lang/$currlang/fonts/default.ttf")) { + $fontpath = "$CFG->dirroot/lang/$currlang/fonts/"; + } else if (file_exists("$CFG->dataroot/lang/default.ttf")) { + $fontpath = "$CFG->dataroot/lang/"; + } else { + $fontpath = "$CFG->libdir/"; + } + + $this->parameter['path_to_fonts'] = $fontpath; + + /// End Moodle mods + + + + $this->calculated['outer_border'] = $this->calculated['boundary_box']; + + // outer padding + $this->calculated['boundary_box']['left'] += $this->parameter['outer_padding']; + $this->calculated['boundary_box']['top'] += $this->parameter['outer_padding']; + $this->calculated['boundary_box']['right'] -= $this->parameter['outer_padding']; + $this->calculated['boundary_box']['bottom'] -= $this->parameter['outer_padding']; + + $this->init_x_axis(); + $this->init_y_axis(); + $this->init_legend(); + $this->init_labels(); + + // take into account tick lengths + $this->calculated['bottom_inner_padding'] = $this->parameter['x_inner_padding']; + if (($this->parameter['x_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) + $this->calculated['bottom_inner_padding'] -= $this->parameter['tick_length']; + $this->calculated['boundary_box']['bottom'] -= $this->calculated['bottom_inner_padding']; + + $this->calculated['left_inner_padding'] = $this->parameter['y_inner_padding']; + if ($this->parameter['y_axis_text_left']) { + if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) + $this->calculated['left_inner_padding'] -= $this->parameter['tick_length']; + } + $this->calculated['boundary_box']['left'] += $this->calculated['left_inner_padding']; + + $this->calculated['right_inner_padding'] = $this->parameter['y_inner_padding']; + if ($this->parameter['y_axis_text_right']) { + if (($this->parameter['y_ticks_colour'] != 'none') && ($this->parameter['tick_length'] < 0)) + $this->calculated['right_inner_padding'] -= $this->parameter['tick_length']; + } + $this->calculated['boundary_box']['right'] -= $this->calculated['right_inner_padding']; + + // boundaryBox now has coords for plotting area. + $this->calculated['inner_border'] = $this->calculated['boundary_box']; + + $this->init_data(); + $this->init_x_ticks(); + $this->init_y_ticks(); + } + + function draw_text() { + $colour = $this->parameter['outer_background']; + if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'fill'); // graph background + + // draw border around image + $colour = $this->parameter['outer_border']; + if ($colour != 'none') $this->draw_rectangle($this->calculated['outer_border'], $colour, 'box'); // graph border + + $this->draw_title(); + $this->draw_x_label(); + $this->draw_y_label_left(); + $this->draw_y_label_right(); + $this->draw_x_axis(); + $this->draw_y_axis(); + if ($this->calculated['y_axis_left']['has_data']) $this->draw_zero_axis_left(); // either draw zero axis on left + else if ($this->calculated['y_axis_right']['has_data']) $this->draw_zero_axis_right(); // ... or right. + $this->draw_legend(); + + // draw border around plot area + $colour = $this->parameter['inner_background']; + if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, 'fill'); // graph background + + // draw border around image + $colour = $this->parameter['inner_border']; + if ($colour != 'none') $this->draw_rectangle($this->calculated['inner_border'], $colour, $this->parameter['inner_border_type']); // graph border } - if (($area!='none') && (((string)$lastY != 'none') && ((string)$thisY != 'none'))) - $this->area($lastX, $lastY, $thisX, $thisY, $area, $colour, $offset); + function draw_stack() { + $this->init(); + $this->draw_text(); + + $yOrder = $this->y_order; // save y_order data. + // iterate over each data set. order is very important if you want to see data correctly. remember shadows!! + foreach ($yOrder as $set) { + $this->y_order = array($set); + $this->init_data(); + $this->draw_data(); + } + $this->y_order = $yOrder; // revert y_order data. - if (($point!='none') && (string)$thisY != 'none') $this->plot($thisX, $thisY, $point, $pointSize, $colour, $offset); + $this->output(); + } - if (($line!='none') && ((string)$thisY != 'none')) { - if ((string)$fromY != 'none') - $this->line($fromX, $fromY, $thisX, $thisY, $line, $brushType, $brushSize, $colour, $offset); + function draw() { + $this->init(); + $this->draw_text(); + $this->draw_data(); + $this->output(); + } - $fromY = $thisY; // start next line from here - $fromX = $thisX; // ... - } else { + // draw a data set + function draw_set($order, $set, $offset) { + if ($offset) @$this->init_variable($colour, $this->y_format[$set]['shadow'], $this->parameter['shadow']); + else $colour = $this->y_format[$set]['colour']; + @$this->init_variable($point, $this->y_format[$set]['point'], 'none'); + @$this->init_variable($pointSize, $this->y_format[$set]['point_size'], $this->parameter['point_size']); + @$this->init_variable($line, $this->y_format[$set]['line'], 'none'); + @$this->init_variable($brushType, $this->y_format[$set]['brush_type'], $this->parameter['brush_type']); + @$this->init_variable($brushSize, $this->y_format[$set]['brush_size'], $this->parameter['brush_size']); + @$this->init_variable($bar, $this->y_format[$set]['bar'], 'none'); + @$this->init_variable($barSize, $this->y_format[$set]['bar_size'], $this->parameter['bar_size']); + @$this->init_variable($area, $this->y_format[$set]['area'], 'none'); + + $lastX = 0; + $lastY = 'none'; + $fromX = 0; $fromY = 'none'; - $fromX = 'none'; + + //print "set $set
"; + //expand_pre($this->calculated['y_plot']); + + foreach ($this->x_data as $index => $x) { + //print "index $index
"; + $thisY = $this->calculated['y_plot'][$set][$index]; + $thisX = $this->calculated['x_plot'][$index]; + + //print "$thisX, $thisY
"; + + if (($bar!='none') && (string)$thisY != 'none') { + if ($relatedset = $this->offset_relation[$set]) { // Moodle + $yoffset = $this->calculated['y_plot'][$relatedset][$index]; // Moodle + } else { // Moodle + $yoffset = 0; // Moodle + } // Moodle + //$this->bar($thisX, $thisY, $bar, $barSize, $colour, $offset, $set); // Moodle + $this->bar($thisX, $thisY, $bar, $barSize, $colour, $offset, $set, $yoffset); // Moodle + } + + if (($area!='none') && (((string)$lastY != 'none') && ((string)$thisY != 'none'))) + $this->area($lastX, $lastY, $thisX, $thisY, $area, $colour, $offset); + + if (($point!='none') && (string)$thisY != 'none') $this->plot($thisX, $thisY, $point, $pointSize, $colour, $offset); + + if (($line!='none') && ((string)$thisY != 'none')) { + if ((string)$fromY != 'none') + $this->line($fromX, $fromY, $thisX, $thisY, $line, $brushType, $brushSize, $colour, $offset); + + $fromY = $thisY; // start next line from here + $fromX = $thisX; // ... + } else { + $fromY = 'none'; + $fromX = 'none'; + } + + $lastX = $thisX; + $lastY = $thisY; + } } - $lastX = $thisX; - $lastY = $thisY; - } -} - -function draw_data() { - // cycle thru y data to be plotted - // first check for drop shadows... - foreach ($this->y_order as $order => $set) { - @$this->init_variable($offset, $this->y_format[$set]['shadow_offset'], $this->parameter['shadow_offset']); - @$this->init_variable($colour, $this->y_format[$set]['shadow'], $this->parameter['shadow']); - if ($colour != 'none') $this->draw_set($order, $set, $offset); - - } - - // then draw data - foreach ($this->y_order as $order => $set) { - $this->draw_set($order, $set, 0); - } -} - -function draw_legend() { - $position = $this->parameter['legend']; - if ($position == 'none') return; // abort if no border - - $borderColour = $this->parameter['legend_border']; - $offset = $this->parameter['legend_offset']; - $padding = $this->parameter['legend_padding']; - $height = $this->calculated['legend']['boundary_box_all']['height']; - $width = $this->calculated['legend']['boundary_box_all']['width']; - $graphTop = $this->calculated['boundary_box']['top']; - $graphBottom = $this->calculated['boundary_box']['bottom']; - $graphLeft = $this->calculated['boundary_box']['left']; - $graphRight = $this->calculated['boundary_box']['right']; - $outsideRight = $this->calculated['outer_border']['right']; - $outsideBottom = $this->calculated['outer_border']['bottom']; - switch ($position) { - case 'top-left': - $top = $graphTop + $offset; - $bottom = $graphTop + $height + $offset; - $left = $graphLeft + $offset; - $right = $graphLeft + $width + $offset; - - break; - case 'top-right': - $top = $graphTop + $offset; - $bottom = $graphTop + $height + $offset; - $left = $graphRight - $width - $offset; - $right = $graphRight - $offset; - - break; - case 'bottom-left': - $top = $graphBottom - $height - $offset; - $bottom = $graphBottom - $offset; - $left = $graphLeft + $offset; - $right = $graphLeft + $width + $offset; - - break; - case 'bottom-right': - $top = $graphBottom - $height - $offset; - $bottom = $graphBottom - $offset; - $left = $graphRight - $width - $offset; - $right = $graphRight - $offset; - break; - - case 'outside-top' : - $top = $graphTop; - $bottom = $graphTop + $height; - $left = $outsideRight - $width - $offset; - $right = $outsideRight - $offset; - break; - - case 'outside-bottom' : - $top = $graphBottom - $height; - $bottom = $graphBottom; - $left = $outsideRight - $width - $offset; - $right = $outsideRight - $offset; - break; - - case 'outside-left' : - $top = $outsideBottom - $height - $offset; - $bottom = $outsideBottom - $offset; - $left = $graphLeft; - $right = $graphLeft + $width; - break; - - case 'outside-right' : - $top = $outsideBottom - $height - $offset; - $bottom = $outsideBottom - $offset; - $left = $graphRight - $width; - $right = $graphRight; - break; - default: // default is top left. no particular reason. - $top = $this->calculated['boundary_box']['top']; - $bottom = $this->calculated['boundary_box']['top'] + $this->calculated['legend']['boundary_box_all']['height']; - $left = $this->calculated['boundary_box']['left']; - $right = $this->calculated['boundary_box']['right'] + $this->calculated['legend']['boundary_box_all']['width']; - -} - // legend border - if($borderColour!='none') $this->draw_rectangle(array('top' => $top, - 'left' => $left, - 'bottom' => $bottom, - 'right' => $right), $this->parameter['legend_border'], 'box'); - - // legend text - $legendText = array('points' => $this->parameter['legend_size'], - 'angle' => 0, - 'font' => $this->parameter['legend_font'], - 'colour' => $this->parameter['legend_colour']); - - $box = $this->calculated['legend']['boundary_box_max']['height']; // use max height for legend square size. - $x = $left + $padding; - $x_text = $x + $box * 2; - $y = $top + $padding; - - foreach ($this->y_order as $set) { - $legendText['text'] = $this->calculated['legend']['text'][$set]; - if ($legendText['text'] != 'none') { - // if text exists then draw box and text - $boxColour = $this->colour[$this->y_format[$set]['colour']]; - - // draw box - ImageFilledRectangle($this->image, $x, $y, $x + $box, $y + $box, $boxColour); - - // draw text - $coords = array('x' => $x + $box * 2, 'y' => $y, 'reference' => 'top-left'); - $legendText['boundary_box'] = $this->calculated['legend']['boundary_box'][$set]; - $this->update_boundaryBox($legendText['boundary_box'], $coords); - $this->print_TTF($legendText); - $y += $padding + $box; + function draw_data() { + // cycle thru y data to be plotted + // first check for drop shadows... + foreach ($this->y_order as $order => $set) { + @$this->init_variable($offset, $this->y_format[$set]['shadow_offset'], $this->parameter['shadow_offset']); + @$this->init_variable($colour, $this->y_format[$set]['shadow'], $this->parameter['shadow']); + if ($colour != 'none') $this->draw_set($order, $set, $offset); + + } + + // then draw data + foreach ($this->y_order as $order => $set) { + $this->draw_set($order, $set, 0); + } } - } - -} - -function draw_y_label_right() { - if (!$this->parameter['y_label_right']) return; - $x = $this->calculated['boundary_box']['right'] + $this->parameter['y_inner_padding']; - if ($this->parameter['y_axis_text_right']) $x += $this->calculated['y_axis_right']['boundary_box_max']['width'] - + $this->calculated['right_inner_padding']; - $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2; - - $label = $this->calculated['y_label_right']; - $coords = array('x' => $x, 'y' => $y, 'reference' => 'left-center'); - $this->update_boundaryBox($label['boundary_box'], $coords); - $this->print_TTF($label); -} - - -function draw_y_label_left() { - if (!$this->parameter['y_label_left']) return; - $x = $this->calculated['boundary_box']['left'] - $this->parameter['y_inner_padding']; - if ($this->parameter['y_axis_text_left']) $x -= $this->calculated['y_axis_left']['boundary_box_max']['width'] - + $this->calculated['left_inner_padding']; - $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2; - - $label = $this->calculated['y_label_left']; - $coords = array('x' => $x, 'y' => $y, 'reference' => 'right-center'); - $this->update_boundaryBox($label['boundary_box'], $coords); - $this->print_TTF($label); -} - -function draw_title() { - if (!$this->parameter['title']) return; - //$y = $this->calculated['outside_border']['top'] + $this->parameter['outer_padding']; - $y = $this->calculated['boundary_box']['top'] - $this->parameter['outer_padding']; - $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2; - $label = $this->calculated['title']; - $coords = array('x' => $x, 'y' => $y, 'reference' => 'bottom-center'); - $this->update_boundaryBox($label['boundary_box'], $coords); - $this->print_TTF($label); -} - -function draw_x_label() { - if (!$this->parameter['x_label']) return; - $y = $this->calculated['boundary_box']['bottom'] + $this->parameter['x_inner_padding']; - if ($this->parameter['x_axis_text']) $y += $this->calculated['x_axis']['boundary_box_max']['height'] - + $this->calculated['bottom_inner_padding']; - $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2; - $label = $this->calculated['x_label']; - $coords = array('x' => $x, 'y' => $y, 'reference' => 'top-center'); - $this->update_boundaryBox($label['boundary_box'], $coords); - $this->print_TTF($label); -} - -function draw_zero_axis_left() { - $colour = $this->parameter['zero_axis']; - if ($colour == 'none') return; - // draw zero axis on left hand side - $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top'] + ($this->calculated['y_axis_left']['max'] * $this->calculated['y_axis_left']['factor'])); - ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]); -} - -function draw_zero_axis_right() { - $colour = $this->parameter['zero_axis']; - if ($colour == 'none') return; - // draw zero axis on right hand side - $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top'] + ($this->calculated['y_axis_right']['max'] * $this->calculated['y_axis_right']['factor'])); - ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]); -} - -function draw_x_axis() { - $gridColour = $this->colour[$this->parameter['grid_colour']]; - $tickColour = $this->colour[$this->parameter['x_ticks_colour']]; - $axis_colour = $this->parameter['axis_colour']; - $xGrid = $this->parameter['x_grid']; - $gridTop = $this->calculated['boundary_box']['top']; - $gridBottom = $this->calculated['boundary_box']['bottom']; - - if ($this->parameter['tick_length'] >= 0) { - $tickTop = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length']; - $tickBottom = $this->calculated['boundary_box']['bottom']; - $textBottom = $tickBottom + $this->calculated['bottom_inner_padding']; - } else { - $tickTop = $this->calculated['boundary_box']['bottom']; - $tickBottom = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length']; - $textBottom = $tickBottom + $this->calculated['bottom_inner_padding']; - } - - $axis_font = $this->parameter['axis_font']; - $axis_size = $this->parameter['axis_size']; - $axis_angle = $this->parameter['x_axis_angle']; - - if ($axis_angle == 0) $reference = 'top-center'; - if ($axis_angle > 0) $reference = 'top-right'; - if ($axis_angle < 0) $reference = 'top-left'; - if ($axis_angle == 90) $reference = 'top-center'; - - //generic tag information. applies to all axis text. - $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour); - - foreach ($this->calculated['x_axis']['tick_x'] as $set => $tickX) { - // draw x grid if colour specified - if ($xGrid != 'none') { - switch ($xGrid) { - case 'line': - ImageLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour); + + function draw_legend() { + $position = $this->parameter['legend']; + if ($position == 'none') return; // abort if no border + + $borderColour = $this->parameter['legend_border']; + $offset = $this->parameter['legend_offset']; + $padding = $this->parameter['legend_padding']; + $height = $this->calculated['legend']['boundary_box_all']['height']; + $width = $this->calculated['legend']['boundary_box_all']['width']; + $graphTop = $this->calculated['boundary_box']['top']; + $graphBottom = $this->calculated['boundary_box']['bottom']; + $graphLeft = $this->calculated['boundary_box']['left']; + $graphRight = $this->calculated['boundary_box']['right']; + $outsideRight = $this->calculated['outer_border']['right']; + $outsideBottom = $this->calculated['outer_border']['bottom']; + switch ($position) { + case 'top-left': + $top = $graphTop + $offset; + $bottom = $graphTop + $height + $offset; + $left = $graphLeft + $offset; + $right = $graphLeft + $width + $offset; + + break; + case 'top-right': + $top = $graphTop + $offset; + $bottom = $graphTop + $height + $offset; + $left = $graphRight - $width - $offset; + $right = $graphRight - $offset; + + break; + case 'bottom-left': + $top = $graphBottom - $height - $offset; + $bottom = $graphBottom - $offset; + $left = $graphLeft + $offset; + $right = $graphLeft + $width + $offset; + break; - case 'dash': - ImageDashedLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour); + case 'bottom-right': + $top = $graphBottom - $height - $offset; + $bottom = $graphBottom - $offset; + $left = $graphRight - $width - $offset; + $right = $graphRight - $offset; break; + + case 'outside-top' : + $top = $graphTop; + $bottom = $graphTop + $height; + $left = $outsideRight - $width - $offset; + $right = $outsideRight - $offset; + break; + + case 'outside-bottom' : + $top = $graphBottom - $height; + $bottom = $graphBottom; + $left = $outsideRight - $width - $offset; + $right = $outsideRight - $offset; + break; + + case 'outside-left' : + $top = $outsideBottom - $height - $offset; + $bottom = $outsideBottom - $offset; + $left = $graphLeft; + $right = $graphLeft + $width; + break; + + case 'outside-right' : + $top = $outsideBottom - $height - $offset; + $bottom = $outsideBottom - $offset; + $left = $graphRight - $width; + $right = $graphRight; + break; + default: // default is top left. no particular reason. + $top = $this->calculated['boundary_box']['top']; + $bottom = $this->calculated['boundary_box']['top'] + $this->calculated['legend']['boundary_box_all']['height']; + $left = $this->calculated['boundary_box']['left']; + $right = $this->calculated['boundary_box']['right'] + $this->calculated['legend']['boundary_box_all']['width']; + + } + // legend border + if($borderColour!='none') $this->draw_rectangle(array('top' => $top, + 'left' => $left, + 'bottom' => $bottom, + 'right' => $right), $this->parameter['legend_border'], 'box'); + + // legend text + $legendText = array('points' => $this->parameter['legend_size'], + 'angle' => 0, + 'font' => $this->parameter['legend_font'], + 'colour' => $this->parameter['legend_colour']); + + $box = $this->calculated['legend']['boundary_box_max']['height']; // use max height for legend square size. + $x = $left + $padding; + $x_text = $x + $box * 2; + $y = $top + $padding; + + foreach ($this->y_order as $set) { + $legendText['text'] = $this->calculated['legend']['text'][$set]; + if ($legendText['text'] != 'none') { + // if text exists then draw box and text + $boxColour = $this->colour[$this->y_format[$set]['colour']]; + + // draw box + ImageFilledRectangle($this->image, $x, $y, $x + $box, $y + $box, $boxColour); + + // draw text + $coords = array('x' => $x + $box * 2, 'y' => $y, 'reference' => 'top-left'); + $legendText['boundary_box'] = $this->calculated['legend']['boundary_box'][$set]; + $this->update_boundaryBox($legendText['boundary_box'], $coords); + $this->print_TTF($legendText); + $y += $padding + $box; + } } + } - if ($this->parameter['x_axis_text'] && !($set % $this->parameter['x_axis_text'])) { // test if tick should be displayed - // draw tick - if ($tickColour != 'none') - ImageLine($this->image, round($tickX), round($tickTop), round($tickX), round($tickBottom), $tickColour); - - // draw axis text - $coords = array('x' => $tickX, 'y' => $textBottom, 'reference' => $reference); - $axisTag['text'] = $this->calculated['x_axis']['text'][$set]; - $axisTag['boundary_box'] = $this->calculated['x_axis']['boundary_box'][$set]; - $this->update_boundaryBox($axisTag['boundary_box'], $coords); - $this->print_TTF($axisTag); + function draw_y_label_right() { + if (!$this->parameter['y_label_right']) return; + $x = $this->calculated['boundary_box']['right'] + $this->parameter['y_inner_padding']; + if ($this->parameter['y_axis_text_right']) $x += $this->calculated['y_axis_right']['boundary_box_max']['width'] + + $this->calculated['right_inner_padding']; + $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2; + + $label = $this->calculated['y_label_right']; + $coords = array('x' => $x, 'y' => $y, 'reference' => 'left-center'); + $this->update_boundaryBox($label['boundary_box'], $coords); + $this->print_TTF($label); } - } -} - -function draw_y_axis() { - $gridColour = $this->colour[$this->parameter['grid_colour']]; - $tickColour = $this->colour[$this->parameter['y_ticks_colour']]; - $axis_colour = $this->parameter['axis_colour']; - $yGrid = $this->parameter['y_grid']; - $gridLeft = $this->calculated['boundary_box']['left']; - $gridRight = $this->calculated['boundary_box']['right']; - - // axis font information - $axis_font = $this->parameter['axis_font']; - $axis_size = $this->parameter['axis_size']; - $axis_angle = $this->parameter['y_axis_angle']; - $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour); - - - if ($this->calculated['y_axis_left']['has_data']) { - // LEFT HAND SIDE - // left and right coords for ticks - if ($this->parameter['tick_length'] >= 0) { - $tickLeft = $this->calculated['boundary_box']['left']; - $tickRight = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length']; - } else { - $tickLeft = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length']; - $tickRight = $this->calculated['boundary_box']['left']; + + + function draw_y_label_left() { + if (!$this->parameter['y_label_left']) return; + $x = $this->calculated['boundary_box']['left'] - $this->parameter['y_inner_padding']; + if ($this->parameter['y_axis_text_left']) $x -= $this->calculated['y_axis_left']['boundary_box_max']['width'] + + $this->calculated['left_inner_padding']; + $y = ($this->calculated['boundary_box']['bottom'] + $this->calculated['boundary_box']['top']) / 2; + + $label = $this->calculated['y_label_left']; + $coords = array('x' => $x, 'y' => $y, 'reference' => 'right-center'); + $this->update_boundaryBox($label['boundary_box'], $coords); + $this->print_TTF($label); } - $textRight = $tickLeft - $this->calculated['left_inner_padding']; - - if ($axis_angle == 0) $reference = 'right-center'; - if ($axis_angle > 0) $reference = 'right-top'; - if ($axis_angle < 0) $reference = 'right-bottom'; - if ($axis_angle == 90) $reference = 'right-center'; - - foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) { - // draw y grid if colour specified - if ($yGrid != 'none') { - switch ($yGrid) { - case 'line': - ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); - break; - case 'dash': - ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); - break; + + function draw_title() { + if (!$this->parameter['title']) return; + //$y = $this->calculated['outside_border']['top'] + $this->parameter['outer_padding']; + $y = $this->calculated['boundary_box']['top'] - $this->parameter['outer_padding']; + $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2; + $label = $this->calculated['title']; + $coords = array('x' => $x, 'y' => $y, 'reference' => 'bottom-center'); + $this->update_boundaryBox($label['boundary_box'], $coords); + $this->print_TTF($label); + } + + function draw_x_label() { + if (!$this->parameter['x_label']) return; + $y = $this->calculated['boundary_box']['bottom'] + $this->parameter['x_inner_padding']; + if ($this->parameter['x_axis_text']) $y += $this->calculated['x_axis']['boundary_box_max']['height'] + + $this->calculated['bottom_inner_padding']; + $x = ($this->calculated['boundary_box']['right'] + $this->calculated['boundary_box']['left']) / 2; + $label = $this->calculated['x_label']; + $coords = array('x' => $x, 'y' => $y, 'reference' => 'top-center'); + $this->update_boundaryBox($label['boundary_box'], $coords); + $this->print_TTF($label); + } + + function draw_zero_axis_left() { + $colour = $this->parameter['zero_axis']; + if ($colour == 'none') return; + // draw zero axis on left hand side + $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top'] + ($this->calculated['y_axis_left']['max'] * $this->calculated['y_axis_left']['factor'])); + ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]); + } + + function draw_zero_axis_right() { + $colour = $this->parameter['zero_axis']; + if ($colour == 'none') return; + // draw zero axis on right hand side + $this->calculated['zero_axis'] = round($this->calculated['boundary_box']['top'] + ($this->calculated['y_axis_right']['max'] * $this->calculated['y_axis_right']['factor'])); + ImageLine($this->image, $this->calculated['boundary_box']['left'], $this->calculated['zero_axis'], $this->calculated['boundary_box']['right'], $this->calculated['zero_axis'], $this->colour[$colour]); + } + + function draw_x_axis() { + $gridColour = $this->colour[$this->parameter['grid_colour']]; + $tickColour = $this->colour[$this->parameter['x_ticks_colour']]; + $axis_colour = $this->parameter['axis_colour']; + $xGrid = $this->parameter['x_grid']; + $gridTop = $this->calculated['boundary_box']['top']; + $gridBottom = $this->calculated['boundary_box']['bottom']; + + if ($this->parameter['tick_length'] >= 0) { + $tickTop = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length']; + $tickBottom = $this->calculated['boundary_box']['bottom']; + $textBottom = $tickBottom + $this->calculated['bottom_inner_padding']; + } else { + $tickTop = $this->calculated['boundary_box']['bottom']; + $tickBottom = $this->calculated['boundary_box']['bottom'] - $this->parameter['tick_length']; + $textBottom = $tickBottom + $this->calculated['bottom_inner_padding']; + } + + $axis_font = $this->parameter['axis_font']; + $axis_size = $this->parameter['axis_size']; + $axis_angle = $this->parameter['x_axis_angle']; + + if ($axis_angle == 0) $reference = 'top-center'; + if ($axis_angle > 0) $reference = 'top-right'; + if ($axis_angle < 0) $reference = 'top-left'; + if ($axis_angle == 90) $reference = 'top-center'; + + //generic tag information. applies to all axis text. + $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour); + + foreach ($this->calculated['x_axis']['tick_x'] as $set => $tickX) { + // draw x grid if colour specified + if ($xGrid != 'none') { + switch ($xGrid) { + case 'line': + ImageLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour); + break; + case 'dash': + ImageDashedLine($this->image, round($tickX), round($gridTop), round($tickX), round($gridBottom), $gridColour); + break; + } + } + + if ($this->parameter['x_axis_text'] && !($set % $this->parameter['x_axis_text'])) { // test if tick should be displayed + // draw tick + if ($tickColour != 'none') + ImageLine($this->image, round($tickX), round($tickTop), round($tickX), round($tickBottom), $tickColour); + + // draw axis text + $coords = array('x' => $tickX, 'y' => $textBottom, 'reference' => $reference); + $axisTag['text'] = $this->calculated['x_axis']['text'][$set]; + $axisTag['boundary_box'] = $this->calculated['x_axis']['boundary_box'][$set]; + $this->update_boundaryBox($axisTag['boundary_box'], $coords); + $this->print_TTF($axisTag); + } + } + } + + function draw_y_axis() { + $gridColour = $this->colour[$this->parameter['grid_colour']]; + $tickColour = $this->colour[$this->parameter['y_ticks_colour']]; + $axis_colour = $this->parameter['axis_colour']; + $yGrid = $this->parameter['y_grid']; + $gridLeft = $this->calculated['boundary_box']['left']; + $gridRight = $this->calculated['boundary_box']['right']; + + // axis font information + $axis_font = $this->parameter['axis_font']; + $axis_size = $this->parameter['axis_size']; + $axis_angle = $this->parameter['y_axis_angle']; + $axisTag = array('points' => $axis_size, 'angle' => $axis_angle, 'font' => $axis_font, 'colour' => $axis_colour); + + + if ($this->calculated['y_axis_left']['has_data']) { + // LEFT HAND SIDE + // left and right coords for ticks + if ($this->parameter['tick_length'] >= 0) { + $tickLeft = $this->calculated['boundary_box']['left']; + $tickRight = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length']; + } else { + $tickLeft = $this->calculated['boundary_box']['left'] + $this->parameter['tick_length']; + $tickRight = $this->calculated['boundary_box']['left']; + } + $textRight = $tickLeft - $this->calculated['left_inner_padding']; + + if ($axis_angle == 0) $reference = 'right-center'; + if ($axis_angle > 0) $reference = 'right-top'; + if ($axis_angle < 0) $reference = 'right-bottom'; + if ($axis_angle == 90) $reference = 'right-center'; + + foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) { + // draw y grid if colour specified + if ($yGrid != 'none') { + switch ($yGrid) { + case 'line': + ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); + break; + case 'dash': + ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); + break; + } + } + + // y axis text + if ($this->parameter['y_axis_text_left'] && !($set % $this->parameter['y_axis_text_left'])) { // test if tick should be displayed + // draw tick + if ($tickColour != 'none') + ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour); + + // draw axis text... + $coords = array('x' => $textRight, 'y' => $tickY, 'reference' => $reference); + $axisTag['text'] = $this->calculated['y_axis_left']['text'][$set]; + $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set]; + $this->update_boundaryBox($axisTag['boundary_box'], $coords); + $this->print_TTF($axisTag); + } } } - // y axis text - if ($this->parameter['y_axis_text_left'] && !($set % $this->parameter['y_axis_text_left'])) { // test if tick should be displayed - // draw tick - if ($tickColour != 'none') - ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour); - - // draw axis text... - $coords = array('x' => $textRight, 'y' => $tickY, 'reference' => $reference); - $axisTag['text'] = $this->calculated['y_axis_left']['text'][$set]; - $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set]; - $this->update_boundaryBox($axisTag['boundary_box'], $coords); - $this->print_TTF($axisTag); + if ($this->calculated['y_axis_right']['has_data']) { + // RIGHT HAND SIDE + // left and right coords for ticks + if ($this->parameter['tick_length'] >= 0) { + $tickLeft = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length']; + $tickRight = $this->calculated['boundary_box']['right']; + } else { + $tickLeft = $this->calculated['boundary_box']['right']; + $tickRight = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length']; + } + $textLeft = $tickRight+ $this->calculated['left_inner_padding']; + + if ($axis_angle == 0) $reference = 'left-center'; + if ($axis_angle > 0) $reference = 'left-bottom'; + if ($axis_angle < 0) $reference = 'left-top'; + if ($axis_angle == 90) $reference = 'left-center'; + + foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) { + if (!$this->calculated['y_axis_left']['has_data'] && $yGrid != 'none') { // draw grid if not drawn already (above) + switch ($yGrid) { + case 'line': + ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); + break; + case 'dash': + ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); + break; + } + } + + if ($this->parameter['y_axis_text_right'] && !($set % $this->parameter['y_axis_text_right'])) { // test if tick should be displayed + // draw tick + if ($tickColour != 'none') + ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour); + + // draw axis text... + $coords = array('x' => $textLeft, 'y' => $tickY, 'reference' => $reference); + $axisTag['text'] = $this->calculated['y_axis_right']['text'][$set]; + $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set]; + $this->update_boundaryBox($axisTag['boundary_box'], $coords); + $this->print_TTF($axisTag); + } + } } } - } - - if ($this->calculated['y_axis_right']['has_data']) { - // RIGHT HAND SIDE - // left and right coords for ticks - if ($this->parameter['tick_length'] >= 0) { - $tickLeft = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length']; - $tickRight = $this->calculated['boundary_box']['right']; - } else { - $tickLeft = $this->calculated['boundary_box']['right']; - $tickRight = $this->calculated['boundary_box']['right'] - $this->parameter['tick_length']; + + function init_data() { + $this->calculated['y_plot'] = array(); // array to hold pixel plotting coords for y axis + $height = $this->calculated['boundary_box']['bottom'] - $this->calculated['boundary_box']['top']; + $width = $this->calculated['boundary_box']['right'] - $this->calculated['boundary_box']['left']; + + // calculate pixel steps between axis ticks. + $this->calculated['y_axis']['step'] = $height / ($this->parameter['y_axis_gridlines'] - 1); + + // calculate x ticks spacing taking into account x offset for ticks. + $extraTick = 2 * $this->parameter['x_offset']; // extra tick to account for padding + $numTicks = $this->calculated['x_axis']['num_ticks'] - 1; // number of x ticks + + // Hack by rodger to avoid division by zero, see bug 1231 + if ($numTicks==0) $numTicks=1; + + $this->calculated['x_axis']['step'] = $width / ($numTicks + $extraTick); + $widthPlot = $width - ($this->calculated['x_axis']['step'] * $extraTick); + $this->calculated['x_axis']['step'] = $widthPlot / $numTicks; + + //calculate factor for transforming x,y physical coords to logical coords for right hand y_axis. + $y_range = $this->calculated['y_axis_right']['max'] - $this->calculated['y_axis_right']['min']; + $y_range = ($y_range ? $y_range : 1); + $this->calculated['y_axis_right']['factor'] = $height / $y_range; + + //calculate factor for transforming x,y physical coords to logical coords for left hand axis. + $yRange = $this->calculated['y_axis_left']['max'] - $this->calculated['y_axis_left']['min']; + $yRange = ($yRange ? $yRange : 1); + $this->calculated['y_axis_left']['factor'] = $height / $yRange; + if ($this->parameter['x_axis_gridlines'] != 'auto') { + $xRange = $this->calculated['x_axis']['max'] - $this->calculated['x_axis']['min']; + $xRange = ($xRange ? $xRange : 1); + $this->calculated['x_axis']['factor'] = $widthPlot / $xRange; + } + + //expand_pre($this->calculated['boundary_box']); + // cycle thru all data sets... + $this->calculated['num_bars'] = 0; + foreach ($this->y_order as $order => $set) { + // determine how many bars there are + if (isset($this->y_format[$set]['bar']) && ($this->y_format[$set]['bar'] != 'none')) { + $this->calculated['bar_offset_index'][$set] = $this->calculated['num_bars']; // index to relate bar with data set. + $this->calculated['num_bars']++; + } + + // calculate y coords for plotting data + foreach ($this->x_data as $index => $x) { + $this->calculated['y_plot'][$set][$index] = $this->y_data[$set][$index]; + + if ((string)$this->y_data[$set][$index] != 'none') { + + if (isset($this->y_format[$set]['y_axis']) && $this->y_format[$set]['y_axis'] == 'right') { + $this->calculated['y_plot'][$set][$index] = + round(($this->y_data[$set][$index] - $this->calculated['y_axis_right']['min']) + * $this->calculated['y_axis_right']['factor']); + } else { + //print "$set $index
"; + $this->calculated['y_plot'][$set][$index] = + round(($this->y_data[$set][$index] - $this->calculated['y_axis_left']['min']) + * $this->calculated['y_axis_left']['factor']); + } + + } + } + } + //print "factor ".$this->calculated['x_axis']['factor']."
"; + //expand_pre($this->calculated['x_plot']); + + // calculate bar parameters if bars are to be drawn. + if ($this->calculated['num_bars']) { + $xStep = $this->calculated['x_axis']['step']; + $totalWidth = $this->calculated['x_axis']['step'] - $this->parameter['bar_spacing']; + $barWidth = $totalWidth / $this->calculated['num_bars']; + + $barX = ($barWidth - $totalWidth) / 2; // starting x offset + for ($i=0; $i < $this->calculated['num_bars']; $i++) { + $this->calculated['bar_offset_x'][$i] = $barX; + $barX += $barWidth; // add width of bar to x offset. + } + $this->calculated['bar_width'] = $barWidth; + } + + } - $textLeft = $tickRight+ $this->calculated['left_inner_padding']; - - if ($axis_angle == 0) $reference = 'left-center'; - if ($axis_angle > 0) $reference = 'left-bottom'; - if ($axis_angle < 0) $reference = 'left-top'; - if ($axis_angle == 90) $reference = 'left-center'; - - foreach ($this->calculated['y_axis']['tick_y'] as $set => $tickY) { - if (!$this->calculated['y_axis_left']['has_data'] && $yGrid != 'none') { // draw grid if not drawn already (above) - switch ($yGrid) { - case 'line': - ImageLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); - break; - case 'dash': - ImageDashedLine($this->image, round($gridLeft), round($tickY), round($gridRight), round($tickY), $gridColour); - break; + + function init_x_ticks() { + // get coords for x axis ticks and data plots + //$xGrid = $this->parameter['x_grid']; + $xStep = $this->calculated['x_axis']['step']; + $ticksOffset = $this->parameter['x_offset']; // where to start drawing ticks relative to y axis. + $gridLeft = $this->calculated['boundary_box']['left'] + ($xStep * $ticksOffset); // grid x start + $tickX = $gridLeft; // tick x coord + + foreach ($this->calculated['x_axis']['text'] as $set => $value) { + //print "index: $set
"; + // x tick value + $this->calculated['x_axis']['tick_x'][$set] = $tickX; + // if num ticks is auto then x plot value is same as x tick + if ($this->parameter['x_axis_gridlines'] == 'auto') $this->calculated['x_plot'][$set] = round($tickX); + //print $this->calculated['x_plot'][$set].'
'; + $tickX += $xStep; + } + + //print "xStep: $xStep
"; + // if numeric x axis then calculate x coords for each data point. this is seperate from x ticks. + $gridX = $gridLeft; + if (empty($this->calculated['x_axis']['factor'])) { + $this->calculated['x_axis']['factor'] = 0; + } + if (empty($this->calculated['x_axis']['min'])) { + $this->calculated['x_axis']['min'] = 0; + } + $factor = $this->calculated['x_axis']['factor']; + $min = $this->calculated['x_axis']['min']; + + if ($this->parameter['x_axis_gridlines'] != 'auto') { + foreach ($this->x_data as $index => $x) { + //print "index: $index, x: $x
"; + $offset = $x - $this->calculated['x_axis']['min']; + + //$gridX = ($offset * $this->calculated['x_axis']['factor']); + //print "offset: $offset
"; + //$this->calculated['x_plot'][$set] = $gridLeft + ($offset * $this->calculated['x_axis']['factor']); + + $this->calculated['x_plot'][$index] = $gridLeft + ($x - $min) * $factor; + + //print $this->calculated['x_plot'][$set].'
'; } } + //expand_pre($this->calculated['boundary_box']); + //print "factor ".$this->calculated['x_axis']['factor']."
"; + //expand_pre($this->calculated['x_plot']); + } + + function init_y_ticks() { + // get coords for y axis ticks + + $yStep = $this->calculated['y_axis']['step']; + $gridBottom = $this->calculated['boundary_box']['bottom']; + $tickY = $gridBottom; // tick y coord - if ($this->parameter['y_axis_text_right'] && !($set % $this->parameter['y_axis_text_right'])) { // test if tick should be displayed - // draw tick - if ($tickColour != 'none') - ImageLine($this->image, round($tickLeft), round($tickY), round($tickRight), round($tickY), $tickColour); - - // draw axis text... - $coords = array('x' => $textLeft, 'y' => $tickY, 'reference' => $reference); - $axisTag['text'] = $this->calculated['y_axis_right']['text'][$set]; - $axisTag['boundary_box'] = $this->calculated['y_axis_left']['boundary_box'][$set]; - $this->update_boundaryBox($axisTag['boundary_box'], $coords); - $this->print_TTF($axisTag); + for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { + $this->calculated['y_axis']['tick_y'][$i] = $tickY; + $tickY -= $yStep; } + } - } -} - -function init_data() { - $this->calculated['y_plot'] = array(); // array to hold pixel plotting coords for y axis - $height = $this->calculated['boundary_box']['bottom'] - $this->calculated['boundary_box']['top']; - $width = $this->calculated['boundary_box']['right'] - $this->calculated['boundary_box']['left']; - - // calculate pixel steps between axis ticks. - $this->calculated['y_axis']['step'] = $height / ($this->parameter['y_axis_gridlines'] - 1); - - // calculate x ticks spacing taking into account x offset for ticks. - $extraTick = 2 * $this->parameter['x_offset']; // extra tick to account for padding - $numTicks = $this->calculated['x_axis']['num_ticks'] - 1; // number of x ticks - - // Hack by rodger to avoid division by zero, see bug 1231 - if ($numTicks==0) $numTicks=1; - - $this->calculated['x_axis']['step'] = $width / ($numTicks + $extraTick); - $widthPlot = $width - ($this->calculated['x_axis']['step'] * $extraTick); - $this->calculated['x_axis']['step'] = $widthPlot / $numTicks; - - //calculate factor for transforming x,y physical coords to logical coords for right hand y_axis. - $y_range = $this->calculated['y_axis_right']['max'] - $this->calculated['y_axis_right']['min']; - $y_range = ($y_range ? $y_range : 1); - $this->calculated['y_axis_right']['factor'] = $height / $y_range; - - //calculate factor for transforming x,y physical coords to logical coords for left hand axis. - $yRange = $this->calculated['y_axis_left']['max'] - $this->calculated['y_axis_left']['min']; - $yRange = ($yRange ? $yRange : 1); - $this->calculated['y_axis_left']['factor'] = $height / $yRange; - if ($this->parameter['x_axis_gridlines'] != 'auto') { - $xRange = $this->calculated['x_axis']['max'] - $this->calculated['x_axis']['min']; - $xRange = ($xRange ? $xRange : 1); - $this->calculated['x_axis']['factor'] = $widthPlot / $xRange; - } - - //expand_pre($this->calculated['boundary_box']); - // cycle thru all data sets... - $this->calculated['num_bars'] = 0; - foreach ($this->y_order as $order => $set) { - // determine how many bars there are - if (isset($this->y_format[$set]['bar']) && ($this->y_format[$set]['bar'] != 'none')) { - $this->calculated['bar_offset_index'][$set] = $this->calculated['num_bars']; // index to relate bar with data set. - $this->calculated['num_bars']++; + + function init_labels() { + if ($this->parameter['title']) { + $size = $this->get_boundaryBox( + array('points' => $this->parameter['title_size'], + 'angle' => 0, + 'font' => $this->parameter['title_font'], + 'text' => $this->parameter['title'])); + $this->calculated['title']['boundary_box'] = $size; + $this->calculated['title']['text'] = $this->parameter['title']; + $this->calculated['title']['font'] = $this->parameter['title_font']; + $this->calculated['title']['points'] = $this->parameter['title_size']; + $this->calculated['title']['colour'] = $this->parameter['title_colour']; + $this->calculated['title']['angle'] = 0; + + $this->calculated['boundary_box']['top'] += $size['height'] + $this->parameter['outer_padding']; + //$this->calculated['boundary_box']['top'] += $size['height']; + + } else $this->calculated['title']['boundary_box'] = $this->get_null_size(); + + if ($this->parameter['y_label_left']) { + $this->calculated['y_label_left']['text'] = $this->parameter['y_label_left']; + $this->calculated['y_label_left']['angle'] = $this->parameter['y_label_angle']; + $this->calculated['y_label_left']['font'] = $this->parameter['label_font']; + $this->calculated['y_label_left']['points'] = $this->parameter['label_size']; + $this->calculated['y_label_left']['colour'] = $this->parameter['label_colour']; + + $size = $this->get_boundaryBox($this->calculated['y_label_left']); + $this->calculated['y_label_left']['boundary_box'] = $size; + //$this->calculated['boundary_box']['left'] += $size['width'] + $this->parameter['inner_padding']; + $this->calculated['boundary_box']['left'] += $size['width']; + + } else $this->calculated['y_label_left']['boundary_box'] = $this->get_null_size(); + + if ($this->parameter['y_label_right']) { + $this->calculated['y_label_right']['text'] = $this->parameter['y_label_right']; + $this->calculated['y_label_right']['angle'] = $this->parameter['y_label_angle']; + $this->calculated['y_label_right']['font'] = $this->parameter['label_font']; + $this->calculated['y_label_right']['points'] = $this->parameter['label_size']; + $this->calculated['y_label_right']['colour'] = $this->parameter['label_colour']; + + $size = $this->get_boundaryBox($this->calculated['y_label_right']); + $this->calculated['y_label_right']['boundary_box'] = $size; + //$this->calculated['boundary_box']['right'] -= $size['width'] + $this->parameter['inner_padding']; + $this->calculated['boundary_box']['right'] -= $size['width']; + + } else $this->calculated['y_label_right']['boundary_box'] = $this->get_null_size(); + + if ($this->parameter['x_label']) { + $this->calculated['x_label']['text'] = $this->parameter['x_label']; + $this->calculated['x_label']['angle'] = $this->parameter['x_label_angle']; + $this->calculated['x_label']['font'] = $this->parameter['label_font']; + $this->calculated['x_label']['points'] = $this->parameter['label_size']; + $this->calculated['x_label']['colour'] = $this->parameter['label_colour']; + + $size = $this->get_boundaryBox($this->calculated['x_label']); + $this->calculated['x_label']['boundary_box'] = $size; + //$this->calculated['boundary_box']['bottom'] -= $size['height'] + $this->parameter['inner_padding']; + $this->calculated['boundary_box']['bottom'] -= $size['height']; + + } else $this->calculated['x_label']['boundary_box'] = $this->get_null_size(); + } - // calculate y coords for plotting data - foreach ($this->x_data as $index => $x) { - $this->calculated['y_plot'][$set][$index] = $this->y_data[$set][$index]; - if ((string)$this->y_data[$set][$index] != 'none') { + function init_legend() { + $this->calculated['legend'] = array(); // array to hold calculated values for legend. + //$this->calculated['legend']['boundary_box_max'] = array('height' => 0, 'width' => 0); + $this->calculated['legend']['boundary_box_max'] = $this->get_null_size(); + if ($this->parameter['legend'] == 'none') return; + + $position = $this->parameter['legend']; + $numSets = 0; // number of data sets with legends. + $sumTextHeight = 0; // total of height of all legend text items. + $width = 0; + $height = 0; + + foreach ($this->y_order as $set) { + $text = isset($this->y_format[$set]['legend']) ? $this->y_format[$set]['legend'] : 'none'; + $size = $this->get_boundaryBox( + array('points' => $this->parameter['legend_size'], + 'angle' => 0, + 'font' => $this->parameter['legend_font'], + 'text' => $text)); + + $this->calculated['legend']['boundary_box'][$set] = $size; + $this->calculated['legend']['text'][$set] = $text; + //$this->calculated['legend']['font'][$set] = $this->parameter['legend_font']; + //$this->calculated['legend']['points'][$set] = $this->parameter['legend_size']; + //$this->calculated['legend']['angle'][$set] = 0; + + if ($text && $text!='none') { + $numSets++; + $sumTextHeight += $size['height']; + } + + if ($size['width'] > $this->calculated['legend']['boundary_box_max']['width']) + $this->calculated['legend']['boundary_box_max'] = $size; + } + + $offset = $this->parameter['legend_offset']; // offset in pixels of legend box from graph border. + $padding = $this->parameter['legend_padding']; // padding in pixels around legend text. + $textWidth = $this->calculated['legend']['boundary_box_max']['width']; // width of largest legend item. + $textHeight = $this->calculated['legend']['boundary_box_max']['height']; // use height as size to use for colour square in legend. + $width = $padding * 2 + $textWidth + $textHeight * 2; // left and right padding + maximum text width + space for square + $height = $padding * ($numSets + 1) + $sumTextHeight; // top and bottom padding + padding between text + text. + + + $this->calculated['legend']['boundary_box_all'] = array('width' => $width, + 'height' => $height, + 'offset' => $offset, + 'reference' => $position); + + switch ($position) { // move in right or bottom if legend is outside data plotting area. + case 'outside-top' : + $this->calculated['boundary_box']['right'] -= $offset + $width; // move in right hand side + break; + case 'outside-bottom' : + $this->calculated['boundary_box']['right'] -= $offset + $width; // move in right hand side + break; + + case 'outside-left' : + $this->calculated['boundary_box']['bottom'] -= $offset + $height; // move in right hand side + break; + + case 'outside-right' : + $this->calculated['boundary_box']['bottom'] -= $offset + $height; // move in right hand side + break; + } + } + + function init_y_axis() { + $this->calculated['y_axis_left'] = array(); // array to hold calculated values for y_axis on left. + $this->calculated['y_axis_left']['boundary_box_max'] = $this->get_null_size(); + $this->calculated['y_axis_right'] = array(); // array to hold calculated values for y_axis on right. + $this->calculated['y_axis_right']['boundary_box_max'] = $this->get_null_size(); + + $axis_font = $this->parameter['axis_font']; + $axis_size = $this->parameter['axis_size']; + $axis_colour = $this->parameter['axis_colour']; + $axis_angle = $this->parameter['y_axis_angle']; + $y_tick_labels = $this->y_tick_labels; + + $this->calculated['y_axis_left']['has_data'] = FALSE; + $this->calculated['y_axis_right']['has_data'] = FALSE; + + // find min and max y values. + $minLeft = $this->parameter['y_min_left']; + $maxLeft = $this->parameter['y_max_left']; + $minRight = $this->parameter['y_min_right']; + $maxRight = $this->parameter['y_max_right']; + $dataLeft = array(); + $dataRight = array(); + foreach ($this->y_order as $order => $set) { if (isset($this->y_format[$set]['y_axis']) && $this->y_format[$set]['y_axis'] == 'right') { - $this->calculated['y_plot'][$set][$index] = - round(($this->y_data[$set][$index] - $this->calculated['y_axis_right']['min']) - * $this->calculated['y_axis_right']['factor']); + $this->calculated['y_axis_right']['has_data'] = TRUE; + $dataRight = array_merge($dataRight, $this->y_data[$set]); } else { - //print "$set $index
"; - $this->calculated['y_plot'][$set][$index] = - round(($this->y_data[$set][$index] - $this->calculated['y_axis_left']['min']) - * $this->calculated['y_axis_left']['factor']); + $this->calculated['y_axis_left']['has_data'] = TRUE; + $dataLeft = array_merge($dataLeft, $this->y_data[$set]); } + } + $dataLeftRange = $this->find_range($dataLeft, $minLeft, $maxLeft, $this->parameter['y_resolution_left']); + $dataRightRange = $this->find_range($dataRight, $minRight, $maxRight, $this->parameter['y_resolution_right']); + $minLeft = $dataLeftRange['min']; + $maxLeft = $dataLeftRange['max']; + $minRight = $dataRightRange['min']; + $maxRight = $dataRightRange['max']; + + $this->calculated['y_axis_left']['min'] = $minLeft; + $this->calculated['y_axis_left']['max'] = $maxLeft; + $this->calculated['y_axis_right']['min'] = $minRight; + $this->calculated['y_axis_right']['max'] = $maxRight; + + $stepLeft = ($maxLeft - $minLeft) / ($this->parameter['y_axis_gridlines'] - 1); + $startLeft = $minLeft; + $step_right = ($maxRight - $minRight) / ($this->parameter['y_axis_gridlines'] - 1); + $start_right = $minRight; + + if ($this->parameter['y_axis_text_left']) { + for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes + // left y axis + if ($y_tick_labels) { + $value = $y_tick_labels[$i]; + } else { + $value = number_format($startLeft, $this->parameter['y_decimal_left'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); + } + $this->calculated['y_axis_left']['data'][$i] = $startLeft; + $this->calculated['y_axis_left']['text'][$i] = $value; // text is formatted raw data + + $size = $this->get_boundaryBox( + array('points' => $axis_size, + 'font' => $axis_font, + 'angle' => $axis_angle, + 'colour' => $axis_colour, + 'text' => $value)); + $this->calculated['y_axis_left']['boundary_box'][$i] = $size; + + if ($size['height'] > $this->calculated['y_axis_left']['boundary_box_max']['height']) + $this->calculated['y_axis_left']['boundary_box_max']['height'] = $size['height']; + if ($size['width'] > $this->calculated['y_axis_left']['boundary_box_max']['width']) + $this->calculated['y_axis_left']['boundary_box_max']['width'] = $size['width']; + + $startLeft += $stepLeft; + } + $this->calculated['boundary_box']['left'] += $this->calculated['y_axis_left']['boundary_box_max']['width'] + + $this->parameter['y_inner_padding']; + } + if ($this->parameter['y_axis_text_right']) { + for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes + // right y axis + $value = number_format($start_right, $this->parameter['y_decimal_right'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); + $this->calculated['y_axis_right']['data'][$i] = $start_right; + $this->calculated['y_axis_right']['text'][$i] = $value; // text is formatted raw data + $size = $this->get_boundaryBox( + array('points' => $axis_size, + 'font' => $axis_font, + 'angle' => $axis_angle, + 'colour' => $axis_colour, + 'text' => $value)); + $this->calculated['y_axis_right']['boundary_box'][$i] = $size; + + if ($size['height'] > $this->calculated['y_axis_right']['boundary_box_max']['height']) + $this->calculated['y_axis_right']['boundary_box_max'] = $size; + if ($size['width'] > $this->calculated['y_axis_right']['boundary_box_max']['width']) + $this->calculated['y_axis_right']['boundary_box_max']['width'] = $size['width']; + + $start_right += $step_right; + } + $this->calculated['boundary_box']['right'] -= $this->calculated['y_axis_right']['boundary_box_max']['width'] + + $this->parameter['y_inner_padding']; } } - } - //print "factor ".$this->calculated['x_axis']['factor']."
"; - //expand_pre($this->calculated['x_plot']); - - // calculate bar parameters if bars are to be drawn. - if ($this->calculated['num_bars']) { - $xStep = $this->calculated['x_axis']['step']; - $totalWidth = $this->calculated['x_axis']['step'] - $this->parameter['bar_spacing']; - $barWidth = $totalWidth / $this->calculated['num_bars']; - - $barX = ($barWidth - $totalWidth) / 2; // starting x offset - for ($i=0; $i < $this->calculated['num_bars']; $i++) { - $this->calculated['bar_offset_x'][$i] = $barX; - $barX += $barWidth; // add width of bar to x offset. - } - $this->calculated['bar_width'] = $barWidth; - } - - -} - -function init_x_ticks() { - // get coords for x axis ticks and data plots - //$xGrid = $this->parameter['x_grid']; - $xStep = $this->calculated['x_axis']['step']; - $ticksOffset = $this->parameter['x_offset']; // where to start drawing ticks relative to y axis. - $gridLeft = $this->calculated['boundary_box']['left'] + ($xStep * $ticksOffset); // grid x start - $tickX = $gridLeft; // tick x coord - - foreach ($this->calculated['x_axis']['text'] as $set => $value) { - //print "index: $set
"; - // x tick value - $this->calculated['x_axis']['tick_x'][$set] = $tickX; - // if num ticks is auto then x plot value is same as x tick - if ($this->parameter['x_axis_gridlines'] == 'auto') $this->calculated['x_plot'][$set] = round($tickX); - //print $this->calculated['x_plot'][$set].'
'; - $tickX += $xStep; - } - - //print "xStep: $xStep
"; - // if numeric x axis then calculate x coords for each data point. this is seperate from x ticks. - $gridX = $gridLeft; - if (empty($this->calculated['x_axis']['factor'])) { - $this->calculated['x_axis']['factor'] = 0; - } - if (empty($this->calculated['x_axis']['min'])) { - $this->calculated['x_axis']['min'] = 0; - } - $factor = $this->calculated['x_axis']['factor']; - $min = $this->calculated['x_axis']['min']; - - if ($this->parameter['x_axis_gridlines'] != 'auto') { - foreach ($this->x_data as $index => $x) { - //print "index: $index, x: $x
"; - $offset = $x - $this->calculated['x_axis']['min']; - - //$gridX = ($offset * $this->calculated['x_axis']['factor']); - //print "offset: $offset
"; - //$this->calculated['x_plot'][$set] = $gridLeft + ($offset * $this->calculated['x_axis']['factor']); - - $this->calculated['x_plot'][$index] = $gridLeft + ($x - $min) * $factor; - - //print $this->calculated['x_plot'][$set].'
'; - } - } - //expand_pre($this->calculated['boundary_box']); - //print "factor ".$this->calculated['x_axis']['factor']."
"; - //expand_pre($this->calculated['x_plot']); -} - -function init_y_ticks() { - // get coords for y axis ticks - - $yStep = $this->calculated['y_axis']['step']; - $gridBottom = $this->calculated['boundary_box']['bottom']; - $tickY = $gridBottom; // tick y coord - - for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { - $this->calculated['y_axis']['tick_y'][$i] = $tickY; - $tickY -= $yStep; - } - -} - -function init_labels() { - if ($this->parameter['title']) { - $size = $this->get_boundaryBox( - array('points' => $this->parameter['title_size'], - 'angle' => 0, - 'font' => $this->parameter['title_font'], - 'text' => $this->parameter['title'])); - $this->calculated['title']['boundary_box'] = $size; - $this->calculated['title']['text'] = $this->parameter['title']; - $this->calculated['title']['font'] = $this->parameter['title_font']; - $this->calculated['title']['points'] = $this->parameter['title_size']; - $this->calculated['title']['colour'] = $this->parameter['title_colour']; - $this->calculated['title']['angle'] = 0; - - $this->calculated['boundary_box']['top'] += $size['height'] + $this->parameter['outer_padding']; - //$this->calculated['boundary_box']['top'] += $size['height']; - - } else $this->calculated['title']['boundary_box'] = $this->get_null_size(); - - if ($this->parameter['y_label_left']) { - $this->calculated['y_label_left']['text'] = $this->parameter['y_label_left']; - $this->calculated['y_label_left']['angle'] = $this->parameter['y_label_angle']; - $this->calculated['y_label_left']['font'] = $this->parameter['label_font']; - $this->calculated['y_label_left']['points'] = $this->parameter['label_size']; - $this->calculated['y_label_left']['colour'] = $this->parameter['label_colour']; - - $size = $this->get_boundaryBox($this->calculated['y_label_left']); - $this->calculated['y_label_left']['boundary_box'] = $size; - //$this->calculated['boundary_box']['left'] += $size['width'] + $this->parameter['inner_padding']; - $this->calculated['boundary_box']['left'] += $size['width']; - - } else $this->calculated['y_label_left']['boundary_box'] = $this->get_null_size(); - - if ($this->parameter['y_label_right']) { - $this->calculated['y_label_right']['text'] = $this->parameter['y_label_right']; - $this->calculated['y_label_right']['angle'] = $this->parameter['y_label_angle']; - $this->calculated['y_label_right']['font'] = $this->parameter['label_font']; - $this->calculated['y_label_right']['points'] = $this->parameter['label_size']; - $this->calculated['y_label_right']['colour'] = $this->parameter['label_colour']; - - $size = $this->get_boundaryBox($this->calculated['y_label_right']); - $this->calculated['y_label_right']['boundary_box'] = $size; - //$this->calculated['boundary_box']['right'] -= $size['width'] + $this->parameter['inner_padding']; - $this->calculated['boundary_box']['right'] -= $size['width']; - - } else $this->calculated['y_label_right']['boundary_box'] = $this->get_null_size(); - - if ($this->parameter['x_label']) { - $this->calculated['x_label']['text'] = $this->parameter['x_label']; - $this->calculated['x_label']['angle'] = $this->parameter['x_label_angle']; - $this->calculated['x_label']['font'] = $this->parameter['label_font']; - $this->calculated['x_label']['points'] = $this->parameter['label_size']; - $this->calculated['x_label']['colour'] = $this->parameter['label_colour']; - - $size = $this->get_boundaryBox($this->calculated['x_label']); - $this->calculated['x_label']['boundary_box'] = $size; - //$this->calculated['boundary_box']['bottom'] -= $size['height'] + $this->parameter['inner_padding']; - $this->calculated['boundary_box']['bottom'] -= $size['height']; - - } else $this->calculated['x_label']['boundary_box'] = $this->get_null_size(); - -} - - -function init_legend() { - $this->calculated['legend'] = array(); // array to hold calculated values for legend. - //$this->calculated['legend']['boundary_box_max'] = array('height' => 0, 'width' => 0); - $this->calculated['legend']['boundary_box_max'] = $this->get_null_size(); - if ($this->parameter['legend'] == 'none') return; - - $position = $this->parameter['legend']; - $numSets = 0; // number of data sets with legends. - $sumTextHeight = 0; // total of height of all legend text items. - $width = 0; - $height = 0; - - foreach ($this->y_order as $set) { - $text = isset($this->y_format[$set]['legend']) ? $this->y_format[$set]['legend'] : 'none'; - $size = $this->get_boundaryBox( - array('points' => $this->parameter['legend_size'], - 'angle' => 0, - 'font' => $this->parameter['legend_font'], - 'text' => $text)); - - $this->calculated['legend']['boundary_box'][$set] = $size; - $this->calculated['legend']['text'][$set] = $text; - //$this->calculated['legend']['font'][$set] = $this->parameter['legend_font']; - //$this->calculated['legend']['points'][$set] = $this->parameter['legend_size']; - //$this->calculated['legend']['angle'][$set] = 0; - - if ($text && $text!='none') { - $numSets++; - $sumTextHeight += $size['height']; - } - - if ($size['width'] > $this->calculated['legend']['boundary_box_max']['width']) - $this->calculated['legend']['boundary_box_max'] = $size; - } - - $offset = $this->parameter['legend_offset']; // offset in pixels of legend box from graph border. - $padding = $this->parameter['legend_padding']; // padding in pixels around legend text. - $textWidth = $this->calculated['legend']['boundary_box_max']['width']; // width of largest legend item. - $textHeight = $this->calculated['legend']['boundary_box_max']['height']; // use height as size to use for colour square in legend. - $width = $padding * 2 + $textWidth + $textHeight * 2; // left and right padding + maximum text width + space for square - $height = $padding * ($numSets + 1) + $sumTextHeight; // top and bottom padding + padding between text + text. - - - $this->calculated['legend']['boundary_box_all'] = array('width' => $width, - 'height' => $height, - 'offset' => $offset, - 'reference' => $position); - - switch ($position) { // move in right or bottom if legend is outside data plotting area. - case 'outside-top' : - $this->calculated['boundary_box']['right'] -= $offset + $width; // move in right hand side - break; - - case 'outside-bottom' : - $this->calculated['boundary_box']['right'] -= $offset + $width; // move in right hand side - break; - - case 'outside-left' : - $this->calculated['boundary_box']['bottom'] -= $offset + $height; // move in right hand side - break; - - case 'outside-right' : - $this->calculated['boundary_box']['bottom'] -= $offset + $height; // move in right hand side - break; - } -} - -function init_y_axis() { - $this->calculated['y_axis_left'] = array(); // array to hold calculated values for y_axis on left. - $this->calculated['y_axis_left']['boundary_box_max'] = $this->get_null_size(); - $this->calculated['y_axis_right'] = array(); // array to hold calculated values for y_axis on right. - $this->calculated['y_axis_right']['boundary_box_max'] = $this->get_null_size(); - - $axis_font = $this->parameter['axis_font']; - $axis_size = $this->parameter['axis_size']; - $axis_colour = $this->parameter['axis_colour']; - $axis_angle = $this->parameter['y_axis_angle']; - $y_tick_labels = $this->y_tick_labels; - - $this->calculated['y_axis_left']['has_data'] = FALSE; - $this->calculated['y_axis_right']['has_data'] = FALSE; - - // find min and max y values. - $minLeft = $this->parameter['y_min_left']; - $maxLeft = $this->parameter['y_max_left']; - $minRight = $this->parameter['y_min_right']; - $maxRight = $this->parameter['y_max_right']; - $dataLeft = array(); - $dataRight = array(); - foreach ($this->y_order as $order => $set) { - if (isset($this->y_format[$set]['y_axis']) && $this->y_format[$set]['y_axis'] == 'right') { - $this->calculated['y_axis_right']['has_data'] = TRUE; - $dataRight = array_merge($dataRight, $this->y_data[$set]); - } else { - $this->calculated['y_axis_left']['has_data'] = TRUE; - $dataLeft = array_merge($dataLeft, $this->y_data[$set]); + + function init_x_axis() { + $this->calculated['x_axis'] = array(); // array to hold calculated values for x_axis. + $this->calculated['x_axis']['boundary_box_max'] = array('height' => 0, 'width' => 0); + + $axis_font = $this->parameter['axis_font']; + $axis_size = $this->parameter['axis_size']; + $axis_colour = $this->parameter['axis_colour']; + $axis_angle = $this->parameter['x_axis_angle']; + + // check whether to treat x axis as numeric + if ($this->parameter['x_axis_gridlines'] == 'auto') { // auto means text based x_axis, not numeric... + $this->calculated['x_axis']['num_ticks'] = sizeof($this->x_data); + $data = $this->x_data; + for ($i=0; $i < $this->calculated['x_axis']['num_ticks']; $i++) { + $value = array_shift($data); // grab value from begin of array + $this->calculated['x_axis']['data'][$i] = $value; + $this->calculated['x_axis']['text'][$i] = $value; // raw data and text are both the same in this case + $size = $this->get_boundaryBox( + array('points' => $axis_size, + 'font' => $axis_font, + 'angle' => $axis_angle, + 'colour' => $axis_colour, + 'text' => $value)); + $this->calculated['x_axis']['boundary_box'][$i] = $size; + if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height']) + $this->calculated['x_axis']['boundary_box_max'] = $size; + } + + } else { // x axis is numeric so find max min values... + $this->calculated['x_axis']['num_ticks'] = $this->parameter['x_axis_gridlines']; + + $min = $this->parameter['x_min']; + $max = $this->parameter['x_max']; + $data = array(); + $data = $this->find_range($this->x_data, $min, $max, $this->parameter['x_resolution']); + $min = $data['min']; + $max = $data['max']; + $this->calculated['x_axis']['min'] = $min; + $this->calculated['x_axis']['max'] = $max; + + $step = ($max - $min) / ($this->calculated['x_axis']['num_ticks'] - 1); + $start = $min; + + for ($i = 0; $i < $this->calculated['x_axis']['num_ticks']; $i++) { // calculate x axis text sizes + $value = number_format($start, $this->parameter['xDecimal'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); + $this->calculated['x_axis']['data'][$i] = $start; + $this->calculated['x_axis']['text'][$i] = $value; // text is formatted raw data + + $size = $this->get_boundaryBox( + array('points' => $axis_size, + 'font' => $axis_font, + 'angle' => $axis_angle, + 'colour' => $axis_colour, + 'text' => $value)); + $this->calculated['x_axis']['boundary_box'][$i] = $size; + + if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height']) + $this->calculated['x_axis']['boundary_box_max'] = $size; + + $start += $step; + } + } + if ($this->parameter['x_axis_text']) + $this->calculated['boundary_box']['bottom'] -= $this->calculated['x_axis']['boundary_box_max']['height'] + + $this->parameter['x_inner_padding']; } - } - $dataLeftRange = $this->find_range($dataLeft, $minLeft, $maxLeft, $this->parameter['y_resolution_left']); - $dataRightRange = $this->find_range($dataRight, $minRight, $maxRight, $this->parameter['y_resolution_right']); - $minLeft = $dataLeftRange['min']; - $maxLeft = $dataLeftRange['max']; - $minRight = $dataRightRange['min']; - $maxRight = $dataRightRange['max']; - - $this->calculated['y_axis_left']['min'] = $minLeft; - $this->calculated['y_axis_left']['max'] = $maxLeft; - $this->calculated['y_axis_right']['min'] = $minRight; - $this->calculated['y_axis_right']['max'] = $maxRight; - - $stepLeft = ($maxLeft - $minLeft) / ($this->parameter['y_axis_gridlines'] - 1); - $startLeft = $minLeft; - $step_right = ($maxRight - $minRight) / ($this->parameter['y_axis_gridlines'] - 1); - $start_right = $minRight; - - if ($this->parameter['y_axis_text_left']) { - for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes - // left y axis - if ($y_tick_labels) { - $value = $y_tick_labels[$i]; + + // find max and min values for a data array given the resolution. + function find_range($data, $min, $max, $resolution) { + if (sizeof($data) == 0 ) return array('min' => 0, 'max' => 0); + foreach ($data as $key => $value) { + if ($value=='none') continue; + if ($value > $max) $max = $value; + if ($value < $min) $min = $value; + } + + if ($max == 0) { + $factor = 1; } else { - $value = number_format($startLeft, $this->parameter['y_decimal_left'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); + if ($max < 0) $factor = - pow(10, (floor(log10(abs($max))) + $resolution) ); + else $factor = pow(10, (floor(log10(abs($max))) - $resolution) ); } - $this->calculated['y_axis_left']['data'][$i] = $startLeft; - $this->calculated['y_axis_left']['text'][$i] = $value; // text is formatted raw data - - $size = $this->get_boundaryBox( - array('points' => $axis_size, - 'font' => $axis_font, - 'angle' => $axis_angle, - 'colour' => $axis_colour, - 'text' => $value)); - $this->calculated['y_axis_left']['boundary_box'][$i] = $size; - - if ($size['height'] > $this->calculated['y_axis_left']['boundary_box_max']['height']) - $this->calculated['y_axis_left']['boundary_box_max']['height'] = $size['height']; - if ($size['width'] > $this->calculated['y_axis_left']['boundary_box_max']['width']) - $this->calculated['y_axis_left']['boundary_box_max']['width'] = $size['width']; - - $startLeft += $stepLeft; - } - $this->calculated['boundary_box']['left'] += $this->calculated['y_axis_left']['boundary_box_max']['width'] - + $this->parameter['y_inner_padding']; - } - - if ($this->parameter['y_axis_text_right']) { - for ($i = 0; $i < $this->parameter['y_axis_gridlines']; $i++) { // calculate y axis text sizes - // right y axis - $value = number_format($start_right, $this->parameter['y_decimal_right'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); - $this->calculated['y_axis_right']['data'][$i] = $start_right; - $this->calculated['y_axis_right']['text'][$i] = $value; // text is formatted raw data - $size = $this->get_boundaryBox( - array('points' => $axis_size, - 'font' => $axis_font, - 'angle' => $axis_angle, - 'colour' => $axis_colour, - 'text' => $value)); - $this->calculated['y_axis_right']['boundary_box'][$i] = $size; - - if ($size['height'] > $this->calculated['y_axis_right']['boundary_box_max']['height']) - $this->calculated['y_axis_right']['boundary_box_max'] = $size; - if ($size['width'] > $this->calculated['y_axis_right']['boundary_box_max']['width']) - $this->calculated['y_axis_right']['boundary_box_max']['width'] = $size['width']; - - $start_right += $step_right; + $factor = round($factor * 1000.0) / 1000.0; // To avoid some wierd rounding errors (Moodle) + + $max = $factor * @ceil($max / $factor); + $min = $factor * @floor($min / $factor); + + //print "max=$max, min=$min
"; + + return array('min' => $min, 'max' => $max); } - $this->calculated['boundary_box']['right'] -= $this->calculated['y_axis_right']['boundary_box_max']['width'] - + $this->parameter['y_inner_padding']; - } -} - -function init_x_axis() { - $this->calculated['x_axis'] = array(); // array to hold calculated values for x_axis. - $this->calculated['x_axis']['boundary_box_max'] = array('height' => 0, 'width' => 0); - - $axis_font = $this->parameter['axis_font']; - $axis_size = $this->parameter['axis_size']; - $axis_colour = $this->parameter['axis_colour']; - $axis_angle = $this->parameter['x_axis_angle']; - - // check whether to treat x axis as numeric - if ($this->parameter['x_axis_gridlines'] == 'auto') { // auto means text based x_axis, not numeric... - $this->calculated['x_axis']['num_ticks'] = sizeof($this->x_data); - $data = $this->x_data; - for ($i=0; $i < $this->calculated['x_axis']['num_ticks']; $i++) { - $value = array_shift($data); // grab value from begin of array - $this->calculated['x_axis']['data'][$i] = $value; - $this->calculated['x_axis']['text'][$i] = $value; // raw data and text are both the same in this case - $size = $this->get_boundaryBox( - array('points' => $axis_size, - 'font' => $axis_font, - 'angle' => $axis_angle, - 'colour' => $axis_colour, - 'text' => $value)); - $this->calculated['x_axis']['boundary_box'][$i] = $size; - if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height']) - $this->calculated['x_axis']['boundary_box_max'] = $size; + + function graph() { + if (func_num_args() == 2) { + $this->parameter['width'] = func_get_arg(0); + $this->parameter['height'] = func_get_arg(1); } + //$this->boundaryBox = array( + $this->calculated['boundary_box'] = array( + 'left' => 0, + 'top' => 0, + 'right' => $this->parameter['width'] - 1, + 'bottom' => $this->parameter['height'] - 1); + + $this->init_colours(); - } else { // x axis is numeric so find max min values... - $this->calculated['x_axis']['num_ticks'] = $this->parameter['x_axis_gridlines']; - - $min = $this->parameter['x_min']; - $max = $this->parameter['x_max']; - $data = array(); - $data = $this->find_range($this->x_data, $min, $max, $this->parameter['x_resolution']); - $min = $data['min']; - $max = $data['max']; - $this->calculated['x_axis']['min'] = $min; - $this->calculated['x_axis']['max'] = $max; - - $step = ($max - $min) / ($this->calculated['x_axis']['num_ticks'] - 1); - $start = $min; - - for ($i = 0; $i < $this->calculated['x_axis']['num_ticks']; $i++) { // calculate x axis text sizes - $value = number_format($start, $this->parameter['xDecimal'], $this->parameter['decimal_point'], $this->parameter['thousand_sep']); - $this->calculated['x_axis']['data'][$i] = $start; - $this->calculated['x_axis']['text'][$i] = $value; // text is formatted raw data - - $size = $this->get_boundaryBox( - array('points' => $axis_size, - 'font' => $axis_font, - 'angle' => $axis_angle, - 'colour' => $axis_colour, - 'text' => $value)); - $this->calculated['x_axis']['boundary_box'][$i] = $size; - - if ($size['height'] > $this->calculated['x_axis']['boundary_box_max']['height']) - $this->calculated['x_axis']['boundary_box_max'] = $size; - - $start += $step; + //ImageColorTransparent($this->image, $this->colour['white']); // colour for transparency } - } - if ($this->parameter['x_axis_text']) - $this->calculated['boundary_box']['bottom'] -= $this->calculated['x_axis']['boundary_box_max']['height'] - + $this->parameter['x_inner_padding']; -} - -// find max and min values for a data array given the resolution. -function find_range($data, $min, $max, $resolution) { - if (sizeof($data) == 0 ) return array('min' => 0, 'max' => 0); - foreach ($data as $key => $value) { - if ($value=='none') continue; - if ($value > $max) $max = $value; - if ($value < $min) $min = $value; - } - - if ($max == 0) { - $factor = 1; - } else { - if ($max < 0) $factor = - pow(10, (floor(log10(abs($max))) + $resolution) ); - else $factor = pow(10, (floor(log10(abs($max))) - $resolution) ); - } - $factor = round($factor * 1000.0) / 1000.0; // To avoid some wierd rounding errors (Moodle) - - $max = $factor * @ceil($max / $factor); - $min = $factor * @floor($min / $factor); - - //print "max=$max, min=$min
"; - - return array('min' => $min, 'max' => $max); -} - -function graph() { - if (func_num_args() == 2) { - $this->parameter['width'] = func_get_arg(0); - $this->parameter['height'] = func_get_arg(1); - } - //$this->boundaryBox = array( - $this->calculated['boundary_box'] = array( - 'left' => 0, - 'top' => 0, - 'right' => $this->parameter['width'] - 1, - 'bottom' => $this->parameter['height'] - 1); - - $this->init_colours(); - - //ImageColorTransparent($this->image, $this->colour['white']); // colour for transparency -} - -function print_TTF($message) { - $points = $message['points']; - $angle = $message['angle']; - $text = $message['text']; - $colour = $this->colour[$message['colour']]; - $font = $this->parameter['path_to_fonts'].$message['font']; - - $x = $message['boundary_box']['x']; - $y = $message['boundary_box']['y']; - $offsetX = $message['boundary_box']['offsetX']; - $offsetY = $message['boundary_box']['offsetY']; - $height = $message['boundary_box']['height']; - $width = $message['boundary_box']['width']; - $reference = $message['boundary_box']['reference']; - - switch ($reference) { - case 'top-left': - case 'left-top': - $y += $height - $offsetY; - //$y += $offsetY; - $x += $offsetX; - break; - case 'left-center': - $y += ($height / 2) - $offsetY; - $x += $offsetX; - break; - case 'left-bottom': - $y -= $offsetY; - $x += $offsetX; - break; - case 'top-center': - $y += $height - $offsetY; - $x -= ($width / 2) - $offsetX; - break; - case 'top-right': - case 'right-top': - $y += $height - $offsetY; - $x -= $width - $offsetX; - break; - case 'right-center': - $y += ($height / 2) - $offsetY; - $x -= $width - $offsetX; - break; - case 'right-bottom': - $y -= $offsetY; - $x -= $width - $offsetX; - break; - case 'bottom-center': - $y -= $offsetY; - $x -= ($width / 2) - $offsetX; - break; - default: - $y = 0; - $x = 0; - break; - } - // start of Moodle addition - $textlib = textlib_get_instance(); - $text = $textlib->utf8_to_entities($text, true, true); //does not work with hex entities! - // end of Moodle addition - ImageTTFText($this->image, $points, $angle, $x, $y, $colour, $font, $text); -} - -// move boundaryBox to coordinates specified -function update_boundaryBox(&$boundaryBox, $coords) { - $width = $boundaryBox['width']; - $height = $boundaryBox['height']; - $x = $coords['x']; - $y = $coords['y']; - $reference = $coords['reference']; - switch ($reference) { - case 'top-left': - case 'left-top': - $top = $y; - $bottom = $y + $height; - $left = $x; - $right = $x + $width; - break; - case 'left-center': - $top = $y - ($height / 2); - $bottom = $y + ($height / 2); - $left = $x; - $right = $x + $width; - break; - case 'left-bottom': - $top = $y - $height; - $bottom = $y; - $left = $x; - $right = $x + $width; - break; - case 'top-center': - $top = $y; - $bottom = $y + $height; - $left = $x - ($width / 2); - $right = $x + ($width / 2); - break; - case 'right-top': - case 'top-right': - $top = $y; - $bottom = $y + $height; - $left = $x - $width; - $right = $x; - break; - case 'right-center': - $top = $y - ($height / 2); - $bottom = $y + ($height / 2); - $left = $x - $width; - $right = $x; - break; - case 'bottom=right': - case 'right-bottom': - $top = $y - $height; - $bottom = $y; - $left = $x - $width; - $right = $x; - break; - default: - $top = 0; - $bottom = $height; - $left = 0; - $right = $width; - break; - } - - $boundaryBox = array_merge($boundaryBox, array('top' => $top, - 'bottom' => $bottom, - 'left' => $left, - 'right' => $right, - 'x' => $x, - 'y' => $y, - 'reference' => $reference)); -} - -function get_null_size() { - return array('width' => 0, - 'height' => 0, - 'offsetX' => 0, - 'offsetY' => 0, - //'fontHeight' => 0 - ); -} - -function get_boundaryBox($message) { - $points = $message['points']; - $angle = $message['angle']; - $font = $this->parameter['path_to_fonts'].$message['font']; - $text = $message['text']; - - //print ('get_boundaryBox'); - //expandPre($message); - - // get font size - $bounds = ImageTTFBBox($points, $angle, $font, "W"); - if ($angle < 0) { - $fontHeight = abs($bounds[7]-$bounds[1]); - } else if ($angle > 0) { - $fontHeight = abs($bounds[1]-$bounds[7]); - } else { - $fontHeight = abs($bounds[7]-$bounds[1]); - } - - // get boundary box and offsets for printing at an angle - // start of Moodle addition - $textlib = textlib_get_instance(); - $text = $textlib->utf8_to_entities($text, true, true); //gd does not work with hex entities! - // end of Moodle addition - $bounds = ImageTTFBBox($points, $angle, $font, $text); - - if ($angle < 0) { - $width = abs($bounds[4]-$bounds[0]); - $height = abs($bounds[3]-$bounds[7]); - $offsetY = abs($bounds[3]-$bounds[1]); - $offsetX = 0; - - } else if ($angle > 0) { - $width = abs($bounds[2]-$bounds[6]); - $height = abs($bounds[1]-$bounds[5]); - $offsetY = 0; - $offsetX = abs($bounds[0]-$bounds[6]); - - } else { - $width = abs($bounds[4]-$bounds[6]); - $height = abs($bounds[7]-$bounds[1]); - $offsetY = 0; - $offsetX = 0; - } - - //return values - return array('width' => $width, - 'height' => $height, - 'offsetX' => $offsetX, - 'offsetY' => $offsetY, - //'fontHeight' => $fontHeight - ); -} - -function draw_rectangle($border, $colour, $type) { - $colour = $this->colour[$colour]; - switch ($type) { - case 'fill': // fill the rectangle - ImageFilledRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour); - break; - case 'box': // all sides - ImageRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour); - break; - case 'axis': // bottom x axis and left y axis - ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); - ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); - break; - case 'y': // left y axis only - case 'y-left': - ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); - break; - case 'y-right': // right y axis only - ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour); - break; - case 'x': // bottom x axis only - ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); - break; - case 'u': // u shaped. bottom x axis and both left and right y axis. - ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); - ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour); - ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); - break; - - } -} - -function init_colours() { - $this->image = ImageCreate($this->parameter['width'], $this->parameter['height']); - // standard colours - $this->colour['white'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF); // first colour is background colour. - $this->colour['black'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0x00); - $this->colour['maroon'] = ImageColorAllocate ($this->image, 0x80, 0x00, 0x00); - $this->colour['green'] = ImageColorAllocate ($this->image, 0x00, 0x80, 0x00); - $this->colour['ltgreen'] = ImageColorAllocate ($this->image, 0x52, 0xF1, 0x7F); - $this->colour['ltltgreen']= ImageColorAllocate ($this->image, 0x99, 0xFF, 0x99); - $this->colour['olive'] = ImageColorAllocate ($this->image, 0x80, 0x80, 0x00); - $this->colour['navy'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0x80); - $this->colour['purple'] = ImageColorAllocate ($this->image, 0x80, 0x00, 0x80); - $this->colour['gray'] = ImageColorAllocate ($this->image, 0x80, 0x80, 0x80); - $this->colour['red'] = ImageColorAllocate ($this->image, 0xFF, 0x00, 0x00); - $this->colour['ltred'] = ImageColorAllocate ($this->image, 0xFF, 0x99, 0x99); - $this->colour['ltltred'] = ImageColorAllocate ($this->image, 0xFF, 0xCC, 0xCC); - $this->colour['orange'] = ImageColorAllocate ($this->image, 0xFF, 0x66, 0x00); - $this->colour['ltorange'] = ImageColorAllocate ($this->image, 0xFF, 0x99, 0x66); - $this->colour['ltltorange'] = ImageColorAllocate ($this->image, 0xFF, 0xcc, 0x99); - $this->colour['lime'] = ImageColorAllocate ($this->image, 0x00, 0xFF, 0x00); - $this->colour['yellow'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0x00); - $this->colour['blue'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0xFF); - $this->colour['ltblue'] = ImageColorAllocate ($this->image, 0x00, 0xCC, 0xFF); - $this->colour['ltltblue'] = ImageColorAllocate ($this->image, 0x99, 0xFF, 0xFF); - $this->colour['fuchsia'] = ImageColorAllocate ($this->image, 0xFF, 0x00, 0xFF); - $this->colour['aqua'] = ImageColorAllocate ($this->image, 0x00, 0xFF, 0xFF); - //$this->colour['white'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF); - // shades of gray - $this->colour['grayF0'] = ImageColorAllocate ($this->image, 0xF0, 0xF0, 0xF0); - $this->colour['grayEE'] = ImageColorAllocate ($this->image, 0xEE, 0xEE, 0xEE); - $this->colour['grayDD'] = ImageColorAllocate ($this->image, 0xDD, 0xDD, 0xDD); - $this->colour['grayCC'] = ImageColorAllocate ($this->image, 0xCC, 0xCC, 0xCC); - $this->colour['gray33'] = ImageColorAllocate ($this->image, 0x33, 0x33, 0x33); - $this->colour['gray66'] = ImageColorAllocate ($this->image, 0x66, 0x66, 0x66); - $this->colour['gray99'] = ImageColorAllocate ($this->image, 0x99, 0x99, 0x99); - - $this->colour['none'] = 'none'; - return true; -} - -function output() { - if ($this->debug) { // for debugging purposes. - //expandPre($this->graph); - //expandPre($this->y_data); - //expandPre($this->x_data); - //expandPre($this->parameter); - } else { - - $expiresSeconds = $this->parameter['seconds_to_live']; - $expiresHours = $this->parameter['hours_to_live']; - - if ($expiresHours || $expiresSeconds) { - $now = mktime (date("H"),date("i"),date("s"),date("m"),date("d"),date("Y")); - $expires = mktime (date("H")+$expiresHours,date("i"),date("s")+$expiresSeconds,date("m"),date("d"),date("Y")); - $expiresGMT = gmdate('D, d M Y H:i:s', $expires).' GMT'; - $lastModifiedGMT = gmdate('D, d M Y H:i:s', $now).' GMT'; - - Header('Last-modified: '.$lastModifiedGMT); - Header('Expires: '.$expiresGMT); + + function print_TTF($message) { + $points = $message['points']; + $angle = $message['angle']; + $text = $message['text']; + $colour = $this->colour[$message['colour']]; + $font = $this->parameter['path_to_fonts'].$message['font']; + + $x = $message['boundary_box']['x']; + $y = $message['boundary_box']['y']; + $offsetX = $message['boundary_box']['offsetX']; + $offsetY = $message['boundary_box']['offsetY']; + $height = $message['boundary_box']['height']; + $width = $message['boundary_box']['width']; + $reference = $message['boundary_box']['reference']; + + switch ($reference) { + case 'top-left': + case 'left-top': + $y += $height - $offsetY; + //$y += $offsetY; + $x += $offsetX; + break; + case 'left-center': + $y += ($height / 2) - $offsetY; + $x += $offsetX; + break; + case 'left-bottom': + $y -= $offsetY; + $x += $offsetX; + break; + case 'top-center': + $y += $height - $offsetY; + $x -= ($width / 2) - $offsetX; + break; + case 'top-right': + case 'right-top': + $y += $height - $offsetY; + $x -= $width - $offsetX; + break; + case 'right-center': + $y += ($height / 2) - $offsetY; + $x -= $width - $offsetX; + break; + case 'right-bottom': + $y -= $offsetY; + $x -= $width - $offsetX; + break; + case 'bottom-center': + $y -= $offsetY; + $x -= ($width / 2) - $offsetX; + break; + default: + $y = 0; + $x = 0; + break; + } + // start of Moodle addition + $textlib = textlib_get_instance(); + $text = $textlib->utf8_to_entities($text, true, true); //does not work with hex entities! + // end of Moodle addition + ImageTTFText($this->image, $points, $angle, $x, $y, $colour, $font, $text); } - if ($this->parameter['file_name'] == 'none') { - switch ($this->parameter['output_format']) { - case 'GIF': - Header("Content-type: image/gif"); // GIF??. switch to PNG guys!! - ImageGIF($this->image); + // move boundaryBox to coordinates specified + function update_boundaryBox(&$boundaryBox, $coords) { + $width = $boundaryBox['width']; + $height = $boundaryBox['height']; + $x = $coords['x']; + $y = $coords['y']; + $reference = $coords['reference']; + switch ($reference) { + case 'top-left': + case 'left-top': + $top = $y; + $bottom = $y + $height; + $left = $x; + $right = $x + $width; + break; + case 'left-center': + $top = $y - ($height / 2); + $bottom = $y + ($height / 2); + $left = $x; + $right = $x + $width; + break; + case 'left-bottom': + $top = $y - $height; + $bottom = $y; + $left = $x; + $right = $x + $width; + break; + case 'top-center': + $top = $y; + $bottom = $y + $height; + $left = $x - ($width / 2); + $right = $x + ($width / 2); break; - case 'JPEG': - Header("Content-type: image/jpeg"); // JPEG for line art??. included for completeness. - ImageJPEG($this->image); + case 'right-top': + case 'top-right': + $top = $y; + $bottom = $y + $height; + $left = $x - $width; + $right = $x; break; - default: - Header("Content-type: image/png"); // preferred output format - ImagePNG($this->image); + case 'right-center': + $top = $y - ($height / 2); + $bottom = $y + ($height / 2); + $left = $x - $width; + $right = $x; + break; + case 'bottom=right': + case 'right-bottom': + $top = $y - $height; + $bottom = $y; + $left = $x - $width; + $right = $x; + break; + default: + $top = 0; + $bottom = $height; + $left = 0; + $right = $width; break; } - } else { - switch ($this->parameter['output_format']) { - case 'GIF': - ImageGIF($this->image, $this->parameter['file_name'].'.gif'); + + $boundaryBox = array_merge($boundaryBox, array('top' => $top, + 'bottom' => $bottom, + 'left' => $left, + 'right' => $right, + 'x' => $x, + 'y' => $y, + 'reference' => $reference)); + } + + function get_null_size() { + return array('width' => 0, + 'height' => 0, + 'offsetX' => 0, + 'offsetY' => 0, + //'fontHeight' => 0 + ); + } + + function get_boundaryBox($message) { + $points = $message['points']; + $angle = $message['angle']; + $font = $this->parameter['path_to_fonts'].$message['font']; + $text = $message['text']; + + //print ('get_boundaryBox'); + //expandPre($message); + + // get font size + $bounds = ImageTTFBBox($points, $angle, $font, "W"); + if ($angle < 0) { + $fontHeight = abs($bounds[7]-$bounds[1]); + } else if ($angle > 0) { + $fontHeight = abs($bounds[1]-$bounds[7]); + } else { + $fontHeight = abs($bounds[7]-$bounds[1]); + } + + // get boundary box and offsets for printing at an angle + // start of Moodle addition + $textlib = textlib_get_instance(); + $text = $textlib->utf8_to_entities($text, true, true); //gd does not work with hex entities! + // end of Moodle addition + $bounds = ImageTTFBBox($points, $angle, $font, $text); + + if ($angle < 0) { + $width = abs($bounds[4]-$bounds[0]); + $height = abs($bounds[3]-$bounds[7]); + $offsetY = abs($bounds[3]-$bounds[1]); + $offsetX = 0; + + } else if ($angle > 0) { + $width = abs($bounds[2]-$bounds[6]); + $height = abs($bounds[1]-$bounds[5]); + $offsetY = 0; + $offsetX = abs($bounds[0]-$bounds[6]); + + } else { + $width = abs($bounds[4]-$bounds[6]); + $height = abs($bounds[7]-$bounds[1]); + $offsetY = 0; + $offsetX = 0; + } + + //return values + return array('width' => $width, + 'height' => $height, + 'offsetX' => $offsetX, + 'offsetY' => $offsetY, + //'fontHeight' => $fontHeight + ); + } + + function draw_rectangle($border, $colour, $type) { + $colour = $this->colour[$colour]; + switch ($type) { + case 'fill': // fill the rectangle + ImageFilledRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour); + break; + case 'box': // all sides + ImageRectangle($this->image, $border['left'], $border['top'], $border['right'], $border['bottom'], $colour); + break; + case 'axis': // bottom x axis and left y axis + ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); + ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); break; - case 'JPEG': - ImageJPEG($this->image, $this->parameter['file_name'].'.jpg'); + case 'y': // left y axis only + case 'y-left': + ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); break; - default: - ImagePNG($this->image, $this->parameter['file_name'].'.png'); + case 'y-right': // right y axis only + ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour); break; + case 'x': // bottom x axis only + ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); + break; + case 'u': // u shaped. bottom x axis and both left and right y axis. + ImageLine($this->image, $border['left'], $border['top'], $border['left'], $border['bottom'], $colour); + ImageLine($this->image, $border['right'], $border['top'], $border['right'], $border['bottom'], $colour); + ImageLine($this->image, $border['left'], $border['bottom'], $border['right'], $border['bottom'], $colour); + break; + } } - ImageDestroy($this->image); - } -} // function output - -function init_variable(&$variable, $value, $default) { - if (!empty($value)) $variable = $value; - else if (isset($default)) $variable = $default; - else unset($variable); -} - -// plot a point. options include square, circle, diamond, triangle, and dot. offset is used for drawing shadows. -// for diamonds and triangles the size should be an even number to get nice look. if odd the points are crooked. -function plot($x, $y, $type, $size, $colour, $offset) { - //print("drawing point of type: $type, at offset: $offset"); - $u = $x + $offset; - $v = $this->calculated['inner_border']['bottom'] - $y + $offset; - $half = $size / 2; - - switch ($type) { - case 'square': - ImageFilledRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]); - break; - case 'square-open': - ImageRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]); - break; - case 'circle': - ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]); - ImageFillToBorder($this->image, $u, $v, $this->colour[$colour], $this->colour[$colour]); - break; - case 'circle-open': - ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]); - break; - case 'diamond': - ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]); - break; - case 'diamond-open': - ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]); - break; - case 'triangle': - ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]); - break; - case 'triangle-open': - ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]); - break; - case 'dot': - ImageSetPixel($this->image, $u, $v, $this->colour[$colour]); - break; - } -} - -function bar($x, $y, $type, $size, $colour, $offset, $index, $yoffset) { - $index_offset = $this->calculated['bar_offset_index'][$index]; - if ( $yoffset ) { - $bar_offsetx = 0; - } else { - $bar_offsetx = $this->calculated['bar_offset_x'][$index_offset]; - } - //$this->dbug("drawing bar at offset = $offset : index = $index: bar_offsetx = $bar_offsetx"); - - $span = ($this->calculated['bar_width'] * $size) / 2; - $x_left = $x + $bar_offsetx - $span; - $x_right = $x + $bar_offsetx + $span; - - if ($this->parameter['zero_axis'] != 'none') { - $zero = $this->calculated['zero_axis']; - if ($this->parameter['shadow_below_axis'] ) $zero += $offset; - $u_left = $x_left + $offset; - $u_right = $x_right + $offset - 1; - $v = $this->calculated['boundary_box']['bottom'] - $y + $offset; - - if ($v > $zero) { - $top = $zero +1; - $bottom = $v; - } else { - $top = $v; - $bottom = $zero - 1; + function init_colours() { + $this->image = ImageCreate($this->parameter['width'], $this->parameter['height']); + // standard colours + $this->colour['white'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF); // first colour is background colour. + $this->colour['black'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0x00); + $this->colour['maroon'] = ImageColorAllocate ($this->image, 0x80, 0x00, 0x00); + $this->colour['green'] = ImageColorAllocate ($this->image, 0x00, 0x80, 0x00); + $this->colour['ltgreen'] = ImageColorAllocate ($this->image, 0x52, 0xF1, 0x7F); + $this->colour['ltltgreen']= ImageColorAllocate ($this->image, 0x99, 0xFF, 0x99); + $this->colour['olive'] = ImageColorAllocate ($this->image, 0x80, 0x80, 0x00); + $this->colour['navy'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0x80); + $this->colour['purple'] = ImageColorAllocate ($this->image, 0x80, 0x00, 0x80); + $this->colour['gray'] = ImageColorAllocate ($this->image, 0x80, 0x80, 0x80); + $this->colour['red'] = ImageColorAllocate ($this->image, 0xFF, 0x00, 0x00); + $this->colour['ltred'] = ImageColorAllocate ($this->image, 0xFF, 0x99, 0x99); + $this->colour['ltltred'] = ImageColorAllocate ($this->image, 0xFF, 0xCC, 0xCC); + $this->colour['orange'] = ImageColorAllocate ($this->image, 0xFF, 0x66, 0x00); + $this->colour['ltorange'] = ImageColorAllocate ($this->image, 0xFF, 0x99, 0x66); + $this->colour['ltltorange'] = ImageColorAllocate ($this->image, 0xFF, 0xcc, 0x99); + $this->colour['lime'] = ImageColorAllocate ($this->image, 0x00, 0xFF, 0x00); + $this->colour['yellow'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0x00); + $this->colour['blue'] = ImageColorAllocate ($this->image, 0x00, 0x00, 0xFF); + $this->colour['ltblue'] = ImageColorAllocate ($this->image, 0x00, 0xCC, 0xFF); + $this->colour['ltltblue'] = ImageColorAllocate ($this->image, 0x99, 0xFF, 0xFF); + $this->colour['fuchsia'] = ImageColorAllocate ($this->image, 0xFF, 0x00, 0xFF); + $this->colour['aqua'] = ImageColorAllocate ($this->image, 0x00, 0xFF, 0xFF); + //$this->colour['white'] = ImageColorAllocate ($this->image, 0xFF, 0xFF, 0xFF); + // shades of gray + $this->colour['grayF0'] = ImageColorAllocate ($this->image, 0xF0, 0xF0, 0xF0); + $this->colour['grayEE'] = ImageColorAllocate ($this->image, 0xEE, 0xEE, 0xEE); + $this->colour['grayDD'] = ImageColorAllocate ($this->image, 0xDD, 0xDD, 0xDD); + $this->colour['grayCC'] = ImageColorAllocate ($this->image, 0xCC, 0xCC, 0xCC); + $this->colour['gray33'] = ImageColorAllocate ($this->image, 0x33, 0x33, 0x33); + $this->colour['gray66'] = ImageColorAllocate ($this->image, 0x66, 0x66, 0x66); + $this->colour['gray99'] = ImageColorAllocate ($this->image, 0x99, 0x99, 0x99); + + $this->colour['none'] = 'none'; + return true; } - switch ($type) { - case 'open': - //ImageRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]); - if ($v > $zero) - ImageRectangle($this->image, round($u_left), $bottom, round($u_right), $bottom, $this->colour[$colour]); - else - ImageRectangle($this->image, round($u_left), $top, round($u_right), $top, $this->colour[$colour]); - ImageRectangle($this->image, round($u_left), $top, round($u_left), $bottom, $this->colour[$colour]); - ImageRectangle($this->image, round($u_right), $top, round($u_right), $bottom, $this->colour[$colour]); - break; - case 'fill': - ImageFilledRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]); - break; + function output() { + if ($this->debug) { // for debugging purposes. + //expandPre($this->graph); + //expandPre($this->y_data); + //expandPre($this->x_data); + //expandPre($this->parameter); + } else { + + $expiresSeconds = $this->parameter['seconds_to_live']; + $expiresHours = $this->parameter['hours_to_live']; + + if ($expiresHours || $expiresSeconds) { + $now = mktime (date("H"),date("i"),date("s"),date("m"),date("d"),date("Y")); + $expires = mktime (date("H")+$expiresHours,date("i"),date("s")+$expiresSeconds,date("m"),date("d"),date("Y")); + $expiresGMT = gmdate('D, d M Y H:i:s', $expires).' GMT'; + $lastModifiedGMT = gmdate('D, d M Y H:i:s', $now).' GMT'; + + Header('Last-modified: '.$lastModifiedGMT); + Header('Expires: '.$expiresGMT); + } + + if ($this->parameter['file_name'] == 'none') { + switch ($this->parameter['output_format']) { + case 'GIF': + Header("Content-type: image/gif"); // GIF??. switch to PNG guys!! + ImageGIF($this->image); + break; + case 'JPEG': + Header("Content-type: image/jpeg"); // JPEG for line art??. included for completeness. + ImageJPEG($this->image); + break; + default: + Header("Content-type: image/png"); // preferred output format + ImagePNG($this->image); + break; + } + } else { + switch ($this->parameter['output_format']) { + case 'GIF': + ImageGIF($this->image, $this->parameter['file_name'].'.gif'); + break; + case 'JPEG': + ImageJPEG($this->image, $this->parameter['file_name'].'.jpg'); + break; + default: + ImagePNG($this->image, $this->parameter['file_name'].'.png'); + break; + } + } + + ImageDestroy($this->image); + } + } // function output + + function init_variable(&$variable, $value, $default) { + if (!empty($value)) $variable = $value; + else if (isset($default)) $variable = $default; + else unset($variable); } - } else { - - $bottom = $this->calculated['boundary_box']['bottom']; - if ($this->parameter['shadow_below_axis'] ) $bottom += $offset; - if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn. - $u_left = $x_left + $offset; - $u_right = $x_right + $offset - 1; - $v = $this->calculated['boundary_box']['bottom'] - $y + $offset; - - // Moodle addition, plus the function parameter yoffset - if ($yoffset) { // Moodle - $yoffset = $yoffset - round(($bottom - $v) / 2.0); // Moodle - $bottom -= $yoffset; // Moodle - $v -= $yoffset; // Moodle - } // Moodle - - switch ($type) { - case 'open': - ImageRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]); - break; - case 'fill': - ImageFilledRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]); - break; + // plot a point. options include square, circle, diamond, triangle, and dot. offset is used for drawing shadows. + // for diamonds and triangles the size should be an even number to get nice look. if odd the points are crooked. + function plot($x, $y, $type, $size, $colour, $offset) { + //print("drawing point of type: $type, at offset: $offset"); + $u = $x + $offset; + $v = $this->calculated['inner_border']['bottom'] - $y + $offset; + $half = $size / 2; + + switch ($type) { + case 'square': + ImageFilledRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]); + break; + case 'square-open': + ImageRectangle($this->image, $u-$half, $v-$half, $u+$half, $v+$half, $this->colour[$colour]); + break; + case 'circle': + ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]); + ImageFillToBorder($this->image, $u, $v, $this->colour[$colour], $this->colour[$colour]); + break; + case 'circle-open': + ImageArc($this->image, $u, $v, $size, $size, 0, 360, $this->colour[$colour]); + break; + case 'diamond': + ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]); + break; + case 'diamond-open': + ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v, $u, $v+$half, $u-$half, $v), 4, $this->colour[$colour]); + break; + case 'triangle': + ImageFilledPolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]); + break; + case 'triangle-open': + ImagePolygon($this->image, array($u, $v-$half, $u+$half, $v+$half, $u-$half, $v+$half), 3, $this->colour[$colour]); + break; + case 'dot': + ImageSetPixel($this->image, $u, $v, $this->colour[$colour]); + break; + } } - } -} - -function area($x_start, $y_start, $x_end, $y_end, $type, $colour, $offset) { - //dbug("drawing area type: $type, at offset: $offset"); - if ($this->parameter['zero_axis'] != 'none') { - $bottom = $this->calculated['boundary_box']['bottom']; - $zero = $this->calculated['zero_axis']; - if ($this->parameter['shadow_below_axis'] ) $zero += $offset; - $u_start = $x_start + $offset; - $u_end = $x_end + $offset; - $v_start = $bottom - $y_start + $offset; - $v_end = $bottom - $y_end + $offset; - switch ($type) { - case 'fill': - // draw it this way 'cos the FilledPolygon routine seems a bit buggy. - ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); - ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); - break; - case 'open': - //ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); - ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); - ImageLine($this->image, $u_start, $v_start, $u_start, $zero, $this->colour[$colour]); - ImageLine($this->image, $u_end, $v_end, $u_end, $zero, $this->colour[$colour]); - break; + + function bar($x, $y, $type, $size, $colour, $offset, $index, $yoffset) { + $index_offset = $this->calculated['bar_offset_index'][$index]; + if ( $yoffset ) { + $bar_offsetx = 0; + } else { + $bar_offsetx = $this->calculated['bar_offset_x'][$index_offset]; + } + //$this->dbug("drawing bar at offset = $offset : index = $index: bar_offsetx = $bar_offsetx"); + + $span = ($this->calculated['bar_width'] * $size) / 2; + $x_left = $x + $bar_offsetx - $span; + $x_right = $x + $bar_offsetx + $span; + + if ($this->parameter['zero_axis'] != 'none') { + $zero = $this->calculated['zero_axis']; + if ($this->parameter['shadow_below_axis'] ) $zero += $offset; + $u_left = $x_left + $offset; + $u_right = $x_right + $offset - 1; + $v = $this->calculated['boundary_box']['bottom'] - $y + $offset; + + if ($v > $zero) { + $top = $zero +1; + $bottom = $v; + } else { + $top = $v; + $bottom = $zero - 1; + } + + switch ($type) { + case 'open': + //ImageRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]); + if ($v > $zero) + ImageRectangle($this->image, round($u_left), $bottom, round($u_right), $bottom, $this->colour[$colour]); + else + ImageRectangle($this->image, round($u_left), $top, round($u_right), $top, $this->colour[$colour]); + ImageRectangle($this->image, round($u_left), $top, round($u_left), $bottom, $this->colour[$colour]); + ImageRectangle($this->image, round($u_right), $top, round($u_right), $bottom, $this->colour[$colour]); + break; + case 'fill': + ImageFilledRectangle($this->image, round($u_left), $top, round($u_right), $bottom, $this->colour[$colour]); + break; + } + + } else { + + $bottom = $this->calculated['boundary_box']['bottom']; + if ($this->parameter['shadow_below_axis'] ) $bottom += $offset; + if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn. + $u_left = $x_left + $offset; + $u_right = $x_right + $offset - 1; + $v = $this->calculated['boundary_box']['bottom'] - $y + $offset; + + // Moodle addition, plus the function parameter yoffset + if ($yoffset) { // Moodle + $yoffset = $yoffset - round(($bottom - $v) / 2.0); // Moodle + $bottom -= $yoffset; // Moodle + $v -= $yoffset; // Moodle + } // Moodle + + switch ($type) { + case 'open': + ImageRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]); + break; + case 'fill': + ImageFilledRectangle($this->image, round($u_left), $v, round($u_right), $bottom, $this->colour[$colour]); + break; + } + } } - } else { - $bottom = $this->calculated['boundary_box']['bottom']; - $u_start = $x_start + $offset; - $u_end = $x_end + $offset; - $v_start = $bottom - $y_start + $offset; - $v_end = $bottom - $y_end + $offset; - - if ($this->parameter['shadow_below_axis'] ) $bottom += $offset; - if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn. - switch ($type) { - case 'fill': - ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]); - break; - case 'open': - ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]); - break; + + function area($x_start, $y_start, $x_end, $y_end, $type, $colour, $offset) { + //dbug("drawing area type: $type, at offset: $offset"); + if ($this->parameter['zero_axis'] != 'none') { + $bottom = $this->calculated['boundary_box']['bottom']; + $zero = $this->calculated['zero_axis']; + if ($this->parameter['shadow_below_axis'] ) $zero += $offset; + $u_start = $x_start + $offset; + $u_end = $x_end + $offset; + $v_start = $bottom - $y_start + $offset; + $v_end = $bottom - $y_end + $offset; + switch ($type) { + case 'fill': + // draw it this way 'cos the FilledPolygon routine seems a bit buggy. + ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); + ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); + break; + case 'open': + //ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $zero, $u_start, $zero), 4, $this->colour[$colour]); + ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); + ImageLine($this->image, $u_start, $v_start, $u_start, $zero, $this->colour[$colour]); + ImageLine($this->image, $u_end, $v_end, $u_end, $zero, $this->colour[$colour]); + break; + } + } else { + $bottom = $this->calculated['boundary_box']['bottom']; + $u_start = $x_start + $offset; + $u_end = $x_end + $offset; + $v_start = $bottom - $y_start + $offset; + $v_end = $bottom - $y_end + $offset; + + if ($this->parameter['shadow_below_axis'] ) $bottom += $offset; + if ($this->parameter['inner_border'] != 'none') $bottom -= 1; // 1 pixel above bottom if border is to be drawn. + switch ($type) { + case 'fill': + ImageFilledPolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]); + break; + case 'open': + ImagePolygon($this->image, array($u_start, $v_start, $u_end, $v_end, $u_end, $bottom, $u_start, $bottom), 4, $this->colour[$colour]); + break; + } + } } - } -} - -function line($x_start, $y_start, $x_end, $y_end, $type, $brush_type, $brush_size, $colour, $offset) { - //dbug("drawing line of type: $type, at offset: $offset"); - $u_start = $x_start + $offset; - $v_start = $this->calculated['boundary_box']['bottom'] - $y_start + $offset; - $u_end = $x_end + $offset; - $v_end = $this->calculated['boundary_box']['bottom'] - $y_end + $offset; - - switch ($type) { - case 'brush': - $this->draw_brush_line($u_start, $v_start, $u_end, $v_end, $brush_size, $brush_type, $colour); - break; - case 'line' : - ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); - break; - case 'dash': - ImageDashedLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); - break; - } -} - -// function to draw line. would prefer to use gdBrush but this is not supported yet. -function draw_brush_line($x0, $y0, $x1, $y1, $size, $type, $colour) { - //$this->dbug("line: $x0, $y0, $x1, $y1"); - $dy = $y1 - $y0; - $dx = $x1 - $x0; - $t = 0; - $watchdog = 1024; // precaution to prevent infinite loops. - - $this->draw_brush($x0, $y0, $size, $type, $colour); - if (abs($dx) > abs($dy)) { // slope < 1 - //$this->dbug("slope < 1"); - $m = $dy / $dx; // compute slope - $t += $y0; - $dx = ($dx < 0) ? -1 : 1; - $m *= $dx; - while (round($x0) != round($x1)) { - if (!$watchdog--) break; - $x0 += $dx; // step to next x value - $t += $m; // add slope to y value - $y = round($t); - //$this->dbug("x0=$x0, x1=$x1, y=$y watchdog=$watchdog"); - $this->draw_brush($x0, $y, $size, $type, $colour); + function line($x_start, $y_start, $x_end, $y_end, $type, $brush_type, $brush_size, $colour, $offset) { + //dbug("drawing line of type: $type, at offset: $offset"); + $u_start = $x_start + $offset; + $v_start = $this->calculated['boundary_box']['bottom'] - $y_start + $offset; + $u_end = $x_end + $offset; + $v_end = $this->calculated['boundary_box']['bottom'] - $y_end + $offset; + + switch ($type) { + case 'brush': + $this->draw_brush_line($u_start, $v_start, $u_end, $v_end, $brush_size, $brush_type, $colour); + break; + case 'line' : + ImageLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); + break; + case 'dash': + ImageDashedLine($this->image, $u_start, $v_start, $u_end, $v_end, $this->colour[$colour]); + break; + } } - } else { // slope >= 1 - //$this->dbug("slope >= 1"); - $m = $dx / $dy; // compute slope - $t += $x0; - $dy = ($dy < 0) ? -1 : 1; - $m *= $dy; - while (round($y0) != round($y1)) { - if (!$watchdog--) break; - $y0 += $dy; // step to next y value - $t += $m; // add slope to x value - $x = round($t); - //$this->dbug("x=$x, y0=$y0, y1=$y1 watchdog=$watchdog"); - $this->draw_brush($x, $y0, $size, $type, $colour); + // function to draw line. would prefer to use gdBrush but this is not supported yet. + function draw_brush_line($x0, $y0, $x1, $y1, $size, $type, $colour) { + //$this->dbug("line: $x0, $y0, $x1, $y1"); + $dy = $y1 - $y0; + $dx = $x1 - $x0; + $t = 0; + $watchdog = 1024; // precaution to prevent infinite loops. + + $this->draw_brush($x0, $y0, $size, $type, $colour); + if (abs($dx) > abs($dy)) { // slope < 1 + //$this->dbug("slope < 1"); + $m = $dy / $dx; // compute slope + $t += $y0; + $dx = ($dx < 0) ? -1 : 1; + $m *= $dx; + while (round($x0) != round($x1)) { + if (!$watchdog--) break; + $x0 += $dx; // step to next x value + $t += $m; // add slope to y value + $y = round($t); + //$this->dbug("x0=$x0, x1=$x1, y=$y watchdog=$watchdog"); + $this->draw_brush($x0, $y, $size, $type, $colour); + + } + } else { // slope >= 1 + //$this->dbug("slope >= 1"); + $m = $dx / $dy; // compute slope + $t += $x0; + $dy = ($dy < 0) ? -1 : 1; + $m *= $dy; + while (round($y0) != round($y1)) { + if (!$watchdog--) break; + $y0 += $dy; // step to next y value + $t += $m; // add slope to x value + $x = round($t); + //$this->dbug("x=$x, y0=$y0, y1=$y1 watchdog=$watchdog"); + $this->draw_brush($x, $y0, $size, $type, $colour); + + } + } + } + + function draw_brush($x, $y, $size, $type, $colour) { + $x = round($x); + $y = round($y); + $half = round($size / 2); + switch ($type) { + case 'circle': + ImageArc($this->image, $x, $y, $size, $size, 0, 360, $this->colour[$colour]); + ImageFillToBorder($this->image, $x, $y, $this->colour[$colour], $this->colour[$colour]); + break; + case 'square': + ImageFilledRectangle($this->image, $x-$half, $y-$half, $x+$half, $y+$half, $this->colour[$colour]); + break; + case 'vertical': + ImageFilledRectangle($this->image, $x, $y-$half, $x+1, $y+$half, $this->colour[$colour]); + break; + case 'horizontal': + ImageFilledRectangle($this->image, $x-$half, $y, $x+$half, $y+1, $this->colour[$colour]); + break; + case 'slash': + ImageFilledPolygon($this->image, array($x+$half, $y-$half, + $x+$half+1, $y-$half, + $x-$half+1, $y+$half, + $x-$half, $y+$half + ), 4, $this->colour[$colour]); + break; + case 'backslash': + ImageFilledPolygon($this->image, array($x-$half, $y-$half, + $x-$half+1, $y-$half, + $x+$half+1, $y+$half, + $x+$half, $y+$half + ), 4, $this->colour[$colour]); + break; + default: + @eval($type); // user can create own brush script. + } } - } -} - -function draw_brush($x, $y, $size, $type, $colour) { - $x = round($x); - $y = round($y); - $half = round($size / 2); - switch ($type) { - case 'circle': - ImageArc($this->image, $x, $y, $size, $size, 0, 360, $this->colour[$colour]); - ImageFillToBorder($this->image, $x, $y, $this->colour[$colour], $this->colour[$colour]); - break; - case 'square': - ImageFilledRectangle($this->image, $x-$half, $y-$half, $x+$half, $y+$half, $this->colour[$colour]); - break; - case 'vertical': - ImageFilledRectangle($this->image, $x, $y-$half, $x+1, $y+$half, $this->colour[$colour]); - break; - case 'horizontal': - ImageFilledRectangle($this->image, $x-$half, $y, $x+$half, $y+1, $this->colour[$colour]); - break; - case 'slash': - ImageFilledPolygon($this->image, array($x+$half, $y-$half, - $x+$half+1, $y-$half, - $x-$half+1, $y+$half, - $x-$half, $y+$half - ), 4, $this->colour[$colour]); - break; - case 'backslash': - ImageFilledPolygon($this->image, array($x-$half, $y-$half, - $x-$half+1, $y-$half, - $x+$half+1, $y+$half, - $x+$half, $y+$half - ), 4, $this->colour[$colour]); - break; - default: - @eval($type); // user can create own brush script. - } -} } // class graph -- 2.39.5