您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
use openstreetmap to navigate wplace faster! press M to pull up the map, and right click to visit that place
// ==UserScript== // @name wplace - simple map browser // @namespace http://pawing.cv // @version v1.2 // @description use openstreetmap to navigate wplace faster! press M to pull up the map, and right click to visit that place // @author cv // @match https://wplace.live/* // @grant GM_openInTab // @grant GM_setValue // @grant GM_getValue // ==/UserScript== (function() { 'use strict'; // i promise the comment hiding the actual html is eye candy and not done with malicious intent 😇 (i mean, you can see the exact code it's inserting below) function openmap() { let popupcode = `<!--wplace.live-map-----------------------------------------------------------------------------------> <!DOCTYPE html> <html lang="en"> <head> <title>OpenStreetMap</title> <meta charset="utf-8"> <meta http-equiv="Content-Security-Policy" content="default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"> <style> @import url("https://fonts.googleapis.com/css2?family=Geist:[email protected]&display=swap"); html, body { height: 100%; line-height: 1; margin: 0; padding: 0; font-family: "Geist", ui-sans-serif, system-ui, sans-serif !important; } #loading { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #f2f7fe; padding: 20px; border-radius: 32px; font-size: 16px; font-weight: 500; color: #394e6a; box-shadow: 0 5px 16px 0 rgba(0,0,0,0.1); z-index: 1000; } .map { height: 100%; width: 100%; display: none; } a, span, p, li, input, ul { font-family: Geist, ui-sans-serif, system-ui, sans-serif !important; user-select: none; } .coords, .small {user-select: all !important} .info { display: flex; flex-direction: row; position: fixed; justify-content: center; align-items: center; top: 1em; left: 50%; transform: translateX(-50%); background: #f2f7fe; padding: 10px; border-radius: 32px; font-size: 13.5px; font-weight: 700; z-index: 1000; box-shadow: 0 5px 16px 0 rgba(0,0,0,0.1); color: #394e6a; pointer-events: none; user-select: none; display: none; } .info svg { padding-left: 3px; padding-right: 2px; width: 15px; } .coords { display: flex; flex-direction: column; position: fixed; width: 300px; bottom: 1em; left: 50%; transform: translateX(-50%); background: #f2f7fe; display: none; padding: 20px; border-radius: 32px; font-size: 18px; z-index: 1000; font-weight: 500; box-shadow: 0 5px 16px 0 rgba(0,0,0,0.1); color: #394e6a; } .small { font-size: 13px; color: #394e6a; opacity: 0.5; } /* Leaflet control styling */ div.leaflet-control-container > div.leaflet-top.leaflet-left > div { border: none; } div.leaflet-control-container > div.leaflet-top.leaflet-left > div > a { display: flex; flex-direction: column; background: #f2f7fe; border-radius: 32px; margin-bottom: 3px; font-size: 13px; box-shadow: 0 5px 16px 0 rgba(0,0,0,0.1); color: #394e6a; } div.leaflet-top.leaflet-right * { border: none; } div.leaflet-top.leaflet-right > div > button, div.leaflet-top.leaflet-right > div { display: flex; flex-direction: column; background: #f2f7fe; border-radius: 32px; margin-bottom: 3px; color: #394e6a; } div.leaflet-top.leaflet-right > div > button { display: none; } div.leaflet-top.leaflet-right > div > div.leaflet-control-geocoder-form { display: inline-block; width: 200px; padding: 10px; box-shadow: 0 5px 16px 0 rgba(0,0,0,0.1); } div.leaflet-top.leaflet-right > div > .leaflet-control-geocoder-alternatives { border-radius: 1px; padding: 10px; } div.leaflet-top.leaflet-right > div:has(.leaflet-control-geocoder-alternatives:not([style*="display: none"])) > .leaflet-control-geocoder-form { box-shadow: none !important; } body > div.map.leaflet-container.leaflet-touch.leaflet-fade-anim.leaflet-grab.leaflet-touch-drag.leaflet-touch-zoom > div.leaflet-control-container > div.leaflet-bottom.leaflet-right { display: none !important; } .leaflet-control-geocoder-form-no-error { text-align: center; color: rgb(179, 97, 97) !important; padding-bottom: 10px; } </style> </head> <body> <div id="loading">Loading map...</div> <div class="info">Choose a location with <svg alt="Right Click" fill="#394e6a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52"><path d="M38 0h4v6h-4V0Zm9 1 4 2c-2 4-2 4-7 5 1-5 1-5 3-7ZM36 5c8 6 9 12 9 22v6c-2 10-5 14-14 19-10 1-16 1-23-6-4-7-5-11-5-19v-6C5 4 21-3 36 5ZM9 17l-1 9h14V7c-7 0-10 5-13 10ZM8 30c2 9 3 13 11 17 11 0 14-1 20-10l1-7H8Zm38-20h6v4h-6v-4Z"/></svg>!</div> <div class="coords"></div> <div class="map" style="width:100%;height:100%"></div> <script> function newcss(url) { return new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = url; link.onload = resolve; link.onerror = reject; document.head.appendChild(link); }); } function newjs(url) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = url; script.onload = resolve; script.onerror = reject; document.head.appendChild(script); }); } async function bootmap() { try { await newcss('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css'); await newjs('https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js'); await newcss('https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css'); await newjs('https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js'); document.getElementById('loading').style.display = 'none'; document.querySelector('.map').style.display = 'block'; document.querySelector('.info').style.display = 'flex'; document.addEventListener("contextmenu", function(e) {e.preventDefault()}); var map = L.map(document.querySelector(".map"), { worldCopyJump: false, continuousWorld: false }).setView([0, 0], 1); map.setMaxBounds([[-85.05112878, -180], [85.05112878, 180]]); L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {noWrap: true}).addTo(map); map.on('drag', function() { if (!map.getBounds().intersects(map.options.maxBounds)) { map.panInsideBounds(map.options.maxBounds, { animate: false }); } }); L.Control.geocoder({ geocoder: L.Control.Geocoder.nominatim() }).addTo(map); var lastlatlng = null; map.on("mousemove", function(e) { lastlatlng = e.latlng; var lat = e.latlng.lat; var lng = e.latlng.lng; var zoom = map.getZoom(); var tile_count = 2048; var tile_size = 1000; var pixel_count = tile_count * tile_size; var x = (lng + 180) / 360; var sinlat = Math.sin(lat * Math.PI / 180); var y = 0.5 - Math.log((1 + sinlat) / (1 - sinlat)) / (4 * Math.PI); x = Math.min(1, Math.max(0, x)); y = Math.min(1, Math.max(0, y)); var px = x * (pixel_count - 1); var py = y * (pixel_count - 1); var t_x = Math.floor(px / tile_size); var t_y = Math.floor(py / tile_size); var p_x = Math.floor(px % tile_size); var p_y = Math.floor(py % tile_size); document.querySelector(".coords").innerHTML = lat.toFixed(6) + ", " + lng.toFixed(6) + " [x" + zoom + "] " + "<br><span class='small'>" + t_x + ", " + t_y + " // " + p_x + ", " + p_y + "</span>"; var coords = document.querySelector(".coords"); if (coords.innerHTML.trim() !== "") { coords.style.display = "flex"; } else { coords.style.display = "none"; } }); document.querySelector(".map").addEventListener("contextmenu", function(ev) { ev.preventDefault(); if (lastlatlng) { var osmzoom = map.getZoom(); var wplacezoom = Math.max(1, Math.min(19, osmzoom)); var wplaceUrl = 'https://wplace.live/?lat=' + lastlatlng.lat + '&lng=' + lastlatlng.lng + '&zoom=' + wplacezoom; window.open(wplaceUrl, '_blank'); window.close(); } }); } catch (error) { document.getElementById('loading').textContent = 'Error loading map: ' + error.message; console.error('map load error!', error); } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', bootmap); } else {bootmap()} </script> </body> </html>`; // the ENTIRE page has to fit inside a data url, since: // - blob:https://wplace.live inherits wplace.live's csp // - about:blank, uh, doesn't work either, fuck if (typeof GM_openInTab !== 'undefined') { const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(popupcode); GM_openInTab(dataUrl, { active: true }); } else { const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(popupcode); const newTab = window.open(dataUrl, '_blank'); if (!newTab) { alert("please allow popups for wplace.live.."); } } } // that isn't an absurd workaround, is it? no? thank god function cleanlink() { const cleanlink = new URL(window.location.href); cleanlink.searchParams.delete('lat'); cleanlink.searchParams.delete('lng'); cleanlink.searchParams.delete('zoom'); window.history.replaceState({}, '', cleanlink.pathname + cleanlink.search + cleanlink.hash); } window.addEventListener('DOMContentLoaded', function() { const url = new URL(window.location.href); if (url.searchParams.has('lat') || url.searchParams.has('lng') || url.searchParams.has('zoom')) { cleanlink(); } }); document.addEventListener('keydown', function(e) { if (e.key === 'M' || e.key === 'm') { openmap(); } }); })();