nakarte

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

index.js (8668B)


      1 import L from 'leaflet';
      2 import {WikimapiaLoader} from './wikimapia-loader';
      3 import './style.css';
      4 import {openPopupWindow} from '~/lib/popup-window';
      5 
      6 function isPointInPolygon(polygon, p) {
      7     var inside = false;
      8     var prevNode = polygon[polygon.length - 1],
      9         node, i;
     10     for (i = 0; i < polygon.length; i++) {
     11         node = polygon[i];
     12         if (
     13             ((node[0] <= p[0] && p[0] < prevNode[0]) || (prevNode[0] <= p[0] && p[0] < node[0])) &&
     14             p[1] < (prevNode[1] - node[1]) * (p[0] - node[0]) / (prevNode[0] - node[0]) + node[1]
     15         ) {
     16             inside = !inside;
     17         }
     18         prevNode = node;
     19     }
     20     return inside;
     21 }
     22 
     23 L.Wikimapia = L.GridLayer.extend({
     24         options: {
     25             tileSize: 1024,
     26             updateWhenIdle: true,
     27             tilesBaseUrl: 'http://wikimapia.org/',
     28         },
     29 
     30         initialize: function(options) {
     31             L.GridLayer.prototype.initialize.call(this, options);
     32             this.loader = null;
     33         },
     34 
     35         onAdd: function(map) {
     36             if (!this.loader) {
     37                 this.loader = new WikimapiaLoader(this.options.tilesBaseUrl, map);
     38             }
     39             L.GridLayer.prototype.onAdd.call(this, map);
     40             this.on('tileunload', this.onTileUnload, this);
     41             this.on('tileload', this.onTileLoad, this);
     42             map.on('mousemove', this.onMouseMove, this);
     43             map.on('click', this.onClick, this);
     44             map.on('zoomend', this.onZoomEnd, this);
     45             map.on('zoomstart', this.onZoomStart, this);
     46         },
     47 
     48         onRemove: function(map) {
     49             map.off('mousemove', this.onMouseMove, this);
     50             map.off('click', this.onClick, this);
     51             if (this.highlightedPlace) {
     52                 this._map.removeLayer(this.highlightedPlace.polygon);
     53                 this._map.removeLayer(this.highlightedPlace.label);
     54                 this.highlightedPlace = null;
     55             }
     56             L.TileLayer.prototype.onRemove.call(this, map);
     57             this.off('tileunload', this.onTileUnload, this);
     58             this.off('tileload', this.onTileLoad, this);
     59             map.off('zoomend', this.onZoomEnd, this);
     60             map.off('zoomstart', this.onZoomStart, this);
     61         },
     62 
     63         drawTile: function(canvas) {
     64             if (!this._map) {
     65                 return;
     66             }
     67             const
     68                 tileData = canvas._tileData,
     69                 adjustment = canvas._adjustment;
     70             if (!tileData) {
     71                 return;
     72             }
     73 
     74             const canvasCtx = canvas.getContext('2d');
     75             canvasCtx.beginPath();
     76             canvasCtx.strokeStyle = '#CFA600';
     77             canvasCtx.lineWidth = 1;
     78             for (let place of tileData.places) {
     79                 let polygon = place.localPolygon;
     80                 if (!polygon) {
     81                     continue;
     82                 }
     83                 if (adjustment) {
     84                     let {multiplier, offsetX, offsetY} = adjustment,
     85                         polygon2 = [];
     86                     for (let i = 0; i < polygon.length; i++) {
     87                         let p = polygon[i];
     88                         polygon2.push({
     89                                 x: p.x * multiplier - offsetX,
     90                                 y: p.y * multiplier - offsetY
     91                             }
     92                         );
     93                     }
     94                     polygon = polygon2;
     95                 }
     96                 canvasCtx.moveTo(polygon[0].x, polygon[0].y);
     97                 let p;
     98                 for (let i = 1; i < polygon.length; i++) {
     99                     p = polygon[i];
    100                     canvasCtx.lineTo(p.x, p.y);
    101                 }
    102                 canvasCtx.lineTo(polygon[0].x, polygon[0].y);
    103             }
    104             canvasCtx.stroke();
    105         },
    106 
    107         createTile: function(coords, done) {
    108             const canvas = L.DomUtil.create('canvas', 'leaflet-tile');
    109             canvas.width = this.options.tileSize;
    110             canvas.height = this.options.tileSize;
    111             let {dataPromise, abortLoading} = this.loader.requestTileData(coords);
    112             dataPromise.then((data) => {
    113                 if (!data.error) {
    114                     canvas._tileData = data.tileData;
    115                     canvas._adjustment = data.adjustment;
    116                     this.drawTile(canvas);
    117                     this._tileOnLoad(done, canvas);
    118                 }
    119             });
    120 
    121             canvas._abortLoading = abortLoading;
    122             return canvas;
    123         },
    124 
    125         _tileOnLoad: function(done, tile) {
    126             // For https://github.com/Leaflet/Leaflet/issues/3332
    127             if (L.Browser.ielt9) {
    128                 setTimeout(L.bind(done, this, null, tile), 0);
    129             } else {
    130                 done(null, tile);
    131             }
    132         },
    133 
    134         onTileUnload: function(e) {
    135             const tile = e.tile;
    136             tile._abortLoading();
    137             delete tile._tileData;
    138             delete tile._adjustment;
    139         },
    140 
    141         onTileLoad: function() {
    142             if (!this.lastMousePos) {
    143                 return;
    144             }
    145             if (this.mapZooming) {
    146                 return;
    147             }
    148             this.updateHighlight();
    149         },
    150 
    151         _tileCoordsFromLatlng: function(latlng) {
    152             let layerPoint = this._map.latLngToLayerPoint(latlng);
    153             layerPoint = layerPoint.add(this._map.getPixelOrigin());
    154             const tileSize = this.options.tileSize;
    155             let coords = {
    156                 x: Math.floor(layerPoint.x / tileSize),
    157                 y: Math.floor(layerPoint.y / tileSize),
    158                 z: this._map.getZoom()
    159             };
    160 
    161             return coords;
    162         },
    163 
    164         getPlaceAtLatlng: function(latlng) {
    165             latlng = latlng.wrap();
    166             const tileCoords = this._tileCoordsFromLatlng(latlng);
    167             let tile = this._tiles[this._tileCoordsToKey(tileCoords)];
    168             if (!tile) {
    169                 return null;
    170             }
    171             const tileData = tile.el._tileData;
    172             if (!tileData) {
    173                 return null;
    174             }
    175 
    176             const places = tileData.places;
    177             const {lat, lng} = latlng;
    178             let bounds, place;
    179             for (let i = places.length - 1; i >= 0; i--) {
    180                 place = places[i];
    181                 bounds = place.boundsWESN;
    182                 if (lng >= bounds[0] && lng <= bounds[1] && lat >= bounds[2] && lat <= bounds[3] &&
    183                     isPointInPolygon(place.polygon, [lat, lng])) {
    184                     return place;
    185                 }
    186             }
    187             return null;
    188         },
    189 
    190         onMouseMove: function(e) {
    191             this.lastMousePos = e.latlng;
    192             this.updateHighlight();
    193         },
    194 
    195         onZoomEnd: function() {
    196             this.mapZooming = false;
    197             this.updateHighlight();
    198         },
    199         onZoomStart: function() {
    200             this.mapZooming = true;
    201         },
    202 
    203         updateHighlight: function() {
    204             if (!this.lastMousePos) {
    205                 return;
    206             }
    207             const place = this.getPlaceAtLatlng(this.lastMousePos);
    208             if (this.highlightedPlace && (!place || this.highlightedPlace.id !== place.id)) {
    209                 this._map.removeLayer(this.highlightedPlace.polygon);
    210                 this._map.removeLayer(this.highlightedPlace.label);
    211                 this.highlightedPlace = null;
    212             }
    213 
    214             if (place && !this.highlightedPlace) {
    215                 this.highlightedPlace = {
    216                     id: place.id,
    217                     polygon: L.polygon(place.polygon, {
    218                             weight: 0,
    219                             color: '#E6B800'
    220                         }
    221                     ),
    222                     label: L.tooltip({className: 'wikimapia-tooltip-wrapper'}, null)
    223                 };
    224                 this.highlightedPlace.label.setLatLng(this.lastMousePos);
    225                 this.highlightedPlace.polygon.addTo(this._map).bringToBack();
    226                 this.highlightedPlace.label.setContent(`<div class="wikimapia-tooltip">${place.title}</div>`);
    227                 this._map.addLayer(this.highlightedPlace.label);
    228             }
    229             if (this.highlightedPlace) {
    230                 this.highlightedPlace.label.setLatLng(this.lastMousePos);
    231             }
    232         },
    233 
    234         onClick: function(e) {
    235             if (this._map.clickLocked) {
    236                 return;
    237             }
    238             const place = this.getPlaceAtLatlng(e.latlng);
    239             if (place) {
    240                 const url = `http://wikimapia.org/${place.id}/ru/`;
    241                 openPopupWindow(url, 564, 'wikimapia-details');
    242             }
    243         },
    244     }
    245 );