GIFgraph::WithMap - generates HTML map text while plotting graph


GIFgraphExtensions documentation Contained in the GIFgraphExtensions distribution.

Index


Code Index:

NAME

Top

GIFgraph::WithMap - generates HTML map text while plotting graph

DESCRIPTION

Top

Generates the html map block for a graph so that data series become 'clickable',

SYNOPSIS

Top

This module extends GIFgraph objects such as GIFgraph::lines. You can do everything that you would with a GIFgraph object. In addition, when the data is plotted, it generates some MAP html text.

The series will be labeled 'series 1', 'series 2' etc. unless the $obj->seriesnames has been set. For each series, it will create a polygon area, with the following structure (assuming series is named 'Green', and that the links member array is empty:

 <AREA
        alt="Green"
        href="#Green"
        onMouseOver="self.status='Green'; return true"
        onMouseOut="self.status=''; return true"
        shape=polygon
        coords="87, 41, 165, 250, 165, 246, 87, 37">

So - clicking on the series will take you to #Green. If you don't specify #Green in the document, clicking on it will do very little. If you have (e.g. in the key) then it should take you there.

new

Top

Use something like

 $map = new GIFgraph::WithMap(new GIFgraph::lines(400,300));

fields

Top

map

Once plot has been called, map contains the map text.

 print $graphWithMap->map;

fuzz

This is the up/down fuzz used to construct the ploygon. It defaults to 1 - so the polygon will be three pixles wide (the pixle drawn and one above and below it).

mapname

Set this before calling plot. This is the name of the map, as given by usemap="#mapname" in <img>. It is a fatal error to try to plot without a name.

seriesnames

Array of names for the series. If a name is absent for a series (or all series) then it will be named Series #. This must be set before the graph is plotted.

 $graphWithMap->seriesnames('name1', 'name2');

Array of links for the series. If a link is absent for a series (or all series) then it will be named #SeriesName (where SeriesName is generated as described in seriwsnames).

Guts

Top

This module uses MRP::BaseClass to implement member access functions.

In the constructor, a new object is created that is a meld of an MRP::BaseClass derived object, and the GIFgraph object passed in. The type of that object is stoored in _GIFgraph. In AUTOLOAD, first I check to see if the GIFgraph object's package named in _GIFgraph implements the function. If it does, then I return the value of that function - i.e. it behaves as if the object inherits from that package. If that fails, then I return the value of SUPER::AUTLOLOAD, which will presumably handle it or die gracefully. Hey presto - dynamic parenting.

@ISA does not include anything to implement a GIFgraph object as a parent. However, I have overridden 'isa' to account for this.


GIFgraphExtensions documentation Contained in the GIFgraphExtensions distribution.

package GIFgraph::WithMap;

use strict;
use vars qw (@ISA %fields $AUTOLOAD $VERSION);
use Carp;
use CGI;

use MRP::BaseClass;

$VERSION = 1.0;

# use AUTOLOAD to pass everything that we can't do to _GIFgraph.
# don't know if this is kosha. AHHHH.
sub AUTOLOAD {
  my $thing = shift;
  my ($package, $function) = $AUTOLOAD =~ m/^(.*)::([^:]+)$/;

  if(ref($thing)) {
    my $delegate = $thing->_GIFgraph;
    $function = join '::', $delegate, $function;
    return $thing->$function(@_);
  }
  die "Could not find method $AUTOLOAD via $thing";
}

sub isa {
  my ($thing, $type) = @_;
  return $thing->_GIFgraph->isa($type) || $thing->SUPER::isa($type);
}

sub new {
  my $class = shift;
  my $GIFgraph = shift;
  my $baseClass = new MRP::BaseClass;

  my $self = $class->rebless($GIFgraph, $baseClass);

  $self->_GIFgraph(ref $GIFgraph);

  return $self;
}

sub draw_data {
  my ($self, $gd, $data) = @_;
  my $fuzz = $self->fuzz;
  my $map = "";
  my $mapname = $self->mapname || confess "You must set the name for this map before calling plot";
  my $seriesnames = $self->seriesnames;
  my $links = $self->links;

  my $delegateFunc = join '::', $self->_GIFgraph, 'draw_data';
  $self->$delegateFunc($gd, $data);
  
  $map = '<MAP NAME="' . $mapname . '">'."\n";
  foreach my $series (1 .. $self->{numsets}) {
    my (@up, @down);
    foreach my $point (0 .. $self->{numpoints}) {
      next unless defined($$data[$series][$point]);
      my ($x, $y) = $self->val_to_pixel($point+1, $$data[$series][$point], $series);
      push @up, $x, $y+$fuzz;
      unshift @down, $x, $y-$fuzz;
    }
    my $seriesname = $seriesnames->[$series-1] || 'series '.$series;
    my $link = $links->[$series-1] || "#$seriesname";
    $map .= join("\n\t",
		 '<AREA',
		 'alt="' . $seriesname . '"',
		 'href="' . $link . '"',
		 'onMouseOver="self.status=' . "'$seriesname'" . '; return true"',
		 'onMouseOut="self.status=' . "''" . '; return true"',
		 'shape=polygon',
		 'coords="' .  join(', ', @up, @down) . '"',
		 );
    $map .= ">\n";
  }
  $map .= "</MAP>\n";

  $self->map($map);
}

BEGIN {
  @ISA = qw (MRP::BaseClass);
  %fields = (
	     'fuzz' => 1,
	     'map' => undef,
	     'mapname' => undef,
	     'seriesnames' => [],
	     'links' => [],
	     '_GIFgraph' => undef,
	    );
  GIFgraph::WithMap->check4Clashes;
}

$VERSION;

__END__