Hack 91. Build Interactive Web-Based Map Applications
MapServer offers a powerful way to publish interactive maps on the World Wide Web.
Bringing interactive maps to the Web may seem like a daunting task. I initially set out to display a map of my home area and plot additional points on top. When I first went on this quest, I was afraid I would have to write kilobytes of code by myself. Fortunately, there are packages out there that do the hard parts, allowing us to focus on making maps.
MapServer, which lives at http://mapserver.gis.umn.edu/, is a great package for making interactive maps. It is a CGI program written in C that creates interactive maps from your spatial data. (You can also use MapServer with Perl, Python, and PHP using the provided MapScript modules). MapServer supports a wide range of spatial data formats, databases, and display formats; it makes publishing maps on the Web not only easier, but also extensible.
8.6.1. Getting and Installing MapServer
MapServer source code is available at http://mapserver.gis.umn.edu/dload.html. There is also a precompiled binary for Windows machines. Binary RPMs for various platforms can be found as part of the PostGIS distribution at http://postgis.refractions.net/rpms/, or from the Mapping Hacks RPM archive at http://mappinghacks.com/rpm. Debian packages are also available, from http://pkg-grass.alioth.debian.org/debian-gis.
MapServer supports a stunning variety of options, from numerous data sources (e.g., PostGIS database) and map output formats (e.g., PDF, SVG, Flash, images). Any binary package must assume some set of pre-installed libraries. Getting these dependencies sorted out adds a lot of complexity to the installation process, which interferes with what is, at heart, a rather simple program. Ironically, the easiest way to get started may be to compile from source:
$ ./configure $ make
This is not the "right" way to configure MapServer, but there is a good chance that this will work (especially if you already have the GD image libraries installed). The document "HOWTO for Getting Started with MapServer" (http://mapserver.gis.umn.edu/doc/getstarted-howto.html) contains links to detailed instructions for building MapServer under other platforms, and with more options.
Once you've compiled MapServer, you can test its capabilities:
$ ./mapserv -v MapServer version 4.2.4 OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP SUPPORTS=FREETYPE INPUT=TIFF INPUT=EPPL7 INPUT=JPEG INPUT=SHAPEFILE
This means that MapServer can read ESRI Shapefiles and write JPEG and PNG images. This is just a taste of what MapServer can do, but "tall trees from little acorns grow."
Copy the program mapserv to a directory that can execute CGI programs. On a default Fedora or Debian system, that is likely to be /var/www/cgi-bin (on a SuSE system, it is probably /srv/www/cgi-bin). Test that the web server is correctly configured by going to http://localhost/cgi-bin/mapserv, or use the server's Internet domain name if you are testing a remote machine (e.g., http://yourserver.com/cgi-bin/mapserv). You should get the message:
No query information to decode. QUERY_STRING is set, but empty.
This means that the program is running but you have not given it anything to do. So how do you give it something to do?
Well, first you need some data. Since our copy of mapserv can display ESRI Shapefiles, let's get the outline of the United States. NationalAtlas.gov contains large amounts of free data about the United States. Go to the "Map Layers Warehouse" page at http://nationalatlas.gov/atlasftp.html. Download the States Information file from http://edcftp.cr.usgs.gov/pub/data/nationalatlas/statesp020.tar.gz. Decompress the files and put them in your data directory, which can be anywhere as long as your web server has permission to read files there.
8.6.2. Directories
You will need to have some other web-server-readable directories in your filesystem for storing the various components of your MapServer installation. I tend to use Fedora-flavored systems, so modify this to suit your preferences:
/var/www/cgi-bin
A directory that your web server uses for CGI programs. Copy the mapserv CGI program here.
/var/www/html
Your document root. This is where the initialization HTML file and the map file (.map) should go.
/var/www/html/data
This will be the repository for your geodata files.
/var/www/html/temp
Temporary directory for images. Your web server must have write permission for this directory.
8.6.3. The Map File
The map file is where you specify what MapServer should do. Here is possibly the simplest map file that will display a shapefile:
MAP SIZE 400 400 EXTENT -125 50 -65 24 LAYER TYPE LINE STATUS DEFAULT DATA "/var/www/html/data/statesp020.shp" CLASS COLOR 0 0 0 END END END
Each section of the map file starts with the name of that section and ends with the word END. Some sections can be nested. This map file says to create an image 400 pixels wide by 400 pixels high that covers the Continental United States, from 65º W to 125º W and from 24º N to 50º N.
One map layer will be shown, and it is the shapefile of the state boundaries. It will be presented in the color black; the colors are RGB triples, so 250 0 0 is all red, 0 255 0 is green, 0 0 255 is blue, and there are 224 more shades of color available.
Name this file mini.map and make sure that the statesp020.shp, .shx, and .dbf files are in the data directory. Figure 8-10 shows the map of the U.S. that you can now generate by going to http://yourserver.com/cgi-bin/mapserv?map=/var/www/html/mini.map&mode=map.
Figure 8-10. The United States, as presented by MapServer
You can also include that URL in your web pages as an image:
The map=/var/www/html/mini.map parameter points to the map file that describes how the map will be generated. The second parameter, mode=map, causes MapServer to return an image file directly.
|
8.6.4. Adding Interactivity
Generating an image from passed parameters is just the tip of the map. You can also create a full layer-based interactive map viewer with just a bit more effort.
For this example, we'll use a shapefile of local roads in Allegheny County, available from http://www.pasda.psu.edu. The specific URL of the file is ftp://pasda.cac.psu.edu/pub/pasda/padot/local/padot-locroads-allegheny_2001.zip. Unzip this file, and put it in your data directory. Be sure that the user permissions for the unzipped files are readable by the web server, or you will get errors telling you: Failed to draw layer!
We now want a more elaborate map file. Save the following text as mapserver.map and put it into your document root (e.g., /var/www/html):
map size 400 400 extent -80.475 39.96 -79.475 40.96 web template mapserver.html imagepath "/var/www/html/temp/" imageurl "/temp/" end layer name allegheny type line status default data "data/allegheny.shp" class color 0 0 0 end end end
In this file we have zoomed in to the area from 39.96ºN, 80.475ºW to 40.96ºN, 79.475ºW. This map file also includes a web section. The template parameter specifies the name of an HTML file that provides the formatting for the web display of our map. In this case, the directory is shown relative to the location of our map file. When we use a template file, mapserv creates an image of the map and writes it to a temporary file in the directory specified by the imagepath parameter. The imageurl parameter specifies the location of that directory relative to our document root, so that the web browser can access those images:
[ Zoom In ] [ Pan ] [ Zoom Out ] Zoom Size
When you invoke MapServer with the previous map file, it will read this HTML template, replacing the appropriate keywords in square brackets, such as [img] and [mapext], with their intended values. There are extensive ways to flesh out the HTML, including JavaScript, Perl, and PHP through MapScript. This is only a brief example, so it includes only the basics needed to display the map and provide minimal navigation. Save this file as mapserver.html in your document root directory.
MapServer is stateless, which means that the program running on the server does not store information about your session. Each request to MapServer includes all of the parameters of your current session. For example, if you zoom in on a map, your current extent (the area that is displayed) is sent with your HTTP request.
We need a way to initialize our MapServer session. There are many possible parameters that we can provide, but the only mandatory parameter is the name of a map file. We can pass this by including it on the command line, or by putting it into a hidden form variable in an HTML file:
This will initialize Mapserver.
Save this file to index.html (or whatever you want), and then load it in your web browser. This displays the message "This will initialize MapServer" and a button labeled Initialize. Click the button, and you will get a map. Alternatively, you can construct a URL with a query string directly in your browsere.g., http://yourserver.com/cgi-bin/mapserv?map=/var/www/html/mapserver.map. In either case, you must provide the full path to your map file relative to the root directory of your filesystem.
Both the URI method and the file method do the same job of passing the location of our map file to MapServer. MapServer then reads the rest the map file and creates a map. The initial output should be a black gob of roads. You should also see the path of the Ohio, Monongahela, and Allegheny rivers as cutouts against the local roadways.
By clicking on the resulting image, it should recenter the image to where you have clicked. The radio buttons at the bottom allow you to zoom in, zoom out, or pan the image. You can select the "zoom in" radio button and then click on the image. The map in Figure 8-11 shows the result of zooming in a bit on our initial squiggle of roads.
Figure 8-11. MapServer and the streets of Pittsburgh
8.6.5. Adding a Point
You can add a point directly in the map file to indicate anything you wish. You can even specify points via URLs, through a database, or from another file. Here, we will specify just one point, for my favorite local coffee shop with free Wi-Fi. First, let's define the symbol that will mark our point. Add this section before the final end tag in your map file:
symbol name "coffee_wifi" type ellipse filled true points 2 1 end end
This creates a symbol named coffee_wifi as an ellipse that is twice as wide as it is tall. This does not control the absolute size at which the symbol will be displayed; that will be determined by the size parameter in the layer that uses the symbol.
Now we can add another layer for our coffee shop, after the coffee_wifi symbol and before our final end tag:
layer name beehive type point status default class color 0 0 255 symbol "coffee_wifi" size 15 label position ur size medium color 0 0 255 outlinecolor 255 255 255 end end feature points -79.98403 40.42775 end text "Beehive" end end
Note how we use the coffee_wifi symbol that we defined earlier, but we set the size and color here. We also set the position of the label to ur, or upper right of the symbol.
The feature section defines an individual point. We can add multiple feature blocks, each with the points (longitude first, as usual) and text (name or label). You should now see a blue dot labeled "Beehive" on the South Side of Pittsburgh, as shown in Figure 8-12.
Figure 8-12. The Beehive Coffee Shop with free Wi-Fi
MapServer does a heck of a lot more than this: raster layers, on-the-fly reprojection, automatic labeling, TrueType fonts, layer queries, attribute filtering, database lookups, and more. Obviously, the next step is to tailor the images to your liking by tweaking your map file and the corresponding HTML. We'll look a little more into this in [Hack #92] .
8.6.6. See Also
http://terrasip.gis.umn.edu/projects/tutorial/
MapServer tutorial
http://mapserver.gis.umn.edu/doc/getstarted-howto.html
Getting started with MapServer
http://omsug.ca/dl/osgis2004/MsTutorialGuide.doc
How to use (almost) every vector data format with MapServer
http://omsug.ca/osgis2004/proceedings.html
From the proceedings of the 2004 North American Open Source GIS Conference
http://maptools.org/ms4w/
MapServer for Windows (MS4W): includes Apache and everything to get started (and more, perhaps too much!)
Drew from Zhrodague