nakarte

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

index.js (3552B)


      1 import L from 'leaflet';
      2 
      3 import Contextmenu from '~/lib/contextmenu';
      4 import {ElevationProvider} from '~/lib/elevations';
      5 import {makeButton} from '~/lib/leaflet.control.commons';
      6 import * as logging from '~/lib/logging';
      7 
      8 import './style.css';
      9 
     10 class ExternalMap {
     11     constructor(urlTemplate, minZoom, maxZoom) {
     12         this.url = urlTemplate;
     13         this.minZoom = minZoom;
     14         this.maxZoom = maxZoom;
     15     }
     16 
     17     async getData(map_) {
     18         const {lat, lng} = map_.getCenter();
     19         let zoom = map_.getZoom();
     20         zoom = Math.min(this.maxZoom, zoom);
     21         zoom = Math.max(this.minZoom, zoom);
     22         return {lat, lng, zoom};
     23     }
     24 
     25     async getUrl(map_) {
     26         return L.Util.template(this.url, await this.getData(map_));
     27     }
     28 }
     29 
     30 class GoogleEarthMap extends ExternalMap {
     31     constructor() {
     32         super('https://earth.google.com/web/@{lat},{lng},0a,{dist}d,35y,0h,0t,0r', 0, 100);
     33     }
     34 
     35     async getData(map_) {
     36         const data = await super.getData(map_);
     37         const windowSize = window.innerHeight;
     38         const earthPerimeter = 40075016;
     39         const degree = Math.PI / 180;
     40         const viewAngle = 35;
     41         let elevation;
     42         try {
     43             elevation = (await new ElevationProvider().get([data]))[0];
     44         } catch (e) {
     45             elevation = 8000;
     46             logging.captureException(e, 'failed to get elevation for GoogleEarth link');
     47         }
     48         const mercatorPixelSize = (earthPerimeter / (256 * 2 ** data.zoom)) * Math.cos(data.lat * degree);
     49         const distInPixels = windowSize / 2 / Math.tan((viewAngle * degree) / 2);
     50         data.dist = distInPixels * mercatorPixelSize + elevation;
     51         return data;
     52     }
     53 }
     54 
     55 const ExternalMaps = L.Control.extend({
     56     options: {
     57         externalMaps: [
     58             {title: 'Google', externalMap: new ExternalMap('https://www.google.com/maps/@{lat},{lng},{zoom}z', 3, 21)},
     59             {
     60                 title: 'Yandex',
     61                 externalMap: new ExternalMap('https://yandex.ru/maps/?ll={lng}%2C{lat}&z={zoom}', 2, 21),
     62             },
     63             {
     64                 title: 'OpenStreetMap',
     65                 externalMap: new ExternalMap('https://www.openstreetmap.org/#map={zoom}/{lat}/{lng}', 0, 19),
     66             },
     67             {title: 'Google Earth 3D', externalMap: new GoogleEarthMap()},
     68             {
     69                 title: 'Mapy.cz',
     70                 externalMap: new ExternalMap('https://en.mapy.cz/turisticka?x={lng}&y={lat}&z={zoom}', 2, 19),
     71             },
     72             {
     73                 title: 'Wikimapia',
     74                 externalMap: new ExternalMap('https://wikimapia.org/#lat={lat}&lon={lng}&z={zoom}', 3, 22),
     75             },
     76         ],
     77     },
     78 
     79     onAdd: function (map) {
     80         this._map = map;
     81         const {container, link} = makeButton(null, 'View this place on another map', 'icon-external-links');
     82         this._container = container;
     83         L.DomEvent.on(link, 'click contextmenu', this.onClick, this);
     84 
     85         const menuItems = [
     86             {text: 'View this place on another map', header: true},
     87             ...this.options.externalMaps.map((it) => ({
     88                 text: it.title,
     89                 callback: this.openExternalMap.bind(this, it.externalMap),
     90             })),
     91         ];
     92         this.menu = new Contextmenu(menuItems);
     93         return container;
     94     },
     95 
     96     onClick: function (e) {
     97         this.menu.show(e);
     98     },
     99 
    100     async openExternalMap(externalMap) {
    101         const url = await externalMap.getUrl(this._map);
    102         window.open(url, '_blank');
    103     },
    104 });
    105 
    106 export {ExternalMaps};