nakarte

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

coverage-layer.js (5403B)


      1 import L from 'leaflet';
      2 import {TiledDataLoader} from '~/lib/tiled-data-loader';
      3 
      4 const MultiLayer = L.Layer.extend({
      5     initialize: function(layers) {
      6         this.layers = layers;
      7     },
      8 
      9     setLayersVisibility: function(e) {
     10         if (!this._map) {
     11             return;
     12         }
     13 
     14         let newZoom;
     15         if (e && e.zoom !== undefined) {
     16             newZoom = e.zoom;
     17         } else {
     18             newZoom = this._map.getZoom();
     19         }
     20 
     21         for (let layer of this.layers) {
     22             if (layer.minZoom <= newZoom && newZoom <= layer.maxZoom) {
     23                 this._map.addLayer(layer.layer);
     24             } else {
     25                 this._map.removeLayer(layer.layer);
     26             }
     27         }
     28     },
     29 
     30     onAdd: function(map) {
     31         this._map = map;
     32         this.setLayersVisibility();
     33         map.on('zoomend', this.setLayersVisibility, this);
     34     },
     35 
     36     onRemove: function() {
     37         for (let layer of this.layers) {
     38             this._map.removeLayer(layer.layer);
     39         }
     40         this._map.off('zoomend', this.setLayersVisibility, this);
     41         this._map.off('zoomanim', this.setLayersVisibility, this);
     42         this._map = null;
     43     }
     44 
     45 });
     46 
     47 class WikimediaLoader extends TiledDataLoader {
     48     constructor(urlTemplate, zoom) {
     49         super();
     50         this.url = urlTemplate;
     51         this.maxZoom = zoom;
     52     }
     53 
     54     getTileUrl(coords) {
     55         const data = {
     56             x: coords.x,
     57             z: coords.z,
     58             y: 2 ** coords.z - 1 - coords.y
     59         };
     60         return L.Util.template(this.url, data);
     61     }
     62 
     63     layerTileToDataTileCoords(layerTileCoords) {
     64         let z = layerTileCoords.z;
     65         let z2 = null;
     66         if (z > this.maxZoom) {
     67             z2 = this.maxZoom;
     68         } else {
     69             return {z, x: layerTileCoords.x, y: layerTileCoords.y};
     70         }
     71 
     72         let multiplier = 1 << (z - z2);
     73         return {
     74             x: Math.floor(layerTileCoords.x / multiplier),
     75             y: Math.floor(layerTileCoords.y / multiplier),
     76             z: z2
     77         };
     78     }
     79 
     80     makeRequestData(dataTileCoords) {
     81         return {
     82             url: this.getTileUrl(dataTileCoords),
     83             options: {
     84                 responseType: 'arraybuffer',
     85                 timeout: 10000,
     86                 isResponseSuccess: (xhr) => xhr.status === 200 || xhr.status === 404
     87             }
     88         };
     89     }
     90 
     91     async processResponse(xhr, originalDataTileCoords) {
     92         let tileData;
     93         if (originalDataTileCoords.z >= this.maxZoom && xhr.status === 200 && xhr.response) {
     94             tileData = new Uint16Array(xhr.response);
     95         } else {
     96             tileData = null;
     97         }
     98 
     99         return {
    100             tileData,
    101             coords: originalDataTileCoords
    102         };
    103     }
    104 }
    105 
    106 const WikimediaVectorCoverage = L.GridLayer.extend({
    107         options: {
    108             tileSize: 256,
    109             color: '#ff00ff',
    110         },
    111 
    112         initialize: function(url, options) {
    113             L.GridLayer.prototype.initialize.call(this, options);
    114             this.loader = new WikimediaLoader(url, 11);
    115         },
    116 
    117         onAdd: function(map) {
    118             L.GridLayer.prototype.onAdd.call(this, map);
    119             this.on('tileunload', this.onTileUnload, this);
    120         },
    121 
    122         onRemove: function(map) {
    123             L.GridLayer.prototype.onRemove.call(this, map);
    124             this.off('tileunload', this.onTileUnload, this);
    125         },
    126 
    127         onTileUnload: function(e) {
    128             const tile = e.tile;
    129             tile._abortLoading();
    130             delete tile._tileData;
    131             delete tile._adjustment;
    132         },
    133 
    134         drawTile: function(canvas, _unused_coords) {
    135             if (!this._map) {
    136                 return;
    137             }
    138             if (!canvas._tileData) {
    139                 return;
    140             }
    141             const dataOffset = 5000;
    142             const dataExtent = 65535 - 2 * dataOffset;
    143             const tileData = canvas._tileData;
    144             let {multiplier, offsetX, offsetY} = canvas._adjustment;
    145             const canvasCtx = canvas.getContext('2d');
    146             const pixelScale = multiplier * 256 / dataExtent;
    147             canvasCtx.fillStyle = this.options.color;
    148             for (let i = 0, l = tileData.length; i < l; i += 2) {
    149                 let x = (tileData[i] - dataOffset) * pixelScale - offsetX * 256;
    150                 let y = (tileData[i + 1] - dataOffset) * pixelScale - offsetY * 256;
    151                 canvasCtx.beginPath();
    152                 canvasCtx.arc(x, y, 5, 0, 2 * Math.PI);
    153                 canvasCtx.fill();
    154             }
    155         },
    156 
    157         createTile: function(coords, done) {
    158             const canvas = L.DomUtil.create('canvas', 'leaflet-tile');
    159             canvas.width = this.options.tileSize;
    160             canvas.height = this.options.tileSize;
    161             let {dataPromise, abortLoading} = this.loader.requestTileData(coords);
    162             dataPromise.then((data) => {
    163                 if (!data.error) {
    164                     canvas._tileData = data.tileData;
    165                     canvas._adjustment = data.adjustment || {multiplier: 1, offsetX: 0, offsetY: 0};
    166                     setTimeout(() => {
    167                         this.drawTile(canvas, coords);
    168                         done(null, canvas);
    169                     }, 1);
    170                 }
    171             });
    172 
    173             canvas._abortLoading = abortLoading;
    174             return canvas;
    175         },
    176     }
    177 );
    178 
    179 export {MultiLayer, WikimediaVectorCoverage};