Init
Initialer Load vom alten Projekt.
BIN
hexgrid.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
108
index.html
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>MapViewer – Spielleiter</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body.paused {
|
||||||
|
outline: 8px solid rgba(0, 150, 255, 0.75);
|
||||||
|
outline-offset: -8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<!-- Weltkarte Button unten links -->
|
||||||
|
<button id="mapToggleButton" title="Weltkarte anzeigen"
|
||||||
|
style="
|
||||||
|
position: fixed;
|
||||||
|
bottom: 15px;
|
||||||
|
left: 15px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
font-size: 60px;
|
||||||
|
background-color: #444;
|
||||||
|
color: green;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 9999;">
|
||||||
|
🗺
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="controls">
|
||||||
|
<label><input type="checkbox" id="toggleFog"></label>
|
||||||
|
<button id="fogMode">Modus: Radierer</button><br>
|
||||||
|
<button id="fogClear">Alles aufdecken</button>
|
||||||
|
<button id="fogFull">Alles vernebeln</button><br>
|
||||||
|
<label>Pinselgröße: <input type="range" id="brushSize" min="1" max="5" value="1" /></label>
|
||||||
|
|
||||||
|
|
||||||
|
<div style="background:#ccc; padding:10px; margin-top:10px;">
|
||||||
|
<label><input type="checkbox" id="toggleHexgrid" checked> Hexgrid anzeigen</label><br>
|
||||||
|
<label>Grid-Skalierung: <input type="range" id="gridScaleSlider" min="0.1" max="4.0" step="0.1" value="1"></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Battlemap-Auswahl Buttons -->
|
||||||
|
<div id="battlemap-buttons" style="position: absolute; top: 175px; left: 10px; background: rgba(255,255,255,0.8); padding: 10px; border-radius: 10px; z-index: 9999;">
|
||||||
|
<strong>Battle Maps:</strong>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<canvas id="mapCanvas"></canvas>
|
||||||
|
|
||||||
|
<iframe id="worldmap-iframe"
|
||||||
|
src="https://map.arenos.danielnagel.at"
|
||||||
|
style="display: none; position: absolute; top: 0; left: 0; width: 100%; height: calc(100% - 130px); z-index: 8000; border: none;">
|
||||||
|
</iframe>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="master.js">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let paused = false;
|
||||||
|
document.addEventListener("keydown", (e) => {
|
||||||
|
if (e.code === "Space") {
|
||||||
|
paused = !paused;
|
||||||
|
document.body.classList.toggle("paused", paused);
|
||||||
|
localStorage.setItem("pauseActive", paused);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// === Dynamische Standardmaps laden ===
|
||||||
|
fetch('/list-maps')
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
const controlDiv = document.getElementById('battlemap-buttons');
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.style.marginTop = '5px';
|
||||||
|
container.style.background = '#ccc';
|
||||||
|
container.style.padding = '5px';
|
||||||
|
|
||||||
|
data.forEach(file => {
|
||||||
|
const button = document.createElement('button');
|
||||||
|
button.textContent = file;
|
||||||
|
button.style.display = 'block';
|
||||||
|
button.style.marginBottom = '5px';
|
||||||
|
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
LoadImageMap(`standard_maps/${file}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
container.appendChild(button);
|
||||||
|
});
|
||||||
|
|
||||||
|
controlDiv.appendChild(container);
|
||||||
|
})
|
||||||
|
.catch(err => console.error('Fehler beim Laden der Battlemap-Liste:', err));
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
||||||
287
master.js
Normal file
|
|
@ -0,0 +1,287 @@
|
||||||
|
const canvas = document.getElementById("mapCanvas");
|
||||||
|
const fogCanvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
const fogCtx = fogCanvas.getContext("2d");
|
||||||
|
const iframe = document.getElementById("worldmap-iframe");
|
||||||
|
|
||||||
|
let image = null;
|
||||||
|
let offsetX = 0, offsetY = 0;
|
||||||
|
let scale = 1;
|
||||||
|
let isDragging = false;
|
||||||
|
let startX, startY;
|
||||||
|
let fogEnabled = false;
|
||||||
|
let fogMode = "erase";
|
||||||
|
let brushSize = 50;
|
||||||
|
let mouseX = 0, mouseY = 0;
|
||||||
|
|
||||||
|
const channel = new BroadcastChannel("mapsync");
|
||||||
|
let MapX = 0;
|
||||||
|
let MapY = 0;
|
||||||
|
let MapZoom = 2;
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
window.addEventListener("resize", resizeCanvas);
|
||||||
|
resizeCanvas();
|
||||||
|
|
||||||
|
// === Fog Controls ===
|
||||||
|
document.getElementById("toggleFog").addEventListener("change", (e) => {
|
||||||
|
fogEnabled = e.target.checked;
|
||||||
|
channel.postMessage({ type: "fogEnabled", enabled: fogEnabled });
|
||||||
|
draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("fogMode").addEventListener("click", () => {
|
||||||
|
fogMode = fogMode === "erase" ? "paint" : "erase";
|
||||||
|
document.getElementById("fogMode").innerText = fogMode === "erase" ? "Modus: Radierer" : "Modus: Nebel";
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("fogClear").addEventListener("click", () => {
|
||||||
|
const btn = document.getElementById("fogClear");
|
||||||
|
btn.disabled = true;
|
||||||
|
setTimeout(() => btn.disabled = false, 1000);
|
||||||
|
fogCtx.clearRect(0, 0, fogCanvas.width, fogCanvas.height);
|
||||||
|
syncFog(); draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("fogFull").addEventListener("click", () => {
|
||||||
|
const btn = document.getElementById("fogFull");
|
||||||
|
btn.disabled = true;
|
||||||
|
setTimeout(() => btn.disabled = false, 1000);
|
||||||
|
fogCtx.fillStyle = "rgba(50, 50, 50, 1)";
|
||||||
|
fogCtx.fillRect(0, 0, fogCanvas.width, fogCanvas.height);
|
||||||
|
syncFog(); draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("brushSize").addEventListener("input", (e) => {
|
||||||
|
brushSize = 50 * parseInt(e.target.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// === Mouse Interaktion ===
|
||||||
|
canvas.addEventListener("dragover", e => e.preventDefault());
|
||||||
|
canvas.addEventListener("drop", e => {
|
||||||
|
e.preventDefault();
|
||||||
|
const file = e.dataTransfer.files[0];
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = evt => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
image = img;
|
||||||
|
//Fog auf Größe des Geladenen Bildes anpassen.
|
||||||
|
fogCanvas.width = img.width;
|
||||||
|
fogCanvas.height = img.height;
|
||||||
|
fogCtx.clearRect(0, 0, fogCanvas.width, fogCanvas.height);
|
||||||
|
draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
channel.postMessage({ type: "mapData", data: evt.target.result });
|
||||||
|
channel.postMessage({ type: "fogEnabled", enabled: fogEnabled });
|
||||||
|
syncFog();
|
||||||
|
};
|
||||||
|
img.src = evt.target.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
function LoadImageMap(i) {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
image = img;
|
||||||
|
fogCanvas.width = img.width;
|
||||||
|
fogCanvas.height = img.height;
|
||||||
|
fogCtx.clearRect(0, 0, fogCanvas.width, fogCanvas.height);
|
||||||
|
draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
channel.postMessage({ type: "mapData", data: i });
|
||||||
|
channel.postMessage({ type: "fogEnabled", enabled: fogEnabled });
|
||||||
|
syncFog();
|
||||||
|
};
|
||||||
|
img.src = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.LoadImageMap = LoadImageMap;
|
||||||
|
|
||||||
|
canvas.addEventListener("mousedown", e => {
|
||||||
|
if (e.button === 1) {
|
||||||
|
isDragging = true;
|
||||||
|
startX = e.clientX - offsetX;
|
||||||
|
startY = e.clientY - offsetY;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
canvas.addEventListener("mouseup", () => { isDragging = false; });
|
||||||
|
canvas.addEventListener("mouseout", () => { isDragging = false; });
|
||||||
|
canvas.addEventListener("mousemove", e => {
|
||||||
|
mouseX = e.clientX;
|
||||||
|
mouseY = e.clientY;
|
||||||
|
if (fogEnabled) draw();
|
||||||
|
if (isDragging) {
|
||||||
|
offsetX = e.clientX - startX;
|
||||||
|
offsetY = e.clientY - startY;
|
||||||
|
syncView();
|
||||||
|
draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
} else if (fogEnabled && e.buttons === 1) {
|
||||||
|
const x = (mouseX - offsetX) / scale;
|
||||||
|
const y = (mouseY - offsetY) / scale;
|
||||||
|
fogCtx.globalCompositeOperation = fogMode === "erase" ? "destination-out" : "source-over";
|
||||||
|
fogCtx.fillStyle = "rgba(50, 50, 50, 0.9)";
|
||||||
|
fogCtx.beginPath();
|
||||||
|
fogCtx.arc(x, y, brushSize, 0, 2 * Math.PI);
|
||||||
|
fogCtx.fill();
|
||||||
|
syncFog(); draw();
|
||||||
|
drawBrushPreview(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
canvas.addEventListener("wheel", e => {
|
||||||
|
e.preventDefault();
|
||||||
|
const worldX = (e.clientX - offsetX) / scale;
|
||||||
|
const worldY = (e.clientY - offsetY) / scale;
|
||||||
|
const zoomFactor = e.deltaY < 0 ? 1.1 : 0.9;
|
||||||
|
scale *= zoomFactor;
|
||||||
|
offsetX = e.clientX - worldX * scale;
|
||||||
|
offsetY = e.clientY - worldY * scale;
|
||||||
|
syncView(); draw();
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
});
|
||||||
|
|
||||||
|
function syncView() {
|
||||||
|
channel.postMessage({ type: "viewData", offsetX, offsetY, scale });
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncFog() {
|
||||||
|
const fogURL = fogCanvas.toDataURL("image/png");
|
||||||
|
channel.postMessage({ type: "fogData", data: fogURL });
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
ctx.setTransform(scale, 0, 0, scale, offsetX, offsetY);
|
||||||
|
ctx.clearRect(-offsetX / scale, -offsetY / scale, canvas.width / scale, canvas.height / scale);
|
||||||
|
if (image) ctx.drawImage(image, 0, 0);
|
||||||
|
if (fogEnabled && fogCanvas.width && fogCanvas.height) {
|
||||||
|
ctx.globalAlpha = 0.4;
|
||||||
|
ctx.drawImage(fogCanvas, 0, 0);
|
||||||
|
ctx.globalAlpha = 1;
|
||||||
|
}
|
||||||
|
if (fogEnabled) drawBrushPreview(mouseX, mouseY);
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawBrushPreview(mouseX, mouseY) {
|
||||||
|
const worldX = (mouseX - offsetX) / scale;
|
||||||
|
const worldY = (mouseY - offsetY) / scale;
|
||||||
|
ctx.save();
|
||||||
|
ctx.setTransform(scale, 0, 0, scale, offsetX, offsetY);
|
||||||
|
ctx.strokeStyle = "rgba(255,255,255,0.8)";
|
||||||
|
ctx.lineWidth = 2 / scale;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(worldX, worldY, brushSize, 0, 2 * Math.PI);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("keydown", (e) => {
|
||||||
|
if (e.key.toLowerCase() === "f") {
|
||||||
|
fogEnabled = !fogEnabled;
|
||||||
|
document.getElementById("toggleFog").checked = fogEnabled;
|
||||||
|
channel.postMessage({ type: "fogEnabled", enabled: fogEnabled });
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("toggleHexgrid").addEventListener("change", (e) => {
|
||||||
|
channel.postMessage({ type: "hexgrid", enabled: e.target.checked });
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById("gridScaleSlider").addEventListener("input", (e) => {
|
||||||
|
const scale = parseFloat(e.target.value);
|
||||||
|
channel.postMessage({ type: "hexgridScale", scale });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// === Weltkarte Funktionen ===
|
||||||
|
let worldMapMode = false;
|
||||||
|
let previousImageSrc = null;
|
||||||
|
|
||||||
|
// === Leaflet View Update Intervall ===
|
||||||
|
setInterval(() => {
|
||||||
|
const iframe = document.getElementById("worldmap-iframe");
|
||||||
|
if (iframe?.contentWindow && worldMapMode) {
|
||||||
|
iframe.contentWindow.postMessage("getView", "*");
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
window.addEventListener("message", (event) => {
|
||||||
|
const data = event.data;
|
||||||
|
if (data?.type === "viewData") {
|
||||||
|
MapX = data.center.lng;
|
||||||
|
MapY = data.center.lat;
|
||||||
|
MapZoom = data.zoom;
|
||||||
|
channel.postMessage({ type: "MapCoord", MapX, MapY, MapZoom}); //Dem Slave die Karten Werte schicken.
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapButton = document.getElementById("mapToggleButton");
|
||||||
|
if (mapButton) {
|
||||||
|
mapButton.addEventListener("click", () => {
|
||||||
|
if (!worldMapMode) {
|
||||||
|
previousImageSrc = image?.src || "pause.png";
|
||||||
|
loadMap();
|
||||||
|
channel.postMessage({ type: "mapMode", enabled: true });
|
||||||
|
mapButton.textContent = "↩️";
|
||||||
|
worldMapMode = true;
|
||||||
|
syncWorldMapView();
|
||||||
|
} else {
|
||||||
|
restoreImage(previousImageSrc);
|
||||||
|
channel.postMessage({ type: "mapMode", enabled: false });
|
||||||
|
mapButton.textContent = "🗺";
|
||||||
|
worldMapMode = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Laden der iframe WorldMap
|
||||||
|
function loadMap() {
|
||||||
|
const iframe = document.getElementById("worldmap-iframe");
|
||||||
|
if (!iframe) return;
|
||||||
|
iframe.style.display = "block";
|
||||||
|
if (iframe.contentWindow) {
|
||||||
|
iframe.contentWindow.postMessage({ action: "syncRequest" }, "*");
|
||||||
|
} else {
|
||||||
|
iframe.onload = () => {
|
||||||
|
iframe.contentWindow.postMessage({ action: "syncRequest" }, "*");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Nach dem schließen der iframe WorldMap, wieder die letzte Map herstellen.
|
||||||
|
function restoreImage(src) {
|
||||||
|
const iframe = document.getElementById("worldmap-iframe");
|
||||||
|
const canvas = document.getElementById("mapCanvas");
|
||||||
|
|
||||||
|
if (iframe) iframe.style.display = "none";
|
||||||
|
if (canvas) canvas.style.display = "block";
|
||||||
|
if (!src) return;
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
image = img;
|
||||||
|
fogCanvas.width = img.width;
|
||||||
|
fogCanvas.height = img.height;
|
||||||
|
fogCtx.clearRect(0, 0, fogCanvas.width, fogCanvas.height);
|
||||||
|
draw();
|
||||||
|
};
|
||||||
|
img.src = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncWorldMapView() {
|
||||||
|
const iframe = document.getElementById("worldmap-iframe");
|
||||||
|
if (worldMapMode && iframe?.contentWindow) {
|
||||||
|
iframe.contentWindow.postMessage("getView", "*");
|
||||||
|
}
|
||||||
|
}
|
||||||
26
server_launcher.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import http.server
|
||||||
|
import socketserver
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
PORT = 8000
|
||||||
|
os.chdir(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
class CustomHandler(http.server.SimpleHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == '/list-maps':
|
||||||
|
try:
|
||||||
|
files = os.listdir('standard_maps')
|
||||||
|
image_files = [f for f in files if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-Type', 'application/json')
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(json.dumps(image_files).encode('utf-8'))
|
||||||
|
except Exception as e:
|
||||||
|
self.send_error(500, f"Fehler: {str(e)}")
|
||||||
|
else:
|
||||||
|
super().do_GET()
|
||||||
|
|
||||||
|
with socketserver.TCPServer(("", PORT), CustomHandler) as httpd:
|
||||||
|
print(f"Starte Server auf Port {PORT}...")
|
||||||
|
httpd.serve_forever()
|
||||||
126
slave.js
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
// slave.js – synchronisiert Ansicht mit master.js (mit direkter URL-Übergabe an Leaflet)
|
||||||
|
|
||||||
|
const canvas = document.getElementById("mapCanvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
let image = null;
|
||||||
|
let fogImage = null;
|
||||||
|
let hexGrid = new Image();
|
||||||
|
hexGrid.src = "hexgrid.png";
|
||||||
|
|
||||||
|
let offsetX = 0, offsetY = 0;
|
||||||
|
let scale = 1;
|
||||||
|
let fogEnabled = false;
|
||||||
|
let hexgridEnabled = false;
|
||||||
|
let hexgridScale = 1;
|
||||||
|
|
||||||
|
let MapX = 0;
|
||||||
|
let MapY = 0;
|
||||||
|
let MapZoom = 2;
|
||||||
|
|
||||||
|
const channel = new BroadcastChannel("mapsync");
|
||||||
|
|
||||||
|
channel.onmessage = (event) => {
|
||||||
|
const msg = event.data;
|
||||||
|
|
||||||
|
if (msg.type === "mapData") {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
image = img;
|
||||||
|
draw();
|
||||||
|
};
|
||||||
|
img.src = msg.data;
|
||||||
|
|
||||||
|
} else if (msg.type === "hexgrid") {
|
||||||
|
hexgridEnabled = msg.enabled;
|
||||||
|
draw();
|
||||||
|
|
||||||
|
} else if (msg.type === "hexgridScale") {
|
||||||
|
hexgridScale = msg.scale;
|
||||||
|
draw();
|
||||||
|
|
||||||
|
} else if (msg.type === "viewData") {
|
||||||
|
offsetX = msg.offsetX;
|
||||||
|
offsetY = msg.offsetY;
|
||||||
|
scale = msg.scale;
|
||||||
|
draw();
|
||||||
|
|
||||||
|
} else if (msg.type === "fogData") {
|
||||||
|
const fog = new Image();
|
||||||
|
fog.onload = () => {
|
||||||
|
fogImage = fog;
|
||||||
|
draw();
|
||||||
|
};
|
||||||
|
fog.src = msg.data;
|
||||||
|
|
||||||
|
} else if (msg.type === "fogEnabled") {
|
||||||
|
fogEnabled = msg.enabled;
|
||||||
|
draw();
|
||||||
|
|
||||||
|
} else if (msg.type === "mapMode") {
|
||||||
|
const iframe = document.getElementById("worldmap-iframe");
|
||||||
|
const canvas = document.getElementById("mapCanvas");
|
||||||
|
|
||||||
|
if (msg.enabled) {
|
||||||
|
iframe.style.display = "block";
|
||||||
|
canvas.style.display = "none";
|
||||||
|
} else {
|
||||||
|
iframe.style.display = "none";
|
||||||
|
canvas.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (msg.type === "MapCoord") {
|
||||||
|
MapX = msg.MapX;
|
||||||
|
MapY = msg.MapY;
|
||||||
|
MapZoom = msg.MapZoom;
|
||||||
|
|
||||||
|
const iframe = document.getElementById("worldmap-iframe");
|
||||||
|
if (iframe && iframe.contentWindow) {
|
||||||
|
iframe.contentWindow.postMessage({
|
||||||
|
type: "setView",
|
||||||
|
center: [MapY, MapX],
|
||||||
|
zoom: MapZoom
|
||||||
|
}, "*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
window.addEventListener("resize", resizeCanvas);
|
||||||
|
resizeCanvas();
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
if (!image) return;
|
||||||
|
ctx.setTransform(scale, 0, 0, scale, offsetX, offsetY);
|
||||||
|
ctx.clearRect(-offsetX / scale, -offsetY / scale, canvas.width / scale, canvas.height / scale);
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
|
||||||
|
if (hexgridEnabled && hexGrid.complete) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
|
ctx.globalAlpha = 0.5;
|
||||||
|
|
||||||
|
const scaleMod = 0.2;
|
||||||
|
const gridWidth = hexGrid.width * (hexgridScale * scaleMod);
|
||||||
|
const gridHeight = hexGrid.height * (hexgridScale * scaleMod);
|
||||||
|
|
||||||
|
const dx = (canvas.width - gridWidth) / 2;
|
||||||
|
const dy = (canvas.height - gridHeight) / 2;
|
||||||
|
|
||||||
|
ctx.drawImage(hexGrid, dx, dy, gridWidth, gridHeight);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
ctx.setTransform(scale, 0, 0, scale, offsetX, offsetY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fogEnabled && fogImage) {
|
||||||
|
ctx.globalAlpha = 1.0;
|
||||||
|
ctx.drawImage(fogImage, 0, 0);
|
||||||
|
ctx.globalAlpha = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
44
spieler.html
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>MapViewer - Spieler</title>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#pauseScreen {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: #000;
|
||||||
|
z-index: 9999;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#pauseScreen img {
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body><div id="pauseScreen"><img src="pause.png" alt="Pause"></div>
|
||||||
|
<canvas id="mapCanvas"></canvas>
|
||||||
|
<script src="slave.js"></script>
|
||||||
|
|
||||||
|
<iframe id="worldmap-iframe"
|
||||||
|
src="https://map.arenos.danielnagel.at"
|
||||||
|
style="display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 9000; border: none;">
|
||||||
|
</iframe>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const pauseScreen = document.getElementById("pauseScreen");
|
||||||
|
function checkPauseState() {
|
||||||
|
const paused = localStorage.getItem("pauseActive") === "true";
|
||||||
|
pauseScreen.style.display = paused ? "block" : "none";
|
||||||
|
requestAnimationFrame(checkPauseState);
|
||||||
|
}
|
||||||
|
requestAnimationFrame(checkPauseState);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
standard_maps/cave.png
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
BIN
standard_maps/city streets.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
standard_maps/farm field.jpg
Normal file
|
After Width: | Height: | Size: 8.5 MiB |
BIN
standard_maps/harbor.png
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
standard_maps/mansion garden.jpg
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
standard_maps/roadside camp.jpg
Normal file
|
After Width: | Height: | Size: 6.5 MiB |
BIN
standard_maps/street.png
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
BIN
standard_maps/tavern.jpg
Normal file
|
After Width: | Height: | Size: 4.9 MiB |
5
starte_viewer.bat
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
@echo off
|
||||||
|
start /min python server_launcher.py
|
||||||
|
timeout /t 2 >nul
|
||||||
|
start http://localhost:8000/index.html
|
||||||
|
start http://localhost:8000/spieler.html
|
||||||
22
style.css
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
#mapCanvas {
|
||||||
|
display: block;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #111;
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
#controls {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
z-index: 10;
|
||||||
|
background: rgba(255, 255, 255, 0.8);
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||