nakarte

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

index.js (4276B)


      1 import {Cache} from '~/lib/cache';
      2 import {XHRQueue} from '~/lib/xhr-promise';
      3 
      4 class TiledDataLoader {
      5     constructor(cacheSize = 50) {
      6         this._cache = new Cache(cacheSize);
      7         this._pendingRequests = {};
      8         this._xhrQueue = new XHRQueue();
      9     }
     10 
     11     makeTileKey(coords) {
     12         return `${coords.x}:${coords.y}:${coords.z}`;
     13     }
     14 
     15     getFromCache(dataTileCoords) {
     16         const key = this.makeTileKey(dataTileCoords);
     17         const res = this._cache.get(key);
     18         res['coords'] = dataTileCoords;
     19         return res;
     20     }
     21 
     22     layerTileToDataTileCoords(layerTileCoords) {
     23         return {...layerTileCoords};
     24     }
     25 
     26     makeRequestData(_unused_dataTileCoords) {
     27         throw new Error('Not implemented');
     28         // return {
     29         //     url,
     30         //     options
     31         // }
     32     }
     33 
     34     processResponse(_unused_xhr, _unused_originalDataTileCoords) {
     35         throw new Error('Not implemented');
     36         // return {
     37         //     tileData,
     38         //     coords
     39         // }
     40     }
     41 
     42     calcAdjustment(layerTileCoords, dataTileCoords) {
     43         if (layerTileCoords.x === dataTileCoords.x &&
     44             layerTileCoords.y === dataTileCoords.y &&
     45             layerTileCoords.z === dataTileCoords.z) {
     46             return null;
     47         }
     48         if (dataTileCoords.z > layerTileCoords.z) {
     49             const multiplier = 1 << (dataTileCoords.z - layerTileCoords.z);
     50             return {multiplier: 1 / multiplier, offsetX: 0, offsetY: 0};
     51         }
     52         const multiplier = 1 << (layerTileCoords.z - dataTileCoords.z);
     53         return {
     54             multiplier,
     55             offsetX: (layerTileCoords.x - dataTileCoords.x * multiplier),
     56             offsetY: (layerTileCoords.y - dataTileCoords.y * multiplier)
     57         };
     58     }
     59 
     60     requestTileData(layerTileCoords) {
     61         const dataTileCoords = this.layerTileToDataTileCoords(layerTileCoords);
     62         let res = this.getFromCache(dataTileCoords);
     63         if (res.found) {
     64             return {
     65                 dataPromise: Promise.resolve({
     66                         coords: res.coords,
     67                         tileData: res.value,
     68                         adjustment: this.calcAdjustment(layerTileCoords, res.coords)
     69                     }
     70                 ),
     71                 abortLoading: () => {
     72                     // no need to abort Promise which is resolved immediately
     73                 }
     74             };
     75         }
     76 
     77         const dataTileKey = this.makeTileKey(dataTileCoords);
     78         if (!(dataTileKey in this._pendingRequests)) {
     79             const {url, options} = this.makeRequestData(dataTileCoords);
     80             const fetchPromise = this._xhrQueue.put(url, options);
     81             const dataPromise = (async() => {
     82                 let xhr;
     83                 try {
     84                     xhr = await fetchPromise;
     85                 } catch (e) {
     86                     return {error: e};
     87                 } finally {
     88                     delete this._pendingRequests[dataTileKey];
     89                 }
     90                 const {tileData, coords} = await this.processResponse(xhr, dataTileCoords);
     91                 this._cache.put(this.makeTileKey(coords), tileData);
     92                 return {tileData, coords};
     93             })();
     94             const pendingRequest = this._pendingRequests[dataTileKey] = {
     95                 dataPromise,
     96                 refCount: 0
     97             };
     98             pendingRequest.abortLoading = () => {
     99                 pendingRequest.refCount -= 1;
    100                 if (pendingRequest.refCount < 1) {
    101                     fetchPromise.abort();
    102                     delete this._pendingRequests[dataTileKey];
    103                 }
    104             };
    105         }
    106 
    107         let pendingRequest = this._pendingRequests[dataTileKey];
    108         pendingRequest.refCount += 1;
    109 
    110         return {
    111             dataPromise: pendingRequest.dataPromise.then((data) => {
    112                     if (data.error) {
    113                         return data;
    114                     }
    115                     return {
    116                         coords: data.coords,
    117                         tileData: data.tileData,
    118                         adjustment: this.calcAdjustment(layerTileCoords, data.coords)
    119                     };
    120             }),
    121             abortLoading: () => pendingRequest.abortLoading()
    122         };
    123     }
    124 }
    125 
    126 export {TiledDataLoader};