Author: | Paul Ramsey |
---|---|
Contact: | pramsey at cleverelephant.ca |
Revision: | $Revision: 8287 $ |
Date: | $Date: 2008-12-26 07:25:23 -0800 (Fri, 26 Dec 2008) $ |
Last Updated: | 2008/04/30 |
Table of Contents
MapServer can feed tile-based map clients directly using the CGI “tile mode”. Tile-based map clients work by dividing the map of the world up into a discrete number of zoom levels, each partitioned into a number of identically sized “tiles”. Instead of accessing a map by requesting a bounding box, a tile client builds a map by accessing individual tiles.
Tile requests are handled by the ‘mapserv’ CGI program. In order to return tiles in the correct projection, MapServer must be built with the –use-proj option turned on. You can check if your version of ‘mapserv’ has projection support by running it with the ‘-v’ option and looking for ‘SUPPORTS=PROJ’.
Example 1. On Unix:
$ ./mapserv -v
MapServer version 4.6.1 OUTPUT=GIF OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=PDF
OUTPUT=SWF OUTPUT=SVG SUPPORTS=PROJ SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER
SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER
INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE DEBUG=MSDEBUG
Example 2. On Windows:
C:\apache\cgi-bin> mapserv -v
MapServer version 4.6.1 OUTPUT=GIF OUTPUT=PNG OUTPUT=JPEG OUTPUT=WBMP OUTPUT=PDF
OUTPUT=SWF OUTPUT=SVG SUPPORTS=PROJ SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER
SUPPORTS=WMS_CLIENT SUPPORTS=WFS_SERVER SUPPORTS=WFS_CLIENT SUPPORTS=WCS_SERVER
INPUT=JPEG INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE DEBUG=MSDEBUG
MapServer requires that each LAYER in your map file have a valid PROJECTION block to support reprojection. Because the tile mode uses reprojection, you will have to ensure each LAYER has a valid PROJECTION block.
Configuration checklist:
- MapServer compiled with PROJ support
- Map file with a PROJECTION defined for every LAYER
The MapServer tile support adds three new directives to the CGI interface:
Spherical Mercator (also called “web mercator” by some) is a world projection. All the major tile-based map interfaces (Google Maps, Microsoft Virtual Earth, Yahoo Maps, OpenLayers) use the spherical mercator system to address tiles.
A spherical mercator set of tiles has the following properties:
- The map has been reprojected to mercator using a spherical mercator algorithm
- There is one tile in the top zoom level, zoom level zero
- Each successive zoom level (z) has 2^z tiles along each axis
- Tiles are 256x256 in size
Google Maps and Virtual Earth both use spherical mercator as their underlying tile projection, but use different formats to address the individual tiles.
Google Maps uses an “x”, “y”, “zoom” format. The zoom indicates which level to pull tiles from, and the “x” and “y” indicate while tile in that zoom level to pull.
Virtual Earth uses a single string to address each tile. The top zoom level in Virtual Earth has four tiles (equivalent to Google’s zoom level 1). The top left tile in the Virtual Earth top zoom level is addessed as “0”, top right as “1”, bottom left as “2” and bottom right as “3”. Each tile the next level is addressed by first referencing the top level tile that contains it, then its address relative to that tile. So the top left tile in the second zoom level is “00” and the bottom right one is “33”. See the Virtual Earth site for more details: http://msdn.microsoft.com/en-us/library/bb545006.aspx
The Google Maps API includes support for using alternative tile sets as overlays, or as alternate base maps. Here is an example of an GTileLayerOverlay
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google/MapServer Tile Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&key=[YOUR KEY HERE]"
type="text/javascript"></script>
<script type="text/javascript">
function load() {
if (GBrowserIsCompatible()) {
var urlTemplate = 'http://localhost/cgi-bin/mapserv?';
urlTemplate += 'map=/var/map.map&';
urlTemplate += 'layers=layer1 layer2&';
urlTemplate += 'mode=tile&';
urlTemplate += 'tilemode=gmap&';
urlTemplate += 'tile={X}+{Y}+{Z}';
var myLayer = new GTileLayer(null,0,18,{
tileUrlTemplate:urlTemplate,
isPng:true,
opacity:1.0 });
var map = new GMap2(document.getElementById("map"));
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(35.35, -80.55), 15);
map.addOverlay(new GTileLayerOverlay(myLayer));
}
}
</script>
</head>
<body onload="load()" onunload="GUnload()">
<div id="map" style="width: 500px; height: 500px"></div>
</body>
</html>
|
Note the format of the tileUrlTemplate: a valid URL, with {X}, {Y} and {Z} substitution tokens that Google Maps will replace with the tile coordinates and zoom level on the fly to retrieve tiles from your server.
You can also use a MapServer tile layer as an alternate base map:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google/MapServer Tile Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&key=[YOUR KEY HERE]"
type="text/javascript"></script>
<script type="text/javascript">
function load() {
if (GBrowserIsCompatible()) {
var urlTemplate = 'http://localhost/cgi-bin/mapserv?';
urlTemplate += 'map=/var/map.map&';
urlTemplate += 'layers=layer1 layer2&';
urlTemplate += 'mode=tile&';
urlTemplate += 'tilemode=gmap&';
urlTemplate += 'tile={X}+{Y}+{Z}';
var myLayer = new GTileLayer(null,0,18,{
tileUrlTemplate:urlTemplate,
isPng:true,
opacity:0.3 });
var map = new GMap2(document.getElementById("map"));
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(35.35, -80.55), 15);
var myMapType = new GMapType([myLayer], new GMercatorProjection(18), 'MapServer');
map.addMapType(myMapType);
}
}
</script>
</head>
<body onload="load()" onunload="GUnload()">
<div id="map" style="width: 500px; height: 500px"></div>
</body>
</html>
|
The only change from the previous example is that we don’t create a GTileLayerOverlay, we create a GMapType, and use addMapType(), instead of addOverlay().
The Virtual Earth API also includes support for using alternative tile sets as overlays, or as alternate base maps. Here is an example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Virtual Earth Example</title>
<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1"></script>
<script type="text/javascript">
var map = null;
function OnLoadMap () {
map = new VEMap("myMap");
map.LoadMap();
var url = "http://localhost/cgi-bin/mapserv?";
url += "map=/var/map.map&";
url += "mode=tile&";
url += "layers=layer1 layer2&";
url += "tilemode=ve&";
url += "tile=%4";
var tileSourceSpec = new VETileSourceSpecification( "myLayer", url );
tileSourceSpec.Opacity = 0.3;
map.AddTileLayer(tileSourceSpec, true);
}
</script>
</head>
<body onload="OnLoadMap();">
<div id="myMap" style="position:relative; width:500px; height:500px;"></div>
</body>
</html>
|