UNPKG

jsfreemaplib

Version:

Miscellaneous JavaScript classes and functions for working with geodata, including working with Spherical Mercator projection and managing XYZ tiles, plus some general UI functions.

118 lines (103 loc) 3.88 kB
const GoogleProjection = require('./GoogleProjection'); const Tile = require('./Tile'); // changes for 0.3.0: // // - Removed tilesLoaded array and replaceed by indexedTiles object, // indexing each tile of data with the z/x/y index of the tile. // // - added getData() method to download (if necessary) and return the data // corresponding to the tile at a given position. // // - added overridable rawTileToStoredTile() method to allow something other // than the raw tiled data (e.g. a DEM object) to be stored class Tiler { constructor(url) { this.tile = new Tile(0, 0, 13); this.url = url; this.sphMerc = new GoogleProjection(); this.indexedTiles = { }; } setZoom(z) { this.tile.z = z; } lonLatToSphMerc(lon, lat) { return this.sphMerc.project(lon, lat); } getTile(sphMercPos, z) { return this.sphMerc.getTile(sphMercPos, z); } async update(pos) { const loadedData = []; let t; if( t = this.needNewData(pos)) { const tilesX = [t.x, t.x-1, t.x+1], tilesY = [t.y, t.y-1, t.y+1]; for(let ix=0; ix<tilesX.length; ix++) { for(let iy=0; iy<tilesY.length; iy++) { const thisTile = new Tile(tilesX[ix], tilesY[iy], t.z); const data = await this.loadTile(thisTile); if(data !== null) { loadedData.push({ data: data, tile: thisTile }); } } } } return loadedData; } getCurrentTiles() { const tiles = []; const tilesX = [this.tile.x, this.tile.x-1, this.tile.x+1], tilesY = [this.tile.y, this.tile.y-1, this.tile.y+1]; for(let ix=0; ix<tilesX.length; ix++) { for(let iy=0; iy<tilesY.length; iy++) { const data = this.indexedTiles[`${this.tile.z}/${tilesX[ix]}/${tilesY[iy]}`]; if(data !== null) { tiles.push({ data: data, tile: new Tile(ix, iy, this.tile.z) }); } } } return tiles; } needNewData(pos) { if(this.tile) { const newTile = this.sphMerc.getTile(pos, this.tile.z); const needUpdate = newTile.x != this.tile.x || newTile.y != this.tile.y; this.tile = newTile; return needUpdate ? newTile : false; } return false; } async loadTile(tile) { const tileIndex = `${tile.z}/${tile.x}/${tile.y}`; if(this.indexedTiles[tileIndex] === undefined) { const tData = await this.readTile(this.url .replace("{x}", tile.x) .replace("{y}", tile.y) .replace("{z}", tile.z) ); this.indexedTiles[tileIndex] = this._rawTileToStoredTile(tile, tData); // now add the data to indexedTiles return this.indexedTiles[tileIndex]; } return null; } async readTile(url) { return null; } // This method was unintentionally duplicated but will not remove until // 0.5.x to avoid breaking anything projectLonLat(lon, lat) { return this.lonLatToSphMerc(lon, lat); } // new for 0.3.0 // for a given sphmerc pos, downloads data if necessary and returns // the data at the tile corresponding to that position async getData (sphMercPos, z=13) { await this.update(sphMercPos); const thisTile = this.sphMerc.getTile(sphMercPos, z); return this.indexedTiles[`${z}/${thisTile.x}/${thisTile.y}`]; } // can be overridden if we want to store something other than the raw data // (for example DEM objects if we are dealing with DEM tiles) _rawTileToStoredTile(tile, data) { return data; } } module.exports = Tiler;