Apache-GDGraph

 view release on metacpan or  search on metacpan

lib/Apache/GD/Graph.pm  view on Meta::CPAN

a parameter in a URL-encoded string, use C<%20>, in a form use a C<+>.

Make sure to use C<cache=0> or C<PerlSetVar CacheSize 0> when debugging,
otherwise you will spend hours being very confused.

=head1 FONTS

GD::Graph has some options that take a font description, such as title_font,
legend_font, etc. (these map to the appropriate set_FOO methods in GD::Graph,
see that manpage).

The following fonts are built-in to GD, these strings will resolve into the
appropriate fonts except when quoted:

gdSmallFont, gdLargeFont, gdMediumBoldFont, gdTinyFont, gdGiantFont

There is also a way to use your own True Type Fonts. See the TTFFontPath
variable under SYNOPSIS for how to set the search path for fonts. MAKE SURE
your fonts are readable by the user the Apache server runs under, this is
usually "www-data" or "nobody". Otherwise your fonts will mysteriously fail
with no notice.

Fonts can also be specified as a relative path to the DocumentRoot of the
server, these must begin with "../". For example, if you have a directory
"fonts" under DocumentRoot, then you might specify a font like so:

	../fonts/arial.ttf

If DocumentRoot happens to be C</var/www> then the font that will be looked up
is C</var/www/fonts/arial.ttf>.

Sizes can be specified by using a list with the name and size. For example, if
arial.ttf can be found somewhere in your TTFFontPath, you can do:

	...title_font=(arial.ttf,20)

To get a title using font Arial, in 20 points.

Note that GD::Text does not parse out the names of fonts and such, you have to
give it an actual filename, matches are case-insensitive. So if using the
Microsoft Windows core fonts, Arial Bold would be C<arialbd.ttf>. Here's an
example:

	http://server/chart?data1=[1,2,3,4,5]&
	title_font=(arialbd.ttf,20)&
	title=Just%20A%20Line

=head1 COLORS

All colors, including those specified for the captionN option, are specified
using the colour names from L<GD::Graph::colour>. They are, at time of writing:

white, lgray, gray, dgray, black, lblue, blue, dblue, gold, lyellow, yellow,
dyellow, lgreen, green, dgreen, lred, red, dred, lpurple, purple, dpurple,
lorange, orange, pink, dpink, marine, cyan, lbrown, dbrown.

=head1 IMAGES

You can place a logo in any corner of the graph using the C<logo>,
C<logo_resize> and C<logo_position> options. See L<GD::Graph>. If you just want
a background image that is resized to fit your graph, see the
C<background_image> option herein.

=head1 TEXT/CAPTIONS

The following GD::Graph options control placing text on the graph: title,
x_label and y_label. L<GD::Graph> for those and related options. In addition,
this modules allows you to use the captionN option(s), to draw arbitrary
strings on the graph. See below.

=head1 IMPLEMENTATION

This module is implemented as a simple Apache mod_perl handler that generates
and returns a png format graph (using Martien Verbruggen's GD::Graph module)
based on the arguments passed in via a query string. It responds with the
content-type "image/png" (or whatever is set via C<PerlSetVar ImageType>), and
sends a Expires: header of 30 days (or whatever is set via C<PerlSetVar
Expires>, or expires in the query string, in days) ahead.

In addition, it keeps a server-side cache in the file system using DeWitt
Clinton's File::Cache module, whose size can be specified via C<PerlSetVar
CacheSize> in bytes.

=head1 OPTIONS

=over 8

=item B<type>

Type of graph to generate, can be lines, bars, points, linespoints, area,
mixed, pie. For a description of these, see L<GD::Graph(3)>. Can also be one of
the 3d types if GD::Graph3d is installed, or anything else with prefix
GD::Graph::.

=item B<width>

Width of graph in pixels, 400 by default.

=item B<height>

Height of graph in pixels, 300 by default.

=item B<expires>

Date of Expires header from now, in days. Same as C<PerlSetVar Expires>.

=item B<image_type>

Same as C<PerlSetVar ImageType>. "png" by default, but can be anything
supported by GD.

If not specified via this option or in the config file, the image type can also
be deduced from a single value in the 'Accept' header of the request.

=item B<jpeg_quality>

Same as C<PerlSetVar JpegQuality>. A number from 0 to 100 that determines the
jpeg quality and the size. If not set at all, the GD library will determine the
optimal setting. Changing this value doesn't seem to do much as far as line
graphs go, but YMMV.

=item B<background_image>

Set an image as the background for the graph. You are responsible for choosing
a sane image to go with your graph, the background should be either transparent
or the same color you will use. This is the same as using the C<logo> parameter
with an image of the same size as the graph, except this option will resize the
image if necessary, making it more convenient for this purpose. The file or URL
can be of any type your copy of GD supports.

=item B<captionN>

Draws a character string using a TrueType font at an arbitrary location.  Takes
an array of
C<($fgcolor,$fontname,$ptsize,$angle,$x,$y,$string[,$box_color,$box_offset])>
where $fgcolor is the foreground color, $fontname is the name of a TTF font see
L</FONTS> , $ptsize is the point size, $x and $y are the coordinates, and
$string is the actual characters to draw.

$box_color and $box_offset are optional parameters, if set the caption will be
drawn with a box around it in that color and that distance from the caption
string. The default offset of 9 should work well in most cases.

N is an integer from 1 onward, like for the dataN option. This lets you specify
multiple strings to draw.

B<Note:> you cannot use builtin GD fonts like gdTinyFont for captions, you have
to use a real TTF font.

This uses the GD stringTTF method, see L<GD>. Colour names are indexed using
the GD::Graph::colour builtins (see above), fonts are resolved by font path or
relative to DocumentRoot, parameters are processed as per L</DATA TYPES>.

Angle is in degrees, you will primarily use angle C<0> for normal left-to-right
text. $x and $y are pixel coordinates from the upper left corner. $fontname is
the name of a true-type font that will be found in the font path L</FONTS>.
Example:

	http://isis/chart?data1=[1,2,3,4,5]&
	caption1=(1,arial.ttf,9,0,30,30,Hello,red)

To draw the box around the caption as a dashed or dotted line use:

=item B<gd_set_style>

This option sets the style for the special gdStyled color index. It's simply a
list of colors that becomes the pattern for lines and such drawn with it. For
example, to get a dashed red line:

	gd_set_style=(red,red,red,red,red,red,
	gdTransparent,gdTransparent,
	gdTransparent,gdTransparent);

The list can be arbitrarily long.

B<Note:> at this time, the only place where you can use colors of this style is
for the box around a caption. Just specify C<gdStyled> as the color.

=item B<cache>

Boolean value which determines whether or not the image will get cached
server-side (for client-side caching, use the "expires" parameter). It is true
(1) by default. Setting C<PerlSetVar CacheSize 0> in the config file will
achieve the same affect as C<cache=0> in the query string.

lib/Apache/GD/Graph.pm  view on Meta::CPAN

		} else {
			$x_labels = undef;
		}
		
# Validate the sizes in order to have a more friendly error.
		if (defined $x_labels) {
			arrayCheck "x_labels" => $x_labels;
			if (scalar @$x_labels != $length) {
				die <<EOF;
Size of x_labels not the same as length of data.
EOF
			}
		} else {
# If x_labels is not an array or empty, fill it with undefs.
			for (1..$length) {
				push @$x_labels, undef;
			}
		}

		my $n = 2;
		for (@data[1..$#data]) {
			if (scalar @$_ != $length) {
				die <<EOF;
Size of data$n does not equal size of data1.
EOF
			}
			$n++;
		}

		my $graph;
		eval {
			no strict 'refs';
			require "GD/Graph/$type.pm";
			$graph = ('GD::Graph::'.$type)->new($width, $height);
		}; if ($@) {
		 die <<EOF;
Could not create an instance of class GD::Graph::$type: $@
EOF
		}

		my $to_file = (parseElement delete $args{to_file})[1];
# Untaint it!
		($to_file) = ($to_file =~ /([\w.\/]+)/);

		for my $option (keys %args) {
			my ($type, $value, @rest) = parse ($args{$option});

			if (my $method = $graph->can("set_$option")) {
				$graph->$method($value, @rest);
			} else {
				if ($type == TYPE_LIST) {
					$value = [ $value, @rest ];
				}
				$args{$option} = $value;
			}

			arrayCheck $option, $value
				if index (ARRAY_OPTIONS, $option) != -1;
		};

# Check if background image specified.
		if (exists $args{background_image}) {
			my $image = new GD::Image($args{background_image});

			die <<EOF if not defined $image;
Could not open your background image: $!
EOF
			$graph->gd->copyResized(
				$image, 0, 0,
				0, 0, $width, $height,
				$image->getBounds
			); 

			delete $args{background_image};
		}

# Check if we need to draw captions, draw them after graph is plotted.
		my @captions;
		$i = 1;
		$key = "caption$i";
		while (exists $args{$key}) {
			die <<EOF unless UNIVERSAL::isa($args{$key}, 'ARRAY');
Caption must be an array. See the Apache::GD::Graph man page or the StringTTF
method in the GD man page for details.
EOF
			push @captions, delete $args{$key};
			$key = "caption".(++$i);
		}

# Style for the special gdStyled color.
		my $gd_style = delete $args{gd_set_style};

		$graph->set(%args);

		my $image = $graph->plot([$x_labels, @data])
			or die <<EOF;
Could not create graph: @{[ $graph->error ]}
EOF

		$image->setStyle (
			map { resolveColor ($graph => $_) }
			@$gd_style
		) if $gd_style;

# Draw captions.
		for my $caption (@captions) {
			undef $@;

# Argument 1 is the color, have to resolve GD::Graph::colour builtins into
# indexes on the GD image.
			$caption->[0] = resolveColor($graph => $caption->[0]);

# Argument 2 to caption is the font name, GD expects a full path.
			$caption->[1] = findFont($caption->[1]);

			my @bounds = $image->stringTTF(@$caption[0..6]);

			die "Could not draw caption: @{[ join ', ', @$caption ]}: $@" if $@;

# Draw box around caption.
			next unless defined(my $box_clr = $caption->[7]);

			my $offset = defined $caption->[8] ?
					$caption->[8] :
					DEFAULT_CAPTION_BOX_OFFSET;
# Upper left.
			$bounds[6] -= $offset;
			$bounds[7] -= $offset;
# Lower right.
			$bounds[2] += $offset;
			$bounds[3] += $offset;

			$image->rectangle(
				@bounds[6,7,2,3],



( run in 3.092 seconds using v1.01-cache-2.11-cpan-d8267643d1d )