Printer Friendly
In this third Part of our OpenStreetMap series we will demonstrate how to use the osm tiles we built in Part 2: Building Tiles with PostGIS OpenStreetMap data.
Creating your own Tile Layer Class
This first part is optional: Note that when you built the tiles, as you got deeper and deeper levels, therw were a lot more tiles and even worse, a lot of those damn tiles were empty.
I personally hate carrying around thousands of files of nothingness. It takes a long time to upload nothing. So what I do first is delete those nothing tiles which there seem to be more of than real tiles before I upload them to my server.
If you are on Windows, the easiest way to do that is with a command line VBscript. Here is a little script to get rid of nothing. Before you do this, set aside one blank tile to use when you get a 404 request.
This will only work on Windows. I haven't figured
out the complimentary command for Linux yet. Simply save the contents of this code to a file called delete_osm_blank_tiles.vbs and edit the last line to point to your osm maptiles cache.
Then run the script at a command line with cscript delete_osm_blank_tiles.vbs.
Sub RecursiveDeleteBlankOSMImages(ByVal strDirectory)
Dim objFolder, objSubFolder, objFile
Dim strExt
Dim strExtensionsToDelete
Dim lngSize
lngSize = 104
strExtensionsToDelete = "png"
Set objFolder = objFSO.GetFolder(strDirectory)
For Each objFile in objFolder.Files
For Each strExt in Split(Ucase(strExtensionsToDelete),",")
If Right(Ucase(objFile.Path), Len(strExt)+1) = "." & strExt AND objFile.Size < lngSize Then
wscript.echo "Deleting:" & objFile.Path
objFile.Delete
End If
Next
Next
For Each objSubFolder in objFolder.SubFolders
RecursiveDeleteBlankOSMImages objSubFolder.Path
Next
End Sub
Dim objFSO
Set objFSO = CreateObject("Scripting.FileSystemObject")
RecursiveDeleteBlankOSMImages "C:\osm_matiles\"
- Copy the tiles to your web server or one of those cloud storage web accessible file distributions like S3.
- Next create a new layer class and save it in it's own JS file. Replace http://localhost/osm_matiles, http://localhost/images/404.png with your own server details.
NOTE: We have an array of 3 tile urls. For our case, this is pretty useless, but for load balancing purposes and to also get rid of javascripts limitations of calling a server x amount of times in any period, you may want to setup more than one tile server
or mask your single tile server with multiple dns names (to fool javscript). So my OpenStreetMapLocal.js file looks
something like below and I place it in the same folder as my mapping application:
OpenLayers.Util.OSMLocal = {};
OpenLayers.Util.OSMLocal.MISSING_TILE_URL = "http://localhost/images/404.png";
OpenLayers.Util.onImageLoadError = function() {
this.src = OpenLayers.Util.OSMLocal.MISSING_TILE_URL;
};
OpenLayers.Layer.OSM.LocalMassachusettsMapnik = OpenLayers.Class(OpenLayers.Layer.OSM, {
initialize: function(name, options) {
var url = [
"http://localhost/osm_matiles/${z}/${x}/${y}.png",
"http://localhost/osm_matiles/${z}/${x}/${y}.png",
"http://localhost/osm_matiles/${z}/${x}/${y}.png"
];
options = OpenLayers.Util.extend({
numZoomLevels: 19,
buffer: 0,
transitionEffect: "resize"
}, options);
var newArguments = [name, url, options];
OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
},
CLASS_NAME: "OpenLayers.Layer.OSM.LocalMassachusettsMapnik"
});
Using your custom tile layer class
Now you link in this file as you would OpenStreetMap file and use this new class as you would any other OpenStreetMap OpenLayer layer class and you can even create ones with different themes if you want by creating a different set of tiles and theming them differently.
That's it folks. Here is a complete version just containing Massachusetts and neighboring State tiles with a complimentary Town boundary layer dished out by our local MassGIS government agency.
<html><title>OpenStreetMap with Local Tile Cache</title>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
<script src="js/OpenStreetMapLocal.js"></script>
<script>
var lat= 42.06651;
var lon=-71.71690;
var zoom=5;
var map;
var ls = new OpenLayers.Control.LayerSwitcher();
var mgisurls = ["http://giswebservices.massgis.state.ma.us/geoserver/wms"];
var prjwgs84 = new OpenLayers.Projection("EPSG:4326");
function init() {
var boundswm = new OpenLayers.Bounds(-8182919, 5035362.5,-7784059.5, 5304535)
map = new OpenLayers.Map ("map", {
controls:[ new OpenLayers.Control.Navigation({'mouseWheelOptions': {interval: 100}}),
new OpenLayers.Control.PanZoomBar(),ls ,
new OpenLayers.Control.Attribution(),
new OpenLayers.Control.MousePosition()
],
maxExtent: boundswm,
maxResolution: 700,
numZoomLevels: 18,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
} );
var lyrMapnik = new OpenLayers.Layer.OSM.LocalMassachusettsMapnik("OSM Mapnik Massachusetts", {'isBaseLayer': true});
var lyrTowns = new OpenLayers.Layer.WMS("Towns", mgisurls,
{ 'layers': "massgis:GISDATA.TOWNS_POLYM",
'styles': "",
'transparent': "true", 'FORMAT': "image/png"},
{ 'isBaseLayer': false, 'attribution': '<br /><a href="http://www.mass.gov/mgis/">MASSGIS (MA ITD)</a>',
'visibility': false, 'buffer': 1, 'singleTile':false, 'tileSize': new OpenLayers.Size(240,150) })
map.addLayers([lyrMapnik, lyrTowns]);
if( ! map.getCenter() ){
var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
map.zoomToExtent(boundswm);
ls.maximizeControl();
}
}
</script>
<body>
<div style="width:880; height:550" id="map"></div>
<script type="text/javascript" defer="true">
init();
</script>
</body>
</html>
To see it in action go to http://www.bostongis.com/demos/OpenLayers/mapnik_localosm.htm
Post Comments About Part 3: Using your own custom built OSM tiles in OpenLayers