diff --git a/fog.js b/fog.js index d8728ea..9b17a96 100644 --- a/fog.js +++ b/fog.js @@ -19,13 +19,26 @@ // =============================== const canvas = document.createElement("canvas"); const ctx = canvas.getContext("2d"); + canvas.style.position = "absolute"; - canvas.style.top = 0; - canvas.style.left = 0; + canvas.style.top = "0"; + canvas.style.left = "0"; canvas.style.pointerEvents = "none"; const revealedPoints = []; + // ------------------------------- + // Utility + // ------------------------------- + function metersToPixels(m, lat) { + return ( + m / 40075017 * + 256 * + Math.pow(2, map.getZoom()) / + Math.cos(lat * Math.PI / 180) + ); + } + function resizeCanvas() { const size = map.getSize(); canvas.width = size.x; @@ -33,47 +46,55 @@ redrawFog(); } + // ------------------------------- + // Fog redraw (最重要) + // ------------------------------- function redrawFog() { - ctx.clearRect(0, 0, canvas.width, canvas.height); + if (!canvas.width || !canvas.height) return; - // 霧 + // ★ 毎回状態を完全リセット(超重要) + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.globalCompositeOperation = "source-over"; + ctx.shadowBlur = 0; + + // 霧を描画 + ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "rgba(0,0,0,0.85)"; ctx.fillRect(0, 0, canvas.width, canvas.height); + // 穴あけ + ctx.save(); ctx.globalCompositeOperation = "destination-out"; ctx.shadowColor = "rgba(0,0,0,1)"; ctx.shadowBlur = 20; - revealedPoints.forEach(latlng => { + for (const latlng of revealedPoints) { const p = map.latLngToContainerPoint(latlng); const r = metersToPixels(REVEAL_RADIUS, latlng.lat); ctx.beginPath(); ctx.arc(p.x, p.y, r, 0, Math.PI * 2); ctx.fill(); - }); + } - ctx.globalCompositeOperation = "source-over"; + ctx.restore(); } - function metersToPixels(m, lat) { - return m / 40075017 * 256 * Math.pow(2, map.getZoom()) / Math.cos(lat * Math.PI / 180); - } - - // =============================== + // ------------------------------- // Map Init - // =============================== + // ------------------------------- function initMap() { map = L.map("locationmap").setView(START_POS, 16); - L.tileLayer("https://{s}.tile.osm.org/{z}/{x}/{y}.png", { + L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { attribution: '© OpenStreetMap contributors' }).addTo(map); map.getPanes().overlayPane.appendChild(canvas); resizeCanvas(); - map.on("resize move zoom", redrawFog); + map.on("resize", resizeCanvas); + map.on("move zoom", redrawFog); playerMarker = L.marker(map.getCenter()).addTo(map); playerMarker.bindPopup("STARTで探索開始").openPopup(); @@ -81,9 +102,9 @@ map.on("click", e => updateLocation(e.latlng)); } - // =============================== + // ------------------------------- // Game Logic - // =============================== + // ------------------------------- function reveal(latlng) { revealedPoints.push(latlng); redrawFog(); @@ -97,10 +118,9 @@ } function onSuccess(pos) { - updateLocation(L.latLng( - pos.coords.latitude, - pos.coords.longitude - )); + updateLocation( + L.latLng(pos.coords.latitude, pos.coords.longitude) + ); } function startWatch() { @@ -120,6 +140,9 @@ titleEl.textContent = "STOP"; } + // ------------------------------- + // Events + // ------------------------------- startBtn.addEventListener("click", startWatch); stopBtn.addEventListener("click", stopWatch);