(() => {
'use strict';
document.addEventListener("DOMContentLoaded", () => {
// ===== 設定 =====
const START_POS = [38.891, 139.824];
const FOG_RADIUS = 40; // 見える半径(m)
const GRID_SIZE = 20; // 解除単位(m)
// ===== DOM =====
const titleEl = document.getElementById("title");
const startBtn = document.getElementById("start");
const stopBtn = document.getElementById("stop");
// ===== 状態 =====
let map;
let playerMarker;
let watchId = null;
let fogLayer = null;
const revealedHoles = [];
// 解除済みグリッド
const revealedGrid = new Set();
// ===== 初期化 =====
function initMap() {
map = L.map("locationmap", { tap: true })
.setView(START_POS, 16);
L.tileLayer("https://{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution:
'© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
playerMarker = L.marker(map.getCenter()).addTo(map);
playerMarker.bindPopup("STARTを押して探索開始").openPopup();
createFogLayer();
// PC検証用
map.on("click", (e) => {
updateLocation(e.latlng);
});
}
// ===== 世界を覆う霧 =====
function createFogLayer() {
const world = [
[-90, -180],
[-90, 180],
[ 90, 180],
[ 90, -180]
];
if (fogLayer) map.removeLayer(fogLayer);
fogLayer = L.polygon(
[world, ...revealedHoles],
{
fillColor: "#000",
fillOpacity: 0.85,
weight: 0
}
).addTo(map);
}
// ===== グリッドID計算 =====
function gridId(latlng) {
const latSize = GRID_SIZE / 111320;
const lngSize = GRID_SIZE / (111320 * Math.cos(latlng.lat * Math.PI / 180));
const gx = Math.floor(latlng.lng / lngSize);
const gy = Math.floor(latlng.lat / latSize);
return `${gx}_${gy}`;
}
// ===== 霧解除 =====
function revealFog(latlng) {
const id = gridId(latlng);
// すでに解除済み → 何もしない
if (revealedGrid.has(id)) return;
revealedGrid.add(id);
const points = [];
const steps = 16;
for (let i = 0; i < steps; i++) {
const angle = (i / steps) * Math.PI * 2;
const dx = (FOG_RADIUS / 111320) * Math.cos(angle);
const dy = (FOG_RADIUS / 111320) * Math.sin(angle);
points.push([
latlng.lat + dy,
latlng.lng + dx
]);
}
revealedHoles.push(points);
createFogLayer();
}
// ===== 位置更新 =====
function updateLocation(latlng) {
map.panTo(latlng);
playerMarker.setLatLng(latlng);
revealFog(latlng);
playerMarker
.setPopupContent("探索中…")
.openPopup();
}
// ===== Geolocation =====
function onSuccess(pos) {
updateLocation(
L.latLng(pos.coords.latitude, pos.coords.longitude)
);
}
function onError() {
playerMarker
.setPopupContent("位置情報を取得できません")
.openPopup();
}
function startWatch() {
stopWatch();
watchId = navigator.geolocation.watchPosition(
onSuccess,
onError,
{ maximumAge: 0, timeout: 3000, enableHighAccuracy: true }
);
titleEl.textContent = "探索中";
}
function stopWatch() {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
titleEl.textContent = "STOP";
}
}
startBtn.addEventListener("click", startWatch);
stopBtn.addEventListener("click", stopWatch);
initMap();
});
})();