Reputation: 144
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
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