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