Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

PerlMapScriptExamples35ex18

Thomas Bonfort edited this page Apr 6, 2012 · 2 revisions

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...

        <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                                                                                       
        <html>                                                                                                                                                                                                                                                                                         
        <head>                                                                                                                                                                                                                                                                                         
                <title>My Mapping Application</title>                                                                                                                                                                                                                                                  
        </head>                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                       
        <body>                                                                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                       
        <form name="mapform" action="index.cgi" method="post">                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                                       
                <table>                                                                                                                                                                                                                                                                                
                        <!-- start map toolbar -->                                                                                                                                                                                                                                                     
                        <tr>                                                                                                                                                                                                                                                                           
                                <td colspan="2">                                                                                                                                                                                                                                                       
                                        <input type="radio" name="tool" value="zoomin" checked>                                                                                                                                                                                                        
                                        <input type="radio" name="tool" value="zoomout">                                                                                                                                                                                                               
                                        <input type="radio" name="tool" value="zoomall" onClick="document.mapform.submit();">                                                                                                                                                                          
                                        <input type="radio" name="tool" value="pan">                                                                                                                                                                                                                   
                                </td>                                                                                                                                                                                                                                                                  
                        </tr>                                                                                                                                                                                                                                                                          
                        <!-- end map toolbar -->                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                                                                                       
                        <tr>                                                                                                                                                                                                                                                                           
                                <!-- start checkboxes for layers -->                                                                                                                                                                                                                                   
                                <td>                                                                                                                                                                                                                                                                   
                                <!-- start layers loop -->                                                                                                                                                                                                                                             
                                <tmpl_loop layers>                                                                                                                                                                                                                                                     
                                        <input type="checkbox" name="draw_layer" value="<tmpl_var layerindx>" <tmpl_var layerchek>>                                                                                                                                                                    
                                        <tmpl_var layername>                                                                                                                                                                                                                                           
                                </tmpl_loop>                                                                                                                                                                                                                                                           
                                <!-- end layers loop -->                                                                                                                                                                                                                                               
                                </td>                                                                                                                                                                                                                                                                  
                                <!-- end checkboxes for layers -->                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                                                                                       
                                <!-- start map image -->                                                                                                                                                                                                                                               
                                <td>                                                                                                                                                                                                                                                                   
                                        <input type="image" name="map" src="<tmpl_var map_img>" border="1">                                                                                                                                                                                            
                                        <input type="hidden" name="currect" value="<tmpl_var currect>">                                                                                                                                                                                                
                                        <input type="hidden" name="tool" value="<tmpl_var tool>">                                                                                                                                                                                                      
                                </td>                                                                                                                                                                                                                                                                  
                                <!-- end map image -->                                                                                                                                                                                                                                                 
                        </tr>                                                                                                                                                                                                                                                                          
                </table>                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                                                                                       
        </form>                                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                                       
        </body>                                                                                                                                                                                                                                                                                        
        </html>                                                                                                                                                                                                                                                                                        

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 PerlMapScrip

Clone this wiki locally

Morty Proxy This is a proxified and sanitized view of the page, visit original site.