nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

commit 4c23ac75a8e4e6f485cea5848afc06fab5bd4bca
parent 6abd1a0478a1d3a17412dd2c5af50ab3897f1048
Author: Sergej Orlov <wladimirych@gmail.com>
Date:   Fri, 27 Jan 2017 01:38:42 +0300

new module: data loader for tiled vector data

Diffstat:
Asrc/lib/tiled-data-loader/index.js | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 122 insertions(+), 0 deletions(-)

diff --git a/src/lib/tiled-data-loader/index.js b/src/lib/tiled-data-loader/index.js @@ -0,0 +1,122 @@ +import {Cache} from 'lib/cache'; +import {XHRQueue} from 'lib/xhr-promise'; + + +class TiledDataLoader { + constructor(cacheSize = 50) { + this._cache = new Cache(cacheSize); + this._pendingRequests = {}; + this._xhrQueue = new XHRQueue(); + } + + makeTileKey(coords) { + return `${coords.x}:${coords.y}:${coords.z}`; + } + + getFromCache(dataTileCoords) { + const key = this.makeTileKey(dataTileCoords); + const res = this._cache.get(key); + res['coords'] = dataTileCoords; + return res; + } + + layerTileToDataTileCoords(layerTileCoords) { + return Object.assign({}, layerTileCoords); + } + + makeRequestData(dataTileCoords) { + throw new Error('Not implemented'); + // return { + // url, + // options + // } + } + + processResponse(xhr, originalDataTileCoords) { + throw new Error('Not implemented'); + // return { + // tileData, + // coords + // } + } + + calcAdjustment(layerTileCoords, dataTileCoords) { + if (layerTileCoords.x == dataTileCoords.x && + layerTileCoords.y == dataTileCoords.y && + layerTileCoords.z == dataTileCoords.z) { + return null; + } + if (dataTileCoords.z > layerTileCoords.z) { + throw new Error('Data tile zoom > map tile zoom'); + } + const multiplier = 1 << (layerTileCoords.z - dataTileCoords.z); + return { + multiplier, + offsetX: (layerTileCoords.x - dataTileCoords.x * multiplier), + offsetY: (layerTileCoords.y - dataTileCoords.y * multiplier) + } + } + + requestTileData(layerTileCoords) { + const dataTileCoords = this.layerTileToDataTileCoords(layerTileCoords); + let res = this.getFromCache(dataTileCoords); + if (res.found) { + return { + dataPromise: Promise.resolve({ + coords: res.coords, + tileData: res.value, + adjustment: this.calcAdjustment(layerTileCoords, res.coords) + } + ), + abortLoading: () => { + } + } + } + + const dataTileKey = this.makeTileKey(dataTileCoords); + if (!(dataTileKey in this._pendingRequests)) { + const {url, options} = this.makeRequestData(dataTileCoords); + const fetchPromise = this._xhrQueue.put(url, options); + // TODO: handle errors + const dataPromise = fetchPromise.then((xhr) => { + const {tileData, coords} = this.processResponse(xhr, dataTileCoords); + this._cache.put(this.makeTileKey(coords), tileData); + delete this._pendingRequests[dataTileKey]; + return { + tileData, + coords + }; + } + ); + const pendingRequest = this._pendingRequests[dataTileKey] = { + dataPromise, + refCount: 0 + }; + pendingRequest.abortLoading = function() { + pendingRequest.refCount -= 1; + if (pendingRequest.refCount < 1) { + fetchPromise.abort(); + delete this._pendingRequests[dataTileKey]; + } + }; + } + + let pendingRequest = this._pendingRequests[dataTileKey]; + pendingRequest.refCount += 1; + + + return { + dataPromise: pendingRequest.dataPromise.then((data) => { + return { + coords: data.coords, + tileData: data.tileData, + adjustment: this.calcAdjustment(layerTileCoords, data.coords) + }; + }), + abortLoading: () => pendingRequest.abortLoading + } + + } +} + +export {TiledDataLoader};