j1n3l0 has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks

I am trying to do something that I believe is possible but may be slightly above my station :(

I have a method in a class which generates image maps from Gnuplot graphs where each data point on the graph is clickable. Trouble is, at present its default behaviour is to just pass the x and y values for the data point back to the script that calls it (the current file).

I would like a situation where I can let the user specify the action (s)he would like to take (such as CSS or Javascript mouseOver action).

My current thinking is to have some sort of "action" attribute which expects a CODE reference detailing the action to take. However I am not quite sure how to implement this.

Does anyone have any ideas ... or am I making things too complicated here?

Here is the method that generates the image map:

# Purpose : Generates an image map with the data available # Usage : $map = $object->image_map; sub image_map { my ($self) = @_; unless (ref $self) { croak "Using Instance method &image_map() as Class method" +; } # Declare some variables my $MAP_FORMAT = qq(<img src="%s" usemap="#%s">\n<map name=" +%s">%s</map>); my $AREA_FORMAT = qq(<area shape=circle coords="%.3f, %.3f, 2 +" href="%s" alt="%s" title="%s">\n); my $action_file = basename($0); # default to current file my $data_file = $self->get_data_file; my $image_file = catfile($self->get_webroot, $self->get_imag +e_file); my $command_file = $self->get_command_file; my $height = $self->get_gnuplot_height; my $width = $self->get_gnuplot_width; my $lmargin = $self->get_gnuplot_lmargin; my $rmargin = $self->get_gnuplot_rmargin; my $tmargin = $self->get_gnuplot_tmargin; my $bmargin = $self->get_gnuplot_bmargin; my $xmin = $self->get_xmin; my $xmax = $self->get_xmax; my $ymin = $self->get_ymin; my $ymax = $self->get_ymax; my $title = $self->get_title; my $legend = $self->get_legend; my $xaxis_label = $self->get_xaxis_label; my $yaxis_label = $self->get_yaxis_label; # Looping through the data ... my $coordinates = "\n"; # for html formatting for my $i ( 0 .. $#{$self->get_xcoords} ) { # Get the x and y coordinates my $xcoord = $self->get_xcoords->[$i]; my $ycoord = $self->get_ycoords->[$i]; my $xvalue = $self->get_xvalues->[$i]; my $yvalue = $self->get_yvalues->[$i]; # Create the image map ... $coordinates .= sprintf $AREA_FORMAT, $xcoord, $ycoord, "$ +action_file?x=$xvalue&y=$yvalue", "Value: [$xvalue, $yvalue]", "Value +: [$xvalue, $yvalue]"; # Save the x and y values to data file print $data_file join("\t", $xvalue, $yvalue), "\n"; } # Generate the gnuplot command my $gnuplot_command = qq( set terminal png set output "$image_file" set size $width, $height set lmargin $lmargin set rmargin $rmargin set tmargin $tmargin set bmargin $bmargin set xrange [$xmin: $xmax] set yrange [$ymin: $ymax] set title "$title" set xlabel "$xaxis_label" set ylabel "$yaxis_label" plot "$data_file" $legend ); # Write gnuplot_command to command_file print $command_file $gnuplot_command or die "Could not write t +o $command_file: $!"; # Run the gnuplot_command throwing any exceptions system("gnuplot $command_file") and croak "Problem running Gnu +plot command: $!"; # Return the image map return sprintf $MAP_FORMAT, $self->get_image_file, "PLOT", "PL +OT", $coordinates; }

Whilst creating the image map, the action: "$action_file?x=$xvalue&y=$yvalue" is currently hard coded. I think this is where I need to provide an action method: "$self->action" that will allow the user to specify his desires.

Any help is appreciated :)

Replies are listed 'Best First'.
Re: User defined action(s)
by j1n3l0 (Friar) on Aug 13, 2007 at 13:38 UTC
    Solved this one.

    What I needed was another attribute to allow the user specify his/her wishes. The default is the same as above (ie. pass the x and y values to current file as parameters).

    Within the image_map() method I have changed the line:

    $coordinates .= sprintf $AREA_FORMAT, $xcoord, $ycoord, "$action_file? +x=$xvalue&y=$yvalue", "Value: [$xvalue, $yvalue]", "Value: [$xvalue, +$yvalue]";

    To:

    $coordinates .= sprintf $AREA_FORMAT, $xcoord, $ycoord, $self->get_act +ion->($i);

    I have also changed $AREA_FORMAT accordingly:

    my $AREA_FORMAT = qq(<area shape=circle coords="%.3f, %.3f, 2" %s>\n) +;

    The user has to ensure his/her subroutine takes one integer as an argument ($i - the current index) and returns a string. That way (s)he can iterate over a number of arrays, hard coded into his subroutine and associate the values correctly.

    As an example, the following code:

    #!/usr/bin/perl -w use strict; use GnuplotImageMap; # generate some values to plot my @xvalues = map { sprintf "%.3f", rand } 1 .. 10; my @yvalues = map { sprintf "%.3f", rand } 1 .. 10; # this is to test the "action" my $alphabets = [ 'a' .. 'z' ]; # generate the image map my $object = GnuplotImageMap->new( xvalues => [@xvalues], yvalues => [@yvalues], # this is where you specify what you want to do ... the default is + as before! action => sub { my ($i) = @_; return $alphabets->[$i] || "out + of bounds here"; }, ); # print out the image map print "\n\nThe image map:\n\n", $object->image_map(), "\n"; exit 0;

    Gives the following output:

    The image map: <img src="C:\DOCUME~1\ionyia\LOCALS~1\Temp\LSPVfXDptt.png" usemap="#PL +OT"> <map name="PLOT"> <area shape=circle coords="605.000, 172.167, 2" a > <area shape=circle coords="308.779, 207.111, 2" b > <area shape=circle coords="588.668, 264.256, 2" c > <area shape=circle coords="70.000, 310.300, 2" d > <area shape=circle coords="397.195, 82.133, 2" e > <area shape=circle coords="249.647, 370.322, 2" f > <area shape=circle coords="273.863, 425.000, 2" g > <area shape=circle coords="544.179, 162.300, 2" h > <area shape=circle coords="598.805, 55.000, 2" i > <area shape=circle coords="332.432, 269.189, 2" j > </map>

    Note the alphabets: increasing from 'a' to 'j' in the image map string :)

    UPDATE:
    Tried to clarify the changes made and their effect on the output.