[GIS] OpenLayers with a small, discrete set of XYZ tiles

openlayers-2

I'm trying to set up a handy map of my Minecraft server to share with my fellow players; the specifics on that front aren't really necessary though — suffice it to say that I have a tile set (each tile 256×256 pixels) representing 6 zoom levels, with a 2×2 grid of tiles at zoom level 0 all the way up to 64×40 tiles at zoom level 5.

After much tinkering and excessive frustration, I have managed to finally get the map fully viewable — but OpenLayers thinks I've got tiles that are outside my bounds, leading to the map being off-center when initially loaded and, more importantly, leaving me thinking that I've merely gotten lucky with the OpenLayers.Bounds declaration and that it will all fall apart completely when the map (and its dimensions) are next updated.

Here's what I'm doing to instantiate the map (additional commented-out OpenLayers.Bounds declarations show some of my thought processes and frustrations):

var map; //The map
var day, night; //The layers, one for a "day" map and one for a "night" map

function init(){
    map = new OpenLayers.Map('map', {
        tileSize: new OpenLayers.Size(256,256), //All my tiles are 256x256
        //I've tried to many different bounds...
        maxExtent: new OpenLayers.Bounds(0,0,16384,10240), //Size of my map at zoom level 5
        //maxExtent: new OpenLayers.Bounds(0,0,512,512),
        //maxExtent: new OpenLayers.Bounds(0,0,8138,5034), //Size of the raw .png image
        //maxExtent: new OpenLayers.Bounds(0,0,8192,8192), //Size of the raw .png image, rounded up to a multiple of 256
        //maxExtent: new OpenLayers.Bounds(0,0,3000,2500),
        maxResolution: 16, //Anything else seems to be even worse -- what's so magical about 16?
        numZoomLevels:6, //Cuz that's how many tile sets mcmap generates
        units: "pixels", //Not listed in the docs, but found on another site -- legit?
        projection: "", //Not listed in the docs, but found on another site -- legit?
        eventListeners: {
            "zoomend": mapEvent,
            "moveend": mapEvent
        }
    });

    //Add the "day" layer
    day = new OpenLayers.Layer.XYZ("Day", "./tiles/x${x}y${y}z${z}.png");
    map.addLayer(day);
    //"Night" layer omitted for brevity

    map.zoomToMaxExtent();
}

This displays my 2×2 grid of tiles at zoom level 0 fine, but in the corner of a larger 4×3 grid — and I can't figure out why! (As of the time of this writing, a live demo of what I'm getting can be found here.)

I believe my problem is with the maxExtent and/or maxResolution options; frankly, I can't make heads or tails of how either of these values actually relate to the tiles I have, especially since "16" seems to be the magic number for the latter, for no reason I can see!

How do I go from a simple set of tiles that I want arranged on an XYZ grid, to a functional OpenLayers map, without OpenLayers requesting extraneous bogus tiles outside the confines of my tile set? Merely having the right values for this particular tile set is insufficient — my tile set will change over time as more of my server's map is explored and revealed, so I need to be able to determine the appropriate values/settings for any arbitrary tile set (well, with 6 zoom levels, at least).

Edit: Just to clarify, I know how to make the pink tiles "disappear", that's not the question — the question is how do I convince OpenLayers that those tiles are "out of bounds" and not even request them in the first place?

Best Answer

Kromey, try this:

  • All tiles in OpenLayers is by default 256x256, so you don't need to explicitly declare it.
  • The bounds you want is in pixels, because you are dealing with an image. So the image that was split up (your original .png at 8138x5034) needs to be a perfect multiple of 256x256. Your intuition about the size being rounded up is a good one, so use that. But also, you can set your bounds higher, but you might end up pulling in status codes of 404 when OpenLayers tries to pull in tiles that are beyond your map's size.
  • What you are missing is resolution: 16
  • The magical part about maxResolution: 16 is that the map knows about it's layer via tiling -- it has no spacial reference, so resolution helps determine how big your map will be. Why 16? I don't know. I do know that resolution and maxResolution is supposed to represent units/pixel.

So, how does the code below help you?

var map; //The map
var day, night; //The layers, one for a "day" map and one for a "night" map

function init(){
  map = new OpenLayers.Map('map', {
    maxExtent: new OpenLayers.Bounds(0,0,8192,8192), //Size of the raw .png image, rounded up to a multiple of 256
    maxResolution: 16,
    resolution: 16,
    numZoomLevels: 6,

    eventListeners: {
        "zoomend": mapEvent,
        "moveend": mapEvent
    }
  });

  //Add the "day" layer
  day = new OpenLayers.Layer.XYZ("Day", "./tiles/x${x}y${y}z${z}.png");
  map.addLayer(day);

  map.zoomToMaxExtent();
}

Cheers!