arenos-map/index.html
2025-09-14 13:25:37 +00:00

186 lines
6.9 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8"/>
<title>Arenos Map</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<style>
html,body,#map {height:100%;margin:0}
.coords{position:absolute;left:6px;bottom:6px;z-index:1000;background:rgba(255,255,255,.85);
padding:3px 6px;font-size:12px;border-radius:4px;font-family:system-ui,Segoe UI,Arial}
.center-dot{position:absolute;top:50%;left:50%;width:5px;height:5px;background:red;border-radius:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 2px rgba(255,255,255,.95),0 0 2px rgba(0,0,0,.35);pointer-events:none;z-index:1001}
.copy-btn{position:absolute;left:6px;bottom:36px;z-index:1000;background:#ef4444;color:#fff;border:0;border-radius:6px;padding:6px 10px;font:600 12px/1 system-ui,Segoe UI,Arial;cursor:pointer;box-shadow:0 1px 2px rgba(0,0,0,.25)}
.copy-btn:active{transform:translateY(1px)}
</style>
</head>
<body>
<div id="map"></div>
<div class="center-dot" aria-hidden="true" title="Kartenmitte"></div>
<div class="coords"></div>
<button class="copy-btn" title="Aktuelle Kartenmitte als Marker-Code kopieren">Marker Koords</button>
<script>
// === Parameter (wie Export) ===
const ORIG_W = 49152; // px
const ORIG_H = 32768; // px
const TILE = 256; // px
const MAX_Z = 7; // 0..7, 0=weit, 7=Originalgröße
// === CRS an Export anpassen: z=7 → scale=1 (1px = 1 Einheits-Pixel), z=0 → 1/128 ===
const CRS_TILES = L.Util.extend({}, L.CRS.Simple, {
transformation: new L.Transformation(1, 0, 1, 0), // y nach unten positiv
scale: z => Math.pow(2, z - MAX_Z), // 7→1, 6→1/2, …, 0→1/128
zoom: s => Math.log(s) / Math.LN2 + MAX_Z
});
// Karte
const bounds = [[0, 0], [ORIG_H, ORIG_W]]; // Pixelkoordinaten (oben/links → unten/rechts)
const map = L.map('map', {
crs: CRS_TILES,
minZoom: 0,
maxZoom: MAX_Z,
preferCanvas: true,
zoomControl: true,
inertia: false,
keepBuffer: 0
});
map.fitBounds(bounds);
map.setMaxBounds(bounds);
// Hilfsfunktion: Tile-Grid je Zoom (wie Exporter)
function gridForZoom(z){
const scale = Math.pow(2, MAX_Z - z); // z=7 → 1
const wZ = Math.ceil(ORIG_W / scale);
const hZ = Math.ceil(ORIG_H / scale);
const tilesX= Math.ceil(wZ / TILE);
const tilesY= Math.ceil(hZ / TILE);
const offX = Math.floor(tilesX / 2);
const offY = Math.floor(tilesY / 2);
return { tilesX, tilesY, offX, offY };
}
// Debug: zeige beim ersten Tile die berechneten Werte
let first = true;
const CenteredTiles = L.GridLayer.extend({
createTile: function (coords, done) {
const img = document.createElement('img');
img.decoding = 'async';
img.referrerPolicy = 'no-referrer';
img.loading = 'lazy';
const { tilesX, tilesY, offX, offY } = gridForZoom(coords.z);
const xC = coords.x - offX; // zentrierte Namen
const yC = coords.y - offY;
const minX = -offX, maxX = tilesX - offX - 1;
const minY = -offY, maxY = tilesY - offY - 1;
if (first) {
console.log(`[z=${coords.z}] tilesX=${tilesX} tilesY=${tilesY} offX=${offX} offY=${offY}`);
console.log('tile coords →', coords, '→ centered', xC, yC, 'validX', minX, maxX, 'validY', minY, maxY);
first = false;
}
// Außerhalb? → transparent (keine HTTP-Requests)
if (xC < minX || xC > maxX || yC < minY || yC > maxY) {
img.width = img.height = TILE;
img.src = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==';
img.onload = () => done(null, img);
return img;
}
img.onload = () => done(null, img);
img.onerror = () => {
img.src = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256">\
<rect width="100%" height="100%" fill="%23ddd"/>\
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle"\
font-family="monospace" font-size="14">no tile</text></svg>';
done(null, img);
};
img.src = `tiles/${coords.z}/${xC}/${yC}.png`;
return img;
}
});
// === check URL hash ===
// Format: #X,Y,Z (z.B. #22884,8249,5)
const hash = window.location.hash.slice(1).split(',');
if (hash.length >= 2) {
const x = parseFloat(hash[0]);
const y = parseFloat(hash[1]);
const z = hash.length >= 3 ? parseInt(hash[2]) : 5;
if (!isNaN(x) && !isNaN(y)) {
map.setView([y, x], isNaN(z) ? 5 : z);
}
}
new CenteredTiles({
tileSize: TILE,
noWrap: true,
bounds: bounds,
minNativeZoom: 0,
maxNativeZoom: MAX_Z
}).addTo(map);
// Koordinatenanzeige
const box = document.querySelector('.coords');
function show(){
const c = map.getCenter();
box.textContent = `X: ${c.lng.toFixed(0)} Y: ${c.lat.toFixed(0)} Z: ${map.getZoom()}`;
}
map.on('move zoom', show); show();
// Button: Marker-Code mit aktuellen (Mitte-)Koordinaten in die Zwischenablage
const copyBtn = document.querySelector('.copy-btn');
function copyText(text){
if (navigator.clipboard && window.isSecureContext){
return navigator.clipboard.writeText(text);
} else {
// Fallback für HTTP/unsichere Kontexte: verstecktes Textfeld + execCommand
const ta = document.createElement('textarea');
ta.value = text;
ta.setAttribute('readonly','');
ta.style.position = 'fixed';
ta.style.left = '-9999px';
ta.style.top = '-9999px';
document.body.appendChild(ta);
ta.focus();
ta.select();
let ok = false;
try { ok = document.execCommand('copy'); } catch(e) { ok = false; }
document.body.removeChild(ta);
return ok ? Promise.resolve() : Promise.reject(new Error('copy failed'));
}
}
copyBtn.addEventListener('click', () => {
const c = map.getCenter();
const X = Math.round(c.lng); // Anzeige links unten: X zuerst
const Y = Math.round(c.lat); // dann Y
const snippet = ` L.marker([${Y},${X}])
.addTo(map)
.bindTooltip("NAME")
.on('click',()=>window.open(
'WIKI_LINK','_blank'
));`;
copyText(snippet).then(() => {
const old = copyBtn.textContent; copyBtn.textContent = 'Kopiert!';
setTimeout(()=> copyBtn.textContent = old, 1200);
}).catch(err => {
console.error(err);
// Letzter Ausweg: Prompt anzeigen, manuell STRG+C drücken
window.prompt('Kopieren fehlgeschlagen. Bitte STRG+C drücken und mit OK schließen:', snippet);
});
});
</script>
<script src="markers.js"></script>
</body>
</html>