diff --git a/fog.js b/fog.js index 60a7e7c..d8728ea 100644 --- a/fog.js +++ b/fog.js @@ -4,8 +4,7 @@ document.addEventListener("DOMContentLoaded", () => { const START_POS = [38.891, 139.824]; - const REVEAL_RADIUS = 40; // m - const EDGE_FIX = 8; // タイル境界対策(px) + const REVEAL_RADIUS = 40; // meters const titleEl = document.getElementById("title"); const startBtn = document.getElementById("start"); @@ -15,72 +14,50 @@ let playerMarker; let watchId = null; - // === 解除済みポイント === + // =============================== + // Canvas Fog + // =============================== + const canvas = document.createElement("canvas"); + const ctx = canvas.getContext("2d"); + canvas.style.position = "absolute"; + canvas.style.top = 0; + canvas.style.left = 0; + canvas.style.pointerEvents = "none"; + const revealedPoints = []; - // === redraw制御(点滅防止)=== - let redrawScheduled = false; - - // =============================== - // Fog Layer - // =============================== - const FogLayer = L.GridLayer.extend({ - createTile(coords) { - const tile = document.createElement('canvas'); - const size = this.getTileSize(); - tile.width = size.x; - tile.height = size.y; - - const ctx = tile.getContext('2d'); - - // 霧 - ctx.fillStyle = 'rgba(0,0,0,0.85)'; - ctx.fillRect(0, 0, size.x, size.y); - - const bounds = this._tileCoordsToBounds(coords); - - revealedPoints.forEach(latlng => { - if (!bounds.contains(latlng)) return; - - const point = map.latLngToContainerPoint(latlng); - const tilePoint = map.latLngToContainerPoint(bounds.getNorthWest()); - - const x = point.x - tilePoint.x; - const y = point.y - tilePoint.y; - const r = metersToPixels(REVEAL_RADIUS, latlng.lat) + EDGE_FIX; - - ctx.save(); - ctx.globalCompositeOperation = 'destination-out'; - ctx.shadowColor = 'rgba(0,0,0,1)'; - ctx.shadowBlur = 15; - - ctx.beginPath(); - ctx.arc(x, y, r, 0, Math.PI * 2); - ctx.fill(); - ctx.restore(); - }); - - return tile; - } - }); - - let fogLayer; - - // =============================== - // 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; + canvas.height = size.y; + redrawFog(); } - function scheduleRedraw() { - if (redrawScheduled) return; - redrawScheduled = true; + function redrawFog() { + ctx.clearRect(0, 0, canvas.width, canvas.height); - requestAnimationFrame(() => { - fogLayer.redraw(); - redrawScheduled = false; + // 霧 + ctx.fillStyle = "rgba(0,0,0,0.85)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); + + ctx.globalCompositeOperation = "destination-out"; + ctx.shadowColor = "rgba(0,0,0,1)"; + ctx.shadowBlur = 20; + + revealedPoints.forEach(latlng => { + 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"; + } + + function metersToPixels(m, lat) { + return m / 40075017 * 256 * Math.pow(2, map.getZoom()) / Math.cos(lat * Math.PI / 180); } // =============================== @@ -93,8 +70,10 @@ attribution: '© OpenStreetMap contributors' }).addTo(map); - fogLayer = new FogLayer(); - fogLayer.addTo(map); + map.getPanes().overlayPane.appendChild(canvas); + + resizeCanvas(); + map.on("resize move zoom", redrawFog); playerMarker = L.marker(map.getCenter()).addTo(map); playerMarker.bindPopup("STARTで探索開始").openPopup(); @@ -107,7 +86,7 @@ // =============================== function reveal(latlng) { revealedPoints.push(latlng); - scheduleRedraw(); + redrawFog(); } function updateLocation(latlng) { @@ -141,9 +120,6 @@ titleEl.textContent = "STOP"; } - // =============================== - // Events - // =============================== startBtn.addEventListener("click", startWatch); stopBtn.addEventListener("click", stopWatch);