diff --git a/fog.js b/fog.js index 9b17a96..c833708 100644 --- a/fog.js +++ b/fog.js @@ -4,7 +4,7 @@ document.addEventListener("DOMContentLoaded", () => { const START_POS = [38.891, 139.824]; - const REVEAL_RADIUS = 40; // meters + const REVEAL_RADIUS = 40; // m const titleEl = document.getElementById("title"); const startBtn = document.getElementById("start"); @@ -14,87 +14,61 @@ 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 = []; - // ------------------------------- - // Utility - // ------------------------------- - function metersToPixels(m, lat) { - return ( - m / 40075017 * - 256 * - Math.pow(2, map.getZoom()) / - Math.cos(lat * Math.PI / 180) - ); - } + // === Canvas霧レイヤ === + const FogLayer = L.GridLayer.extend({ + createTile: function (coords) { + const tile = document.createElement('canvas'); + const size = this.getTileSize(); + tile.width = size.x; + tile.height = size.y; - function resizeCanvas() { - const size = map.getSize(); - canvas.width = size.x; - canvas.height = size.y; - redrawFog(); - } + const ctx = tile.getContext('2d'); - // ------------------------------- - // Fog redraw (最重要) - // ------------------------------- - function redrawFog() { - if (!canvas.width || !canvas.height) return; + // 霧を塗る + ctx.fillStyle = 'rgba(0,0,0,0.85)'; + ctx.fillRect(0, 0, size.x, size.y); - // ★ 毎回状態を完全リセット(超重要) - ctx.setTransform(1, 0, 0, 1, 0, 0); - ctx.globalCompositeOperation = "source-over"; - ctx.shadowBlur = 0; + // タイル境界の緯度経度 + const bounds = this._tileCoordsToBounds(coords); - // 霧を描画 - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.fillStyle = "rgba(0,0,0,0.85)"; - ctx.fillRect(0, 0, canvas.width, canvas.height); + // 解除ポイントを削る + revealedPoints.forEach(latlng => { + if (!bounds.contains(latlng)) return; - // 穴あけ - ctx.save(); - ctx.globalCompositeOperation = "destination-out"; - ctx.shadowColor = "rgba(0,0,0,1)"; - ctx.shadowBlur = 20; + const point = map.latLngToContainerPoint(latlng); + const tilePoint = map.latLngToContainerPoint(bounds.getNorthWest()); - for (const latlng of revealedPoints) { - const p = map.latLngToContainerPoint(latlng); - const r = metersToPixels(REVEAL_RADIUS, latlng.lat); + const x = point.x - tilePoint.x; + const y = point.y - tilePoint.y; - ctx.beginPath(); - ctx.arc(p.x, p.y, r, 0, Math.PI * 2); - ctx.fill(); + ctx.globalCompositeOperation = 'destination-out'; + ctx.beginPath(); + ctx.arc(x, y, metersToPixels(REVEAL_RADIUS, latlng.lat), 0, Math.PI * 2); + ctx.fill(); + }); + + return tile; } + }); - ctx.restore(); + let fogLayer; + + 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.openstreetmap.org/{z}/{x}/{y}.png", { + L.tileLayer("https://{s}.tile.osm.org/{z}/{x}/{y}.png", { attribution: '© OpenStreetMap contributors' }).addTo(map); - map.getPanes().overlayPane.appendChild(canvas); - - resizeCanvas(); - map.on("resize", resizeCanvas); - map.on("move zoom", redrawFog); + fogLayer = new FogLayer(); + fogLayer.addTo(map); playerMarker = L.marker(map.getCenter()).addTo(map); playerMarker.bindPopup("STARTで探索開始").openPopup(); @@ -102,25 +76,21 @@ map.on("click", e => updateLocation(e.latlng)); } - // ------------------------------- - // Game Logic - // ------------------------------- function reveal(latlng) { revealedPoints.push(latlng); - redrawFog(); + fogLayer.redraw(); // ← ここが重要 } function updateLocation(latlng) { - map.panTo(latlng, { animate: false }); + map.panTo(latlng); playerMarker.setLatLng(latlng); reveal(latlng); + playerMarker.setPopupContent("探索中…").openPopup(); } function onSuccess(pos) { - updateLocation( - L.latLng(pos.coords.latitude, pos.coords.longitude) - ); + updateLocation(L.latLng(pos.coords.latitude, pos.coords.longitude)); } function startWatch() { @@ -134,15 +104,13 @@ } function stopWatch() { - if (!watchId) return; - navigator.geolocation.clearWatch(watchId); - watchId = null; - titleEl.textContent = "STOP"; + if (watchId) { + navigator.geolocation.clearWatch(watchId); + watchId = null; + titleEl.textContent = "STOP"; + } } - // ------------------------------- - // Events - // ------------------------------- startBtn.addEventListener("click", startWatch); stopBtn.addEventListener("click", stopWatch);