(() => {
'use strict';
document.addEventListener("DOMContentLoaded", () => {
const START_POS = [38.891, 139.824];
const REVEAL_RADIUS = 40; // meters
const titleEl = document.getElementById("title");
const startBtn = document.getElementById("start");
const stopBtn = document.getElementById("stop");
let map;
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 = [];
function resizeCanvas() {
const size = map.getSize();
canvas.width = size.x;
canvas.height = size.y;
redrawFog();
}
function redrawFog() {
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.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);
}
// ===============================
// Map Init
// ===============================
function initMap() {
map = L.map("locationmap").setView(START_POS, 16);
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 move zoom", redrawFog);
playerMarker = L.marker(map.getCenter()).addTo(map);
playerMarker.bindPopup("STARTで探索開始").openPopup();
map.on("click", e => updateLocation(e.latlng));
}
// ===============================
// Game Logic
// ===============================
function reveal(latlng) {
revealedPoints.push(latlng);
redrawFog();
}
function updateLocation(latlng) {
map.panTo(latlng, { animate: false });
playerMarker.setLatLng(latlng);
reveal(latlng);
playerMarker.setPopupContent("探索中…").openPopup();
}
function onSuccess(pos) {
updateLocation(L.latLng(
pos.coords.latitude,
pos.coords.longitude
));
}
function startWatch() {
stopWatch();
watchId = navigator.geolocation.watchPosition(
onSuccess,
null,
{ enableHighAccuracy: true }
);
titleEl.textContent = "探索中";
}
function stopWatch() {
if (!watchId) return;
navigator.geolocation.clearWatch(watchId);
watchId = null;
titleEl.textContent = "STOP";
}
startBtn.addEventListener("click", startWatch);
stopBtn.addEventListener("click", stopWatch);
initMap();
});
})();