tuhbooh commited on
Commit
2dab26e
·
verified ·
1 Parent(s): 735aaeb

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +105 -85
index.html CHANGED
@@ -3,69 +3,81 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Leaflet Realtime P2P - Minh Đức</title>
7
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
8
  <style>
9
- body, html { margin: 0; padding: 0; height: 100%; overflow: hidden; font-family: sans-serif; }
10
- #map { height: 100%; width: 100%; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  .map-title {
12
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
13
- z-index: 1000; background: white; padding: 8px 15px;
14
- border-radius: 20px; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.2);
15
- }
16
- .status-bar {
17
- position: absolute; bottom: 20px; left: 10px; z-index: 1000;
18
- background: rgba(0,0,0,0.7); color: white; padding: 5px 10px;
19
- font-size: 12px; border-radius: 5px;
20
  }
21
  </style>
22
  </head>
23
  <body>
24
 
25
- <div class="map-title">📍 Bản đồ Realtime P2P - Minh Đức</div>
 
26
  <div id="map"></div>
27
- <div class="status-bar" id="status">Đang khởi tạo Peer...</div>
28
 
29
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
30
  <script src="https://unpkg.com/peerjs@1.5.2/dist/peerjs.min.js"></script>
31
 
32
  <script>
33
- // --- CẤU HÌNH ---
34
- const ROOM_PREFIX = "minh-duc-room-";
35
- const MAX_PEERS = 10; // Quét tối đa 10 người để tránh lag
36
  const remoteMarkers = {};
 
37
 
38
- // --- KHỞI TẠO BẢN ĐỒ ---
39
- const map = L.map('map').setView([10.7626, 106.6602], 13);
40
- L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
41
- attribution: '© OpenStreetMap'
42
- }).addTo(map);
43
 
44
- // Marker riêng cho bạn bè (Màu đỏ)
45
- const friendIcon = L.icon({
46
- iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png',
47
- iconSize: [25, 41], iconAnchor: [12, 41], popupAnchor: [1, -34]
 
48
  });
49
 
50
- // --- LOGIC PEERJS ---
51
- const myNumber = Math.floor(Math.random() * MAX_PEERS);
52
- const myId = ROOM_PREFIX + myNumber;
53
  const peer = new Peer(myId);
54
 
55
- document.getElementById('status').innerText = "ID của bạn: " + myId + " (Đang quét bạn bè...)";
56
-
57
  peer.on('open', (id) => {
58
- // Tự động tìm kết nối với các ID khác trong dải từ 0 - MAX_PEERS
59
  for (let i = 0; i < MAX_PEERS; i++) {
60
- if (i !== myNumber) {
61
- connectToPeer(ROOM_PREFIX + i);
62
- }
63
  }
64
  });
65
 
66
- peer.on('connection', (conn) => {
67
- handleData(conn);
68
- });
69
 
70
  function connectToPeer(targetId) {
71
  const conn = peer.connect(targetId);
@@ -73,67 +85,75 @@
73
  }
74
 
75
  function handleData(conn) {
76
- conn.on('data', async (data) => {
77
- if (data.lat && data.lng) {
78
- // Nếu chưa có marker hoặc người dùng di chuyển xa, cập nhật địa chỉ
79
- updateUserOnMap(conn.peer, data);
 
 
 
 
 
80
  }
81
  });
82
  }
83
 
84
- // --- HÀM LẤY ĐỊA CHỈ TỪ TỌA ĐỘ (Reverse Geocoding) ---
85
- // Sử dụng Nominatim miễn phí, không cần API Key
86
- async function getAddress(lat, lng) {
87
- try {
88
- const response = await fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${lat}&lon=${lng}&zoom=18&addressdetails=1`);
89
- const data = await response.json();
90
- return data.display_name || "Không xác định được địa chỉ";
91
- } catch (error) {
92
- return "Lỗi lấy địa chỉ";
93
- }
94
- }
95
-
96
- async function updateUserOnMap(peerId, coords) {
97
  if (remoteMarkers[peerId]) {
98
- // Cập nhật vị trí marker
99
- remoteMarkers[peerId].marker.setLatLng([coords.lat, coords.lng]);
100
-
101
- // Cứ sau mỗi 10 giây hoặc khi click mới cập nhật lại địa chỉ để tránh spam server Nominatim
102
- if (Date.now() - remoteMarkers[peerId].lastUpdate > 10000) {
103
- const addr = await getAddress(coords.lat, coords.lng);
104
- remoteMarkers[peerId].marker.getPopup().setContent(`<b>User: ${peerId}</b><br>${addr}`);
105
- remoteMarkers[peerId].lastUpdate = Date.now();
106
- }
107
  } else {
108
- // Tạo mới marker
109
- const addr = await getAddress(coords.lat, coords.lng);
110
- const marker = L.marker([coords.lat, coords.lng], {icon: friendIcon})
111
- .addTo(map)
112
- .bindPopup(`<b>User: ${peerId}</b><br>${addr}`);
113
 
114
- remoteMarkers[peerId] = { marker, lastUpdate: Date.now() };
 
 
 
115
  }
116
  }
117
 
118
- // --- GỬI VỊ TRÍ MỖI 1 GIÂY ---
119
- setInterval(() => {
120
- if (navigator.geolocation) {
121
- navigator.geolocation.getCurrentPosition((position) => {
122
- const myData = {
123
- lat: position.coords.latitude,
124
- lng: position.coords.longitude
125
- };
126
-
127
- // Gửi dữ liệu cho tất cả các kết nối đang mở
128
- Object.values(peer.connections).forEach(conns => {
129
- conns.forEach(c => {
130
- if (c.open) c.send(myData);
131
- });
132
- });
 
133
  });
134
- }
135
- }, 1000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
 
137
  </script>
138
  </body>
139
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>P2P Locator - Minh Đức Edition</title>
7
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
8
  <style>
9
+ body, html { margin: 0; padding: 0; height: 100%; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
10
+ #map { height: 100vh; width: 100%; }
11
+
12
+ /* Hiệu ứng nhấp nháy cho dấu chấm */
13
+ .pulse {
14
+ width: 15px; height: 15px; background: #ff4444;
15
+ border-radius: 50%; box-shadow: 0 0 0 rgba(255, 68, 68, 0.4);
16
+ animation: pulse 2s infinite;
17
+ }
18
+ @keyframes pulse {
19
+ 0% { box-shadow: 0 0 0 0 rgba(255, 68, 68, 0.7); }
20
+ 70% { box-shadow: 0 0 0 15px rgba(255, 68, 68, 0); }
21
+ 100% { box-shadow: 0 0 0 0 rgba(255, 68, 68, 0); }
22
+ }
23
+
24
+ /* Danh sách người dùng */
25
+ #user-list {
26
+ position: absolute; top: 70px; right: 10px; z-index: 1000;
27
+ background: white; padding: 10px; border-radius: 8px;
28
+ max-height: 200px; overflow-y: auto; box-shadow: 0 2px 10px rgba(0,0,0,0.2);
29
+ width: 180px;
30
+ }
31
+ .user-item {
32
+ padding: 5px; cursor: pointer; border-bottom: 1px solid #eee; font-size: 13px;
33
+ }
34
+ .user-item:hover { background: #f0f0f0; }
35
+
36
  .map-title {
37
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
38
+ z-index: 1000; background: #333; color: white; padding: 8px 20px;
39
+ border-radius: 30px; font-size: 14px;
 
 
 
 
 
40
  }
41
  </style>
42
  </head>
43
  <body>
44
 
45
+ <div class="map-title">📍 Hệ thống định vị P2P - Minh Đức</div>
46
+ <div id="user-list"><b>Đang online:</b><div id="list-content"></div></div>
47
  <div id="map"></div>
 
48
 
49
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
50
  <script src="https://unpkg.com/peerjs@1.5.2/dist/peerjs.min.js"></script>
51
 
52
  <script>
53
+ const ROOM_PREFIX = "m-duc-group-";
54
+ const MAX_PEERS = 10;
 
55
  const remoteMarkers = {};
56
+ let myMarker;
57
 
58
+ // 1. Khởi tạo Map
59
+ const map = L.map('map').setView([10.7626, 106.6602], 15);
60
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
 
 
61
 
62
+ // Icon chấm tròn nhấp nháy
63
+ const pulseIcon = L.divIcon({
64
+ className: 'pulse-container',
65
+ html: '<div class="pulse"></div>',
66
+ iconSize: [20, 20]
67
  });
68
 
69
+ // 2. PeerJS
70
+ const myNum = Math.floor(Math.random() * MAX_PEERS);
71
+ const myId = ROOM_PREFIX + myNum;
72
  const peer = new Peer(myId);
73
 
 
 
74
  peer.on('open', (id) => {
 
75
  for (let i = 0; i < MAX_PEERS; i++) {
76
+ if (i !== myNum) connectToPeer(ROOM_PREFIX + i);
 
 
77
  }
78
  });
79
 
80
+ peer.on('connection', (conn) => { handleData(conn); });
 
 
81
 
82
  function connectToPeer(targetId) {
83
  const conn = peer.connect(targetId);
 
85
  }
86
 
87
  function handleData(conn) {
88
+ conn.on('data', (data) => {
89
+ updateRemoteUser(conn.peer, data);
90
+ });
91
+ // Khi bạn bè offline
92
+ conn.on('close', () => {
93
+ if(remoteMarkers[conn.peer]) {
94
+ map.removeLayer(remoteMarkers[conn.peer].marker);
95
+ delete remoteMarkers[conn.peer];
96
+ renderUserList();
97
  }
98
  });
99
  }
100
 
101
+ // 3. Cập nhật vị trí bạn
102
+ async function updateRemoteUser(peerId, data) {
 
 
 
 
 
 
 
 
 
 
 
103
  if (remoteMarkers[peerId]) {
104
+ remoteMarkers[peerId].marker.setLatLng([data.lat, data.lng]);
 
 
 
 
 
 
 
 
105
  } else {
106
+ const marker = L.marker([data.lat, data.lng], {icon: pulseIcon}).addTo(map);
107
+ marker.bindPopup(`<b>${peerId}</b><br>Đang lấy địa chỉ...`);
108
+
109
+ remoteMarkers[peerId] = { marker, lat: data.lat, lng: data.lng };
110
+ renderUserList();
111
 
112
+ // Lấy địa chỉ (Reverse Geocoding)
113
+ fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${data.lat}&lon=${data.lng}`)
114
+ .then(res => res.json())
115
+ .then(d => marker.getPopup().setContent(`<b>${peerId}</b><br>${d.display_name}`));
116
  }
117
  }
118
 
119
+ // 4. Cập nhật vị trí chính mình (Chức năng cũ)
120
+ function updateMyLocation() {
121
+ navigator.geolocation.watchPosition((pos) => {
122
+ const { latitude: lat, longitude: lng } = pos.coords;
123
+ const myCoords = { lat, lng };
124
+
125
+ if (!myMarker) {
126
+ myMarker = L.marker([lat, lng]).addTo(map).bindPopup("Bạn đang ở đây").openPopup();
127
+ map.setView([lat, lng]); // Tự động zoom vào mình lúc đầu
128
+ } else {
129
+ myMarker.setLatLng([lat, lng]);
130
+ }
131
+
132
+ // Gửi cho bạn bè
133
+ Object.values(peer.connections).forEach(conns => {
134
+ conns.forEach(c => { if (c.open) c.send(myCoords); });
135
  });
136
+ }, null, { enableHighAccuracy: true });
137
+ }
138
+
139
+ // 5. Danh sách người dùng để Click-to-View
140
+ function renderUserList() {
141
+ const container = document.getElementById('list-content');
142
+ container.innerHTML = "";
143
+ Object.keys(remoteMarkers).forEach(id => {
144
+ const div = document.createElement('div');
145
+ div.className = "user-item";
146
+ div.innerText = "👤 " + id;
147
+ div.onclick = () => {
148
+ const m = remoteMarkers[id];
149
+ map.flyTo([m.marker.getLatLng().lat, m.marker.getLatLng().lng], 17);
150
+ m.marker.openPopup();
151
+ };
152
+ container.appendChild(div);
153
+ });
154
+ }
155
 
156
+ updateMyLocation();
157
  </script>
158
  </body>
159
  </html>