0

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
}

3 Answers 3

1

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.

0

lThanks for the help!

My final code:

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


const path = '/chunks/{x}.{y}.png?cash={time}'

const layer = L.tileLayer(path, {
    maxNativeZoom: 1, 
    minNativeZoom: 1,
    time: 0
}).addTo(map)

function VectorToString(vector) {
    return vector.x + "." + vector.y
}

class TileHandler {
    constructor(layer){
        this.layer = layer
        this.layers = {}

        this.layer.on('tileload', (tile) =>  {
            this.layers[VectorToString(tile.coords)] = tile
        })
         
        
        this.layer.on('tileunload', (tile) => {
            delete this.layers[VectorToString(tile.coords)]
        })
    }

    update(position){
        const tile = this.layers[VectorToString(position)]
        const url = L.Util.template(tile.target._url, {
            ...position,
            time: new Date().getTime()
        })
        if (!tile) return
        tile.tile.src = url
    }
}
0

Without using the Leaflet library tooling, we could force the browser to reload all visible tiles from the server, by fetching again their URL.

document.querySelectorAll(".leaflet-tile-container img").forEach(e => {
  fetch(e.src)
    .then(b => {
      return b.blob()
    })
    .then(b => {
      e.src = URL.createObjectURL(b)
    })
})

Not the answer you're looking for? Browse other questions tagged or ask your own question.