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

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址