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:28, 27 August 2025 by QTPi (talk | contribs)

Map Tools

Click on pin to view selfie.
Saved ✅
` : ''; return `${t||'Untitled'}${d?`
${d}
`:''}${img}`; } // Load background image to get pixel bounds 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); // Single layer for selfies (no legend) const selfies = L.layerGroup().addTo(map); // Add / build marker 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), { className:'tv-popup', maxWidth:600, minWidth:200, autoPan:true }); m.on('click', () => m.openPopup()); 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 checks: username required; file type/size optional but validated function validateInputs(){ const name = tI.value.trim(); if(!name){ alert('Please enter a player username.'); tI.focus(); return false; } const f = pI.files[0]; if(f){ 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 to place let placing=null; addBtn.onclick = () => { if(!validateInputs()) 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=''; } }); }; // 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;