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:
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};