typescriptopenlayers-5mbtiles

Openlayers 5 serve local MBTiles


I'm trying to serve tiles from a local .mbtiles in an Ionic 4 project.

Step by step I managed to download the mbtiles and to create successfully the source using XYZ

new XYZ({
  tileLoadFunction: (tile: ImageTile, url) => {
    //stuff
  },
  tileUrlFunction: (c) => {
    return c[0] + '/' + c[1] + '/' + c[2];
  },
  projection: 'EPSG:3857'
});

Basically, if I add the following line to //stuff it works (I took as an example a basic base64 string that represents a green square)

tile.getImage().setAttribute('src', 'base 64 string here');

But when I tried to retrieve the tile from the mbtiles using SQLite it stopped working. I tried various combinations of code but none worked as expected.

I could notice that it's because the tileLoadFunction doesn't wait for the asynchronous call to the SQLite database and render the image when is still empty. If for example, I use this code with the getTile function returning a Promise, it does not work.

getTile(tile.getTileCoord()).then((base64) => {
  tile.getImage().setAttribute('src', base64);
})

The fact is that it enters in the then and executes the local code and the base64 string that I get I know is correct. Apparently OpenLayers is rendering the tile before the getTile is resolved.

I also found out that the tileloaderror event is dispatched for every tile, but I don't know how I could use it as an advantage.


Solution

  • This is the solution I found to make it work.

    Apparently the problem was not the call to a async function but the call to the getTileCoord function that I was doing to pass the correct parameter to the async function. I do not know why this happened but removing that call and changing it calculating the coordinates from the url parameter of the tileLoadFunction solved the problem.

    The resulting code looks like this

    new XYZ({
      tileLoadFunction: (tile: any, url) => {
        let coords: [number, number, number] = [0, 0, 0];
        let tmp: string[] = url.split('/');
        for (let i in tmp) {
          coords[i] = parseInt(tmp[i]);
        }
        coords[2] = -coords[2]; // the y coordinates is negative
        this.storageService.getTile(coords).then(function (tileBase64: string) {
          tile.getImage().src = tileBase64;
        });
      },
      tileUrlFunction: (c) => {
        return c[0] + '/' + c[1] + '/' + c[2];
      },
      projection: 'EPSG:3857'
    });