MapViewer/master.js
Daniel c0beeeff92 Init
Initialer Load vom alten Projekt.
2025-08-30 22:02:13 +02:00

288 lines
8.6 KiB
JavaScript

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", "*");
}
}