diff --git a/map4.js b/map4.js
index 3dca566..da600c3 100644
--- a/map4.js
+++ b/map4.js
@@ -21,10 +21,10 @@
let lastLat = null;
let lastLng = null;
-// 駅マーカー用
+// 駅マーカー
let stationMarkers = [];
-// 目的地
+// 目的地関連
let targetMarker = null;
let targetLat = null;
let targetLng = null;
@@ -35,22 +35,16 @@
// 駅アイコン
const stationIcon = L.icon({
- iconUrl:
- "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-blue.png",
- shadowUrl:
- "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
+ iconUrl: "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-blue.png",
+ shadowUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
- shadowSize: [41, 41],
- shadowAnchor: [13, 41],
});
-// 赤ピン(目的地)
+// 目的地ピン(赤)
const targetIcon = L.icon({
- iconUrl:
- "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png",
- shadowUrl:
- "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
+ iconUrl: "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png",
+ shadowUrl: "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
});
@@ -65,14 +59,14 @@
}
// ===================================
-// 小型ピン
+// 小型ピン(自分:緑、他人:黄)
// ===================================
function createLabeledMarker(lat, lng, name, isSelf) {
const pinUrl = isSelf
? "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png"
: "https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-gold.png";
- const iconHtml = `
+ const html = `
${name}
@@ -82,18 +76,20 @@
return L.marker([lat, lng], {
icon: L.divIcon({
className: "custom-pin",
- html: iconHtml,
+ html: html,
iconSize: [32, 32],
iconAnchor: [16, 32],
}),
- });
+ });実際どのようにサイトを作るのか、具体的な手順を知りたい。
+
+
}
// ===================================
function getPosition() {
return new Promise((res, rej) => {
navigator.geolocation.getCurrentPosition(
- (pos) => res(pos.coords),
+ p => res(p.coords),
rej,
{ enableHighAccuracy: true }
);
@@ -108,7 +104,7 @@
maxZoom: 19,
}).addTo(map);
- // ★ 目的地設定:マップをクリックすると赤ピンを置く
+ // ★目的地設定(マップをタップ)
map.on("click", (e) => {
targetLat = e.latlng.lat;
targetLng = e.latlng.lng;
@@ -121,7 +117,7 @@
}).addTo(map);
const box = document.getElementById("targetInfo");
- box.textContent = `目的地を設定しました!距離を計算中…`;
+ box.textContent = "目的地を設定しました!距離を計算中…";
});
}
@@ -148,10 +144,6 @@
selfMarker = createLabeledMarker(lastLat, lastLng, currentUser, true);
selfMarker.addTo(map);
-
- selfMarker.on("click", (e) => {
- map.panTo(e.latlng, { animate: true, duration: 0.4 });
- });
}
// ===================================
@@ -169,11 +161,10 @@
li.classList.add(isOnline ? "online" : "offline");
- const circleColor = row.device_id === deviceId ? "#58c16b" : "#FFD700";
-
+ const color = row.device_id === deviceId ? "#58c16b" : "#FFD700";
const icon = document.createElement("div");
icon.className = "member-icon";
- icon.style.background = circleColor;
+ icon.style.background = color;
const name = document.createElement("span");
name.textContent = row.user_name;
@@ -184,17 +175,6 @@
li.append(icon, name, status);
- li.onclick = () => {
- const marker =
- row.device_id === deviceId
- ? selfMarker
- : otherMarkers.find((m) => m._deviceId === row.device_id);
-
- if (marker) {
- map.panTo(marker.getLatLng(), { animate: true, duration: 0.5 });
- }
- };
-
list.appendChild(li);
});
}
@@ -209,50 +189,45 @@
latestByDevice = {};
- if (Array.isArray(data)) {
- for (const r of data) {
- if (!latestByDevice[r.device_id]) latestByDevice[r.device_id] = r;
- }
- }
+ data?.forEach((r) => {
+ if (!latestByDevice[r.device_id]) latestByDevice[r.device_id] = r;
+ });
showMemberList(latestByDevice);
- otherMarkers.forEach((m) => map.removeLayer(m));
+ otherMarkers.forEach(m => map.removeLayer(m));
otherMarkers = [];
Object.values(latestByDevice).forEach((row) => {
if (row.device_id === deviceId) return;
const mk = createLabeledMarker(row.lat, row.lng, row.user_name, false);
- mk._deviceId = row.device_id;
-
- mk.on("click", (e) => {
- map.panTo(e.latlng, { animate: true, duration: 0.4 });
- });
-
mk.addTo(map);
otherMarkers.push(mk);
});
}
// ===================================
-// 距離計算(メートル)
+// 距離(メートル)
+// ===================================
function distanceMeters(lat1, lng1, lat2, lng2) {
const R = 6371000;
- const toRad = (d) => (d * Math.PI) / 180;
+ const toRad = (d) => d * Math.PI / 180;
+
const dLat = toRad(lat2 - lat1);
const dLng = toRad(lng2 - lng1);
+
const a =
Math.sin(dLat / 2)**2 +
Math.cos(toRad(lat1)) *
- Math.cos(toRad(lat2)) *
- Math.sin(dLng / 2)**2;
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
- return R * c;
+ Math.cos(toRad(lat2)) *
+ Math.sin(dLng / 2)**2;
+
+ return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
// ===================================
-// 到着判定
+// ★到着判定
// ===================================
function checkArrival() {
if (!targetLat || !targetLng) return;
@@ -260,11 +235,10 @@
const d = distanceMeters(lastLat, lastLng, targetLat, targetLng);
const box = document.getElementById("targetInfo");
- box.textContent = `目的地まで 約 ${(d/1000).toFixed(2)} km`;
+ box.textContent = `目的地まで 約 ${(d / 1000).toFixed(2)} km`;
if (d < 120 && !arrived) {
arrived = true;
-
box.textContent = "🎉 目的地に到着しました! 🎉";
box.style.background = "#ffe4e1";
box.style.borderLeft = "5px solid #ff4d6d";
@@ -274,6 +248,66 @@
}
// ===================================
+// ★駅検索(Overpass API)
+// ===================================
+async function fetchStationsAround(lat, lng) {
+ const query = `
+ [out:json];
+ node["railway"="station"](around:5000,${lat},${lng});
+ out;
+ `;
+ const url = "https://overpass-api.de/api/interpreter?data=" + encodeURIComponent(query);
+
+ const res = await fetch(url);
+ if (!res.ok) throw new Error("Overpass API error");
+ const json = await res.json();
+ return json.elements || [];
+}
+
+// 最寄り駅表示
+async function loadStations() {
+ const box = document.getElementById("nearestBox");
+
+ try {
+ const stations = await fetchStationsAround(lastLat, lastLng);
+
+ stationMarkers.forEach(m => map.removeLayer(m));
+ stationMarkers = [];
+
+ if (stations.length === 0) {
+ box.textContent = "駅が見つかりませんでした。";
+ return;
+ }
+
+ let nearest = null;
+ let nearestDist = Infinity;
+
+ stations.forEach(st => {
+ const name = st.tags?.name || "駅名不明";
+ const sLat = st.lat;
+ const sLng = st.lon;
+
+ const d = distanceMeters(lastLat, lastLng, sLat, sLng);
+ if (d < nearestDist) {
+ nearestDist = d;
+ nearest = { name, lat: sLat, lng: sLng };
+ }
+
+ const mk = L.marker([sLat, sLng], { icon: stationIcon }).addTo(map);
+ mk.bindPopup(`${name}駅`);
+ stationMarkers.push(mk);
+ });
+
+ const distKm = (nearestDist / 1000).toFixed(2);
+ box.textContent = `最寄り駅:${nearest.name}(約 ${distKm} km)`;
+
+ } catch (e) {
+ console.error(e);
+ box.textContent = "駅情報を取得できませんでした。";
+ }
+}
+
+// ===================================
async function main() {
loadParams();
@@ -293,10 +327,10 @@
await saveMyLocation(lat, lng);
await showOtherUsers();
- // 駅読み込み(初回のみ)
+ // 駅読み込み(最初だけ)
loadStations();
- // ★ 2秒ごとに位置更新 → 到着判定
+ // ★2秒ごとに位置更新&到着判定
setInterval(async () => {
try {
const pos = await getPosition();
@@ -309,13 +343,12 @@
} catch {}
}, 2000);
- // 他ユーザーは毎秒更新
setInterval(showOtherUsers, 1000);
document.getElementById("exitBtn").onclick = () =>
(location.href = "index.html");
- setTimeout(() => map.invalidateSize(), 400);
+ setTimeout(() => map.invalidateSize(), 300);
}
window.addEventListener("DOMContentLoaded", main);