1
0
mirror of https://github.com/php/web-php.git synced 2026-04-28 01:13:10 +02:00
Files
Rasmus Lerdorf 6b2d7bb52f June numbers - spruce up the graph code slightly. It now generates a PNG
instead of a GIF to be more politically correct and it also uses slightly
transparent bars.
2001-07-21 02:27:53 +00:00

386 lines
9.2 KiB
C++

<?php /* -*- C++ -*- */
/*
** $Id$
** $Source$
**
** PHP Class for creating bar charts using the GD library functions.
**
** Authors: Bjørn Borud, <borud@guardian.no>
*/
class barchart {
/* minimum allowed maximum */
var $min_allowed_max;
/* Image data */
var $im;
var $width, $height;
var $white, $black, $gray;
var $data;
var $colors;
var $legends;
/* margins for drawing area */
var $left = 60;
var $right = 200;
var $top = 70;
var $bottom = 70;
var $y_tick_padding = 10;
/* drawing parameters */
var $bar_width;
var $bar_padding = 5; /* space between bars */
var $y_scale;
/* legends, labels and titles */
var $y_label = "";
var $title = "";
/* drawing area (the graph without borders etc.) */
var $d_width, $d_height;
var $y_ticks;
var $y_data_max;
var $y_bar_max;
var $num_bars, $bar_width, $num_parts;
/* default fonts */
var $legend_font = 2;
/* Compute the values for Y axis ticks */
function get_y_ticks ($y_max) {
$order_y = floor(log10($y_max));
$magnitude = pow(10, $order_y);
$fdig = ($y_max / $magnitude) * 10;
$top = ceil($fdig) * $magnitude * 0.1;
/* Limit number of divisions to max 10*/
if ($fdig < 50) {
$divs = 0.5;
} else {
$divs = 1.0;
}
/* compute number of horizontal Y lines */
$tlines = $top / ($divs * $magnitude);
for ($i = 0; $i < $tlines; $i++) {
$retval[] = ($i + 1) * $divs * $magnitude;
}
return($retval);
}
/* find the max sum of a bar */
function get_max_value ($d) {
$bar_count = count($d);
$part_count = count($d[0]);
$max_value = 0;
for ($i = 0; $i < $bar_count; $i++) {
$sum = 0;
for ($j = 0; $j < $part_count; $j++) {
$sum += $d[$i][$j];
}
if ($sum > $max_value) {
$max_value = $sum;
}
}
/* If max is too small, set it to something sane. */
if ($max_value <= $this->min_allowed_max) {
$max_value = $this->min_allowed_max;
}
return($max_value);
}
function init($x, $y, $d, $c, $l) {
$this->min_allowed_max = 5;
$this->im = ImageCreateTrueColor($x, $y);
$this->width = $x;
$this->height = $y;
$this->data = $d;
$this->legends = $l;
$this->num_bars = count($this->data);
$this->num_parts = count($this->data[0]);
/* drawing area */
$this->d_width = $this->width - $this->right - $this->left;
$this->d_height = $this->height - $this->top - $this->bottom;
$this->y_data_max = $this->get_max_value($this->data);
$this->y_ticks = $this->get_y_ticks($this->y_data_max);
$this->y_bar_max = $this->y_ticks[count($this->y_ticks) - 1];
$this->bar_width = ($this->d_width / $this->num_bars);
/* if the bar width is real small then round to 1 */
if ($this->bar_width < 1) {
$this->bar_width = 1;
$this->bar_padding = 0;
}
$this->y_scale = $this->d_height / $this->y_bar_max;
$this->white = ImageColorAllocate($this->im, 255, 255, 255);
$this->black = ImageColorAllocate($this->im, 0, 0, 0);
$this->red = ImageColorAllocate($this->im, 190, 0, 0);
$this->green = ImageColorAllocate($this->im, 0, 190, 0);
$this->blue = ImageColorAllocate($this->im, 0, 0, 190);
$this->gray = ImageColorAllocate($this->im, 204, 204, 204);
$num_colors = count($c);
ImageAlphaBlending($this->im, false);
ImageFilledRectangle($this->im, 0, 0, $x, $y, $this->white);
ImageAlphaBlending($this->im, true);
for ($i = 0; $i < $num_colors; $i++) {
if(count($c[$i])>3) {
$this->colors[] = ImageColorResolveAlpha($this->im,
$c[$i][0],
$c[$i][1],
$c[$i][2],
$c[$i][3]);
} else {
$this->colors[] = ImageColorAllocate($this->im,
$c[$i][0],
$c[$i][1],
$c[$i][2]);
}
}
}
/*
** remap a pair of coordinates. sort coordinates if we're
** going to use them to draw a rectangle by setting the last
** argument equal to 1
*/
function remap_quad($x1, $y1, $x2, $y2, $rect) {
$tx1 = $x1 + $this->left;
$tx2 = $x2 + $this->left;
$ty1 = $this->height - $this->bottom - $y1;
$ty2 = $this->height - $this->bottom - $y2;
if ($rect == 1) {
if ($tx1 > $tx2) { $tmp = $tx1; $tx1 = $tx2; $tx2 = $tmp;}
if ($ty1 > $ty2) { $tmp = $ty1; $ty1 = $ty2; $ty2 = $tmp;}
}
return(array($tx1, $ty1, $tx2, $ty2));
}
function draw_point($x, $y) {
ImageLine($this->im, $x-4, $y-4, $x+4, $y+4, $this->black);
ImageLine($this->im, $x-4, $y+4, $x+4, $y-4, $this->black);
}
function draw_line($x1, $y1, $x2, $y2, $color) {
$c = $this->remap_quad($x1, $y1, $x2, $y2, 0);
ImageLine($this->im, $c[0], $c[1], $c[2], $c[3], $color);
}
function draw_filled_rect($x1, $y1, $x2, $y2, $color) {
$c = $this->remap_quad($x1, $y1, $x2, $y2, 1);
ImageFilledRectangle($this->im, $c[0], $c[1],
$c[2], $c[3], $color);
}
function draw_string ($size, $x, $y, $s, $color) {
$c = $this->remap_quad($x, $y, 0, 0, 0);
ImageString($this->im, $size, $c[0], $c[1], $s, $color);
}
function draw_string_up($size, $x, $y, $s, $color) {
$c = $this->remap_quad($x, $y, 0, 0, 0);
ImageStringUp($this->im, $size, $c[0], $c[1], $s, $color);
}
function string_width ($s, $size) {
return(strlen($s) * ImageFontWidth($size));
}
function draw_title($title, $fontsize) {
$x = ($this->width - $this->string_width($title, $fontsize)) / 2;
$y = ($this->top - $this->yx[$fontsize]) / 3;
ImageString($this->im, $fontsize, $x, $y, $title, $this->black);
}
function draw_x_labels ($labels, $fontsize) {
/* how many lines of labels */
$n_lines = count($labels);
$y_offset = 10;
/* y position of the first row of labels */
$y = $this->height - $this->bottom + $y_offset;
for ($i = 0; $i < $n_lines; $i++) {
/* number of "columns" */
$n_strings = count($labels[$i]);
$dx = $this->d_width / (double)$n_strings;
$half_padded_dx = ($dx - $this->bar_padding) / 2.0;
for ($j = 0; $j < $n_strings; $j++) {
$label_width = $this->string_width($labels[$i][$j], $fontsize);
$x = $this->left + ($j * $dx) + $this->bar_padding +
$half_padded_dx - ($label_width / 2);
ImageString($this->im,
$fontsize,
$x,
$y,
$labels[$i][$j],
$this->black);
}
$y += ImageFontHeight($fontsize) + 2;
}
}
function draw_axis ($axis_color, $font_color, $fontsize) {
$this->draw_line(0,-1,$this->d_width + 10 ,-1, $axis_color);
$this->draw_line(0,0,0,$this->d_height + 10, $axis_color);
$num_y_lines = count($this->y_ticks);
/* draw the zero */
$this->draw_string($fontsize,
- (ImageFontWidth($fontsize)
+ $this->y_tick_padding),
(ImageFontHeight($fontsize) * 0.5),
0,
$font_color);
/* draw the horizontal lines and their values */
for ($i = 0; $i < $num_y_lines; $i++) {
$y = $this->y_scale * $this->y_ticks[$i];
$this->draw_line(0, $y, $this->d_width, $y, $axis_color);
$y_tick = (int) $this->y_ticks[$i];
$x_pos = - ($this->string_width($y_tick, $fontsize)
+ $this->y_tick_padding);
$this->draw_string($fontsize,
$x_pos,
$y + (ImageFontHeight($fontsize) * 0.5),
$y_tick,
$font_color);
}
}
function draw_legends ($fontsize) {
$num_legends = count($this->legends);
$y1 = 0;
for ($i = $num_legends -1; $i >= 0; $i--) {
$x1 = $this->d_width + 20;
$y1 += ImageFontHeight($fontsize) * 2;
$x2 = $this->d_width + 20 + ImageFontHeight($fontsize);
$y2 = $y1 + ImageFontHeight($fontsize);
$this->draw_filled_rect($x1, $y1, $x2, $y2, $this->colors[$i]);
$this->draw_string($fontsize,
$x2 + 10,
$y2,
$this->legends[$i],
$this->black);
}
/* Draw Y axis unit */
$yaxisunit_font = 2;
$ycenterpos = ($this->d_height / 2) - ($this->string_width($yaxisunit_font, $this->y_label) / 2);
$this->draw_string_up($yaxisunit_font, -60, $ycenterpos, $this->y_label, $this->black);
/* Draw graph title */
$title_font = 5;
$xcenterpos = ($this->d_width / 2) - ($this->string_width($title_font, $this->title) / 2);
$this->draw_string($title_font, $xcenterpos, $this->d_height + 40, $this->title, $this->black);
}
function draw_bars() {
for ($i = 0; $i < $this->num_bars; $i++) {
$x1 = $i * $this->bar_width + $this->bar_padding;
$x2 = $x1 + $this->bar_width - $this->bar_padding;
$y1 = 0;
for ($j = $this->num_parts-1; $j >= 0; $j--) {
$y2 = $y1 + $this->data[$i][$j];
$this->draw_filled_rect($x1,
$y1 * $this->y_scale,
$x2,
$y2 * $this->y_scale,
$this->colors[$j] );
$y1 += $this->data[$i][$j];
}
}
}
function display() {
$this->draw_axis($this->black, $this->red, 2);
$this->draw_legends($this->legend_font);
$this->draw_bars();
ImagePNG($this->im);
}
function destroy() {
if ($this->im) {
ImageDestroy($this->im);
}
}
};
/*
* Local Variables:
* tab-width: 3
* End:
*/
?>