Creating Maps
Creating Maps
Creating Maps
8/23/2005
?
Creating Maps with PHP MapScript
There are few people who don't find maps intriguing, especially old maps with a antique look to them. So it is quite natural that digital mapping has become so popular. Where would we be without visualizing election results on a map? How effective would it be to hear about current affairs around the world without seeing how the countries involved are geographically related to their neighbors? The Google Maps and Mapquest.com's of the world are a popular incarnation of some exciting web mapping technology that you too can use. With a few pieces of mapping data, a mapping programming library and a PHP script, you can create custom and interactive maps.
MapServer concepts
MapServer's core configuration is through a text-based runtime configuration file. Referred to as a map file, it is the core of most MapServer-based applications. The CGI program or custom MapScript application reads this configuration information, accesses data, draws the map and returns a graphic ready for online viewing. This can also be run as a stand-alone command line program without any connection to the web. The examples in this hack use PHP MapScript from the command line. You can take these examples and modify them to suit your custom web environment. The map file has a simple hierarchical object structure, with object inheriting settings from their children. This hack uses a very simple map file that is only intended for use with PHP MapScript. To run it in a CGI environment you would need set more settings. You will also learn how to make an application without having a map file, creating it in runtime within a PHP script.
3 of 9
For other operating systems you may need to compile your own MapServer from source. This will, optionally, create the PHP MapScript libraries and is not always simple to do.
CAN WE PUT THIS DATA FILE SOMEWHERE ON OREILLYNET INSTEAD? For other data sources including satellite imagery, country boundary lines, remote web services, etc. see my book Web Mapping Illustrated (http://oreilly.com/catalog/webmapping) or online sites like freegis.org. For these examples, you will put your scripts in one folder and your data in a sub-folder. Create a folder for your scripts and a sub-folder called data to store your image file. Unzip the cloud_image.zip file into the data folder, it should create two files. A .tif file holding the image and a .tfw file that holds some geographic referencing information.
with a specific map file. Example 1 shows the listing of the bare minimum PHP code required. Example 1. Basic PHP script access to a map file for rendering a map image.
<?PHP // ex1_map_basic.php // Tyler Mitchell, August 2005 // Build a map using a pre-made map file // Load MapScript extension if (!extension_loaded("MapScript")) dl('php_mapscript.'.PHP_SHLIB_SUFFIX); // Create a map object. $oMap = ms_newMapObj("map_points.map"); // Render the map into an image object $oMapImage = $oMap->draw(); // Save the map to an image file $oMapImage->saveImage("worldmap.png"); ?>
As you can see it is really only four lines of PHP code to go through the basic mapping steps: load the MapScript extension, open the map file, render the map image, and save the image to a file. The result of the script is a single image, worldmap.png. Open the image in your favorite image viewer and you should see a global image. All the map settings are done in the map configuration file. Example 2 shows the contents of the map file. It includes a single layer of mapping data using the global map GeoTIFF image. This is an extremely simple example that probably won't work outside of the MapScript environment (i.e. using CGI MapServer). For more details on the options and settings in a MapServer configuration file see the map file reference documentation on the MapServer website: http://ms.gis.umn.edu. Example 2. Contents of the basic map file.
MAP NAME MAP_POINTS SIZE 600 300 EXTENT -180 -90 180 90 LAYER NAME clouds TYPE RASTER STATUS DEFAULT DATA "data/global_clouds.tif" END END
5 of 9
The resulting map image is shown in Figure 2. fig2_zoom.png Figure 2. Map centered on North American extents. Your script can do much more if you make it interactive for the user. By linking MapScript code into your web applications, you can provide limitless opportunities for zooming in/out of the map, turning layers on and off, adding more data, changing colours, etc. Refer to the PHP MapScript documentation to get an idea of other methods and properties.
7 of 9
CLASS COLOR 250 0 0 OUTLINECOLOR 255 255 255 SYMBOL "circle" SIZE 10 LABEL POSITION AUTO COLOR 250 0 0 OUTLINECOLOR 255 255 255 END END END END
The resulting map is shown in Figure 3. fig3_inline_point.png Figure 3. Map showing the inline point and label that was added to the map. Don't be too distracted by the symbol setting. While it looks obscure, you will likely not need to create additional ones until you start doing more advanced line symbology or area shading. While handy, a map file is not inherently dynamic, this is where PHP comes in. Example 5 is an extensive example showing how to create the entire map all using PHP and no map file. It also includes a section that will pull coordinates from a text file and dynamically add them to the map when it is rendered. Example 6 shows the contents of the simple text file (points.txt) containing the longitude/latitude point coordinates and a text label, delimited with commas (and with no header line). This file should be saved in the data sub-folder. Example 5. PHP script showing how to set a number of map settings without using a map file and importing points from a text file.
<?PHP // ex5_map_points.php // Build a map using a single GeoTIFF // and a text file of coordinates/labels. // Does not require a mapserver map file to run. // Tyler Mitchell, August, 2005 // Load MapScript extension if (!extension_loaded("MapScript")) dl('php_mapscript.'.PHP_SHLIB_SUFFIX); // Create a map object. Provide empty string if not // using an existing map file $oMap = ms_newMapObj(""); // Set size of the output map image $oMap->setSize(600,300); // Set the geographic extents of the map.
$oMap->setExtent(-180,-90,180,90); // Create a map symbol, used as a brush pattern // for drawing map features (lines, points, etc.) $nSymbolId = ms_newSymbolObj($oMap, "circle"); $oSymbol = $oMap->getsymbolobjectbyid($nSymbolId); $oSymbol->set("type", MS_SYMBOL_ELLIPSE); $oSymbol->set("filled", MS_TRUE); $aPoints[0] = 1; $aPoints[1] = 1; $oSymbol->setpoints($aPoints); // Create a data layer and associate it with the map. // This is the raster layer showing some cloud imagery $oLayerClouds = ms_newLayerObj($oMap); $oLayerClouds->set( "name", "clouds"); $oLayerClouds->set( "type", MS_LAYER_RASTER); $oLayerClouds->set( "status", MS_DEFAULT); $oLayerClouds->set( "data","data/global_clouds.tif"); // Create another layer to hold point locations $oLayerPoints = ms_newLayerObj($oMap); $oLayerPoints->set( "name", "custom_points"); $oLayerPoints->set( "type", MS_LAYER_POINT); $oLayerPoints->set( "status", MS_DEFAULT); // Open file with coordinates and label text (x,y,label) $fPointList = file("data/points.txt"); // For each line in the text file foreach ($fPointList as $sPointItem) { $aPointArray = explode(",",$sPointItem); // :TRICKY: Although we are creating points // we are required to use a line object (newLineObj) // with only one point. I call it a CoordList object // for simplicity since we aren't really drawing a line. $oCoordList = ms_newLineObj(); $oPointShape = ms_newShapeObj(MS_SHAPE_POINT); $oCoordList->addXY($aPointArray[0],$aPointArray[1]); $oPointShape->add($oCoordList); $oPointShape->set( "text", chop($aPointArray[2])); $oLayerPoints->addFeature($oPointShape); } // Create a class object to set feature drawing styles. $oMapClass = ms_newClassObj($oLayerPoints); // Create a style object defining how to draw features $oPointStyle = ms_newStyleObj($oMapClass); $oPointStyle->color->setRGB(250,0,0); $oPointStyle->outlinecolor->setRGB(255,255,255); $oPointStyle->set( "symbolname", "circle"); $oPointStyle->set( "size", "10");
9 of 9
// Create label settings for drawing text labels $oMapClass->label->set( "position", MS_AUTO); $oMapClass->label->color->setRGB(250,0,0); $oMapClass->label->outlinecolor->setRGB(255,255,255); // Render the map into an image object $oMapImage = $oMap->draw(); // Save the map to an image file $oMapImage->saveImage("worldmap.png"); ?>
Should remove comments from above code to shorten it up? Example 6. Listing of the points.txt file.
-118.35,34.06,Angie -118.40,34.03,Ray -111.99,33.52,Alice -95.45,29.75,David 144.85,-37.85,Mark
The output of the final map is shown in Figure 4. To take this example a step further, you could set up the dynamic point generator as a separate class. Then you could call this class from other PHP scripts, e.g. scripts that take coordinates as user input, and have them drawn on your map. fig4_all_points.png Figure 4. Map showing points and labels taken from text file.
Learning more
To learn more about MapServer and other open source geospatial technologies, there are many great places to get started. The community actively uses mailing lists, IRC discussion channels and holds annual conferences. To find other users in your area, ask on a mailing list. The MapServer mailing list tends to be a focal point for many other projects as they tend to be intertwined, so it may be the best place to look for help from a human. Web Mapping Illustrated (O'Reilly, 2005) covers a wide range of information including MapServer, spatial databases, OGC web services, data conversion, map projections and much more. Other books on related (open source) subjects include: Mapping Hacks (O'Reilly, 2005), Beginning MapServer (Apress, not yet released) and Pragmatic GIS (Pragmatic, not yet released).