您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
use shortcut to help you mapping on map-making app
// ==UserScript== // @name Map-Making Shortcuts // @namespace https://gf.qytechs.cn/users/1179204 // @description use shortcut to help you mapping on map-making app // @version 1.4.0 // @license BSD // @author KaKa // @match *://map-making.app/maps/* // @grant GM_addStyle // @icon https://www.svgrepo.com/show/521871/switch.svg // ==/UserScript== (function(){ /* ------------------------------------------------------------------------------- */ /* ----- KEYBOARD SHORTCUTS (MUST Refresh PAGE FOR CHANGES TO TAKE EFFECT) -------- */ /* ------------------------------------------------------------------------------- */ const KEYBOARD_SHORTCUTS = { // Single key switchLoc: 'Q', rewindLoc: 'E', deleteLoc: 'C', closeAndSaveLoc: 'V', copyLoc:'G', hideElement:'H', deSelectAll:'Z', pruneDuplicates:'P', tagDialog:'T', // SHIFT key is need deleteTags:'B', resetGulf:'M', classicMap:'N', findLinkPanos:'K', exportAsCsv: 'D', fullScreenMap:'F', }; /* ############################################################################### */ /* ##### DON'T MODIFY ANYTHING BELOW HERE UNLESS YOU KNOW WHAT YOU ARE DOING ##### */ /* ############################################################################### */ let selections,currentIndex let mapListener let isDrawing, isShift,isCtrl,isApplied,isASV,isYSV,isHidden,isOpen,refreshScheduled let startX, startY, endX, endY let selectionBox let style let actionIndex=-1 let currentNumberKey = null; let shiftPressed = false; let overlay = null; let originalParent = null; let originalNextSibling = null; let tagContainer = null; let shortcuts = loadShortcuts(); GM_addStyle(` .tag[data-shortcut-bound] { box-shadow: inset 0 0 0 3px rgb(0, 102, 255) !important; } `) function exportAsCsv(locs){ const csvContent = jsonToCSV(locs); downloadCSV(csvContent); } function downloadCSV(csvContent, fileName = "output.csv") { const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); if (link.download !== undefined) { const url = URL.createObjectURL(blob); link.setAttribute('href', url); link.setAttribute('download', fileName); link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } } function getTagsForRow(item, maxTags) { const tags = item.tags || []; return Array.from({ length: maxTags }, (_, index) => tags[index] || ''); } function getFormattedDate(dateStr) { if (!dateStr) return ''; const date = new Date(dateStr); if (isNaN(date.getTime())) return ''; const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); return `${year}-${month}`; } function getMaxTagCount(jsonData) { let maxTags = 0; jsonData.forEach(item => { if (item.tags && item.tags.length > maxTags) { maxTags = item.tags.length; } }); return maxTags; } function jsonToCSV(jsonData) { const maxTags = getMaxTagCount(jsonData); const tagHeaders = Array.from({ length: maxTags }, (_, i) => `tag${i + 1}`); const headers = ["lat", "lng", "panoId", "heading", "pitch", "zoom", "date", ...tagHeaders]; const rows = jsonData.map(item => { const lat = item.location.lat|| ''; const lng = item.location.lng|| ''; const panoId = item.panoId|| ''; const heading = item.heading|| ''; const pitch = item.pitch|| ''; const zoom = item.zoom || ''; const date = getFormattedDate(item.panoDate)||''; const tags = getTagsForRow(item, maxTags); return [ lat, lng, panoId, heading, pitch, zoom, date, ...tags ]; }); const csvContent = [headers, ...rows].map(row => row.join(",")).join("\n"); return csvContent; } function switchLoc(locs) { const isReview = document.querySelector('.review-header'); if(isReview){ const nextBtn = document.querySelector('[data-qa="review-next"]'); if (nextBtn) { nextBtn.click(); } } else{ if(editor.currentLocation) editor.closeLocation(editor.currentLocation.updatedProps) if (!currentIndex) { currentIndex =1; } else { currentIndex +=1 if (currentIndex>locs.length){ currentIndex=1 } } editor.openLocation(locs[currentIndex-1]); focusOnLoc(locs[currentIndex-1]) } } function rewindLoc(locs) { const isReview = document.querySelector('.review-header'); if(isReview){ const prevBtn = document.querySelector('[data-qa="review-prev"]'); if (prevBtn) { prevBtn.click(); } } else{ if(editor.currentLocation) editor.closeLocation(editor.currentLocation.updatedProps) if (!currentIndex) { currentIndex =1; } else { currentIndex -=1 if (currentIndex<1) currentIndex=locs.length } editor.openLocation(locs[currentIndex-1]); //focusOnLoc(locs[currentIndex-1]) } } function focusOnLoc(loc){ map.setCenter(loc.location) map.setZoom(16) } function deleteLoc(loc){ const isReview = document.querySelector('.review-header'); if (isReview) { const deleteButton = document.querySelector('[data-qa="location-delete"]'); if (deleteButton) { deleteButton.click(); } } else editor.closeAndDeleteLocation(loc) } function copyLoc(){ editor.addLocation(editor.currentLocation.updatedProps) } function closeAndSaveLoc(){ const isReview = document.querySelector('.review-header'); if (isReview) { const saveButton = document.querySelector('[data-qa="location-save"]'); if (saveButton) { saveButton.click(); } } else editor.closeLocation(editor.currentLocation.updatedProps) } function setZoom(z){ if(z<0)z=0 if(z>4)z=4 const svControl=unsafeWindow.streetView svControl.setZoom(z) } function deleteTags() { let selections = editor.selections; while (selections.length > 0) { const item = selections[0]; const tag = JSON.parse(item.key); const tagName = tag.tagName; const locations = item.locations; editor.deleteTag(tagName, locations); selections = editor.selections; } } function customLayer(name,tileUrl,maxZoom,minZoom){ return new google.maps.ImageMapType({ getTileUrl: function(coord, zoom) { return tileUrl .replace('{z}', zoom) .replace('{x}', coord.x) .replace('{y}', coord.y); }, tileSize: new google.maps.Size(256, 256), name: name, maxZoom:maxZoom, minZoom:minZoom||1 }); } function classicMap(){ var tileUrl = `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!2szh!3sCN!5e1105!12m1!1e3!12m1!1e2!4e0!5m5!1e0!8m2!1e1!1e1!8i47083502!6m6!1e12!2i2!11e0!39b0!44e0!50e0` const tileLayer=customLayer('google_labels_reset',tileUrl,20) map.mapTypes.stack.layers[0]=tileLayer map.setMapTypeId('stack') } function resetGulf(){ var tileUrl = `https://maps.googleapis.com/maps/vt?pb=%211m5%211m4%211i{z}%212i{x}%213i{y}%214i256%212m2%211e0%212sm%213m17%212sen%213sMX%215e18%2112m4%211e68%212m2%211sset%212sRoadmap%2112m3%211e37%212m1%211ssmartmaps%2112m4%211e26%212m2%211sstyles%212ss.e%3Ag%7Cp.v%3Aoff%2Cs.t%3A1%7Cs.e%3Ag.s%7Cp.v%3Aon%2Cs.e%3Al%7Cp.v%3Aon%215m1%215f1.350000023841858` if(JSON.parse(localStorage.getItem('mapBoldCountryBorders')))tileUrl=`https://maps.googleapis.com/maps/vt?pb=%211m5%211m4%211i{z}%212i{x}%213i{y}%214i256%212m2%211e0%212sm%213m17%212sen%213smx%215e18%2112m4%211e68%212m2%211sset%212sRoadmap%2112m3%211e37%212m1%211ssmartmaps%2112m4%211e26%212m2%211sstyles%212ss.t%3A17%7Cs.e%3Ag.s%7Cp.w%3A2%7Cp.c%3A%23000000%2Cs.e%3Ag%7Cp.v%3Aoff%2Cs.t%3A1%7Cs.e%3Ag.s%7Cp.v%3Aon%2Cs.e%3Al%7Cp.v%3Aon%215m1%215f1.350000023841858` if(JSON.parse(localStorage.getItem('mapBoldSubdivisionBorders')))tileUrl=`https://maps.googleapis.com/maps/vt?pb=%211m5%211m4%211i{z}%212i{x}%213i{y}%214i256%212m2%211e0%212sm%213m17%212sen%213smx%215e18%2112m4%211e68%212m2%211sset%212sRoadmap%2112m3%211e37%212m1%211ssmartmaps%2112m4%211e26%212m2%211sstyles%212ss.t%3A18%7Cs.e%3Ag.s%7Cp.w%3A3%2Cs.e%3Al%7Cp.v%3Aoff%2Cs.t%3A1%7Cs.e%3Ag.s%7Cp.v%3Aoff%215m1%215f1.350000023841858` if(JSON.parse(localStorage.getItem('mapBoldSubdivisionBorders'))&&JSON.parse(localStorage.getItem('mapBoldCountryBorders')))tileUrl=`https://maps.googleapis.com/maps/vt?pb=%211m5%211m4%211i{z}%212i{x}%213i{y}%214i256%212m2%211e0%212sm%213m17%212sen%213smx%215e18%2112m4%211e68%212m2%211sset%212sRoadmap%2112m3%211e37%212m1%211ssmartmaps%2112m4%211e26%212m2%211sstyles%212ss.t%3A17%7Cs.e%3Ag.s%7Cp.w%3A2%7Cp.c%3A%23000000%2Cs.t%3A18%7Cs.e%3Ag.s%7Cp.w%3A3%2Cs.e%3Ag%7Cp.v%3Aoff%2Cs.t%3A1%7Cs.e%3Ag.s%7Cp.v%3Aon%2Cs.e%3Al%7Cp.v%3Aon%215m1%215f1.350000023841858` const tileLayer=customLayer('google_labels_reset',tileUrl,20) map.mapTypes.stack.layers[2]=tileLayer map.setMapTypeId('stack') } function setHW(){ map.mapTypes.stack.layers.splice(2, 1) const tileUrl = `https://maprastertile-drcn.dbankcdn.cn/display-service/v1/online-render/getTile/24.12.10.10/{z}/{x}/{y}/?language=zh&p=46&scale=2&mapType=ROADMAP&presetStyleId=standard&pattern=JPG&key=DAEDANitav6P7Q0lWzCzKkLErbrJG4kS1u%2FCpEe5ZyxW5u0nSkb40bJ%2BYAugRN03fhf0BszLS1rCrzAogRHDZkxaMrloaHPQGO6LNg==` const tileLayer=customLayer('Petal_Maps',tileUrl,20) map.mapTypes.stack.layers[0]=tileLayer map.setMapTypeId('stack') } function setGD(){ const tileUrl = `https://t2.tianditu.gov.cn/ter_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=75f0434f240669f4a2df6359275146d2` const tileLayer=customLayer('GaoDe_Terrain',tileUrl,20) //map.mapTypes.stack.layers[0]=tileLayer const tileUrl_ = `https://t2.tianditu.gov.cn/ibo_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ibo&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=75f0434f240669f4a2df6359275146d2` const tileLayer_=customLayer('GaoDe_Border',tileUrl_,10) map.mapTypes.stack.layers[1]=tileLayer_ const _tileUrl = `https://t2.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILECOL={x}&TILEROW={y}&TILEMATRIX={z}&tk=75f0434f240669f4a2df6359275146d2` const _tileLayer=customLayer('GaoDe_Labels',_tileUrl,20) //map.mapTypes.stack.layers[2]=_tileLayer map.setMapTypeId('stack') } function setYandex(){ const svUrl=`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` const baseUrl=`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` const svLayer=customLayer('Yandex_StreetView',svUrl,20,5) const baseLayer=customLayer('Yandex_Maps',baseUrl,20,1) map.mapTypes.stack.layers.splice(2, 0,svLayer) map.mapTypes.stack.layers.splice(2, 0,baseLayer) map.mapTypes.set("stack",map.mapTypes.stack.layers) map.setMapTypeId('stack') } function setApple(){ const svUrl=`https://lookmap.eu.pythonanywhere.com/bluelines_raster_2x/{z}/{x}/{y}.png` const svLayer=customLayer('Apple_StreetView',svUrl,16) map.mapTypes.stack.layers.splice(2, 0,svLayer) map.setMapTypeId('stack') } function getBingTilesUrl(tileX, tileY, zoom, type) { var quadKey = tileXYToQuadKey(tileX, tileY, zoom); const tileUrl=`https://t.ssl.ak.dynamic.tiles.virtualearth.net/comp/ch/${quadKey}?it=Z,HC` return tileUrl } function tileXYToQuadKey(tileX, tileY, zoom) { var quadKey = ''; for (var i = zoom; i > 0; i--) { var digit = 0; var mask = 1 << (i - 1); if ((tileX & mask) !== 0) { digit += 1; } if ((tileY & mask) !== 0) { digit += 2; } quadKey += digit.toString(); } return quadKey; } function setBing(){ const svLayer = new google.maps.ImageMapType({ getTileUrl: function(coord, zoom) { return getBingTilesUrl(coord.x,coord.y,zoom) .replace('{z}', zoom) .replace('{x}', coord.x) .replace('{y}', coord.y); }, tileSize: new google.maps.Size(256, 256), name: 'Bing_StreetSide', maxZoom:20 }); map.mapTypes.stack.layers.splice(2, 0,svLayer) map.setMapTypeId('stack') } async function downloadTile(id,g) { try { const response = await fetch(`https://streetviewpixels-pa.googleapis.com/v1/tile?cb_client=apiv3&panoid=${id}&output=tile&x=${g==='Gen4'?18:16}&y=${g==='Gen4'?13:11}&zoom=5&nbt=1&fover=2`); const imageBlob = await response.blob(); const img = new Image(); img.onload = function() { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); const dataUrl = canvas.toDataURL('image/jpeg'); const link = document.createElement('a'); link.href = dataUrl; link.download = id+'.jpg'; link.click(); }; img.src = URL.createObjectURL(imageBlob); } catch (error) { console.error('Error:', error); } } function lon2tile(lng,zoom) { return (lng+180)/360*Math.pow(2,zoom); } function lat2tile(lat,zoom){ return (1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom); } function lonLatToEpsg3395Tile(lng, lat, zoom) { return [lon2tile(lng,zoom), lat2tile(lat,zoom)]; } function getMap(){ let element = document.getElementsByClassName("map-embed")[0] try{ const keys = Object.keys(element) const key = keys.find(key => key.startsWith("__reactFiber$")) const props = element[key] if(!map)window.map=props.pendingProps.children[1].props.children[1].props.map } catch(e){ console.error('Failed to get map: '+e) } } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function fetchPanorama(service,panoId) { await delay(100); return await service.getPanorama({ pano: panoId }); } async function findLinkPanos() { const startLoc = editor.currentLocation.updatedProps; let prevHeading = startLoc.heading; let service = new google.maps.StreetViewService(); let metadata = await fetchPanorama(service,startLoc.panoId); while (metadata.data.links.length == 2) { let nextLoc = metadata.data.links.find(loc => Math.abs(loc.heading - prevHeading) <= 90); if (nextLoc) { metadata = await fetchPanorama(service,nextLoc.pano); editor.addLocation({ location: { lat: metadata.data.location.latLng.lat(), lng: metadata.data.location.latLng.lng() }, panoId: metadata.data.location.pano, heading: nextLoc.heading, pitch: 0, zoom: 0, tags: [], flags: 1 }); prevHeading = nextLoc.heading; } else break } } function toggleElementHidden() { if(!isHidden){ style = GM_addStyle(` .embed-controls {display: none !important} .SLHIdE-sv-links-control {display: none !important} [class$="gmnoprint"], [class$="gm-style-cc"] {display: none !important} `); isHidden = true; } else{ style.remove() isHidden=false; } } async function checkPano(panoId){ let service = new google.maps.StreetViewService(); const data= await service.getPanorama({ pano: panoId }) return data.data } function getTileUrl(lat,lng){ function lon2tile(lng,zoom) { return (Math.floor((lng+180)/360*Math.pow(2,zoom))); } function lat2tile(lat,zoom){ return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom))); } const zoom=20 const tileX=lon2tile(lng,zoom) const tileY=lat2tile(lat,zoom) return `https://www.google.com/maps/vt?pb=!1m7!8m6!1m3!1i${zoom}!2i${tileX}!3i${tileY}!2i9!3x1!2m2!1e0!2sm!3m5!2sen!3sus!5e1105!12m1!1e3!4e0!5m4!1e0!8m2!1e1!1e1!6m6!1e12!2i2!11e0!39b0!44e0!50e0` } function handleNumberKey(key) { const tagName = shortcuts[key]; const tagEls = findTagElements(tagName); if (tagEls.length>0) { const tagEl = tagEls[0]; const deleteBtn = tagEl.querySelector('.tag__button--delete'); const addBtn = tagEl.querySelector('.tag__button--add'); const btnToClick = deleteBtn || addBtn; if (btnToClick) { btnToClick.click(); } } else { const btns = document.querySelectorAll('.tag__button--add'); const index = key - 1; if (btns[index]) { btns[index].click(); } } } function refreshAllBadges() { const tags = document.querySelectorAll('.tag'); tags.forEach(tag => { const tagName = getTagName(tag); const num = Object.entries(shortcuts).find(([k, v]) => v === tagName)?.[0]; if (num) { applyBadge(tag, num); markTagHighlight(tag, true); } else { removeBadge(tag); markTagHighlight(tag, false); } }); } function getStorageKey() { const parts = location.pathname.split('/'); const idx = parts.indexOf('maps'); const mapId =idx >= 0 && idx + 1 < parts.length ? parts[idx + 1] : 'default'; return `tagShortcuts_${mapId}` } function loadShortcuts() { try { return JSON.parse(localStorage.getItem(getStorageKey()) || '{}'); } catch { return {}; } } function saveShortcuts() { localStorage.setItem(getStorageKey(), JSON.stringify(shortcuts)); } function getTagName(tag) { const selectors = ['.tag__text', '.tag__text-container', 'label[for]', 'span']; for (const sel of selectors) { const el = tag.querySelector(sel); if (el) { const clone = el.cloneNode(true); clone.querySelectorAll(`.tag-shortcut-number, small`).forEach(e => e.remove()); const name = clone.textContent.trim(); if (name) return name; } } return tag.textContent.trim().replace(/\s*\d+$/, ''); } function findTagElements(name) { if(!name) return[] return Array.from(document.querySelectorAll(".tag")).filter(tag => getTagName(tag) === name); } function markTagHighlight(tag, highlight) { if (highlight) { tag.setAttribute('data-shortcut-bound', 'true'); } else { tag.removeAttribute('data-shortcut-bound'); } } function applyBadge(tagEl, number) { if (!tagEl || typeof tagEl.querySelector !== "function") return; const selectors = ['.tag__text', '.tag__text-container', 'label[for]', 'span']; let container = null; for (const sel of selectors) { const el = tagEl.querySelector(sel); if (el) { container = el; break; } } if (!container) container = tagEl; const existing = container.querySelector('.tag-shortcut-number'); if (existing) existing.remove(); const badge = document.createElement('small'); badge.className = 'tag-shortcut-number'; badge.textContent = number; badge.style.position = 'absolute'; badge.style.top = '-5px'; badge.style.right = '-5px'; badge.style.background = 'rgb(0, 102, 255)'; badge.style.color = 'white'; badge.style.borderRadius = '50%'; badge.style.width = '18px'; badge.style.height = '18px'; badge.style.display = 'flex'; badge.style.alignItems = 'center'; badge.style.justifyContent = 'center'; badge.style.fontSize = '0.7rem'; badge.style.fontWeight = 'bold'; badge.style.zIndex = '10'; badge.style.pointerEvents = 'none'; container.style.position = 'relative'; container.appendChild(badge); } function removeBadge(tagEl) { const badge = tagEl.querySelector(`.tag-shortcut-number`); if (badge) badge.remove(); } function showTagOverlay() { const fullscreenParent = document.fullscreenElement if (!fullscreenParent || isOpen || document.querySelector('.tag-overlay')) return; tagContainer = document.querySelector('.location-preview__tags'); if (!tagContainer) return; overlay = document.createElement('div'); overlay.className = 'tag-overlay'; overlay.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.85); z-index: 2147483647; display: flex; justify-content: center; align-items: center;`; fullscreenParent.appendChild(overlay); const container = document.createElement('div'); container.className = 'tag-overlay-container'; container.style.cssText = ` position: relative; width: 90%; max-width: 600px; max-height: 80vh; background: #1a1a1a; border-radius: 12px; padding: 20px; overflow: auto; z-index: 2147483647; box-shadow: 0 10px 50px rgba(0, 0, 0, 0.7); border: 1px solid #444; `; const closeBtn = document.createElement('button'); closeBtn.textContent = '×'; closeBtn.className = 'tag-overlay-close'; closeBtn.style.cssText = ` position: absolute; top: 15px; right: 15px; background: none; border: none; font-size: 24px; cursor: pointer; color: white; z-index: 10; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: all 0.2s ease; `; closeBtn.addEventListener('mouseenter', () => { closeBtn.style.background = 'rgba(255, 255, 255, 0.1)'; }); closeBtn.addEventListener('mouseleave', () => { closeBtn.style.background = 'none'; }); closeBtn.addEventListener('click', closeTagOverlay); container.appendChild(closeBtn); originalParent = tagContainer.parentNode; originalNextSibling = tagContainer.nextSibling; container.appendChild(tagContainer); overlay.appendChild(container); tagContainer.classList.add('tag-overlay-content'); /*setTimeout(() => { const input = tagContainer.querySelector('.form-add-tag__input'); if (input) { input.focus(); input.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }, 100);*/ overlay._escHandler = (e) => { if (e.key === 'Escape') { closeTagOverlay(); } }; document.addEventListener('keydown', overlay._escHandler, true); overlay.addEventListener('click', (e) => { if (e.target === overlay) { closeTagOverlay(); } }); isOpen = true; } function closeTagOverlay() { if (!isOpen || !overlay) return; if (overlay._escHandler) { document.removeEventListener('keydown', overlay._escHandler, true); } if (tagContainer && originalParent) { tagContainer.classList.remove('tag-overlay-content'); if (originalNextSibling) { originalParent.insertBefore(tagContainer, originalNextSibling); } else { originalParent.appendChild(tagContainer); } } overlay.remove(); overlay = null; isOpen = false; } function toggleTagOverlay() { if (isOpen) { closeTagOverlay(); } else { showTagOverlay(); } } let onKeyDown =async (e) => { if (e.target.tagName === 'INPUT' || e.target.isContentEditable||!isApplied) { return; } if (e.shiftKey) isShift = true; if (e.ctrlKey) isCtrl = true; const activeSelections=editor.selections.length > 0 ? editor.selections.flatMap(selection => selection.locations) : locations if (e.key >= '1' && e.key <= '9') { e.stopImmediatePropagation(); currentNumberKey = parseInt(e.key); } if (!e.ctrlKey&&!e.shiftKey&&!e.metaKey&&e.key.toLowerCase()=== KEYBOARD_SHORTCUTS.tagDialog.toLowerCase()) { e.stopImmediatePropagation(); toggleTagOverlay(); } if (!e.shiftKey&&!e.ctrlKey&&(e.key === KEYBOARD_SHORTCUTS.hideElement || e.key === KEYBOARD_SHORTCUTS.hideElement.toLowerCase())) { e.stopImmediatePropagation(); toggleElementHidden() } else if (!e.shiftKey&&!e.ctrlKey&&(e.key === KEYBOARD_SHORTCUTS.deSelectAll || e.key === KEYBOARD_SHORTCUTS.deSelectAll.toLowerCase())) { e.stopImmediatePropagation(); editor.resetSelections() } else if (!e.shiftKey&&!e.ctrlKey&&(e.key === KEYBOARD_SHORTCUTS.copyLoc || e.key === KEYBOARD_SHORTCUTS.copyLoc.toLowerCase())) { e.stopImmediatePropagation(); copyLoc() } else if (e.key === KEYBOARD_SHORTCUTS.switchLoc || e.key === KEYBOARD_SHORTCUTS.switchLoc.toLowerCase()) { e.stopImmediatePropagation(); switchLoc(activeSelections) } else if (e.key === KEYBOARD_SHORTCUTS.rewindLoc || e.key === KEYBOARD_SHORTCUTS.rewindLoc.toLowerCase()) { e.stopImmediatePropagation(); rewindLoc(activeSelections) } else if (!e.shiftKey&&!e.ctrlKey&&(e.key === KEYBOARD_SHORTCUTS.deleteLoc || e.key === KEYBOARD_SHORTCUTS.deleteLoc.toLowerCase())) { e.stopImmediatePropagation(); deleteLoc(activeSelections[currentIndex-1]) } else if (!e.shiftKey&&!e.ctrlKey&&(e.key === KEYBOARD_SHORTCUTS.closeAndSaveLoc || e.key === KEYBOARD_SHORTCUTS.closeAndSaveLoc.toLowerCase())) { e.stopImmediatePropagation(); closeAndSaveLoc() } else if (e.key === KEYBOARD_SHORTCUTS.pruneDuplicates || e.key === KEYBOARD_SHORTCUTS.pruneDuplicates.toLowerCase()){ const duplicates=editor.selections.flatMap(selection=>{if (selection.key.includes('dup') ) return selection}) if (duplicates.length>0){ duplicates.forEach((dup)=>{ editor.pruneDuplicates(dup) }) } } if ((e.shiftKey)&&(e.key === KEYBOARD_SHORTCUTS.exportAsCsv || e.key === KEYBOARD_SHORTCUTS.exportAsCsv.toLowerCase())) { e.stopImmediatePropagation(); exportAsCsv(activeSelections) } if ((e.shiftKey)&&(e.key === KEYBOARD_SHORTCUTS.resetGulf || e.key === KEYBOARD_SHORTCUTS.resetGulf.toLowerCase())) { e.stopImmediatePropagation(); resetGulf() } if ((e.shiftKey)&&(e.key === KEYBOARD_SHORTCUTS.classicMap || e.key === KEYBOARD_SHORTCUTS.classicMap.toLowerCase())) { e.stopImmediatePropagation(); classicMap() } if ((e.shiftKey)&&(e.key === KEYBOARD_SHORTCUTS.deleteTags || e.key === KEYBOARD_SHORTCUTS.deleteTags.toLowerCase())) { e.stopImmediatePropagation(); deleteTags() } if (e.shiftKey&&(e.key === KEYBOARD_SHORTCUTS.findLinkPanos || e.key === KEYBOARD_SHORTCUTS.findLinkPanos.toLowerCase())) { e.stopImmediatePropagation(); findLinkPanos(); } if ((e.shiftKey)&&(e.key === KEYBOARD_SHORTCUTS.fullScreenMap || e.key === KEYBOARD_SHORTCUTS.fullScreenMap.toLowerCase())) { e.stopImmediatePropagation(); document.getElementsByClassName("gm-fullscreen-control")[0].click() } if (e.shiftKey) { shiftPressed = true; } if ((e.shiftKey)&&(e.key === 'h' || e.key === 'H')) { e.stopImmediatePropagation(); setHW() //setBing() } /*if (e.key === 't' || e.key === 'T') { e.stopImmediatePropagation(); getEditor() const panos=[] for (const loc of selections) { const panoId=loc.panoId var gen if (loc.tags.includes('Gen4')) gen='Gen4' if(panoId) panos.push({id:panoId,g:gen}) } const downloadPromises = panos.map(pano => downloadTile(pano.id, pano.g)); await Promise.all(downloadPromises); };*/ } document.addEventListener("keydown", onKeyDown); var shortCutButton = document.createElement('button'); shortCutButton.textContent = 'Shortcut Off'; shortCutButton.style.position = 'absolute'; shortCutButton.style.top = '8px'; shortCutButton.style.right = '700px'; shortCutButton.style.zIndex = '9999'; shortCutButton.style.borderRadius = "18px"; shortCutButton.style.padding = "5px 10px"; shortCutButton.style.border = "none"; shortCutButton.style.backgroundColor = "#4CAF50"; shortCutButton.style.color = "white"; shortCutButton.style.cursor = "pointer"; shortCutButton.addEventListener('click', function(){ if(isApplied){ isApplied=false shortCutButton.style.border='none' shortCutButton.textContent = 'Shortcut Off'; } else {isApplied=true shortCutButton.textContent = 'ShortCut On'; shortCutButton.style.border='2px solid #fff'} }); document.body.appendChild(shortCutButton) document.addEventListener('keyup', function(e) { if (e.target.tagName === 'INPUT' || e.target.isContentEditable||!isApplied) { return; } if (!e.ctrlKey ) isCtrl = false; if(!e.shiftKey) isShift=false if (e.key >= '1' && e.key <= '9') { e.stopImmediatePropagation(); handleNumberKey(parseInt(e.key)) currentNumberKey = null; } }); document.body.addEventListener('mousedown', (e) => { const tagEl = e.target.closest(".tag"); if (!tagEl) return; if (!e.button === 0) return; const tagName = getTagName(tagEl); if (!tagName) return; if (isCtrl) { const matched = Object.entries(shortcuts).find(([k, v]) => v === tagName); if (matched) { const [num] = matched; delete shortcuts[num]; saveShortcuts(); removeBadge(tagEl); } } else if (currentNumberKey) { for (const [k, v] of Object.entries(shortcuts)) { if (parseInt(k) === currentNumberKey || v === tagName) { delete shortcuts[k]; const oldTags = findTagElements(v); oldTags.forEach(t => removeBadge(t)); } } shortcuts[currentNumberKey] = tagName; saveShortcuts(); applyBadge(tagEl, currentNumberKey); } }, true); document.addEventListener('mousedown', function(e) { if (e.button === 0&&isShift) { isDrawing = true; startX = e.clientX; startY = e.clientY; document.body.style.userSelect = 'none' selectionBox = document.createElement('div'); selectionBox.style.position = 'absolute'; selectionBox.style.border = '2px solid rgba(0, 128, 255, 0.7)'; selectionBox.style.backgroundColor = 'rgba(0, 128, 255, 0.2)'; document.body.appendChild(selectionBox); } }); document.addEventListener('mousemove', function(e) { if (isDrawing) { endX = e.clientX; endY = e.clientY; const width = Math.abs(endX - startX); const height = Math.abs(endY - startY); selectionBox.style.left = `${Math.min(startX, endX)}px`; selectionBox.style.top = `${Math.min(startY, endY)}px`; selectionBox.style.width = `${width}px`; selectionBox.style.height = `${height}px`; selectionBox.style.zIndex = '999999'; } }); document.addEventListener('mouseup', function(e) { if (isDrawing) { isDrawing = false; const rect = selectionBox.getBoundingClientRect(); document.body.removeChild(selectionBox); const elements = document.querySelectorAll('ul.tag-list'); elements.forEach(element => { const childrens = element.querySelectorAll('li.tag.has-button'); childrens.forEach(child => { const childRect = child.getBoundingClientRect(); if ( childRect.top >= rect.top && childRect.left >= rect.left && childRect.bottom <= rect.bottom && childRect.right <= rect.right ) { child.click(); document.body.style.userSelect = 'text'; } }); }); } }); const observer = new MutationObserver(() => { if (refreshScheduled) return; refreshScheduled = true; setTimeout(() => { refreshScheduled = false; refreshAllBadges(); }, 200); }); observer.observe(document.body, { childList: true, subtree: true, }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址