Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.
Revision as of 22:19, 27 August 2025 by QTPi (talk | contribs)

Map Tools

👉 Click a map icon to view details.
🖱️ Right click on map icon to delete (if Delete mode is ON).
Saved ✅
` : ''; return `${t||'Untitled'}${d?`
${d}
`:''}${img}`; } const img = new Image(); img.onload = () => { const w = img.naturalWidth, h = img.naturalHeight; const map = L.map('map', { crs:L.CRS.Simple, minZoom:-2, maxZoom:5, zoomControl:true }); const bounds = [[0,0],[h,w]]; L.imageOverlay(MAP_IMAGE_URL, bounds, { crossOrigin:'anonymous' }).addTo(map); map.fitBounds(bounds); const selfies = L.layerGroup().addTo(map); L.control.layers(null, { 'Selfies 📸': selfies }, { collapsed:false, position:'topleft' }).addTo(map); // Delete mode let deleteMode=false; const delBtn=document.getElementById('m-delmode'); delBtn.onclick=()=>{ deleteMode=!deleteMode; delBtn.textContent='Delete mode: '+(deleteMode?'ON':'OFF'); delBtn.classList.toggle('on', deleteMode); }; function addMarker(latlng, title, desc, imgUrl){ const m = L.marker(latlng,{icon:icon(), title:title||'Selfie', desc:desc||'', imgUrl:imgUrl||null}).addTo(selfies); m.bindPopup(popupHtml(title,desc,imgUrl)); m.on('click', () => m.openPopup()); m.on('contextmenu', () => { if(deleteMode){ selfies.removeLayer(m); saveShared().catch(console.warn); } }); return m; } function collectMarkers(){ const all=[]; selfies.eachLayer(l=>{ const ll=l.getLatLng(); all.push({type:'selfie', y:ll.lat, x:ll.lng, title:l.options.title||'Selfie', desc:l.options.desc||'', img:l.options.imgUrl||null}); }); return all; } async function saveShared(){ const payload = JSON.stringify(collectMarkers()); const res = await fetch(SAVE_URL,{ method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ data: payload }) }); if(!res.ok) throw new Error(await res.text()); toast('Saved ✅'); } function applyMarkers(arr){ arr.forEach(m => addMarker([m.y,m.x], m.title||'Selfie', m.desc||'', m.img||null)); } // UI refs const tI=document.getElementById('m-title'), dI=document.getElementById('m-desc'), pI=document.getElementById('m-photo'), addBtn=document.getElementById('m-add'); // Client-side file checks (jpg/jpeg/png/webp ≤ 10MB) function validatePhoto(){ const f = pI.files[0]; if(!f) return true; const ok = ['image/jpeg','image/png','image/webp']; if(!ok.includes(f.type)){ alert('Only JPG/JPEG, PNG, or WEBP allowed.'); pI.value=''; return false; } if(f.size > 10*1024*1024){ alert('Image is over 10MB.'); pI.value=''; return false; } return true; } async function uploadPhotoIfAny(){ const f = pI.files[0]; if(!f) return null; const fd = new FormData(); fd.append('photo', f); const res = await fetch(UPLOAD_URL, { method:'POST', body: fd }); if(!res.ok) throw new Error(await res.text()); const j = await res.json(); return j.url; } // Add -> click map let placing=null; addBtn.onclick = () => { if(!validatePhoto()) return; placing = { title: tI.value, desc: dI.value }; addBtn.textContent='Click map…'; addBtn.disabled=true; map.getContainer().style.cursor='crosshair'; function cancel(){ placing=null; addBtn.textContent='Add to Map'; addBtn.disabled=false; map.getContainer().style.cursor=''; document.removeEventListener('keydown',esc); } function esc(e){ if(e.key==='Escape') cancel(); } document.addEventListener('keydown',esc); map.once('click', async e => { try{ const imgUrl = await uploadPhotoIfAny(); // may be null addMarker([e.latlng.lat,e.latlng.lng], placing.title, placing.desc, imgUrl); await saveShared(); }catch(err){ alert('Could not add selfie: ' + err.message); } finally{ cancel(); tI.value=''; dI.value=''; pI.value=''; } }); }; // Export PNG (hides panel for clean capture) document.getElementById('m-export').onclick = async () => { try{ const panel=document.getElementById('tv-panel'); const prev=panel.style.display; panel.style.display='none'; await new Promise(r=>setTimeout(r,50)); const canvas = await html2canvas(document.getElementById('map'), { useCORS:true, backgroundColor:null, scale:2 }); panel.style.display = prev || ''; const a=document.createElement('a'); a.href=canvas.toDataURL('image/png'); a.download='selfies-map.png'; document.body.appendChild(a); a.click(); document.body.removeChild(a); }catch(e){ alert('Export failed'); console.error(e); } }; // Initial load (async function(){ try{ const res = await fetch(DATA_URL,{cache:'no-store'}); if(!res.ok) throw new Error('HTTP '+res.status); const arr = await res.json(); selfies.clearLayers(); applyMarkers(arr); }catch(e){ console.warn('Could not load shared data:', e); } })(); }; img.src = MAP_IMAGE_URL;