GeoGuessr Custom Maps

playing with modified maps in geoguessr games

  1. // ==UserScript==
  2. // @name GeoGuessr Custom Maps
  3. // @description playing with modified maps in geoguessr games
  4. // @version 1.2.0
  5. // @match *://www.geoguessr.com/*
  6. // @author KaKa
  7. // @license BSD
  8. // @require https://update.greasyfork.org/scripts/502813/1423193/Geoguessr%20Tag.js
  9. // @icon https://www.svgrepo.com/show/392367/interaction-interface-layer-layers-location-map.svg
  10. // @namespace https://greasyfork.org/users/1179204
  11. // ==/UserScript==
  12.  
  13. (function() {
  14.  
  15. /*=========================================================================Modifiy your guess map here==================================================================================*/
  16.  
  17. let customOptions={
  18.  
  19. Language:'en', //en,zh,ja,fr,de,es
  20.  
  21. Google_StreetView_Layer_Lines_Style:'Default', // More styles see below
  22.  
  23. Google_StreetView_Layer_Shortcut:'V',
  24.  
  25. Google_Labels_Layer_Shortcut:'G',
  26.  
  27. Google_Terrain_Layer_Shortcut:'T',
  28.  
  29. Google_Satellite_Layer_Shortcut:'B',
  30.  
  31. Apple_StreetView_Layer_Shortcut:'P',
  32.  
  33. Yandex_StreetView_Layer_Shortcut:'Y',
  34.  
  35. OpenWeather_Shortcut:'Q',
  36.  
  37. OpenWeather_Style:'radar', //'radar': Global Precipitation; 'CL':Cloud; 'APM':Pressure; 'TA2'Temperature; 'WS10':Wind Speed;
  38.  
  39. OpenWeather_Date:'now', // foramt:yyyy-mm-dd, less than one week ago
  40.  
  41. Bing_Maps_Style:'r', // 'a':satellite(without labels); 'h':hybrid; 'r':roadmap,'sre':terrain
  42.  
  43. Map_Tiler_Style:'basic', //basic,satellite,bright,landscape,ocean,outdoor,topo,streets,dataviz
  44.  
  45. Carto_Style:'light_all', //light_all,dark_all
  46.  
  47. Thunderforest_Style:'spinal-map'} //spinal-map,landscape,outdoors,atlas,transport,
  48.  
  49.  
  50. let tileServices=["Google_Maps","OpenStreetMap","Bing_Maps","Map_Tiler","Thunderforest","Carto","Yandex_Maps","Petal_Maps"]
  51.  
  52. let colorOptions={
  53.  
  54. Default:['1098ad','99e9f2'],
  55.  
  56. Crimson:['f03e3e','ffc9c9'],
  57.  
  58. Deep_Pink:['d6336c','fcc2d7'],
  59.  
  60. Blue_Violet:['ae3ec9','eebefa'],
  61.  
  62. Slate_Blue:['7048e8','d0bfff'],
  63.  
  64. Royal_Blue:['4263eb','bac8ff'],
  65.  
  66. Dodger_Blue: ['1c7ed6','a5d8ff'],
  67.  
  68. Sea_Green:['0ca678','96f2d7'],
  69.  
  70. Lime_Green:['37b24d','b2f2bb'],
  71.  
  72. OliveDrab:['74b816','d8f5a2'],
  73.  
  74. Orange:['f59f00','ffec99'],
  75.  
  76. Dark_Orange:['f76707','ffd8a8'],
  77.  
  78. Brown:['bd5f1b','f7ca9e'],
  79. }
  80.  
  81. /*======================================================================================================================================================================================*/
  82.  
  83. let map,google,customMapType,initLayer=tag
  84. let currentLayers=JSON.parse(localStorage.getItem('custom_layers'));
  85. if(!currentLayers){
  86. currentLayers=["Google_Maps","Google_Labels"]
  87. localStorage.setItem('custom_layers', JSON.stringify(currentLayers));
  88. }
  89.  
  90. const openWeatherBaseURL = "https://g.sat.owm.io/vane/2.0/weather";
  91. const radarURL = `https://b.sat.owm.io/maps/2.0/radar/{z}/{x}/{y}?appid=9de243494c0b295cca9337e1e96b00e2&day=${getNow(customOptions.OpenWeather_Date)}`;
  92.  
  93. const openWeatherURL = (customOptions.OpenWeather_Style === 'radar')
  94. ? radarURL
  95. : `${openWeatherBaseURL}/${customOptions.OpenWeather_Style}/{z}/{x}/{y}?appid=9de243494c0b295cca9337e1e96b00e2&&date=${getTimestamp(customOptions.OpenWeather_Date)}&fill_bound=true`;
  96.  
  97. let tileUrls = {
  98. Petal_Maps: `https://maprastertile-drcn.dbankcdn.cn/display-service/v1/online-render/getTile/24.12.10.10/{z}/{x}/{y}/?language=${customOptions.Language}&p=46&scale=2&mapType=ROADMAP&presetStyleId=standard&pattern=JPG&key=DAEDANitav6P7Q0lWzCzKkLErbrJG4kS1u%2FCpEe5ZyxW5u0nSkb40bJ%2BYAugRN03fhf0BszLS1rCrzAogRHDZkxaMrloaHPQGO6LNg==`,
  99. OpenStreetMap: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
  100. Map_Tiler:`https://api.maptiler.com/maps/${customOptions.Map_Tiler_Style}-v2/256/{z}/{x}/{y}.png?key=0epLOAjD7fw17tghcyee`,
  101. Thunderforest:`https://b.tile.thunderforest.com/${customOptions.Thunderforest_Style}/{z}/{x}/{y}@2x.png?apikey=6a53e8b25d114a5e9216df5bf9b5e9c8`,
  102. Carto:`https://cartodb-basemaps-3.global.ssl.fastly.net/${customOptions.Carto_Style}/{z}/{x}/{y}.png`,
  103. Google_Maps:`https://mapsresources-pa.googleapis.com/v1/tiles?map_id=61449c20e7fc278b&version=15797339025669136861&pb=!1m7!8m6!1m3!1i{z}!2i{x}!3i{y}!2i9!3x1!2m2!1e0!2sm!3m7!2s${customOptions.Language}!3sus!5e1105!12m1!1e3!12m1!1e2!4e0!5m5!1e0!8m2!1e1!1e1!8i47083502!6m6!1e12!2i2!11e0!39b0!44e0!50e0`,
  104. Google_Terrain:`https://mapsresources-pa.googleapis.com/v1/tiles?map_id=61449c20e7fc278b&version=15797339025669136861&pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e4!2st!3i725!2m3!1e0!2sr!3i725483392!3m12!2s${customOptions.Language}!3sUS!5e18!12m1!1e3!2m2!1sset!2sTerrain!12m3!1e37!2m1!1ssmartmaps!4e0!5m2!1e3!5f2!23i56565656!26m2!1e2!1e3`,
  105. Google_Satellite:`https://mts1.googleapis.com/vt?hl=${customOptions.Language}-US&lyrs=s&x={x}&y={y}&z={z}`,
  106. Google_StreetView:`https://maps.googleapis.com/maps/vt?pb=%211m5%211m4%211i{z}%212i{x}%213i{y}%214i256%212m8%211e2%212ssvv%214m2%211scc%212s*211m3*211e2*212b1*213e2*212b1*214b1%214m2%211ssvl%212s*212b1%213m17%212sen%213sUS%215e18%2112m4%211e68%212m2%211sset%212sRoadmap%2112m3%211e37%212m1%211ssmartmaps%2112m4%211e26%212m2%211sstyles%212ss.e%3Ag.f%7Cp.c%3A%23${colorOptions[customOptions.Google_StreetView_Layer_Lines_Style][0]}%7Cp.w%3A1%2Cs.e%3Ag.s%7Cp.c%3A%23${colorOptions[customOptions.Google_StreetView_Layer_Lines_Style][1]}%7Cp.w%3A3%215m1%215f1.35`,
  107. Google_Satellite_Road:`https://maps.googleapis.com/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m2!1e0!2sm!3m14!2s${customOptions.Language}!3sUS!5e18!12m4!1e68!2m2!1sset!2sRoadmapSatellite!12m3!1e37!2m1!1ssmartmaps!12m1!1e3!5m1!5f1.35`,
  108. Google_Hybrid_Labels:`https://www.google.com/maps/vt?pb=!1m7!8m6!1m3!1i{z}!2i{x}!3i{y}!2i9!3x1!2m2!1e0!2sm!3m7!2s${customOptions.Language}!3sus!5e1105!12m1!1e4!12m1!1e2!4e0!5m5!1e0!8m2!1e1!1e1!8i47083502!6m6!1e12!2i2!11e0!39b0!44e0!50e0`,
  109. Google_Labels:`https://maps.googleapis.com/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m2!1e0!2sm!3m17!2s${customOptions.Language}!3sUS!5e1105!12m4!1e68!2m2!1sset!2sRoadmap!12m3!1e37!2m1!1ssmartmaps!12m4!1e26!2m2!1sstyles!2ss.t:18|s.e:g.s|p.w:3,s.e:g|p.v:off,s.t:1|s.e:g.s|p.v:off,s.e:l|p.v:on!4i0!5m2!1e0!5f2`,
  110. Apple_StreetView:`https://lookmap.eu.pythonanywhere.com/bluelines_raster_2x/{z}/{x}/{y}.png`,
  111. Yandex_StreetView:`https://core-stv-renderer.maps.yandex.net/2.x/tiles?l=stv&x={x}&y={y}&z={z}&scale=1&v=2025.04.04.20.13-1_25.03.31-4-24330`,
  112. Yandex_Maps:`https://core-renderer-tiles.maps.yandex.net/tiles?l=map&v=5.04.07-2~b:250311142430~ib:250404100358-24371&x={x}&y={y}&z={z}&scale=1&lang=en_US`,
  113. OpenWeather: openWeatherURL
  114. }
  115.  
  116. function getMap(){
  117. let element = document.getElementsByClassName("guess-map_canvas__cvpqv")[0]
  118. if(!element) element=document.getElementsByClassName("run-game-guess-map-contents_canvas__XQRwC")[0]
  119. if(!element) return
  120. try{
  121. //if (!element) element=document.getElementsByClassName("coordinate-result-map_map__Yh2Il")[0]
  122. const keys = Object.keys(element)
  123.  
  124. const key = keys.find(key => key.startsWith("__reactFiber$"))
  125. const props = element[key]
  126. map=props.return.return.memoizedProps.map
  127. if(!map) map=props.return.memoizedState.memoizedState.current.instance
  128. google=unsafeWindow.google
  129. customMapType=setMapType()
  130. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  131. map.mapTypes.set("roadmap",layers)
  132. }
  133. catch(error){
  134. console.error('Failed to get map')
  135. }
  136. }
  137.  
  138. function OC(controlDiv, layer) {
  139. controlDiv.style.margin='10px'
  140. controlDiv.style.backgroundColor = '#fff';
  141. controlDiv.style.height = '30px';
  142. controlDiv.style.boxShadow = 'rgba(0, 0, 0, 0.3) 0px 1px 4px -1px';
  143. controlDiv.style.borderRadius = '5px';
  144.  
  145. var opacitySlider = document.createElement('input');
  146.  
  147. opacitySlider.setAttribute('type', 'range');
  148. opacitySlider.setAttribute('min', '0');
  149. opacitySlider.setAttribute('max', '100');
  150. opacitySlider.setAttribute('value', '100');
  151. opacitySlider.setAttribute('step', '1');
  152. opacitySlider.style.width = '100px';
  153. opacitySlider.style.height='20px'
  154. opacitySlider.style.marginTop='5px'
  155. opacitySlider.addEventListener('input', function() {
  156. var opacity = opacitySlider.value / 100
  157. layer.set('opacity',opacity)
  158. });
  159.  
  160. controlDiv.appendChild(opacitySlider);
  161. }
  162.  
  163. function addOpacityControl(m, layer) {
  164. var opacityControlDiv = document.createElement('div');
  165. new OC(opacityControlDiv, layer);
  166. opacityControlDiv.id=layer.name
  167. opacityControlDiv.index = 1;
  168. m.controls[google.maps.ControlPosition.TOP_RIGHT].push(opacityControlDiv);
  169. }
  170.  
  171. function removeOpacityControl(id) {
  172. var controls = map.controls[google.maps.ControlPosition.TOP_RIGHT];
  173. if(controls&&controls.getLength()>0){
  174. if(!id) controls.removeAt(0)
  175. else{
  176. for (var i = 0; i < controls.getLength(); i++) {
  177. var control = controls.getAt(i);
  178. if (control.id === id) {
  179. controls.removeAt(i);
  180. break;
  181. }
  182. }
  183. }
  184. }
  185. }
  186.  
  187. function MR(e, t) {
  188. return new Promise(n => {
  189. google.maps.event.addListenerOnce(e, t, n);
  190. });
  191. }
  192.  
  193. function getNow(date) {
  194. if(date!='now'){
  195. return date
  196. }
  197. const now = new Date();
  198. now.setHours(now.getHours() - 1);
  199. return now.toISOString().slice(0, 14)+'00';
  200. }
  201.  
  202. function getTimestamp(date){
  203. var parsedDate
  204. if (date=== 'now') {
  205. parsedDate= new Date()
  206. return Math.floor(parsedDate.getTime() / 1000)
  207. }
  208. parsedDate = new Date(date);
  209.  
  210. if (isNaN(parsedDate.getTime())) {
  211. throw new Error('Invalid date format');
  212. }
  213. return Math.floor(parsedDate.getTime() / 1000);
  214.  
  215. }
  216.  
  217. function extractTileCoordinates(url) {
  218. const regex = /!1i(\d+)!2i(\d+)!3i(\d+)!4i(\d+)/;
  219. const matches = url.match(regex);
  220.  
  221. if (matches && matches.length === 5) {
  222. const z = matches[1];
  223. const x = matches[2];
  224. const y = matches[3];
  225. return { z, x, y };
  226. } else {
  227. return null;
  228. }
  229. }
  230.  
  231. function BaiduProjection() {
  232. var R = 6378206;
  233. var R_MINOR = 6356584.314245179;
  234. var bounds = new google.maps.LatLngBounds(
  235. new google.maps.LatLng(-19994619.55417086, -20037725.11268234),
  236. new google.maps.LatLng(19994619.55417086, 20037725.11268234)
  237. );
  238.  
  239. this.fromLatLngToPoint = function(latLng) {
  240.  
  241. var lat = latLng.lat() * Math.PI / 180;
  242. var lng = latLng.lng() * Math.PI / 180;
  243.  
  244. var x = lng * R;
  245. var y = Math.log(Math.tan(Math.PI / 4 + lat / 2)) * R;
  246.  
  247. var scale = 1 / Math.pow(2, 18);
  248. var origin = new google.maps.Point(bounds.getSouthWest().lng(), bounds.getNorthEast().lat());
  249. return new google.maps.Point(
  250. (x - origin.x) * scale,
  251. (origin.y - y) * scale
  252. );
  253. };
  254.  
  255. this.fromPointToLatLng = function(point) {
  256. var scale = 1 / Math.pow(2, 18);
  257. var origin = new google.maps.Point(bounds.getSouthWest().lng(), bounds.getNorthEast().lat());
  258.  
  259. var x = point.x / scale + origin.x;
  260. var y = origin.y - point.y / scale;
  261.  
  262. var lng = x / R * 180 / Math.PI;
  263. var lat = (2 * Math.atan(Math.exp(y / R)) - Math.PI / 2) * 180 / Math.PI;
  264.  
  265. return new google.maps.LatLng(lat, lng);
  266. };
  267.  
  268. return this;
  269. }
  270.  
  271. function getBingTiles(tileX, tileY, zoom, type) {
  272. var quadKey = tileXYToQuadKey(tileX, tileY, zoom);
  273. if(type==='cn'){
  274. const subdomains = ['r1', 'r2', 'r0', 'r3'];
  275. const subdomain = subdomains[(tileX + tileY) % subdomains.length];
  276. const baseUrl=`https://t.ssl.ak.dynamic.tiles.virtualearth.net/comp/ch/${quadKey}?mkt=${customOptions.Language}-Us&ur=cn&it=G,LC,L&jp=1&og=2618&sv=9.33&n=t&dre=1&o=webp,95&cstl=s23&st=bld|v:0`
  277. return baseUrl
  278. }
  279. else{
  280.  
  281. const subdomains = ['ecn.t0', 'ecn.t1', 'ecn.t2', 'ecn.t3'];
  282.  
  283. const subdomain = subdomains[(tileX + tileY) % subdomains.length];
  284. const baseUrl = `https://${subdomain}.tiles.virtualearth.net/tiles/`;
  285.  
  286. return baseUrl + type + quadKey + '.jpeg?g=14792';}
  287. }
  288.  
  289. function tileXYToQuadKey(tileX, tileY, zoom) {
  290. var quadKey = '';
  291. for (var i = zoom; i > 0; i--) {
  292. var digit = 0;
  293. var mask = 1 << (i - 1);
  294. if ((tileX & mask) !== 0) {
  295. digit += 1;
  296. }
  297. if ((tileY & mask) !== 0) {
  298. digit += 2;
  299. }
  300. quadKey += digit.toString();
  301. }
  302. return quadKey;
  303. }
  304.  
  305. function setMapType(){
  306. class customMapType extends google.maps.ImageMapType {
  307. constructor(layers, options = null) {
  308. const defaultOptions = {
  309. getTileUrl: function(coord, zoom) {
  310. return null;
  311. },
  312. tileSize: new google.maps.Size(256, 256),
  313. maxZoom: 20,
  314. name: 'CustomMapType',
  315. };
  316.  
  317.  
  318. super({...defaultOptions, ...options});
  319. this.layers = layers;
  320. }
  321.  
  322. getTile(t, n, r) {
  323. const o = this.layers.map(i => {
  324. if (typeof i.getTile !== 'function') {
  325. console.error('getTile method is missing in layer:', i);
  326. }
  327. return i.getTile(t, n, r);
  328. });
  329. const s = document.createElement("div");
  330. s.append(...o);
  331.  
  332. Promise.all(o.map(i => MR(i, "load"))).then(() => {
  333. google.maps.event.trigger(s, "load");
  334. });
  335.  
  336. return s;
  337. }
  338.  
  339.  
  340. releaseTile(tile) {
  341. let index = 0;
  342. for (const child of tile.children) {
  343. if (child instanceof HTMLElement) {
  344. this.layers[index]?.releaseTile(child);
  345. index += 1;
  346. }
  347. }
  348. }
  349. }
  350. return customMapType
  351. }
  352.  
  353. function setTileLayer(layerName){
  354.  
  355. var tileLayer
  356. const tileUrl = tileUrls[layerName];
  357. if (layerName==='Bing_Maps'){
  358. tileLayer = new google.maps.ImageMapType({
  359. getTileUrl: function(coord, zoom) {
  360. return getBingTiles(coord.x,coord.y,zoom,customOptions.Bing_Maps_Style)
  361. .replace('{z}', zoom)
  362. .replace('{x}', coord.x)
  363. .replace('{y}', coord.y);
  364. },
  365. tileSize: new google.maps.Size(256, 256),
  366. name: layerName,
  367. maxZoom:20
  368. });}
  369. else if(layerName==='Bing_Terrain'){
  370. tileLayer = new google.maps.ImageMapType({
  371. getTileUrl: function(coord, zoom) {
  372. if(zoom>15) return ``
  373. return getBingTiles(coord.x,coord.y,zoom,'sre')
  374. .replace('{z}', zoom)
  375. .replace('{x}', coord.x)
  376. .replace('{y}', coord.y);
  377. },
  378. tileSize: new google.maps.Size(256, 256),
  379. name: layerName,
  380. maxZoom:15
  381. });}
  382. else if(layerName==='Bing_Maps_CN'){
  383. tileLayer = new google.maps.ImageMapType({
  384. getTileUrl: function(coord, zoom) {
  385. return getBingTiles(coord.x,coord.y,zoom,'cn')
  386. .replace('{z}', zoom)
  387. .replace('{x}', coord.x)
  388. .replace('{y}', coord.y);
  389. },
  390. tileSize: new google.maps.Size(256, 256),
  391. name: layerName,
  392. maxZoom:20
  393. });}
  394. else{
  395. tileLayer = new google.maps.ImageMapType({
  396. getTileUrl: function(coord, zoom) {
  397. return tileUrl
  398. .replace('{z}', zoom)
  399. .replace('{x}', coord.x)
  400. .replace('{y}', coord.y);
  401. },
  402. tileSize: new google.maps.Size(256, 256),
  403. name:layerName,
  404. maxZoom:20,
  405. })}
  406. if (layerName.includes('StreetView') || layerName.includes('Weather')) {
  407. if (!document.getElementById(layerName)) addOpacityControl(map, tileLayer);
  408. }
  409. return tileLayer
  410. }
  411.  
  412. function resetGoogle(){
  413. currentLayers[0]='Google_Maps'
  414. if(!currentLayers.includes('Google_Labels'))currentLayers.push('Google_Labels')
  415. currentLayers = currentLayers.filter(layer => layer !== 'Google_Hybrid_Labels')
  416. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  417. map.mapTypes.set("roadmap",layers)
  418. }
  419.  
  420. let onKeyDown = (e) => {
  421. if ( e.target.tagName === 'TEXTAREA' || e.target.isContentEditable) return
  422. if (e.key >= '1' && e.key <= '7') {
  423. e.stopImmediatePropagation();
  424. if(!map) getMap()
  425. const tileIndex=parseInt(e.key)
  426. const layerName=tileServices[tileIndex]
  427. if(!currentLayers.includes(layerName)){
  428. initLayer(`layer:${layerName}`)
  429. currentLayers[0]=layerName
  430. currentLayers = currentLayers.filter(layer => layer!== 'Google_Labels'&&layer!== 'Google_Hybrid_Labels')
  431. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  432. map.mapTypes.set("roadmap",layers)
  433. }
  434.  
  435. else resetGoogle()
  436. }
  437.  
  438. else if (e.key === '0') resetGoogle()
  439.  
  440. else if (e.key === customOptions.Google_StreetView_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_StreetView_Layer_Shortcut) {
  441. e.stopImmediatePropagation();
  442. if(!map) getMap()
  443. initLayer(`layer:Google_StreetView`)
  444. if(!currentLayers.includes('Google_StreetView')){
  445. currentLayers.splice(1, 0, 'Google_StreetView');
  446. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  447. map.mapTypes.set("roadmap",layers)
  448. }
  449. else{currentLayers = currentLayers.filter(layer => layer !== 'Google_StreetView')
  450. removeOpacityControl('Google_StreetView')
  451. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  452. map.mapTypes.set("roadmap",layers)}
  453. }
  454.  
  455. else if (e.key === customOptions.Apple_StreetView_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Apple_StreetView_Layer_Shortcut) {
  456. e.stopImmediatePropagation();
  457. if(!map) getMap()
  458. if(!currentLayers.includes('Apple_StreetView')){
  459. initLayer(`layer:Apple_StreetView`)
  460. currentLayers.splice(1, 0, 'Apple_StreetView');
  461. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  462. map.mapTypes.set("roadmap",layers)
  463. }
  464. else{currentLayers = currentLayers.filter(layer => layer !== 'Apple_StreetView')
  465. removeOpacityControl('Apple_StreetView')
  466. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  467. map.mapTypes.set("roadmap",layers)}
  468. }
  469.  
  470. else if (e.key === customOptions.Yandex_StreetView_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Yandex_StreetView_Layer_Shortcut) {
  471. e.stopImmediatePropagation();
  472. if(!map) getMap()
  473. initLayer(`layer:Yandex_StreetView`)
  474. if(!currentLayers.includes('Yandex_StreetView')){
  475. currentLayers.splice(1, 0, 'Yandex_StreetView');
  476. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  477. map.mapTypes.set("roadmap",layers)
  478. }
  479. else{currentLayers = currentLayers.filter(layer => layer !== 'Yandex_StreetView')
  480. removeOpacityControl('Yandex_StreetView')
  481. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  482. map.mapTypes.set("roadmap",layers)}
  483. }
  484.  
  485. else if (e.key === customOptions.Google_Labels_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_Labels_Layer_Shortcut) {
  486. e.stopImmediatePropagation();
  487. if(!map) getMap()
  488. initLayer(`layer:Google_Labels`)
  489. if(!currentLayers.includes('Google_Labels')&&!currentLayers.includes('Google_Hybrid_Labels')){
  490. currentLayers.includes('Google_Satellite')?currentLayers.push('Google_Hybrid_Labels'):currentLayers.push('Google_Labels');
  491. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)))
  492. map.mapTypes.set("roadmap",layers)}
  493.  
  494. else{currentLayers = currentLayers.filter(layer => layer !== 'Google_Labels'&&layer !== 'Google_Hybrid_Labels')
  495. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)))
  496. map.mapTypes.set("roadmap",layers)}
  497. }
  498.  
  499. else if (e.key === customOptions.Google_Terrain_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_Terrain_Layer_Shortcut) {
  500. e.stopImmediatePropagation();
  501. if(!map) getMap()
  502. initLayer(`layer:Google_Terrain`)
  503. if(!currentLayers.includes('Google_Terrain')){
  504. currentLayers[0]='Google_Terrain'
  505. if(!currentLayers.includes('Google_Labels'))currentLayers.push('Google_Labels')
  506. currentLayers = currentLayers.filter(layer => layer !== 'Google_Hybrid_Labels')
  507. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  508. map.mapTypes.set("roadmap",layers)}
  509.  
  510. else resetGoogle()
  511. }
  512.  
  513. else if (e.key === customOptions.Google_Satellite_Layer_Shortcut.toLowerCase()|| e.key === customOptions.Google_Satellite_Layer_Shortcut) {
  514. e.stopImmediatePropagation();
  515. if(!map) getMap()
  516. initLayer(`layer:Google_Satellite`)
  517. if(!currentLayers.includes('Google_Satellite')){
  518. currentLayers[0]='Google_Satellite'
  519. if(!currentLayers.includes('Google_Hybrid_Labels'))currentLayers.push('Google_Hybrid_Labels')
  520. currentLayers = currentLayers.filter(layer => layer !== 'Google_Labels')
  521. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  522. map.mapTypes.set("roadmap",layers)}
  523.  
  524. else resetGoogle()
  525. }
  526.  
  527. else if (e.key === customOptions.OpenWeather_Shortcut.toLowerCase()|| e.key === customOptions.OpenWeather_Shortcut) {
  528. e.stopImmediatePropagation();
  529. if(!map) getMap()
  530. if(!currentLayers.includes('OpenWeather')){
  531. initLayer(`layer:OpenWeather`)
  532. currentLayers.splice(1, 0, 'OpenWeather');
  533. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  534. map.mapTypes.set("roadmap",layers)
  535. }
  536.  
  537. else{currentLayers = currentLayers.filter(layer => layer !== 'OpenWeather')
  538. removeOpacityControl('OpenWeather')
  539. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  540. map.mapTypes.set("roadmap",layers)}
  541. }
  542.  
  543. else if (e.key === 'e'|| e.key ==='E') {
  544. if(!map) getMap()
  545. e.stopImmediatePropagation();
  546. currentLayers=['Google_Maps_new']
  547. const layers =new customMapType(currentLayers.map(layerName => setTileLayer(layerName)));
  548. map.mapTypes.set("roadmap",layers)
  549. }
  550.  
  551. localStorage.setItem('custom_layers', JSON.stringify(currentLayers));
  552. map.setMapTypeId("roadmap")
  553. }
  554.  
  555. document.addEventListener("keydown", onKeyDown);
  556. const intervalId = setInterval(() => {
  557. getMap();
  558. if (map) {
  559. clearInterval(intervalId)}
  560. }, 500);
  561.  
  562. })();