= !MapScript HTML Template = Using HTML::Template allows (almost) complete separation of programming from display. Not only is this useful if separating responsibility for programming from html and web design, it is also a cleaner code which allows for easy changes later on as new functionality is added to the application. There are many templating solutions in the Perl world. I like HTML::Template for its utter simplicity and effectiveness at doing what it claims to do. The following Perl script/template combo shows a simple example of making a map and displaying it. ---- {{{ #!perl #!/usr/bin/perl -w # Import the modules use strict; use CGI::Pretty qw(:standard); use HTML::Template; use mapscript; # Create new template my $template = HTML::Template->new( filename => 'index.tmpl' ); $ENV{MS_ERRORFILE} = "path/to/mapserver.log"; # Mapserver error log # create a new map object my $mapObj = new mapscript::mapObj("mymapfile.map") or die("$mapscript::ms_error->{message}"); my @draw_layers = param('draw_layer'); # layers to be drawn submitted by the user # submitted as form variables, usually via # checkboxes checked or unchecked for the # layers to be drawn. my @layers; # layers to be sent back to the browser to # construct the set of checkboxes so the # user may choose what to draw my $tool = param("tool") eq "" ? "zoomin" : param("tool"); # currently selected tool my $x = param("map.x"); # coordinates of the mouseclick on the map my $y = $mapObj->{height} - param("map.y"); # invert the y coordinate because image # origin is top-left while map origin is # bottom-left my $zf = 2; # zoom in/out by this much my $jitter = 20; # Catch jerky mouse movement my $mapname_suf = time() . ".png"; # Tmp map and legend image names my $mapimgname = $mapObj->{name} . "_map_" . $mapname_suf; # # Store max extent my $mminx = $mapObj->{extent}->{minx}; my $mminy = $mapObj->{extent}->{miny}; my $mmaxx = $mapObj->{extent}->{maxx}; my $mmaxy = $mapObj->{extent}->{maxy}; # variables to hold new extent my ($minx, $miny, $maxx, $maxy); # $currect are the current geo rect coords used to calc the new geo rect coords. # $currect arrives at the server as a hidden form field submitted by the user. # split the form field value into component bounding coordinates. my ($f_minx, $f_miny, $f_maxx, $f_maxy) = split(" ", param("currect")); # Check if this is the first visit or a return visit. If $f_minx variable # (or any of the form variables calculated above) is empty then this is the # first visit if (($f_minx eq "") || ($tool eq "zoomall")) { # make new extent equal to max extent ($minx, $miny, $maxx, $maxy) = ($mminx, $mminy, $mmaxx, $mmaxy); for (0..$mapObj->{numlayers} - 1) { my $layerObj = $mapObj->getLayer($_); my %layer = ( 'layername' => $layerObj->{name}, 'layerindx' => $layerObj->{index}, 'layerchek' => $layerObj->{status} ? "checked" : "" ); push(@layers, \%layer); } } else { # Calc the amount of $zf based on the kind of redraw tool. # Pan will have a $zf of 1, while zoomout will inverse the $zf. # Leave $zf alone in case of zoomin. if ($tool eq "pan") { $zf = 1; } elsif ($tool eq "zoomput") { $zf = 1 / $zf; } # Calculate cellsize in x and y directions. cellsize is the geographic # size of each pixel on the screen. my $old_ground_width = $f_maxx - $f_minx; my $old_ground_height = $f_maxy - $f_miny; my $cx = $old_ground_width / $mapObj->{width}; my $cy = $old_ground_height / $mapObj->{height}; my $new_ground_width = $old_ground_width / $zf; my $new_ground_height = $old_ground_height / $zf; # use the cellsize and the zoom to calc the new extent $minx = ($f_minx + ($x * $cx)) - ($new_ground_width / 2); $miny = ($f_miny + ($y * $cy)) - ($new_ground_height / 2); $maxx = ($f_minx + ($x * $cx)) + ($new_ground_width / 2); $maxy = ($f_miny + ($y * $cx)) + ($new_ground_height / 2); # now figure out what layers to draw. # loop over all the layers... for (0..$mapObj->{numlayers} - 1) { # get the layer my $layerObj = $mapObj->getLayer($_); # toggle layer on if requested by user, otherwise toggle off $layerObj->{status} = grep($layerObj->{index} == $_, @draw_layers) ? 1 : 0; my %layer = ( 'layername' => $layerObj->{name}, 'layerindx' => $layerObj->{index}, 'layerchek' => $layerObj->{status} ? "checked" : "" ); push(@layers, \%layer); } } # set the new map extent $mapObj->{extent}->{minx} = $minx; $mapObj->{extent}->{miny} = $miny; $mapObj->{extent}->{maxx} = $maxx; $mapObj->{extent}->{maxy} = $maxy; # create the map my $imgObj = $mapObj->draw() or die('Unable to draw map'); $imgObj->saveImage( $mapimgname, $mapscript::MS_PNG, $mapObj->{interlace}, $mapObj->{transparent}, $mapObj->{imagequality} ); # ref to array of layers info to be sent back to the browser $template->param(layers => \@layers); # create vars to be sent back to the browser $template->param(map_img => "path/to/$mapimgname"); $template->param(currect => "$minx $miny $maxx $maxy"); #reset the tool to zoomin, if necessary $template->param(tool => ($tool eq "zoomall") ? "zoomin" : "$tool"); # Send the obligatory Content-Type and output the template print "Content-Type: text/html\n\n"; print $template->output; exit(0); }}} Meanwhile, in the template... {{{ My Mapping Application
>
}}} I encourage reading documentation for HTML::Template, and using it or some other templating solution to create web applications. Email me if further help is needed, or ask on the list. -- Puneet Kishor (pkishor at geoanalytics dot com) ---- back to PerlMapScript