Search code examples
javascriptleaflet

Update/Reload specific tile in leaflet dynamicly


If my server tells the clients when and what tile to reload/update, how can reload/update the tile sent from the server? I'm using the L.CRS.Simple CRS. And I have no zoom levels on a custom game map.

Here is my code:

var map = L.map('map', {
    crs: L.CRS.Simple,
    attributionControl: false
}).setView([0, 0], 2)

L.tileLayer('/chunks/{x}.{y}.png', {
 maxNativeZoom: 1, 
 minNativeZoom: 1,
}).addTo(map)


function ReloadTile(x,y){
   // UPDATE TILE HERE Request for example /chunks/{1}.{1}.png depending on input
}

Solution

  • First, listen to the tileload and tileunload events of the L.TileLayer to grab references to tiles as they load (and free those references as they unload), e.g.

    let myTileLayer = L.tileLayer(...);
    
    let tileRefs = {};
    
    myTileLayer.on('tileload', function(ev) {
       tileRefs[ ev.coords.x + ',' + ev.coords.y ] = ev.tile;
    });
    myTileLayer.on('tileunload', function(ev) {
       delete tileRefs[ ev.coords.x + ',' + ev.coords.y ];
    });
    

    ...so whenever you want to update a tile, you just have to search for it in the data structure.

    Remember that in order to reload a HTMLImageElement, you've got to change its src property, e.g.:

    function ReloadTile(x,y){
       const tile = tileRefs[x + ',' + y];
       if (!tile) {
          // Tile is not currently loaded on the screen
          return;
       }
       tile.src = "/chunks/{1}.{1}.png";
    }
    

    Beware of requesting a URL that your browser has cached. Do your homework regarding cache busting and relevant HTTP headers.

    Note that I'm using a javascript Object as key-value data structure, and string concatenation to build up a unique key per tile. You're free to use other data structures (such a Map) and any other method to index the tiles (such as a double-depth data structure for x-y, or triple-depth for x-y-z, or indexing by tile URL). Also note that the sample code is usign only the X and Y coordinates of the tile since your TileLayer seems to have only one zoom level.