home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / xampp / xampp-perl-addon-1.4.9-installer.exe / Map.pm < prev    next >
Encoding:
Perl POD Document  |  2002-06-14  |  23.3 KB  |  619 lines

  1. package GD::Graph::Map;
  2.  
  3. use GD::Graph::axestype;
  4. use GD::Graph::utils qw(:all);
  5. use strict qw(vars subs refs);
  6. use vars qw(@EXPORT_OK $VERSION);
  7. use constant PI => 4 * atan2(1,1);
  8. require Exporter;
  9.  
  10. @GD::Graph::Map::ISA = qw(Exporter);
  11. @EXPORT_OK = qw(set imagemap);
  12. $VERSION = 1.05;
  13.  
  14. #--------------------------------------------- set defaults
  15. my $ANGLE_OFFSET = 90;
  16. my %Defaults = ( #Default Href is JavaScript code, which do nothing
  17.                  href   => 'javascript:;',
  18.                  lhref  => 'javascript:;',
  19.                  hrefs  => [],
  20.                  lhrefs => [],
  21.                  #Default information and legend
  22.                  info   => 'x=%x   y=%y',
  23.                  legend => '%l',
  24.                  #Line width for lines and linespoints graph
  25.                  linewidth => 3,
  26.                );
  27.  
  28. my %No_Tags = ('img_src'   => 0, 'img_usemap' => 0, 'img_ismap'   => 0,
  29.                'img_width' => 0, 'img_height' => 0 , 'img_border' => 0);
  30.  
  31.  
  32. #********************************************* PUBLIC methods of class
  33.  
  34. #--------------------------------------------- constructor of object
  35. sub new #($graphs, [%options])
  36. { my $type = shift;
  37.   my $class = ref $type || $type;
  38.   my $self = {GDGraph => shift, %Defaults};
  39.   bless $self, $class;
  40.   $self->set(@_) if @_;
  41.   return $self;
  42. } #new
  43.  
  44. #--------------------------------------------- routine for set options
  45. sub set
  46. { my $self = shift;
  47.   my %options = @_;
  48.   map { 
  49.     $self->{$_} = $options{$_} unless exists $No_Tags{lc($_)}
  50.   } keys %options;
  51. } #set
  52.  
  53. #--------------------------------------------- routine for make image maps
  54. sub imagemap($$$) #($file, \@data)
  55. { my $self = shift;
  56.   my $type = ref $self->{GDGraph};
  57.   if ($type eq 'GD::Graph::pie') { $self->piemap(@_) }
  58.   elsif ($type eq 'GD::Graph::bars') { $self->barsmap(@_) }
  59.   elsif ($type eq 'GD::Graph::lines') { $self->linesmap(@_) }
  60.   elsif ($type eq 'GD::Graph::points') { $self->pointsmap(@_) }
  61.   elsif ($type eq 'GD::Graph::linespoints') { $self->pointsmap(@_,1) }
  62.   else {die "object $type is not supported"};
  63. } #imagemap
  64.  
  65.  
  66. #********************************************* PRIVATE methods of class
  67.  
  68.  
  69. #--------------------------------------------- make map for Lines graph
  70. sub linesmap($$) #($file, \@data)
  71. { my $self = shift;
  72.   my ($file, $data) = @_;
  73.   my $gr = $self->{GDGraph};
  74.   my $lw = int (($self->{linewidth} + 1) / 2);
  75.   my $name = defined $self->{mapName} ? $self->{mapName} : time;
  76.   my $s = "<Map Name=$name>\n";
  77.   foreach (1 .. $gr->{_data}->num_sets) 
  78.   { my @values = $gr->{_data}->y_values($_);
  79.     $s .= "\t<Area Shape=polygon Coords=\"";
  80.     my @points;
  81.     for (my $i = 0; $i < @values; $i++)
  82.     { my ($x, $y) = $gr->val_to_pixel($i + 1, $data->[$_][$i], $_);
  83.       push @points, [$x, $y];
  84.       $s .= "$x, @{[$y - $lw]}, ";
  85.     }
  86.     foreach (reverse @points)
  87.     { my ($x, $y) = @$_;
  88.       $s .= "$x, @{[$y + $lw]}, ";
  89.     } #foreach
  90.     chop $s; chop $s;
  91.     my $href = $self->{lhrefs}->[$_ - 1];
  92.     $href = $self->{lhref} unless defined($href);
  93.     $href =~ s/%l/$gr->{legend}->[$_ - 1]/g;
  94.     my $info = $self->{info};
  95.     $info =~ s/%l/$gr->{legend}->[$_ - 1]/g;
  96.     $s .= "\" Href=\"$href\" Title=\"$info\" Alt=\"$info\" onMouseOver=\"window.status=\'$info\'; return true;\" onMouseOut=\"window.status=\'\'; return true;\"";
  97.     if ($self->{newWindow} and not $href =~ /javascript:/i)
  98.     { my $s_;
  99.       map
  100.       { $s_ .= "$1=@{[$self->{$_}]}," if $_ =~ /window_(\w+)/i and $self->{$_};
  101.       } keys %$self;
  102.       chop $s_;
  103.       $s .= " Target=\"_$name\" onClick=\"window.open(\'\', \'_$name\', \'$s_\'); return true;  \"";
  104.     } #if
  105.     $s .= ">\n";
  106.   } #foreach
  107.   $s .= $self->imagelegend($file, $data) if defined($gr->{legend});
  108.   $s .= "</Map>\n";
  109.   unless ($self->{noImgMarkup})
  110.   { $s .= "<Img UseMap=#$name Src=\"$file\" border=0 Height=@{[$gr->{height}]} Width=@{[$gr->{width}]} ";
  111.     map
  112.    { $s .= "$1=@{[$self->{$_}]} " if $_ =~ /img_(\w+)/i and $self->{$_};
  113.    } keys %$self;
  114.    chop $s;
  115.    $s .= ">\n";
  116.   } #unless
  117.   return $s;
  118. } #linesmap
  119.  
  120.  
  121. #----------------------------------- Make map for Points and LinesPoints graphs
  122. sub pointsmap($$$) #($file, \@data, $lines)
  123. { my $self = shift;
  124.   my ($file, $data, $lines) = @_;
  125.   my $gr = $self->{GDGraph};
  126.   my $lw = int (($self->{linewidth} + 1) / 2) if $lines;
  127.   my $name = defined $self->{mapName} ? $self->{mapName} : time;
  128.   $gr->check_data($data);
  129.   $gr->setup_coords($data);
  130.   my $s = "<Map Name=$name>\n";
  131.   foreach (1 .. $gr->{_data}->num_sets) 
  132.   { my @values = $gr->{_data}->y_values($_);
  133.     my ($s1, @points);
  134.     for (my $i = 0; $i < @values; $i++)
  135.     { next unless defined $values[$i];
  136.       my ($xp, $yp) = (defined($gr->{x_min_value}) and defined($gr->{x_max_value})) ?
  137.         $gr->val_to_pixel($gr->{_data}->get_x($i), $values[$i], $_) :
  138.         $gr->val_to_pixel($i + 1, $values[$i], $_);
  139.       if ($lines)
  140.       { push @points, [$xp, $yp];
  141.         $s1 .= "$xp, @{[$yp - $lw]}, ";
  142.       } #if
  143.       my ($l, $r, $b, $t) = $gr->marker_coordinates($xp, $yp);
  144.       $s .= "\t<Area Shape=rect Coords=\"$l, $t, $r, $b\" ";
  145.       my $href = ${$self->{hrefs}}[$_ - 1][$i];
  146.       $href = $self->{href} unless defined($href);
  147.       $href =~ s/%x/$data->[0][$i]/g; $href =~ s/%y/$data->[$_][$i]/g;
  148.       $href = $1.(sprintf "%$2f", $data->[0][$i]).$3 if ($href =~ /(^.*)%(\.\d)x(.*&)/);
  149.       $href = $1.(sprintf "%$2f", $data->[$_][$i]).$3 if ($href =~ /(^.*)%(\.\d)y(.*$)/);
  150.       $href =~ s/%l/@{$gr->{legend}}->[$_ - 1]/g;
  151.       my $info = $self->{info};
  152.       $info =~ s/%x/$data->[0][$i]/g; $info =~ s/%y/$data->[$_][$i]/g;
  153.       $info = $1.(sprintf "%$2f", $data->[0][$i]).$3 if ($info =~ /(^.*)%(\.\d)x(.*&)/);
  154.       $info = $1.(sprintf "%$2f", $data->[$_][$i]).$3 if ($info =~ /(^.*)%(\.\d)y(.*$)/);
  155.       $info =~ s/%l/@{$gr->{legend}}->[$_ - 1]/g;
  156.       $s .= "Href=\"$href\" Title=\"$info\" Alt=\"$info\" onMouseOver=\"window.status=\'$info\'; return true;\" onMouseOut=\"window.status=\'\'; return true;\"";
  157.       if ($self->{newWindow} and not $href =~ /javascript:/i)
  158.       { my $s_;
  159.         map
  160.         { $s_ .= "$1=".$self->{$_}."," if (($_ =~ /window_(\w*)/i) and ($self->{$_} != 0))
  161.         } keys %{$self};
  162.         chop $s_;
  163.         $s .= " Target=_$name";
  164.         $s .= " onClick=\"window.open(\'\', \'_$name\', \'$s_\'); return true;\"";
  165.       } #if
  166.       $s .= ">\n";
  167.     } #foreach
  168.     if ($lines)
  169.     { foreach (reverse @points)
  170.       { my ($x, $y) = @$_;
  171.         $s1 .= "$x, @{[$y + $lw]}, ";
  172.       } #foreach
  173.       chop $s1; chop $s1;
  174.       my $lhref = $self->{lhrefs}->[$_ - 1];
  175.       $lhref = $self->{lhref} unless defined($lhref);
  176.       $lhref =~ s/%l/$gr->{legend}->[$_ - 1]/g;
  177.       my $legend = $self->{legend};
  178.       $legend =~ s/%l/$gr->{legend}->[$_ - 1]/g;
  179.       $s .= "\t<Area Shape=polygon Coords=\"$s1\" Href=\"$lhref\" Title=\"$legend\" Alt=\"$legend\" onMouseOver=\"window.status=\'$legend\'; return true;\" onMouseOut=\"window.status=\'\'; return true;\"";
  180.       if ($self->{newWindow} and not $lhref =~ /javascript:/i)
  181.       { my $s_;
  182.         map
  183.         { $s_ .= "$1=@{[$self->{$_}]}," if $_ =~ /window_(\w+)/i and $self->{$_};
  184.         } keys %$self;
  185.         chop $s_;
  186.         $s .= " Target=\"_$name\" onClick=\"window.open(\'\', \'_$name\', \'$s_\'); return true;  \"";
  187.       } #if
  188.       $s .= ">\n"; $s1 = "";
  189.     } #if
  190.   }
  191.   $s .= $self->imagelegend($file, $data) if defined($gr->{legend});
  192.   $s .= "</Map>\n";
  193.   unless ($self->{noImgMarkup})
  194.   { $s .= "<Img UseMap=#$name Src=\"$file\" border=0 Height=@{[$gr->{height}]} Width=@{[$gr->{width}]} ";
  195.     map
  196.     { $s .= "$1=".($self->{$_})." " if ($_ =~ /img_(\w*)/i) and defined($self->{$_})
  197.     } keys %{$self};
  198.     chop $s;
  199.     $s .= ">\n";
  200.   } #unless
  201.   return $s;
  202. } #pointsmap
  203.  
  204. #--------------------------------------------- make map for Bar graph
  205. sub barsmap($$) #($file, \@data)
  206. { my $self = shift;
  207.   my ($file, $data) = @_;
  208.   my $gr = $self->{GDGraph};
  209.   my $name = defined $self->{mapName} ? $self->{mapName} : time;
  210.   $gr->check_data($data);
  211.   $gr->setup_coords($data);
  212.   my $s = "<Map Name=$name>\n";
  213.   foreach (1 .. $gr->{_data}->num_sets) 
  214.   { my $bar_s = $gr->{bar_spacing}/2;
  215.     my @values = $gr->{_data}->y_values($_);
  216.     for (my $i = 0; $i < @values; $i++) 
  217.     { my $value = $values[$i];
  218.       next unless defined $value;
  219.       my $bottom = $gr->_get_bottom($_, $i);
  220.       $value = $gr->{_data}->get_y_cumulative($_, $i) if ($gr->{cumulate});
  221.       my ($xp, $t) = $gr->val_to_pixel($i + 1, $value, $_);
  222.       my ($l, $r);
  223.       if ($gr->{overwrite})
  224.       {    $l = int($xp - $gr->{x_step}/2 + $bar_s + 1);
  225.     $r = int($xp + $gr->{x_step}/2 - $bar_s);
  226.     if ($gr->{cumulate})
  227.     { $bottom = ($gr->val_to_pixel($i + 1, $gr->{_data}->get_y_cumulative($_ - 1, $i), 
  228.         $_ - 1))[1] - 1 if $_ > 1;
  229.     }
  230.     else
  231.     { $bottom = ($gr->val_to_pixel($i + 1, ($gr->{_data}->y_values($_ + 1))[$i], $_ + 1))[1] - 1
  232.         if (($value > 0 and ($gr->{_data}->y_values($_ + 1))[$i] > 0) or
  233.           ($value < 0 and ($gr->{_data}->y_values($_ + 1))[$i] < 0)) and
  234.           $_ != $gr->{_data}->num_sets;
  235.     }
  236.       }    
  237.       else 
  238.       {    $l = int($xp - $gr->{x_step}/2
  239.          + ($_ - 1) * $gr->{x_step}/$gr->{_data}->num_sets + $bar_s + 1);
  240.     $r = int($xp - $gr->{x_step}/2
  241.          + $_ * $gr->{x_step}/$gr->{_data}->num_sets - $bar_s);
  242.       }
  243.       $s .= "\t<Area Shape=rect Coords=\"";
  244.       $s .= $value >= 0 ? "$l, $t, $r, $bottom\" " : "$l, $bottom, $r, $t\" ";
  245.       my $href = ${$self->{hrefs}}[$_ - 1][$i];
  246.       $href = $self->{href} unless defined($href);
  247.       $href =~ s/%x/$data->[0][$i]/g; $href =~ s/%y/$data->[$_][$i]/g;
  248.       $href = $1.(sprintf "%$2f", $data->[0][$i]).$3 if ($href =~ /(^.*)%(\.\d)x(.*$)/);
  249.       $href = $1.(sprintf "%$2f", $data->[$_][$i]).$3 if ($href =~ /(^.*)%(\.\d)y(.*$)/);
  250.       $href =~ s/%l/@{$gr->{legend}}->[$_ - 1]/g;
  251.       my $info = $self->{info};
  252.       $info =~ s/%x/$data->[0][$i]/g; $info =~ s/%y/$data->[$_][$i]/g;
  253.       $info = $1.(sprintf "%$2f", $data->[0][$i]).$3 if ($info =~ /(^.*)%(\.\d)x(.*$)/);
  254.       $info = $1.(sprintf "%$2f", $data->[$_][$i]).$3 if ($info =~ /(^.*)%(\.\d)y(.*$)/);
  255.       $info =~ s/%l/@{$gr->{legend}}->[$_ - 1]/g;
  256.       $s .= "Href=\"$href\" Title=\"$info\" Alt=\"$info\" onMouseOver=\"window.status=\'$info\'; return true;\" onMouseOut=\"window.status=\'\'; return true;\"";
  257.       if ($self->{newWindow} and not $href =~ /javascript:/i)
  258.       { my $s_;
  259.         map
  260.         { $s_ .= "$1=".$self->{$_}."," if (($_ =~ /window_(\w*)/i) and ($self->{$_} != 0))
  261.         } keys %{$self};
  262.         chop $s_;
  263.         $s .= " Target=_$name";
  264.         $s .= " onClick=\"window.open(\'\', \'_$name\', \'$s_\'); return true;\"";
  265.       } #if
  266.       $s .= ">\n";
  267.     }
  268.   }
  269.   $s .= $self->imagelegend($file, $data) if defined($gr->{legend});
  270.   $s .= "</Map>\n";
  271.   unless ($self->{noImgMarkup})
  272.   { $s .= "<Img UseMap=#$name Src=\"$file\" border=0 Height=@{[$gr->{height}]} Width=@{[$gr->{width}]} ";
  273.     map
  274.     { $s .= "$1=".($self->{$_})." " if ($_ =~ /img_(\w*)/i) and defined($self->{$_})
  275.     } keys %{$self};
  276.     chop $s;
  277.     $s .= ">\n";
  278.   } #unless
  279.   return $s;
  280. } #barsmap
  281.  
  282. #--------------------------------------------- make map for Pie graph
  283. sub piemap($$) #($file, \@data)
  284. { my $self = shift;
  285.   my ($file, $data) = @_;
  286.   my $gr = $self->{GDGraph};
  287.   my $name = defined $self->{mapName} ? $self->{mapName} : time;
  288.   my $s = "<Map Name=$name>\n";
  289.   $gr->check_data($data);
  290.   $gr->setup_coords();
  291.   
  292.   $ANGLE_OFFSET += $gr->{start_angle};
  293.   my $sum = 0;
  294.   my @values = $gr->{_data}->y_values(1);
  295.   foreach (@values) {$sum += $_}
  296.   die "Pie data total is <= 0" unless $sum > 0;
  297.   my $pb = $self->{start_angle};
  298.   for (my $i = 0; $i < @values; $i++) {
  299.     my $pa = $pb;
  300.     $pb += 360 * $values[$i]/$sum;
  301.     $s .= "\t<Area Shape=polygon Coords=\"".join(', ', int($gr->{xc}), int($gr->{yc}));
  302.     my ($xe, $ye) = &GD::Graph::pie::cartesian($gr->{w}/2, $pa, $gr->{xc}, 
  303.                               $gr->{yc}, $gr->{h}/$gr->{w});
  304.     my $oldj = $pa;
  305.     for (my $j = $pa; $j < $pb; $j += 10) {
  306.       $xe = int($gr->{xc} + $gr->{w} * cos(($ANGLE_OFFSET + $j) * PI / 180) / 2);
  307.       $ye = int($gr->{yc} + $gr->{h} * sin(($ANGLE_OFFSET + $j) * PI / 180) / 2);
  308.       if ($gr->{'3d'})
  309.       { $s .= ", $xe, $ye" if ($j == $pa and in_front($pa));
  310.         $s .= ", ".$gr->{left}.", ".($ye + $gr->{pie_height}).", ".$gr->{left}.", ".$ye if (($j > 90) and ($oldj < 90));
  311.         $s .= ", ".$gr->{right}.", ".($ye + $gr->{pie_height}).", ".$gr->{right}.", ".$ye if (($j > 270) and ($oldj < 270));
  312.         $s .= in_front($j) ? ", $xe, @{[$ye + $gr->{pie_height}]}" : ", $xe, $ye";
  313.       } #if
  314.       else { $s .= ", $xe, $ye" }
  315.       $oldj = $j;
  316.     }
  317.     $xe = int($gr->{xc} + $gr->{w} * cos(($ANGLE_OFFSET + $pb) * PI / 180) / 2);
  318.     $ye = int($gr->{yc} + $gr->{h} * sin(($ANGLE_OFFSET + $pb) * PI / 180) / 2);
  319.     $s .= ", $xe, ".($ye + $gr->{pie_height}) if (in_front($pb) and ($gr->{'3d'}));
  320.     $pa = 100 * $data->[1][$i] / $sum;
  321.     my $href = ${$self->{hrefs}}[$i];
  322.     $href = $self->{href} unless $href;
  323.     $href =~ s/%p/%.0p/g; $href =~ s/%s/$sum/g; $href =~ s/%y/$data->[1][$i]/g;
  324.     $href = $1.(sprintf "%$2f", $pa).$3 if ($href =~ /(^.*)%(\.\d)p(.*$)/);
  325.     $href = $1.(sprintf "%$2f", $sum).$3 if ($href =~ /(^.*)%(\.\d)s(.*$)/);
  326.     $href =~ s/%x/$data->[0][$i]/g;
  327.     $href = $1.(sprintf "%$2f", $data->[1][$i]).$3 if ($href =~ /(^.*)%(\.\d)y(.*$)/);
  328.     my $info = $self->{info};
  329.     $info =~ s/%p/%.0p/g; $info =~ s/%s/$sum/g; $info =~ s/%y/$data->[1][$i]/g;
  330.     $info = $1.(sprintf "%$2f", $pa).$3 if ($info =~ /(^.*)%(\.\d)p(.*$)/);
  331.     $info = $1.(sprintf "%$2f", $sum).$3 if ($info =~ /(^.*)%(\.\d)s(.*$)/);
  332.     $info =~ s/%x/$data->[0][$i]/g;
  333.     $info = $1.(sprintf "%$2f", $data->[1][$i]).$3 if ($info =~ /(^.*)%(\.\d)y(.*$)/);
  334.     $s .= ", $xe, $ye\" Href=\"$href\" Title=\"$info\" Alt=\"$info\" onMouseOver=\"window.status=\'$info\'; return true;\" onMouseOut=\"window.status=\'\'; return true;\"";
  335.     if ($self->{newWindow} and not $href =~ /javascript:/i)
  336.     { my $s_;
  337.       map
  338.       { $s_ .= "$1=".$self->{$_}."," if (($_ =~ /window_(\w*)/i) and ($self->{$_} != 0))
  339.       } keys %{$self};
  340.       chop $s_;
  341.       $s .= " Target=_$name";
  342.       $s .= " onClick=\"window.open(\'\', \'_$name\', \'$s_\')\"; return true;";
  343.     } #if
  344.     $s .= ">\n";
  345.   }
  346.   $s .= "</Map>\n";
  347.   unless ($self->{noImgMarkup})
  348.   { $s .= "<Img UseMap=#$name Src=\"$file\" border=0 Height=@{[$gr->{height}]} Width=@{[$gr->{width}]} ";
  349.     map
  350.     { $s .= "$1=".($self->{$_})." " if ($_ =~ /img_(\w*)/i) and defined($self->{$_})
  351.     } keys %{$self};
  352.     chop $s;
  353.     $s .= ">\n";
  354.   } #unless
  355.   return $s;
  356. } #piemap
  357.  
  358. #--------------------------------------------- private routines used by all objects
  359. sub in_front($) #(angle)
  360. { my $a = level_angle(shift);
  361.   ($a < $ANGLE_OFFSET or $a > (360 - $ANGLE_OFFSET)) ? 1 : 0;
  362. } #in_front
  363.  
  364. sub level_angle($) #(angle)
  365. { my $a = shift;
  366.   return level_angle($a - 360) if $a > 360;
  367.   return level_angle($a + 360) if $a < 0;
  368.   return $a;
  369. } #level_angle
  370.  
  371. sub imagelegend($$) #($file, \@data)
  372. { my $self = shift;
  373.   my $file = shift;
  374.   my $data = shift;
  375.   my $gr = $self->{GDGraph};
  376.   my $name = defined $self->{mapName} ? $self->{mapName} : time;
  377.   my $s = '';
  378.   my $xl = $gr->{lg_xs} + $gr->{legend_spacing};
  379.   my $y  = $gr->{lg_ys} + $gr->{legend_spacing} - 1;
  380.   my $i = 0;
  381.   my $row = 1;
  382.   my $x = $xl;
  383.   foreach my $legend (@{$gr->{legend}})
  384.   { $i++;
  385.     last if $i > $gr->{_data}->num_sets;
  386.     my $xe = $x;
  387.     next unless defined($legend) && $legend ne "";
  388.     my $lhref = @{$self->{lhrefs}}->[$i - 1];
  389.     $lhref = $self->{lhref} unless defined($lhref);
  390.     $lhref =~ s/%l/$_/g;
  391.     $legend = $self->{legend};
  392.     $legend =~ s/%l/$_/g;
  393.     my $ye = $y + int($gr->{lg_el_height}/2 - $gr->{legend_marker_height}/2);
  394.     $s .= "\t<Area Shape=rect Coords=\"$xe, $ye, ".($xe + $gr->{legend_marker_width}).", ".($ye + $gr->{legend_marker_height})."\" Href=\"$lhref\" Title=\"$legend\" Alt=\"$legend\" onMouseOver=\"window.status=\'$legend\'; return true;\" onMouseOut=\"window.status=\'\'; return true;\"";
  395.     if ($self->{newWindow} and $lhref ne $self->{href}) #$xe + $gr->{legend_marker_width}
  396.     { my $s_;
  397.       map
  398.       { $s_ .= "$1=".$self->{$_}."," if (($_ =~ /window_(\w*)/i) and ($self->{$_} != 0))
  399.       } keys %{$self};
  400.       chop $s_;
  401.       $s .= " Target=_$name";
  402.       $s .= " onClick=\"window.open(\'\', \'_$name\', \'$s_\'); return true;\"";
  403.     } #if
  404.     $s .= ">\n";
  405.     $xe += $self->{legend_marker_width} + $self->{legend_spacing};
  406.     $x += $gr->{lg_el_width};
  407.     if (++$row > $gr->{lg_cols})
  408.     { $row = 1;
  409.       $y += $gr->{lg_el_height};
  410.       $x = $xl;
  411.     }
  412.   }
  413.   return $s;
  414. } #imagelegend
  415.  
  416. 1;
  417.  
  418. __END__
  419.  
  420. =head1 NAME
  421.  
  422. B<GD::Graph::Map> - generate HTML map text for GD::Graph diagramms.
  423.  
  424. =head1 SYNOPSIS
  425.  
  426. use GD::Graph::Map;
  427.  
  428. $map = new GD::Graph::Map($gr_object);
  429.  
  430. $map->set(key1 => value1, key2 => value2 ...);
  431.  
  432. $HTML_map = $map->imagemap($gr_file, \@data);
  433.  
  434. =head1 DESCRIPTION
  435.  
  436. This is a I<perl5> module to generate HTML map text for following GD::Graph objects
  437. B<GD::Graph::pie>, B<GD::Graph::bars>, B<GD::Graph::lines>, B<GD::Graph::area>,
  438. B<GD::Graph::point> and B<GD::Graph::linespoints>.
  439. As a result of its work is created HTML code containing IMG and MAP tags.
  440. You simply need to insert this code into the necessary place of your HTML page.
  441. In the inserted thus image, its certain parts are the references and at a
  442. choice their mouse in a status line of your browser displays the additional
  443. information (see Samples).
  444.  
  445. =head1 SAMPLES
  446.  
  447. See the samples directory in the distribution.
  448.  
  449. =head1 USAGE
  450.  
  451. First of all you must create the B<GD::Graph> object and set options if it is necessary.
  452. Then create array of data and use plot routine for create graph image.
  453. For example create B<GD::Graph::pie> object:
  454.  
  455.   $graph = new GD::Graph::pie;
  456.  
  457.   $graph->set('title'        => 'A Pie Chart',
  458.               'label'        => 'Label',
  459.               'axislabelclr' => 'black',
  460.               'pie_height'   => 80);
  461.  
  462.   @data = (["1st","2nd","3rd","4th","5th","6th"],
  463.            [    4,    2,    3,    4,    3,  3.5]);
  464.  
  465.   $PNGimage = 'Demo.png';
  466.   open PNG, '>$pngimage';
  467.   binmode PNG; #only for Windows like platforms
  468.   print PNG $graph->plot(\@data)->png;
  469.   close PNG;
  470.  
  471. Then create B<GD::Graph::Map> object. And set options using set routine, or set it
  472. in constructor immediately. If it is necessary create hrefs and legend arrays:
  473.  
  474.   $map = new GD::Graph::Map($graph, newWindow => 1);
  475.  
  476.   $map->set(info => "%x slice contains %.1p% of %s (%x)");
  477.  
  478. Create HTML map text using the same array of data as use GD::Graph::plot routine
  479. and name of the your graph file:
  480.  
  481.   $HTML_map = $map->imagemap($GIFimage, \@data);
  482.  
  483. Now you can insert $HTML_map into the necessary place of your HTML page.
  484. You also can create only MAP tag with determined by you map name. For more
  485. information look at noImgMarkup and mapName options of the set routine.
  486.  
  487. =head1 METHODS AND FUNCTIONS
  488.  
  489. =over 4
  490.  
  491. =item Constructor
  492.  
  493. Constructor of object has following syntax:
  494.  
  495.   new GD::Graph::Map($gr_object,
  496.     [key1 => value1, key2 => value2 ...]);
  497.  
  498. where $gr_object this is one of the following graph objects: B<GD::Graph::pie>,
  499. B<GD::Graph::bars>, B<GD::Graph::lines>, B<GD::Graph::area>, B<GD::Graph::point>
  500. or B<GD::Graph::linespoints>; key1, value1 ... the same as using in the set routine.
  501. NOTE: Before use constructor you should at first set all properties for graph object,
  502. because they will be using for generetaing properly HTML map.
  503.  
  504. =item imagemap(I<$gr_file>, I<\@data>)
  505.  
  506. Generate HTML map text using the graph file $file and reference to array
  507. of data - \@data, which must be the same as using in plot routine.
  508.  
  509. =item set(I<key1> => I<value1>, I<key2> => I<value2> .... )
  510.  
  511. Set options. See OPTIONS.
  512.  
  513. =back
  514.  
  515. =head1 OPTIONS
  516.  
  517. =over *
  518.  
  519. =item B<hrefs>, B<lhrefs>
  520.  
  521. Sets hyper reference for each data (hrefs), and for each legend (lhrefs).
  522. Array @hrefs must the same size as arrays in @data list, otherwise null
  523. elements of @hrefs will set to default. Similarly array @lhrefs must the same
  524. size as the legend array. Default uses the simple JavaScript code 'javascript:;'
  525. instead reference, which do nothing (but in the some browsers it can work incorrectly).
  526.  
  527. Example of I<@hrefs> array:
  528.  
  529. for the I<GD::Graph::pie> object:
  530.  
  531. if     @data  = ([  "1st",  "2nd",  "3rd"],
  532.                  [      4,      2,      3]);
  533.  
  534. then   @hrefs =  ["1.htm","2.htm","3.htm"];
  535.  
  536.  
  537. for the other objects:
  538.  
  539. if     @data  = ([  "1st",  "2nd",  "3rd"],
  540.                  [      5,     12,     24],
  541.                  [      1,      2,      5]);
  542.  
  543. then   @hrefs = (["1.htm","2.htm","3.htm"],
  544.                  ["4.htm","5.htm","6.htm"]);
  545.  
  546. Example of I<@lhrefs> array;
  547.  
  548. if    @legend = [  'one',  'two','three'];
  549.  
  550. then  @lhrefs = ["1.htm","2.htm","3.htm"];
  551.  
  552.  
  553.  
  554. =item B<info>, B<legend>
  555.  
  556. Set information string for the data and for the legend. It will be displayed in the status line
  557. of your browser. Format of this string the same for each data, but you can use special
  558. symbols for receive individual information. Now available following symbols:
  559. I<%x> - Will be replaced on the x values in @data (first array)
  560. I<%y> - Will be replaced on the y values in @data (other arrays)
  561. I<%s> - Will be replaced on the sum of all y values.
  562. I<%l> - Will be replaced on the legend. For all objects, except the B<GD::Graph::pie> object.
  563. I<%p> - Will be replaced on the value, which show what part from all contains this data
  564. (in percentages).
  565.  
  566. I<%s> and I<%p> symbols can useing only in the B<GD::Graph::pie> object. I<%l> symbol
  567. vice versa available for all objects, except the B<GD::Graph::pie> object. And I<%x>, I<%y>
  568. symbols available for all objects, except the B<GD::Graph::lines> and the B<GD::Graph::area>
  569. objects.
  570. For the numerical parameters (%x, %y, %s and %p) you can use special format
  571. (the same as uses sprintf routine) for round data: %.d{x|y|p|s}, where 'd' is a digit
  572. from 0 to 9.
  573. For example %.0p or %.3x. It is desirable uses if %x, %y, %s or %p is the floating numbers.
  574. Default is 'x=%x y=%y' for info, and '%l' for legend.
  575.  
  576. =item B<img_*>
  577.  
  578. You can set any attribute in the IMG tag (except UseMap, Src, Width, Height and Border,
  579. they will be set automatically) use set routine: set(img_option => value), where 'option'
  580. is the IMG attribute. For instance: routine set(img_Alt => 'Example') will include Alt='Example'
  581. in the IMG tag.
  582.  
  583. =item B<newWindow>, B<window_*>
  584.  
  585. If the newWindow attribute is set to the TRUE and link does not contains JavaScript code
  586. (like javascript:), that link will be open in the new navigator window. Parameters of the
  587. new window you can establish using the window_* parameters, similarly the img_*.
  588.  
  589. =item B<mapName>
  590.  
  591. If mapName is TRUE the map will have this name. Default is time().
  592.  
  593. =item B<noImgMarkup>
  594.  
  595. If noImgMarkup is TRUE will be printed only the MAP tag, without
  596. the <Img UseMap=... > markup. You will have to print your own.
  597. Useful if the Graph is generated and poured directly to the a
  598. web-browser and not plotted to a GIF file.
  599.  
  600. =back
  601.  
  602. =head1 AUTHOR
  603.  
  604. Roman Kosenko
  605.  
  606. =head2 Contact info
  607.  
  608. E-mail:    ra@amk.lg.ua
  609.  
  610. Home page: http://amk.lg.ua/~ra/Map
  611.  
  612. =head2 Copyright
  613.  
  614. Copyright (C) 1999 Roman Kosenko.
  615. All rights reserved.  This package is free software;
  616. you can redistribute it and/or modify it under the same
  617. terms as Perl itself.
  618.  
  619.