nakarte

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

layers.js (57526B)


      1 import L from "leaflet";
      2 import '~/lib/leaflet.layer.yandex';
      3 import '~/lib/leaflet.layer.google';
      4 import {BingLayer} from '~/lib/leaflet.layer.bing';
      5 import config from './config';
      6 import '~/lib/leaflet.layer.soviet-topomaps-grid';
      7 import '~/lib/leaflet.layer.westraPasses';
      8 import '~/lib/leaflet.layer.wikimapia';
      9 import {GeocachingSu} from '~/lib/leaflet.layer.geocaching-su';
     10 import {RetinaTileLayer} from '~/lib/leaflet.layer.RetinaTileLayer';
     11 import urlViaCorsProxy from '~/lib/CORSProxy';
     12 import '~/lib/leaflet.layer.TileLayer.cutline';
     13 import {getCutline} from '~/lib/layers-cutlines';
     14 import {LayerCutlineOverview} from '~/lib/leaflet.layer.LayerCutlineOverview';
     15 
     16 class LayerGroupWithOptions extends L.LayerGroup {
     17     constructor(layers, options) {
     18         super(layers);
     19         L.setOptions(this, options);
     20     }
     21 }
     22 
     23     const layersDefs = [
     24                 {
     25                     title: 'OpenStreetMap',
     26                     description: 'OSM default style',
     27                     isDefault: true,
     28                     layer: L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png',
     29                         {
     30                             code: 'O',
     31                             isOverlay: false,
     32                             scaleDependent: true,
     33                             print: true,
     34                             jnx: true,
     35                             shortName: 'osm',
     36                             attribution: '<a href="https://www.openstreetmap.org/copyright">' +
     37                                 '&copy; OpenStreetMap contributors</a>',
     38                         }
     39                     )
     40                 },
     41                 {
     42                     title: 'ESRI Satellite',
     43                     isDefault: true,
     44                     layer: L.tileLayer(
     45                         'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
     46                         {
     47                             code: 'E',
     48                             isOverlay: false,
     49                             scaleDependent: false,
     50                             maxNativeZoom: 18,
     51                             print: true,
     52                             jnx: true,
     53                             shortName: 'esri',
     54                             attribution:
     55                                 '<a href="https://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9">' +
     56                                 'ESRI World Imagery for ArcGIS</a>',
     57                         }
     58                     )
     59                 },
     60                 {
     61                     title: 'Yandex map',
     62                     isDefault: true,
     63                     layer: new L.Layer.Yandex.Map(
     64                         {
     65                             scaleDependent: true,
     66                             code: 'Y',
     67                             isOverlay: false,
     68                             print: true,
     69                             jnx: true,
     70                             shortName: 'yandex',
     71                             attribution: '<a href="https://yandex.ru/maps/">Yandex</a>',
     72                         }
     73                     )
     74                 },
     75                 {
     76                     title: 'Yandex Satellite',
     77                     isDefault: true,
     78                     layer: new L.Layer.Yandex.Sat(
     79                         {
     80                             scaleDependent: false,
     81                             code: 'S',
     82                             isOverlay: false,
     83                             print: true,
     84                             jnx: true,
     85                             shortName: 'yandex_sat',
     86                             attribution: '<a href="https://yandex.ru/maps/?l=sat">Yandex</a>',
     87                         }
     88                     )
     89                 },
     90                 {
     91                     title: 'Google Map',
     92                     isDefault: true,
     93                     layer: new L.Layer.GoogleMap(
     94                         {
     95                             code: 'G',
     96                             isOverlay: false,
     97                             scaleDependent: true,
     98                             print: true,
     99                             jnx: true,
    100                             shortName: 'google',
    101                             attribution: '<a href="https://www.google.com/maps">Google</a>',
    102                         }
    103                     )
    104                 },
    105                 {
    106                     title: 'Google Hybrid',
    107                     isDefault: false,
    108                     layer: new L.Layer.GoogleHybrid(
    109                         {
    110                             code: 'Gh',
    111                             isOverlay: true,
    112                             scaleDependent: true,
    113                             print: true,
    114                             jnx: false,
    115                             shortName: 'google_hybrid',
    116                             isOverlayTransparent: true,
    117                             attribution: '<a href="https://www.google.com/maps/@43.0668619,60.5738071,13622628m' +
    118                                 '/data=!3m1!1e3">Google</a>',
    119                         }
    120                     )
    121                 },
    122                 {
    123                     title: 'Google Satellite',
    124                     isDefault: true,
    125                     layer: new L.Layer.GoogleSat(
    126                         {
    127                             code: 'L',
    128                             isOverlay: false,
    129                             scaleDependent: false,
    130                             print: true,
    131                             jnx: true,
    132                             shortName: 'google_sat',
    133                             attribution: '<a href="https://www.google.com/maps/@43.0668619,60.5738071,13622628m' +
    134                                 '/data=!3m1!1e3">Google</a>',
    135                         }
    136                     )
    137                 },
    138                 {
    139                     title: 'Google Terrain',
    140                     isDefault: true,
    141                     layer: new L.Layer.GoogleTerrain({
    142                             code: 'P',
    143                             isOverlay: false,
    144                             scaleDependent: false,
    145                             print: true,
    146                             jnx: true,
    147                             shortName: 'google_terrain',
    148                             attribution: '<a href="https://www.google.com/maps/@43.1203575,42.1105049,9.58z' +
    149                                 '/data=!5m1!1e4">Google</a>',
    150                         }
    151                     )
    152                 },
    153                 {
    154                     title: 'Bing Satellite',
    155                     isDefault: true,
    156                     layer: new BingLayer(config.bingKey,
    157                         {
    158                             code: 'I',
    159                             isOverlay: false,
    160                             scaleDependent: false,
    161                             print: true,
    162                             jnx: true,
    163                             shortName: 'bing_sat'
    164                         }
    165                     )
    166                 },
    167                 {
    168                     title: 'Topomapper 1km',
    169                     isDefault: true,
    170                     layer: L.tileLayer(
    171                         urlViaCorsProxy(
    172                             'http://88.99.52.155/cgi-bin/tapp/tilecache.py/1.0.0/topomapper_v2/{z}/{x}/{y}.jpg'
    173                         ),
    174                         {
    175                             code: 'T',
    176                             isOverlay: false,
    177                             scaleDependent: false,
    178                             maxNativeZoom: 13,
    179                             noCors: false,
    180                             print: true,
    181                             jnx: true,
    182                             shortName: 'topomapper_1k',
    183                             attribution: '<a href="https://play.google.com/store/apps/' +
    184                                 'details?id=com.atlogis.sovietmaps.free&hl=en&gl=US">Russian Topo Maps</a>',
    185                         }
    186                     )
    187                 },
    188 
    189                 {
    190                     title: 'Topo 10km',
    191                     isDefault: true,
    192                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/topo001m/{z}/{x}/{y}",
    193                         {
    194                             code: 'D',
    195                             isOverlay: true,
    196                             isOverlayTransparent: false,
    197                             tms: true,
    198                             scaleDependent: false,
    199                             maxNativeZoom: 9,
    200                             print: true,
    201                             jnx: true,
    202                             shortName: 'topo_10k'
    203                         }
    204                     )
    205                 },
    206                 {
    207                     title: 'GGC 2 km',
    208                     isDefault: true,
    209                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/ggc2000/{z}/{x}/{y}",
    210                         {
    211                             code: 'N',
    212                             isOverlay: true,
    213                             isOverlayTransparent: false,
    214                             tms: true,
    215                             scaleDependent: false,
    216                             maxNativeZoom: 12,
    217                             print: true,
    218                             jnx: true,
    219                             shortName: 'ggc_2k'
    220                         }
    221                     )
    222                 },
    223                 {
    224                     title: 'ArbaletMO',
    225                     isDefault: true,
    226                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/ArbaletMO/{z}/{x}/{y}",
    227                         {
    228                             code: 'A',
    229                             isOverlay: true,
    230                             isOverlayTransparent: false,
    231                             tms: true,
    232                             scaleDependent: false,
    233                             maxNativeZoom: 13,
    234                             print: true,
    235                             jnx: true,
    236                             shortName: 'arbalet',
    237                             attribution:
    238                                 '<a href="http://www.velozona.ru/forums/showmessage.php?id=3370">Arbalet (2004)</a>',
    239                         }
    240                     )
    241                 },
    242                 {
    243                     title: 'Slazav mountains',
    244                     isDefault: true,
    245                     layer: L.tileLayer("https://slazav.xyz/tiles/hr/{x}-{y}-{z}.png",
    246                         {
    247                             code: 'Q',
    248                             isOverlay: true,
    249                             isOverlayTransparent: false,
    250                             tms: false,
    251                             scaleDependent: false,
    252                             maxNativeZoom: 13,
    253                             noCors: true,
    254                             print: true,
    255                             jnx: true,
    256                             shortName: 'slazav_mountains',
    257                             attribution: '<a href="http://slazav.xyz/maps">Vladislav Zavjalov</a>',
    258                         }
    259                     )
    260                 },
    261                 {
    262                     title: 'GGC 1km',
    263                     isDefault: true,
    264                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/ggc1000/{z}/{x}/{y}",
    265                         {
    266                             code: 'J',
    267                             isOverlay: true,
    268                             isOverlayTransparent: false,
    269                             tms: true,
    270                             scaleDependent: false,
    271                             maxNativeZoom: 13,
    272                             print: true,
    273                             jnx: true,
    274                             shortName: 'ggc_1k'
    275                         }
    276                     )
    277                 },
    278                 {
    279                     title: 'Topo 1km',
    280                     isDefault: true,
    281                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/topo1000/{z}/{x}/{y}",
    282                         {
    283                             code: 'C',
    284                             isOverlay: true,
    285                             isOverlayTransparent: false,
    286                             tms: true,
    287                             scaleDependent: false,
    288                             maxNativeZoom: 13,
    289                             print: true,
    290                             jnx: true,
    291                             shortName: 'topo_1k'
    292                         }
    293                     )
    294                 },
    295                 {
    296                     title: 'GGC 500m',
    297                     isDefault: true,
    298                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/ggc500/{z}/{x}/{y}",
    299                         {
    300                             code: 'F',
    301                             isOverlay: true,
    302                             isOverlayTransparent: false,
    303                             tms: true,
    304                             scaleDependent: false,
    305                             maxNativeZoom: 14,
    306                             print: true,
    307                             jnx: true,
    308                             shortName: 'ggc_500'
    309                         }
    310                     )
    311                 },
    312                 {
    313                     title: 'Topo 500m',
    314                     isDefault: true,
    315                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/topo500/{z}/{x}/{y}",
    316                         {
    317                             code: 'B',
    318                             isOverlay: true,
    319                             isOverlayTransparent: false,
    320                             tms: true,
    321                             scaleDependent: false,
    322                             maxNativeZoom: 14,
    323                             print: true,
    324                             jnx: true,
    325                             shortName: 'topo_500'
    326                         }
    327                     )
    328                 },
    329                 {
    330                     title: 'GGC 250m',
    331                     isDefault: true,
    332                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/ggc250/{z}/{x}/{y}",
    333                         {
    334                             code: 'K',
    335                             isOverlay: true,
    336                             isOverlayTransparent: false,
    337                             tms: true,
    338                             scaleDependent: false,
    339                             maxNativeZoom: 15,
    340                             print: true,
    341                             jnx: true,
    342                             shortName: 'ggc_250'
    343                         }
    344                     )
    345                 },
    346                 {
    347                     title: 'Slazav Moscow region map',
    348                     isDefault: true,
    349                     layer: L.tileLayer("https://slazav.xyz/tiles/podm/{x}-{y}-{z}.png",
    350                         {
    351                             code: 'Z',
    352                             isOverlay: true,
    353                             isOverlayTransparent: false,
    354                             tms: false,
    355                             scaleDependent: false,
    356                             maxNativeZoom: 14,
    357                             noCors: true,
    358                             print: true,
    359                             jnx: true,
    360                             shortName: 'slazav',
    361                             attribution: '<a href="http://slazav.xyz/maps">Vladislav Zavjalov</a>',
    362                         }
    363                     )
    364                 },
    365                 {
    366                     title: 'Races',
    367                     isDefault: true,
    368                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/adraces/{z}/{x}/{y}",
    369                         {
    370                             code: 'U',
    371                             isOverlay: true,
    372                             isOverlayTransparent: false,
    373                             tms: true,
    374                             scaleDependent: false,
    375                             maxNativeZoom: 15,
    376                             print: true,
    377                             jnx: true,
    378                             shortName: 'races'
    379                         }
    380                     )
    381                 },
    382                 {
    383                     title: 'O-sport',
    384                     isDefault: true,
    385                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/osport/{z}/{x}/{y}",
    386                         {
    387                             code: 'R',
    388                             isOverlay: true,
    389                             isOverlayTransparent: false,
    390                             tms: true,
    391                             scaleDependent: false,
    392                             maxNativeZoom: 17,
    393                             print: true,
    394                             jnx: true,
    395                             shortName: 'osport'
    396                         }
    397                     )
    398                 },
    399                 {
    400                     title: 'Soviet topo maps grid',
    401                     isDefault: true,
    402                     layer: new L.Layer.SovietTopoGrid({
    403                         code: 'Ng',
    404                         isOverlay: true,
    405                         print: false,
    406                         jnx: false
    407                     })
    408                 },
    409                 {
    410                     title: 'Wikimapia',
    411                     isDefault: true,
    412                     layer: new L.Wikimapia({
    413                         code: 'W',
    414                         isOverlay: true,
    415                         print: false,
    416                         jnx: false,
    417                         attribution: '<a href="https://wikimapia.org/">Wikimapia</a>',
    418                         tilesBaseUrl: config.wikimapiaTilesBaseUrl,
    419                     })
    420                 },
    421                 {
    422                     title: 'Mountain passes (Westra)',
    423                     isDefault: true,
    424                     layer: new L.Layer.WestraPasses(config.westraDataBaseUrl, {
    425                         code: 'Wp',
    426                         print: true,
    427                         jnx: false,
    428                         scaleDependent: true,
    429                         isOverlay: true,
    430                         isOverlayTransparent: true,
    431                         shortName: 'passes',
    432                         markersOptions: {
    433                             isOverlay: true,
    434                             isOverlayTransparent: true,
    435                             shortName: 'passes'
    436                         },
    437                         attribution: '<a href="http://westra.ru/passes/">Westra passes catalog</a>',
    438                     })
    439                 },
    440                 {
    441                     title: 'OpenTopoMap',
    442                     isDefault: false,
    443                     layer: L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',
    444                         {
    445                             code: 'Otm',
    446                             isOverlay: false,
    447                             maxNativeZoom: 15,
    448                             scaleDependent: true,
    449                             print: true,
    450                             jnx: true,
    451                             noCors: false,
    452                             shortName: 'opentopo',
    453                             attribution: '<a href="https://opentopomap.org/">OpenTopoMap</a>',
    454                             hotkey: 'V',
    455                         }
    456                     )
    457                 },
    458                 {
    459                     title: 'OpenCycleMap',
    460                     description: '<a href="https://www.opencyclemap.org/docs/">(Info and key)</a>',
    461                     isDefault: false,
    462                     layer: L.tileLayer('https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png',
    463                         {
    464                             code: 'Ocm',
    465                             isOverlay: false,
    466                             scaleDependent: true,
    467                             print: true,
    468                             jnx: true,
    469                             shortName: 'opencyclemap',
    470                             attribution: '<a href="https://www.opencyclemap.org/">Thunderforest OpenCycleMap</a>',
    471                         }
    472                     )
    473                 },
    474                 {
    475                     title: 'OSM Outdoors',
    476                     isDefault: false,
    477                     layer: L.tileLayer('https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png',
    478                         {
    479                             code: 'Oso',
    480                             isOverlay: false,
    481                             scaleDependent: true,
    482                             print: true,
    483                             jnx: true,
    484                             shortName: 'osm_outdoors',
    485                             attribution:
    486                                 '<a href="https://www.thunderforest.com/maps/outdoors/">Thunderforest Outdoors</a>',
    487                         }
    488                     )
    489                 },
    490                 {
    491                     title: 'Eurasia 25km',
    492                     description: '1975-80',
    493                     isDefault: false,
    494                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/eurasia25km/{z}/{x}/{y}",
    495                         {
    496                             code: 'E25m',
    497                             isOverlay: true,
    498                             isOverlayTransparent: false,
    499                             tms: true,
    500                             maxNativeZoom: 9,
    501                             print: true,
    502                             jnx: true,
    503                             scaleDependent: false,
    504                             shortName: 'eurasia_25k'
    505                         }
    506                     )
    507                 },
    508                 {
    509                     title: 'Caucasus 1km',
    510                     isDefault: false,
    511                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/new_gsh_100k/{z}/{x}/{y}",
    512                         {
    513                             code: 'NT1',
    514                             isOverlay: true,
    515                             isOverlayTransparent: false,
    516                             tms: true,
    517                             maxNativeZoom: 14,
    518                             print: true,
    519                             jnx: true,
    520                             scaleDependent: false,
    521                             shortName: 'caucasus_1k',
    522                             attribution: '<a href="http://genshtab-yuga.narod.ru/">Topo maps (2006)</a>',
    523                         }
    524                     )
    525                 },
    526                 {
    527                     title: 'Caucasus 500m',
    528                     isDefault: false,
    529                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/new_gsh_050k/{z}/{x}/{y}",
    530                         {
    531                             code: 'NT5',
    532                             isOverlay: true,
    533                             isOverlayTransparent: false,
    534                             tms: true,
    535                             maxNativeZoom: 15,
    536                             print: true,
    537                             jnx: true,
    538                             scaleDependent: false,
    539                             shortName: 'caucasus_500',
    540                             attribution: '<a href="http://genshtab-yuga.narod.ru/">Topo maps (1998 - 2003)</a>',
    541                         }
    542                     )
    543                 },
    544                 {
    545                     title: 'Topo 250m',
    546                     isDefault: false,
    547                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/topo250/{z}/{x}/{y}",
    548                         {
    549                             code: 'T25',
    550                             isOverlay: true,
    551                             isOverlayTransparent: false,
    552                             tms: true,
    553                             maxNativeZoom: 15,
    554                             print: true,
    555                             jnx: true,
    556                             scaleDependent: false,
    557                             shortName: 'topo_250'
    558                         }
    559                     )
    560                 },
    561                 {
    562                     title: 'Montenegro topo 250m',
    563                     description: '1970-72',
    564                     isDefault: false,
    565                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/montenegro250m/{z}/{x}/{y}",
    566                         {
    567                             code: 'MN25',
    568                             isOverlay: true,
    569                             isOverlayTransparent: false,
    570                             tms: true,
    571                             maxNativeZoom: 15,
    572                             print: true,
    573                             jnx: true,
    574                             scaleDependent: false,
    575                             shortName: 'montenegro_250'
    576                         }
    577                     )
    578                 },
    579                 {
    580                     title: 'Mountains by Aleksey Tsvetkov',
    581                     description:
    582                         'Tian Shan, Dzungaria, <a href="http://pereval.g-utka.ru/">http://pereval.g-utka.ru/</a>',
    583                     isDefault: true,
    584                     layer: new LayerGroupWithOptions(
    585                         [
    586                             L.tileLayer(
    587                                 urlViaCorsProxy(
    588                                     'http://nakartetiles.s3-website.eu-central-1.amazonaws.com/{z}/{x}/{y}.png'
    589                                 ),
    590                                 {
    591                                     isOverlay: true,
    592                                     isOverlayTransparent: false,
    593                                     tms: false,
    594                                     minZoom: 2,
    595                                     maxNativeZoom: 15,
    596                                     print: true,
    597                                     jnx: true,
    598                                     scaleDependent: false,
    599                                     noCors: false,
    600                                     shortName: 'tsvetkov_mountains',
    601                                     cutline: getCutline('tsvetkov_mountains'),
    602                                     bounds: [
    603                                         [40.66664, 71.00007],
    604                                         [45.33338, 81.00001],
    605                                     ],
    606                                     attribution: '<a href="http://pereval.g-utka.ru/">Aleksey Tsvetkov</a>',
    607                                 }
    608                             ),
    609                             new LayerCutlineOverview(getCutline('tsvetkov_mountains'), 6,
    610                                 'Mountains by Aleksey Tsvetkov'),
    611                         ],
    612                         {
    613                             code: 'Mt',
    614                             isOverlay: true,
    615                             isWrapper: true,
    616                         }
    617                     ),
    618                 },
    619                 {
    620                     title: 'geocaching.su',
    621                     isDefault: false,
    622                     layer: new GeocachingSu(config.geocachingSuUrl, {
    623                         code: 'Gc',
    624                         isOverlay: true,
    625                         isOverlayTransparent: true,
    626                         print: true,
    627                         jnx: false,
    628                         shortName: 'geocaching',
    629                         attribution: '<a href="https://geocaching.su/">geocaching.su</a>',
    630                     })
    631                 },
    632                 {
    633                     title: 'OpenStreetMap GPS traces',
    634                     isDefault: false,
    635                     layer: L.tileLayer('https://{s}.gps-tile.openstreetmap.org/lines/{z}/{x}/{y}.png',
    636                         {
    637                             code: 'Ot',
    638                             isOverlay: true,
    639                             isOverlayTransparent: true,
    640                             scaleDependent: true,
    641                             print: true,
    642                             jnx: false,
    643                             shortName: 'osm_gps_traces',
    644                             attribution: '<a href="https://www.openstreetmap.org/#&layers=G">' +
    645                                 'OpenStreetMap public GPS traces</a>',
    646                         }
    647                     )
    648                 },
    649                 {
    650                     title: 'Strava heatmap (all)',
    651                     isDefault: false,
    652                     layer: new RetinaTileLayer(
    653                         [
    654                             urlViaCorsProxy(
    655                                 'https://heatmap-external-a.strava.com/tiles-auth/all/hot/{z}/{x}/{y}.png?px=256'
    656                             ),
    657                             urlViaCorsProxy(
    658                                 'https://heatmap-external-a.strava.com/tiles-auth/all/hot/{z}/{x}/{y}.png?px=512'
    659                             ),
    660                         ],
    661                         {
    662                             code: 'Sa',
    663                             isOverlay: true,
    664                             isOverlayTransparent: true,
    665                             scaleDependent: false,
    666                             print: true,
    667                             jnx: false,
    668                             subdomains: 'abc',
    669                             noCors: true,
    670                             shortName: 'strava_all',
    671                             retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
    672                             attribution: '<a href="https://www.strava.com/heatmap">Strava Global Heatmap</a>',
    673                             opacity: 0.75,
    674                         }
    675                     )
    676                 },
    677                 {
    678                     title: 'Strava heatmap (run)',
    679                     isDefault: false,
    680                     layer: new RetinaTileLayer(
    681                         [
    682                             urlViaCorsProxy(
    683                                 'https://heatmap-external-a.strava.com/tiles-auth/run/hot/{z}/{x}/{y}.png?px=256'
    684                             ),
    685                             urlViaCorsProxy(
    686                                 'https://heatmap-external-a.strava.com/tiles-auth/run/hot/{z}/{x}/{y}.png?px=512'
    687                             ),
    688                         ],
    689                         {
    690                             code: 'Sr',
    691                             isOverlay: true,
    692                             isOverlayTransparent: true,
    693                             scaleDependent: false,
    694                             print: true,
    695                             jnx: false,
    696                             subdomains: 'abc',
    697                             noCors: true,
    698                             shortName: 'strava_run',
    699                             retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
    700                             attribution: '<a href="https://www.strava.com/heatmap">Strava Global Heatmap</a>',
    701                             opacity: 0.75,
    702                         }
    703                     )
    704                 },
    705                 {
    706                     title: 'Strava heatmap (ride)',
    707                     isDefault: false,
    708                     layer: new RetinaTileLayer(
    709                         [
    710                             urlViaCorsProxy(
    711                                 'https://heatmap-external-a.strava.com/tiles-auth/ride/hot/{z}/{x}/{y}.png?px=256'
    712                             ),
    713                             urlViaCorsProxy(
    714                                 'https://heatmap-external-a.strava.com/tiles-auth/ride/hot/{z}/{x}/{y}.png?px=512'
    715                             ),
    716                         ],
    717                         {
    718                             code: 'Sb',
    719                             isOverlay: true,
    720                             isOverlayTransparent: true,
    721                             scaleDependent: false,
    722                             print: true,
    723                             jnx: false,
    724                             subdomains: 'abc',
    725                             noCors: true,
    726                             shortName: 'strava_ride',
    727                             retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
    728                             attribution: '<a href="https://www.strava.com/heatmap">Strava Global Heatmap</a>',
    729                             opacity: 0.75,
    730                         }
    731                     )
    732                 },
    733                 {
    734                     title: 'Strava heatmap (winter)',
    735                     isDefault: false,
    736                     layer: new RetinaTileLayer(
    737                         [
    738                             urlViaCorsProxy(
    739                                 'https://heatmap-external-a.strava.com/tiles-auth/winter/hot/{z}/{x}/{y}.png?px=256'
    740                             ),
    741                             urlViaCorsProxy(
    742                                 'https://heatmap-external-a.strava.com/tiles-auth/winter/hot/{z}/{x}/{y}.png?px=512'
    743                             ),
    744                         ],
    745                         {
    746                             code: 'Sw',
    747                             isOverlay: true,
    748                             isOverlayTransparent: true,
    749                             scaleDependent: false,
    750                             print: true,
    751                             jnx: false,
    752                             subdomains: 'abc',
    753                             noCors: true,
    754                             shortName: 'strava_winter',
    755                             retinaOptionsOverrides: [{maxNativeZoom: 16}, {maxNativeZoom: 15}],
    756                             attribution: '<a href="https://www.strava.com/heatmap">Strava Global Heatmap</a>',
    757                             opacity: 0.75,
    758                         }
    759                     )
    760                 },
    761                 {
    762                     title: 'Norway paper map',
    763                     isDefault: false,
    764                     layer: new L.TileLayer(
    765                         'https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=toporaster4&zoom={z}&x={x}&y={y}', // eslint-disable-line max-len
    766                         {
    767                             code: 'Np',
    768                             isOverlay: true,
    769                             isOverlayTransparent: false,
    770                             maxNativeZoom: 16,
    771                             tms: false,
    772                             print: true,
    773                             jnx: true,
    774                             scaleDependent: true,
    775                             noCors: false,
    776                             shortName: 'norway_paper',
    777                             bounds: [[57.81324, 4.19674], [71.27961, 31.56094]],
    778                             attribution: '<a href="https://www.geonorge.no/aktuelt/om-geonorge/brukerveiledning' +
    779                                 '/#!#se_paa_kart">Geonorge</a>',
    780                         }
    781                     )
    782                 },
    783                 {
    784                     title: 'Norway topo',
    785                     isDefault: false,
    786                     layer: new L.TileLayer(
    787                         'https://opencache.statkart.no/gatekeeper/gk/gk.open_gmaps?layers=topo4&zoom={z}&x={x}&y={y}',
    788                         {
    789                             code: 'Nm',
    790                             isOverlay: true,
    791                             isOverlayTransparent: false,
    792                             tms: false,
    793                             print: true,
    794                             jnx: true,
    795                             scaleDependent: true,
    796                             noCors: false,
    797                             shortName: 'norway_topo',
    798                             bounds: [[57.81324, 4.19674], [71.27961, 31.56094]],
    799                             attribution: '<a href="https://www.geonorge.no/aktuelt/om-geonorge/brukerveiledning' +
    800                                 '/#!#se_paa_kart">Geonorge</a>',
    801                         }
    802                     )
    803                 },
    804                 {
    805                     // Вместо 404 отдают 500 для отсутствующих тайлов
    806                     title: 'Norway roads',
    807                     description: '<a href="https://kart.finn.no/">https://kart.finn.no/</a>',
    808                     isDefault: false,
    809                     layer: L.tileLayer("https://maptiles1.finncdn.no/tileService/1.0.3/normap/{z}/{x}/{y}.png",
    810                         {
    811                             code: 'Nr',
    812                             isOverlay: true,
    813                             isOverlayTransparent: false,
    814                             tms: false,
    815                             print: true,
    816                             jnx: true,
    817                             scaleDependent: true,
    818                             noCors: false,
    819                             shortName: 'norway_roads',
    820                             bounds: [[57.81324, 4.19674], [71.27961, 31.56094]],
    821                             cutline: getCutline('norway'),
    822                             attribution: '<a href="https://kart.finn.no/">finn.no</a>',
    823                         }
    824                     )
    825                 },
    826                 {
    827                     title: 'Czech base',
    828                     isDefault: false,
    829                     layer: new RetinaTileLayer(
    830                         [
    831                             `https://api.mapy.cz/v1/maptiles/basic/256/{z}/{x}/{y}?apikey=${config.mapyCz}`,
    832                             `https://api.mapy.cz/v1/maptiles/basic/256@2x/{z}/{x}/{y}?apikey=${config.mapyCz}`,
    833                         ],
    834                         {
    835                             code: 'Czb',
    836                             isOverlay: false,
    837                             tms: false,
    838                             print: true,
    839                             jnx: true,
    840                             scaleDependent: true,
    841                             shortName: 'czech',
    842                             attribution: '<a href="https://mapy.cz/zakladni">mapy.cz base map</a>',
    843                         }
    844                     )
    845                 },
    846                 {
    847                     title: 'mapy.cz tourist',
    848                     isDefault: true,
    849                     layer: new RetinaTileLayer(
    850                         [
    851                             `https://api.mapy.cz/v1/maptiles/outdoor/256/{z}/{x}/{y}?apikey=${config.mapyCz}`,
    852                             `https://api.mapy.cz/v1/maptiles/outdoor/256@2x/{z}/{x}/{y}?apikey=${config.mapyCz}`,
    853                         ],
    854                         {
    855                             code: 'Czt',
    856                             isOverlay: false,
    857                             tms: false,
    858                             print: true,
    859                             jnx: true,
    860                             scaleDependent: true,
    861                             shortName: 'czech_tourist',
    862                             hotkey: 'H',
    863                             attribution: '<a href="https://mapy.cz/turisticka">mapy.cz outdoor map</a>',
    864                         }
    865                     )
    866                 },
    867                 {
    868                     title: 'Czech winter',
    869                     isDefault: false,
    870                     layer: L.tileLayer(
    871                         `https://api.mapy.cz/v1/maptiles/winter/256/{z}/{x}/{y}?apikey=${config.mapyCz}`,
    872                         {
    873                             code: 'Czw',
    874                             isOverlay: false,
    875                             tms: false,
    876                             print: true,
    877                             jnx: true,
    878                             scaleDependent: true,
    879                             shortName: 'czech_winter',
    880                             attribution: '<a href="https://mapy.cz/zimni">mapy.cz winter map</a>',
    881                         }
    882                     )
    883                 },
    884                 {
    885                     title: 'Finland Topo',
    886                     description: '<a href="https://laji.fi/en/map/">LAJI.FI</a>',
    887                     isDefault: false,
    888                     layer: L.tileLayer(
    889                         "https://proxy.laji.fi/mml_wmts/maasto/wmts/1.0.0/maastokartta/default/WGS84_Pseudo-Mercator/" +
    890                         "{z}/{y}/{x}.png",
    891                         {
    892                             code: 'Fmk',
    893                             isOverlay: true,
    894                             isOverlayTransparent: false,
    895                             tms: false,
    896                             print: true,
    897                             jnx: true,
    898                             scaleDependent: true,
    899                             noCors: false,
    900                             shortName: 'finland_topo',
    901                             bound: [[59.45416, 19.08321], [70.09211, 31.58671]],
    902                             cutline: getCutline('finland'),
    903                             attribution: '<a href="https://laji.fi/en/map/">LAJI.FI</a>',
    904                         }
    905                     )
    906                 },
    907                 {
    908                     title: 'France Topo 250m',
    909                     isDefault: false,
    910                     layer: new LayerGroupWithOptions(
    911                         [
    912                             L.tileLayer(
    913                                 'https://wxs.ign.fr/an7nvfzojv5wa96dsga5nk8w/geoportail/wmts?' +
    914                                 'layer=GEOGRAPHICALGRIDSYSTEMS.MAPS.SCAN25TOUR.CV&style=normal&tilematrixset=PM&' +
    915                                 'Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fjpeg&' +
    916                                 'TileMatrix={z}&TileCol={x}&TileRow={y}',
    917                                 {
    918                                     minZoom: 6,
    919                                     maxNativeZoom: 16,
    920                                     bounds: [
    921                                         [-46.44072, -178.18694],
    922                                         [51.12562, 77.61086],
    923                                     ],
    924                                     isOverlay: true,
    925                                     isOverlayTransparent: false,
    926                                     tms: false,
    927                                     print: true,
    928                                     jnx: true,
    929                                     scaleDependent: false,
    930                                     shortName: 'france_topo_25k',
    931                                     cutline: getCutline('france'),
    932                                     attribution: '<a href="https://www.geoportail.gouv.fr/carte">' +
    933                                         'IGN (France) topographic map</a>',
    934                                 }
    935                             ),
    936                             new LayerCutlineOverview(getCutline('france'), 5, 'France Topo 250m (zoom ≥ 6)'),
    937                         ],
    938                         {
    939                             code: 'Ft',
    940                             isOverlay: true,
    941                             isWrapper: true,
    942                         }
    943                     ),
    944                 },
    945                 {
    946                     title: 'Great Britain Topo',
    947                     isDefault: false,
    948                     layer: new LayerGroupWithOptions(
    949                         [
    950                             new BingLayer(config.bingKey, {
    951                                 type: 'OrdnanceSurvey',
    952                                 minZoom: 12,
    953                                 maxNativeZoom: 16,
    954                                 bounds: [
    955                                     [49.83793, -7.75643],
    956                                     [60.87164, 1.82356],
    957                                 ],
    958                                 isOverlay: true,
    959                                 isOverlayTransparent: false,
    960                                 scaleDependent: true,
    961                                 print: true,
    962                                 jnx: true,
    963                                 shortName: 'england_topo',
    964                                 cutline: getCutline('great_britain'),
    965                                 attribution: '<a href="https://docs.microsoft.com/en-us/bingmaps/v8-web-control/' +
    966                                     'map-control-api/maptypeid-enumeration">Ordnance Survey</a>',
    967                             }),
    968                             new LayerCutlineOverview(getCutline('great_britain'), 11, 'Great Britain Topo (zoom ≥ 12)'),
    969                         ],
    970                         {
    971                             code: 'Gbt',
    972                             isOverlay: true,
    973                             isWrapper: true,
    974                         }
    975                     ),
    976                 },
    977                 {
    978                     title: 'Waymarked Cycling Trails',
    979                     description:
    980                         '<a href="https://cycling.waymarkedtrails.org/">https://cycling.waymarkedtrails.org</a>',
    981                     isDefault: false,
    982                     layer: L.tileLayer('https://tile.waymarkedtrails.org/cycling/{z}/{x}/{y}.png',
    983                         {
    984                             code: 'Wc',
    985                             isOverlay: true,
    986                             tms: false,
    987                             print: true,
    988                             jnx: false,
    989                             scaleDependent: true,
    990                             shortName: 'cycling_trails',
    991                             isOverlayTransparent: true,
    992                             attribution: '<a href="https://cycling.waymarkedtrails.org/">Waymarked Cycling Trails</a>',
    993                         })
    994                 },
    995                 {
    996                     title: 'Waymarked Hiking Trails',
    997                     description: '<a href="https://hiking.waymarkedtrails.org/">https://hiking.waymarkedtrails.org</a>',
    998                     isDefault: false,
    999                     layer: L.tileLayer('https://tile.waymarkedtrails.org/hiking/{z}/{x}/{y}.png',
   1000                         {
   1001                             code: 'Wh',
   1002                             isOverlay: true,
   1003                             tms: false,
   1004                             print: true,
   1005                             jnx: false,
   1006                             scaleDependent: true,
   1007                             shortName: 'hiking_trails',
   1008                             isOverlayTransparent: true,
   1009                             attribution: '<a href="https://hiking.waymarkedtrails.org/">Waymarked Hiking Trails</a>',
   1010                         })
   1011                 },
   1012                 {
   1013                     title: 'Slovakia topo',
   1014                     description: '<a href="https://mapy.hiking.sk">https://mapy.hiking.sk/</a>',
   1015                     isDefault: false,
   1016                     layer: new LayerGroupWithOptions(
   1017                         [
   1018                             L.tileLayer('https://static.mapy.hiking.sk/topo/{z}/{x}/{y}.png', {
   1019                                 isOverlay: true,
   1020                                 tms: false,
   1021                                 print: true,
   1022                                 jnx: true,
   1023                                 scaleDependent: true,
   1024                                 shortName: 'slovakia_topo',
   1025                                 isOverlayTransparent: false,
   1026                                 maxNativeZoom: 15,
   1027                                 minZoom: 10,
   1028                                 bounds: [
   1029                                     [47.5172, 16.74316],
   1030                                     [49.91343, 22.74837],
   1031                                 ],
   1032                                 noCors: true,
   1033                                 cutline: getCutline('slovakia'),
   1034                                 attribution: '<a href="https://mapy.hiking.sk/">mapy.hiking.sk</a>',
   1035                             }),
   1036                             new LayerCutlineOverview(getCutline('slovakia'), 9, 'Slovakia topo (zoom ≥ 10)'),
   1037                         ],
   1038                         {
   1039                             code: 'St',
   1040                             isOverlay: true,
   1041                             isWrapper: true,
   1042                         }
   1043                     ),
   1044                 },
   1045                 {
   1046                     title: 'Yandex tracks (zoom ≥ 10)',
   1047                     isDefault: false,
   1048                     layer: new L.Layer.Yandex.Tracks(
   1049                         {
   1050                             scaleDependent: true,
   1051                             code: 'Ytr',
   1052                             isOverlay: true,
   1053                             isOverlayTransparent: true,
   1054                             print: true,
   1055                             jnx: false,
   1056                             shortName: 'yandex_tracks',
   1057                             noCors: true,
   1058                             attribution: '<a href="https://n.maps.yandex.ru/">Yandex Map Editor</a>',
   1059                         }
   1060                     )
   1061                 },
   1062                 {
   1063                     title: 'Spain topo',
   1064                     isDefault: false,
   1065                     layer: L.tileLayer(
   1066                             'https://www.ign.es/wmts/mapa-raster?layer=MTN&style=default&' +
   1067                             'tilematrixset=GoogleMapsCompatible&Service=WMTS&Request=GetTile&Version=1.0.0&' +
   1068                             'Format=image%2Fjpeg&TileMatrix={z}&TileCol={x}&TileRow={y}',
   1069                             {
   1070                                 code: 'Sp',
   1071                                 isOverlay: true,
   1072                                 tms: false,
   1073                                 print: true,
   1074                                 jnx: true,
   1075                                 scaleDependent: true,
   1076                                 shortName: 'spain_topo',
   1077                                 isOverlayTransparent: false,
   1078                                 bounds: [[35.9024, -9.51828], [43.8375, 4.50439]],
   1079                                 noCors: false,
   1080                                 cutline: getCutline('spain'),
   1081                                 attribution: '<a href="https://www.ign.es/iberpix2/visor/">' +
   1082                                     'IGN (Spain) topographic map</a>'
   1083                             }
   1084                     )
   1085                 },
   1086                 {
   1087                     title: 'Switzerland topo',
   1088                     isDefault: false,
   1089                     layer: new RetinaTileLayer(
   1090                         [
   1091                             null,
   1092                             urlViaCorsProxy(
   1093                                 'https:///wmts10.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/' +
   1094                                 '3857/{z}/{x}/{y}.jpeg'
   1095                             ),
   1096                         ],
   1097 
   1098                         {
   1099                                 code: 'Si',
   1100                                 isOverlay: true,
   1101                                 tms: false,
   1102                                 print: true,
   1103                                 jnx: true,
   1104                                 scaleDependent: true,
   1105                                 shortName: 'swiss_topo',
   1106                                 isOverlayTransparent: false,
   1107                                 bounds: [[45.80269, 5.87352], [47.86445, 10.6847]],
   1108                                 noCors: false,
   1109                                 maxNativeZoom: 16,
   1110                                 tileSize: 128,
   1111                                 zoomOffset: 1,
   1112                                 cutline: getCutline('switzerland'),
   1113                                 attribution: '<a href="https://map.geo.admin.ch/?topic=swisstopo&lang=en&bgLayer=' +
   1114                                     'ch.swisstopo.pixelkarte-farbe&E=2586000.76&N=1202020.96&zoom=1">Swisstopo'
   1115                             }, true
   1116                     )
   1117                 },
   1118                 {
   1119                     title: 'Mountains by Alexander Purikov',
   1120                     isDefault: false,
   1121                     layer: L.tileLayer("https://{s}.tiles.nakarte.me/purikov/{z}/{x}/{y}",
   1122                         {
   1123                             code: 'Pur',
   1124                             isOverlay: true,
   1125                             isOverlayTransparent: false,
   1126                             tms: true,
   1127                             scaleDependent: false,
   1128                             maxNativeZoom: 14,
   1129                             noCors: false,
   1130                             print: true,
   1131                             jnx: true,
   1132                             shortName: 'purikov_mountains',
   1133                             attribution: '<a href="https://westra.ru/reports/">Alexander Purikov</a>',
   1134                         }
   1135                     )
   1136                 },
   1137     ];
   1138 
   1139     const groupsDefs = [
   1140         {
   1141             title: 'Default layers',
   1142             layers: [
   1143                 'OpenStreetMap',
   1144                 'ESRI Satellite',
   1145                 'Yandex map',
   1146                 'Yandex Satellite',
   1147                 'Google Map',
   1148                 'Google Satellite',
   1149                 'Google Terrain',
   1150                 'Bing Satellite',
   1151                 'Topomapper 1km',
   1152                 'Topo 10km',
   1153                 'GGC 2 km',
   1154                 'ArbaletMO',
   1155                 'Mountains by Aleksey Tsvetkov',
   1156                 'Slazav mountains',
   1157                 'GGC 1km',
   1158                 'Topo 1km',
   1159                 'GGC 500m',
   1160                 'Topo 500m',
   1161                 'GGC 250m',
   1162                 'Slazav Moscow region map',
   1163                 'Races',
   1164                 'O-sport',
   1165                 'Soviet topo maps grid',
   1166                 'Wikimapia',
   1167                 'Mountain passes (Westra)'
   1168             ],
   1169         },
   1170         {
   1171             title: 'OpenStreetMap alternatives',
   1172             layers: [
   1173                 'OpenTopoMap',
   1174                 'OpenCycleMap',
   1175                 'OSM Outdoors'
   1176             ],
   1177         },
   1178         {
   1179             title: 'Topo maps',
   1180             layers: [
   1181                 'Eurasia 25km',
   1182                 'Caucasus 1km',
   1183                 'Caucasus 500m',
   1184                 'Topo 250m',
   1185                 'Montenegro topo 250m',
   1186                 'Finland Topo',
   1187                 'France Topo 250m',
   1188                 'Great Britain Topo',
   1189                 'Slovakia topo',
   1190                 'Spain topo',
   1191                 'Switzerland topo',
   1192             ],
   1193         },
   1194         {
   1195             title: 'Miscellaneous',
   1196             layers: [
   1197                 'Mountains by Alexander Purikov',
   1198                 'Google Hybrid',
   1199                 'geocaching.su'
   1200             ]
   1201         },
   1202         {
   1203             title: 'Routes and traces',
   1204             layers: [
   1205                 'Waymarked Hiking Trails',
   1206                 'Waymarked Cycling Trails',
   1207                 'OpenStreetMap GPS traces',
   1208                 'Strava heatmap (all)',
   1209                 'Strava heatmap (run)',
   1210                 'Strava heatmap (ride)',
   1211                 'Strava heatmap (winter)',
   1212                 'Yandex tracks (zoom ≥ 10)',
   1213             ],
   1214 
   1215         },
   1216         {
   1217             title: 'Norway <a href="https://www.ut.no/kart/">https://www.ut.no/kart/</a>',
   1218             layers: [
   1219                 'Norway paper map',
   1220                 'Norway topo',
   1221                 'Norway roads'
   1222             ],
   1223 
   1224         },
   1225         {
   1226             title: 'Czech <a href="https://mapy.cz">https://mapy.cz</a>',
   1227             layers: [
   1228                 'Czech base',
   1229                 'mapy.cz tourist',
   1230                 'Czech winter'
   1231             ],
   1232         },
   1233     ];
   1234 
   1235     const titlesByOrder = [
   1236         // common base layers
   1237         // OSM
   1238         'OpenStreetMap',
   1239         'OpenTopoMap',
   1240         'OpenCycleMap',
   1241         'OSM Outdoors',
   1242         'mapy.cz tourist',
   1243         // Satellite
   1244         'ESRI Satellite',
   1245         'Yandex Satellite',
   1246         'Google Satellite',
   1247         'Bing Satellite',
   1248         // Commercial maps
   1249         'Yandex map',
   1250         'Google Map',
   1251         'Google Terrain',
   1252         // Topo maps
   1253         'Topomapper 1km',
   1254 
   1255         // local base layers
   1256         'Czech base',
   1257         'Czech winter',
   1258 
   1259         // map overlays
   1260         '#custom-bottom',
   1261         'Eurasia 25km',
   1262         'Topo 10km',
   1263         'GGC 2 km',
   1264         'ArbaletMO',
   1265         'Norway roads',
   1266         'Norway paper map',
   1267         'Norway topo',
   1268         'Finland Topo',
   1269         'Slovakia topo',
   1270         'Spain topo',
   1271         'Mountains by Alexander Purikov',
   1272         'Mountains by Aleksey Tsvetkov',
   1273         'Slazav mountains',
   1274         'GGC 1km',
   1275         'Topo 1km',
   1276         'Caucasus 1km',
   1277         'Great Britain Topo',
   1278         'GGC 500m',
   1279         'Topo 500m',
   1280         'Caucasus 500m',
   1281         'GGC 250m',
   1282         'Topo 250m',
   1283         'Montenegro topo 250m',
   1284         'France Topo 250m',
   1285         'Switzerland topo',
   1286         'Slazav Moscow region map',
   1287         'Races',
   1288         'O-sport',
   1289         '#custom-top',
   1290 
   1291         // line overlays
   1292         'Google Hybrid',
   1293         'Waymarked Hiking Trails',
   1294         'Waymarked Cycling Trails',
   1295         'OpenStreetMap GPS traces',
   1296         'Strava heatmap (all)',
   1297         'Strava heatmap (run)',
   1298         'Strava heatmap (ride)',
   1299         'Strava heatmap (winter)',
   1300         'Yandex tracks (zoom ≥ 10)',
   1301         'Soviet topo maps grid',
   1302         'Wikimapia',
   1303 
   1304         // point overlays
   1305         'Mountain passes (Westra)',
   1306         'geocaching.su',
   1307     ];
   1308 
   1309 function getLayers() {
   1310     // set metadata
   1311     for (let layer of layersDefs) {
   1312         layer.layer.meta = {title: layer.title};
   1313     }
   1314 
   1315     // assign order to layers
   1316     const orderByTitle = {};
   1317     for (let i = 0; i < titlesByOrder.length; i++) {
   1318         let title = titlesByOrder[i];
   1319         orderByTitle[title] = i + 1;
   1320     }
   1321 
   1322     for (let layer of layersDefs) {
   1323         const title = layer.title;
   1324         layer.order = orderByTitle[title];
   1325         if (!layer.order) {
   1326             throw new Error(`Layer title not found in titlesByOrder list: ${title}`);
   1327         }
   1328     }
   1329 
   1330     // divide layers by groups
   1331     const grouppedLayers = [];
   1332     const layersByTitle = {};
   1333     for (let layer of layersDefs) {
   1334         layersByTitle[layer.title] = layer;
   1335     }
   1336     for (let groupDef of groupsDefs) {
   1337         let group = {group: groupDef.title, layers: []};
   1338         grouppedLayers.push(group);
   1339         for (let title of groupDef.layers) {
   1340             let layer = layersByTitle[title];
   1341             group.layers.push(layer);
   1342         }
   1343     }
   1344 
   1345     return {
   1346         layers: grouppedLayers,
   1347         customLayersOrder: {
   1348             top: orderByTitle['#custom-top'],
   1349             bottom: orderByTitle['#custom-bottom'],
   1350 
   1351         }
   1352     };
   1353 }
   1354 
   1355 export {getLayers, layersDefs, groupsDefs, titlesByOrder};