Problem
You want to use a graph image produced by GD::Graph::* as an imagemap in a web page
Solution
Install and use
GD::Graph::Map to create an HTML fragment for img and map tags.
#! perl -w
use GD::Graph::pie;
use GD::Graph::Map;
use GD::Graph::bars;
use CGI qw (param header);
use CGI::Carp (fatalsToBrowser);
use strict;
# some bogus sales data
my %sales = (
Tom => {
Ravioli => 20,
Lasagne => 30,
SpaghettiOs => 50
},
Dick => {
Chai => 25,
Green => 30,
Oolong =>40
},
Harry => {
Kiwi => 10,
Tomato => 15,
Grapes => 40
},
Elspeth => {
knives=> 40,
fistpacks=>40,
truncheons=>35
}
);
#
# if there's a name, show that person's sales;
#
if (param ("name")) {
my $name=param ("name"); # get requested person's name
# primitive error checking.
die "salesman not found. Insert salesman and press any key to cont
+inue.\n" unless exists ($sales{$name});
# prepare data.
# this is not incredibly readable, but I wanted to see if it could
+ be done this way... perl continues to amuse and amaze...
# to clarify, we're adding the names of the person's products in t
+he first arrayref,
# and the sales in the second array.
#
my @data = ([keys % {$sales {param ("name")}}], [values % {$sales
+{param ("name")}}]);
#
# prepare & display graph.
# please refer to GD::Graph's docs if this doesn't make sense.
#
my $my_graph = new GD::Graph::bars( 200, 200 ) || die "$!";
$my_graph->set(
x_label => 'Products',
y_label => 'Dollars',
title => "Sales for $name",
bar_spacing => 8
) ;
open PNG, ">../htdocs/$name.png";
binmode PNG;
print PNG $my_graph->plot(\@data)->png;
close PNG;
# finally, print out html;
print header;
print "<HTML><BODY BGCOLOR=white>\n";
print "<IMG SRC=\"/$name.png\">";
print "</BODY></HTML>";
} else {
#
# no name selected; show pie chart.
#
my @chartdata;
# start by pushing the names of the salesmen onto chartdata in an
+arrayref.
push @chartdata, [sort keys %sales];
my @salestotals;
my $urlbase="http://127.0.0.1/cgi-bin/gdmap2.cgi?name=";
my @urls;
#this loop does 2 things.
# first it gathers the total sales for each salesman (the inner fo
+reach loop) and pushes
# that value onto @salestotals, which is used to create the graph.
# After that, it creates a url and stores it for creation of the i
+mage map.
foreach (sort keys %sales) {
my $sum;
foreach my $item (keys (%{$sales{$_}})) {$sum+=$sales{$_}{$ite
+m}}
push @salestotals, $sum;
push @urls, $urlbase.$_;
}
# now we're finished with that, add the sales totals to the chart
+data
push @chartdata, [@salestotals];
# all the data's ready for the graph,
# time to plot it out.
# if this doesn't make sense to you, review GD::Graph workings
my $my_graph = new GD::Graph::pie( 200, 200 );
$my_graph->set(
'3d' => 0,
label => 'Sales totals',
);
open PNG, ">../htdocs/salesinfo.png";
binmode PNG;
print PNG $my_graph->plot(\@chartdata)->png;
close PNG;
# ok, the graph's finished. now make the map.
# the hrefs param is the list of urls to map to
# noImgMarkup indicates that only the <map> tag should be created,
# by default, GD::Graph::Map will create both the <map> and an <im
+g> tag
# mapName is, ha-ha, will be the name of the map.
# info will show mouseover data for the map.
my $map = new GD::Graph::Map($my_graph,
hrefs=>\@urls ,
noImgMarkup=>1,
mapName=>"salesmap",
info => 'Total sales for %x: %y (%p%)'
);
#finally, show the html
print header;
print "<HTML><BODY BGCOLOR=white>\n",
'<IMG SRC="/salesinfo.png" usemap="#salesmap">',
($map->imagemap("salesinfo.png", \@chartdata)),
"</BODY></HTML>";
}
Discussion
This module prepares an imagemap based on the contents of a GD::Graph object,
and has several constructor options that will alter the contents of the map or
its behavior.
The foremost among these is the
hrefs parameter (an arrayref) -- this list
determines what each map region links to. If there are more regions than hrefs,
say by having 8 series of data, but only 4 href elements, each 'leftover' series
will have 'javascript:;' for a link. This behavior is a little quirky; it seems
like the author could have stopped creating map regions after the last one was
finished, but this behavior is apparently to quell some odd behavior on older
browsers.
Next is the
noImgMarkup option -- this suppresses the output of the img
tag, and can be useful if you have a static image that may require several
different maps, or whenever the image is either static or has been generated
previously.
mapName overrides the default name attribute for the map tag. As the
default tag is set to
time (), this may not be useful when
noImgMarkup is set.
the
info (and
legend, see POD) param determines what information will be
displayed when mousing over a region.
There are a set of options to control the attributes of the img tag (
img_*, but these
may be of reduced value for most, as most of the common attributes are preset
when the tag is generated.
Finally, if you'd like the linked page to appear in a separate browser window,
setting
newWindow to true tag will accomplish the job.
Of course, this module requires that you have previous knowledge of the assorted
GD::Graph modules.