Shreya Pandita
Shreya Pandita

Reputation: 144

In Leaflet, how to load tiles only when clicking on each?

I have a leaflet map consisting of a satellite image with lat-long metadata. My objective is to display a rectangle highlighting the selected tile on mouseclick and fetch the corresponding tile. The L.rectangle method needs bounds to display the rectangle. In order to calculate the SE and NW corners, I use the following function that I found at https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_numbers_to_lon..2Flat.

This is for SE and the same function is changed for getting NW as seen in the above link. These are used as bounds for the rectangle.

//I have a fixed zoom level for my problem :4

function(xtile,ytile,zoom) //here i am giving the tile location coordinates as the input
{ 
n=2.0**zoom;
lon= (xtile+1)/n*360-180;
lat_rad=Math.atan(Math.Sinh(Math.PI*(1-2*(ytile+1)/n)));
lat=lat_rad(180/Math.PI);
return[-lat,lon] 
}

The output comes out to be as follows:

NW -782.67,-112.4
SE -79.163,-89.9
with(suppose) xtile=5 and ytile=14

The actual output however should have been:

NW -66.51,-45
SE -74.01,-22.5
and the corresponding(again,suppose) xtile=5 and ytile=1 

So basically, for some tiles , the rectangle shows just fine. But for others, it jumps to some other tile. I have a display window for the selected tileand when the rectangle jumps, neither the selected tile nor the highlighted tile is fetched. I will be really thankful is someone can help me with this.

Upvotes: 1

Views: 622

Answers (1)

IvanSanchez
IvanSanchez

Reputation: 19069

My objective is to display a rectangle highlighting the selected tile on mouseclick and fetch the corresponding tile.

Then a good approach to the root problem is to use a custom L.GridLayer, since it provides functionality to create empty tiles, attach events to them and handle tile coordinates without the need to handle bounding boxes explicitly.

It would go like this:

L.GridLayer.ClickyLoad = L.GridLayer.extend({

  // By default, the container for a whole zoom level worth of visible tiles
  // has a "pointer-events: none" CSS property. Override this whenever a new
  // level container is created. This is needed for pointer (mouse) interaction.
  _onCreateLevel: function(level) {
    level.el.style.pointerEvents = 'inherit';
  },

  // The tiles shall be empty <div>s with some DOM events attached.
  createTile: function(coords){

        var tile = L.DomUtil.create('div');

    tile.style.border = '1px solid black';

    // Highlighting the tile on mouse hover is just swag.    
    L.DomEvent.on(tile, 'mouseover', function(){
      tile.style.border = '2px solid red';
    });
    L.DomEvent.on(tile, 'mouseout', function(){
      tile.style.border = '1px solid black';
    });

    // When a tile is clicked, calculate the URL of the tile (using the same 
    // logic as L.TileLayer.getTileUrl() ), create a <img> element, and put
    // the newly created image inside the empty <div> tile.
    L.DomEvent.on(tile, 'click', function(){
      var img = L.DomUtil.create('img');
      img.src = L.Util.template('https://tile.openstreetmap.org/{z}/{x}/{y}.png', coords);
      tile.appendChild(img);
    });

    return tile;
  }
});

// Create instance and add to map
(new L.GridLayer.ClickyLoad()).addTo(map);

See a fully working example here.

As usual with this kind of non-trivial-looking examples, reading through the Leaflet documentation, the tutorial about extending classes, and the Leaflet source code itself is recommended.

Upvotes: 2

Related Questions