Search code examples
javascriptleaflettile

Leaflet: misalignment of tiles and negative y coordinates


I am trying to generate a custom non-geographical map with Leaflet using my own tiles.

For the moment I created 10x10 dummy tiles of size 256x256px each with a random solid color using imagemagick. They are placed in public/map-tiles/1/map_x_y.png where x takes values from 0 to 9 (resp. y).

Since this is a non-geographical map, I paid attention to change crs to L.CRS.Simple (see http://leafletjs.com/examples/crs-simple/crs-simple.html):

var map = L.map('map', {
  minZoom: 1,
  maxZoom: 1,
  center: [0, 0],
  crs: L.CRS.Simple
}).setView([0, 0], 1);

L.tileLayer('/map-tiles/{z}/map_{x}_{y}.png', {
    bounds: [[0, 0], [2560, 2560]],
    tms: true
}).addTo(map);

However this produces tiles slightly shifted and thus misaligned:

misaligned tiles

Also, tiles with negative y coordinates are fetched, which results in 404d requests, as seen in the console.

What can be the cause of this behavior?

EDIT 1: as IvanSanchez pointed out, the misalignment was caused by the missing leaflet.css stylesheet.

I still have the problem with negative coordinates. As suggested, I added bounds (see updated code above). Observations:

  • with bounds [[0, 0], [2560, 2560]]: no tiles displayed altogether, blank screen.
  • with bounds [[-1280, -1280], [1280, 1280]]: all tiles displayed, but negative tiles fetched (eg (5,-1)) resulting in 404s.

EDIT 2: after several tests it looks like the negative tiles are indeed the product of the y-axis handling (http://leafletjs.com/examples/wms/wms.html). The origin is top left, y going downward. I expected the tiles below the origin to be fetched, not above.

What I tried in order to keep my convention with x and y both increasing (that is x increases to the right, y increases downward, tiles with positive coordinate components are fetched from 0 to 9):

  • setting tms: true for tileLayer. No success, tiles with negative y are still fetched .
  • changing {y} to {-y} in the tileLayer source path. Results in Error: No value provided for variable {-y}. My script is using Leaflet 1.3.1.

Solution

  • In a map with L.CRS.Simple, all TileLayers have infinite bounds by default.

    If you want a TileLayer to request tiles only in a given area, read the Leaflet API documentation, specifically a TileLayer option named bounds (inherited from GridLayer options). Let me quote:

    bounds
    type LatLngBounds
    default undefined
    If set, tiles will only be loaded inside the set LatLngBounds.

    You also mention:

    Weirdly enough, it tries to fetch tiles with negative coordinates [...]

    That's not weird, it's behaviour as designed. There is nothing inherently wrong (nor weird) with negative coordinates, and negative tile coordinates are valid and documented in some tile standards


    So if you have 10x10 tiles of 256px in size ranging from [0, 0] to [10, 10], you might want something like

    L.tileLayer('/map-tiles/map_{x}_{y}.png', {
      bounds: [[0, 0], [2560, 2560]]
    }).addTo(map);
    

    If the center of your data is the [0, 0] point and your tiles span from [-5, -5] to [5, 5] you might instead want something like

    L.tileLayer('/map-tiles/map_{x}_{y}.png', {
      bounds: [[-1280, -1280], [1280, 1280]]
    }).addTo(map);