Skip to content

Instantly share code, notes, and snippets.

@patrykkalinowski
Created August 29, 2023 08:57
Show Gist options
  • Save patrykkalinowski/45b610532b2710d91f2e39145c0469bf to your computer and use it in GitHub Desktop.
Save patrykkalinowski/45b610532b2710d91f2e39145c0469bf to your computer and use it in GitHub Desktop.
Code to save slippy map tiles to indexedDB as blobs. Uses Dexie
function lon2tile(lon,zoom) {
return (Math.floor((lon+180)/360*Math.pow(2,zoom)))
}
function lat2tile(lat,zoom) {
return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom)))
}
async function downloadTile(zoom, column, tile) {
let row = await db.tiles.get({
zoom: zoom,
column: column,
tile: tile
})
if (row) {
return
}
let root_url = "https://a.tile.openstreetmap.org/"
// TODO: select random subdomain between a, b and c
let url = `${root_url}${zoom}/${column}/${tile}.png`
let response = await fetch(url);
return await response.blob()
}
async function saveTile(zoom, column, tile, blob) {
if (blob) {
// add tile only if image blob is in argument
await db.tiles.add({
zoom: zoom,
column: column,
tile: tile,
blob: blob
})
}
// TODO: update progress
}
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
}
}
export async function calculateTiles(zoom, north_edge, west_edge, south_edge, east_edge) {
var top_tile = lat2tile(north_edge, zoom); // eg.lat2tile(34.422, 9);
var left_tile = lon2tile(west_edge, zoom);
var bottom_tile = lat2tile(south_edge, zoom);
var right_tile = lon2tile(east_edge, zoom);
var width = Math.abs(left_tile - right_tile) + 1;
var height = Math.abs(top_tile - bottom_tile) + 1;
let total_tiles = width * height; // -> eg. 377
for (let c = left_tile; c <= right_tile; c++) {
// for each column, get all tiles in this column
for (let t = top_tile; t <= bottom_tile; t++) {
// for each tile, print URL
// console.log(`/${zoom}/${c}/${t}.png`)
let image = await downloadTile(zoom, c, t)
await saveTile(zoom, c, t, image)
// debugging
// let tile_url = await getOfflineTileURL([zoom, c, t])
// if (tile_url) {
// console.log(tile_url)
// // map_store.update(map => {
// // map.offline_tile_url = tile_url
// // return map
// // });
// }
}
}
}
for (let zoom = 1; zoom <= 18; zoom++) {
calculateTiles(zoom, 50.1, 20, 50, 20.1)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment