I am building an openlayers app which allows user to use offline tile images stored in IndexedDB as blobs:
export async function getOfflineTileURL(coordinates) {
// input: coordinates[zoom, column, tile]
let row = await db.tiles.get({
zoom: coordinates[0],
column: coordinates[1],
tile: coordinates[2]
})
if (row) {
// if tile image exists in database, return its URL
return URL.createObjectURL(row.blob)
} else {
return
// TODO: return URL to online source as backup
}
}
db
is Dexie.org database (wrapper for IndexedDB).
I want to use tileUrlFunction
to return URL for the requested tile:
new TileLayer({
source: new XYZ({
tileUrlFunction: async(tileCoord) => {
return await getOfflineTileURL(tileCoord)
}
})
})
I cannot use url
property in XYZ source because I cannot control output of URL.createObjectURL
, it's just random string (ex. blob:http://localhost:5173/a0cdebd5-df03-4134-9e93-b4d8ad888d6d
And I cannot use titleURLFunction, because my code has to be async (Dexie and IndexedDB are asynchronous) and openlayers function only works synchronously (titleURLFunction from the code above returns http://localhost:5173/[object%20Promise]
)
Is there a way I can make it work?
It can be done via the tileLoadFunction
, which is asynchronous
tileLoadFunction: async function (tile, src) {
const coordinates = tile.getTileCoord();
let row = await db.tiles.get({
zoom: coordinates[0],
column: coordinates[1],
tile: coordinates[2]
})
const image = tile.getImage();
if (row) {
// if tile image exists in database, return its URL
const result = URL.createObjectURL(row.blob);
image.addEventListener('load', function() {
URL.revokeObjectURL(result);
});
image.src = result;
} else {
image.src = src;
}
}