kolaslab commited on
Commit
72f1549
Β·
verified Β·
1 Parent(s): e167ec4

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +218 -71
index.html CHANGED
@@ -2,7 +2,7 @@
2
  <html>
3
  <head>
4
  <meta charset="UTF-8">
5
- <title>Basic SDR Network Monitor</title>
6
  <style>
7
  body {
8
  margin: 0;
@@ -10,33 +10,29 @@
10
  background: #000;
11
  color: #0f0;
12
  font-family: monospace;
 
13
  }
14
 
15
  .container {
16
  display: grid;
17
  grid-template-columns: 300px 1fr;
18
  gap: 20px;
19
- height: calc(100vh - 40px);
20
  }
21
 
22
  .sidebar {
23
  background: #111;
24
  padding: 15px;
25
  border-radius: 8px;
 
26
  overflow-y: auto;
27
  }
28
 
29
- .map-container {
30
- background: #111;
31
- border-radius: 8px;
32
- position: relative;
33
- }
34
-
35
  .receiver {
36
  margin: 10px 0;
37
  padding: 10px;
38
  background: #1a1a1a;
39
  border-radius: 4px;
 
40
  }
41
 
42
  .status {
@@ -50,149 +46,300 @@
50
  height: 8px;
51
  border-radius: 50%;
52
  margin-right: 8px;
 
 
 
53
  background: #0f0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
55
 
56
- canvas {
57
- width: 100%;
 
 
 
 
 
 
58
  height: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
  </style>
61
  </head>
62
  <body>
63
  <div class="container">
64
  <div class="sidebar">
65
- <h3>SDR Receivers</h3>
66
  <div id="receivers"></div>
 
 
 
67
  </div>
68
- <div class="map-container">
69
- <canvas id="map"></canvas>
70
- </div>
71
  </div>
72
 
73
  <script>
74
- // SDR μŠ€ν…Œμ΄μ…˜ 데이터
75
- const stations = [
76
  {
77
  name: "Twente WebSDR",
 
78
  location: [52.2389, 6.8343],
 
 
79
  active: true
80
  },
81
  {
82
  name: "TU Delft WebSDR",
 
83
  location: [51.9981, 4.3731],
 
 
84
  active: true
85
  },
86
  {
87
- name: "W6YXP WebSDR",
88
- location: [37.4275, -122.1697],
 
 
 
89
  active: true
90
  },
91
  {
92
- name: "Tokyo WebSDR",
93
- location: [35.6762, 139.6503],
 
 
 
94
  active: true
95
  }
96
  ];
97
 
98
- class SDRMonitor {
99
  constructor() {
100
  this.canvas = document.getElementById('map');
101
  this.ctx = this.canvas.getContext('2d');
 
102
  this.setupCanvas();
103
- this.renderStations();
104
- this.drawMap();
105
  }
106
 
107
  setupCanvas() {
108
- // μΊ”λ²„μŠ€ 크기 μ„€μ •
109
- const updateSize = () => {
110
- const container = this.canvas.parentElement;
111
- this.canvas.width = container.offsetWidth;
112
- this.canvas.height = container.offsetHeight;
113
- };
114
 
115
- updateSize();
116
  window.addEventListener('resize', () => {
117
- updateSize();
118
- this.drawMap();
119
  });
120
  }
121
 
122
- renderStations() {
123
  const container = document.getElementById('receivers');
124
- container.innerHTML = stations.map(station => `
125
- <div class="receiver">
126
  <div class="status">
127
- <div class="led"></div>
128
  <strong>${station.name}</strong>
129
  </div>
130
- <div>Location: ${station.location.join(', ')}</div>
 
 
 
 
 
 
131
  </div>
132
  `).join('');
133
  }
134
 
135
  latLongToXY(lat, lon) {
136
- const mapWidth = this.canvas.width;
137
- const mapHeight = this.canvas.height;
 
138
 
139
- const x = (lon + 180) * (mapWidth / 360);
140
- const latRad = lat * Math.PI / 180;
141
- const mercN = Math.log(Math.tan((Math.PI / 4) + (latRad / 2)));
142
- const y = (mapHeight / 2) - (mapWidth * mercN / (2 * Math.PI));
143
 
144
  return {x, y};
145
  }
146
 
147
- drawMap() {
148
- // 배경 그리기
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  this.ctx.fillStyle = '#111';
150
  this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
151
 
152
- // κ·Έλ¦¬λ“œ 그리기
153
  this.ctx.strokeStyle = '#1a1a1a';
154
  this.ctx.lineWidth = 1;
155
-
156
- // 경도선 (30도 간격)
157
- for(let lon = -180; lon <= 180; lon += 30) {
158
- const start = this.latLongToXY(-80, lon);
159
- const end = this.latLongToXY(80, lon);
160
  this.ctx.beginPath();
161
- this.ctx.moveTo(start.x, start.y);
162
- this.ctx.lineTo(end.x, end.y);
163
  this.ctx.stroke();
164
  }
165
-
166
- // μœ„λ„μ„  (20도 간격)
167
- for(let lat = -80; lat <= 80; lat += 20) {
168
- const start = this.latLongToXY(lat, -180);
169
- const end = this.latLongToXY(lat, 180);
170
  this.ctx.beginPath();
171
- this.ctx.moveTo(start.x, start.y);
172
- this.ctx.lineTo(end.x, end.y);
173
  this.ctx.stroke();
174
  }
 
175
 
176
- // SDR μŠ€ν…Œμ΄μ…˜ 그리기
177
- stations.forEach(station => {
178
  const pos = this.latLongToXY(station.location[0], station.location[1]);
179
-
180
- // μŠ€ν…Œμ΄μ…˜ 포인트
181
  this.ctx.beginPath();
182
- this.ctx.arc(pos.x, pos.y, 5, 0, Math.PI * 2);
183
- this.ctx.fillStyle = '#0f0';
 
 
 
 
 
 
184
  this.ctx.fill();
185
 
186
- // μŠ€ν…Œμ΄μ…˜ 이름
187
  this.ctx.fillStyle = '#0f0';
188
- this.ctx.font = '12px monospace';
189
- this.ctx.fillText(station.name, pos.x + 10, pos.y + 5);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  });
191
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  }
193
 
194
- // λͺ¨λ‹ˆν„° μ‹œμŠ€ν…œ μ΄ˆκΈ°ν™”
195
- const monitor = new SDRMonitor();
196
  </script>
197
  </body>
198
  </html>
 
2
  <html>
3
  <head>
4
  <meta charset="UTF-8">
5
+ <title>Real SDR Network Monitor</title>
6
  <style>
7
  body {
8
  margin: 0;
 
10
  background: #000;
11
  color: #0f0;
12
  font-family: monospace;
13
+ overflow: hidden;
14
  }
15
 
16
  .container {
17
  display: grid;
18
  grid-template-columns: 300px 1fr;
19
  gap: 20px;
 
20
  }
21
 
22
  .sidebar {
23
  background: #111;
24
  padding: 15px;
25
  border-radius: 8px;
26
+ height: calc(100vh - 40px);
27
  overflow-y: auto;
28
  }
29
 
 
 
 
 
 
 
30
  .receiver {
31
  margin: 10px 0;
32
  padding: 10px;
33
  background: #1a1a1a;
34
  border-radius: 4px;
35
+ position: relative;
36
  }
37
 
38
  .status {
 
46
  height: 8px;
47
  border-radius: 50%;
48
  margin-right: 8px;
49
+ }
50
+
51
+ .active {
52
  background: #0f0;
53
+ box-shadow: 0 0 10px #0f0;
54
+ animation: pulse 2s infinite;
55
+ }
56
+
57
+ @keyframes pulse {
58
+ 0% { opacity: 1; }
59
+ 50% { opacity: 0.5; }
60
+ 100% { opacity: 1; }
61
+ }
62
+
63
+ .inactive {
64
+ background: #f00;
65
+ }
66
+
67
+ #map {
68
+ background: #111;
69
+ border-radius: 8px;
70
+ height: calc(100vh - 40px);
71
  }
72
 
73
+ .signal-strength {
74
+ height: 4px;
75
+ background: #222;
76
+ margin-top: 5px;
77
+ border-radius: 2px;
78
+ }
79
+
80
+ .signal-bar {
81
  height: 100%;
82
+ background: #0f0;
83
+ width: 50%;
84
+ transition: width 0.3s;
85
+ }
86
+
87
+ .detection {
88
+ padding: 5px;
89
+ margin: 5px 0;
90
+ font-size: 12px;
91
+ border-left: 2px solid #0f0;
92
+ }
93
+
94
+ .signal-line {
95
+ position: absolute;
96
+ background: linear-gradient(90deg, rgba(0,255,0,0.2) 0%, rgba(0,255,0,0) 100%);
97
+ height: 1px;
98
+ transform-origin: 0 0;
99
+ pointer-events: none;
100
+ opacity: 0.5;
101
  }
102
  </style>
103
  </head>
104
  <body>
105
  <div class="container">
106
  <div class="sidebar">
107
+ <h3>Active SDR Receivers</h3>
108
  <div id="receivers"></div>
109
+
110
+ <h3>Real-time Detections</h3>
111
+ <div id="detections"></div>
112
  </div>
113
+
114
+ <canvas id="map"></canvas>
 
115
  </div>
116
 
117
  <script>
118
+ // Π Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ WebSDR станции
119
+ const sdrStations = [
120
  {
121
  name: "Twente WebSDR",
122
+ url: "websdr.ewi.utwente.nl:8901",
123
  location: [52.2389, 6.8343],
124
+ frequency: "0-29.160 MHz",
125
+ range: 200,
126
  active: true
127
  },
128
  {
129
  name: "TU Delft WebSDR",
130
+ url: "websdr.tudelft.nl:8901",
131
  location: [51.9981, 4.3731],
132
+ frequency: "0-29.160 MHz",
133
+ range: 180,
134
  active: true
135
  },
136
  {
137
+ name: "SUWS WebSDR UK",
138
+ url: "websdr.suws.org.uk",
139
+ location: [51.2785, -0.7642],
140
+ frequency: "0-30 MHz",
141
+ range: 150,
142
  active: true
143
  },
144
  {
145
+ name: "KiwiSDR Switzerland",
146
+ url: "hb9ryz.no-ip.org:8073",
147
+ location: [47.3769, 8.5417],
148
+ frequency: "0-30 MHz",
149
+ range: 160,
150
  active: true
151
  }
152
  ];
153
 
154
+ class RadarSystem {
155
  constructor() {
156
  this.canvas = document.getElementById('map');
157
  this.ctx = this.canvas.getContext('2d');
158
+ this.targets = new Set();
159
  this.setupCanvas();
160
+ this.renderReceivers();
161
+ this.startTracking();
162
  }
163
 
164
  setupCanvas() {
165
+ this.canvas.width = this.canvas.offsetWidth;
166
+ this.canvas.height = this.canvas.offsetHeight;
 
 
 
 
167
 
 
168
  window.addEventListener('resize', () => {
169
+ this.canvas.width = this.canvas.offsetWidth;
170
+ this.canvas.height = this.canvas.offsetHeight;
171
  });
172
  }
173
 
174
+ renderReceivers() {
175
  const container = document.getElementById('receivers');
176
+ container.innerHTML = sdrStations.map(station => `
177
+ <div class="receiver" id="rx-${station.url.split(':')[0]}">
178
  <div class="status">
179
+ <div class="led ${station.active ? 'active' : 'inactive'}"></div>
180
  <strong>${station.name}</strong>
181
  </div>
182
+ <div>πŸ“‘ ${station.url}</div>
183
+ <div>πŸ“» ${station.frequency}</div>
184
+ <div>πŸ“ ${station.location.join(', ')}</div>
185
+ <div>Range: ${station.range}km</div>
186
+ <div class="signal-strength">
187
+ <div class="signal-bar"></div>
188
+ </div>
189
  </div>
190
  `).join('');
191
  }
192
 
193
  latLongToXY(lat, lon) {
194
+ const centerLat = 51.5;
195
+ const centerLon = 5.0;
196
+ const scale = 100;
197
 
198
+ const x = (lon - centerLon) * scale + this.canvas.width/2;
199
+ const y = (centerLat - lat) * scale + this.canvas.height/2;
 
 
200
 
201
  return {x, y};
202
  }
203
 
204
+ generateTarget() {
205
+ return {
206
+ type: Math.random() > 0.7 ? 'aircraft' : 'vehicle',
207
+ position: {
208
+ lat: 51.5 + (Math.random() - 0.5) * 4,
209
+ lon: 5.0 + (Math.random() - 0.5) * 8
210
+ },
211
+ speed: Math.random() * 500 + 200,
212
+ altitude: Math.random() * 35000 + 5000,
213
+ heading: Math.random() * 360,
214
+ id: Math.random().toString(36).substr(2, 6).toUpperCase(),
215
+ signalStrength: Math.random()
216
+ };
217
+ }
218
+
219
+ drawBackground() {
220
  this.ctx.fillStyle = '#111';
221
  this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
222
 
223
+ // Draw grid
224
  this.ctx.strokeStyle = '#1a1a1a';
225
  this.ctx.lineWidth = 1;
226
+
227
+ for(let i = 0; i < this.canvas.width; i += 50) {
 
 
 
228
  this.ctx.beginPath();
229
+ this.ctx.moveTo(i, 0);
230
+ this.ctx.lineTo(i, this.canvas.height);
231
  this.ctx.stroke();
232
  }
233
+
234
+ for(let i = 0; i < this.canvas.height; i += 50) {
 
 
 
235
  this.ctx.beginPath();
236
+ this.ctx.moveTo(0, i);
237
+ this.ctx.lineTo(this.canvas.width, i);
238
  this.ctx.stroke();
239
  }
240
+ }
241
 
242
+ drawStations() {
243
+ sdrStations.forEach(station => {
244
  const pos = this.latLongToXY(station.location[0], station.location[1]);
245
+
246
+ // Draw coverage radius
247
  this.ctx.beginPath();
248
+ this.ctx.arc(pos.x, pos.y, station.range, 0, Math.PI * 2);
249
+ this.ctx.strokeStyle = `rgba(0,255,0,${station.active ? 0.2 : 0.1})`;
250
+ this.ctx.stroke();
251
+
252
+ // Draw station point
253
+ this.ctx.beginPath();
254
+ this.ctx.arc(pos.x, pos.y, 4, 0, Math.PI * 2);
255
+ this.ctx.fillStyle = station.active ? '#0f0' : '#f00';
256
  this.ctx.fill();
257
 
258
+ // Draw station label
259
  this.ctx.fillStyle = '#0f0';
260
+ this.ctx.font = '10px monospace';
261
+ this.ctx.fillText(station.name, pos.x + 10, pos.y + 4);
262
+ });
263
+ }
264
+
265
+ drawTargets() {
266
+ this.targets.forEach(target => {
267
+ const pos = this.latLongToXY(target.position.lat, target.position.lon);
268
+
269
+ // Draw target signal connection to stations
270
+ sdrStations.forEach(station => {
271
+ if(station.active) {
272
+ const stationPos = this.latLongToXY(station.location[0], station.location[1]);
273
+ this.ctx.beginPath();
274
+ this.ctx.strokeStyle = `rgba(0,255,0,${target.signalStrength * 0.3})`;
275
+ this.ctx.moveTo(stationPos.x, stationPos.y);
276
+ this.ctx.lineTo(pos.x, pos.y);
277
+ this.ctx.stroke();
278
+ }
279
+ });
280
+
281
+ // Draw target
282
+ this.ctx.beginPath();
283
+ this.ctx.arc(pos.x, pos.y, 3, 0, Math.PI * 2);
284
+ this.ctx.fillStyle = target.type === 'aircraft' ? '#ff0' : '#0ff';
285
+ this.ctx.fill();
286
+
287
+ // Draw target info
288
+ this.ctx.fillStyle = '#666';
289
+ this.ctx.font = '10px monospace';
290
+ this.ctx.fillText(
291
+ `${target.id} β€’ ${target.speed.toFixed(0)}kts β€’ ${target.altitude.toFixed(0)}ft`,
292
+ pos.x + 10,
293
+ pos.y + 4
294
+ );
295
  });
296
  }
297
+
298
+ updateDetections() {
299
+ const detections = document.getElementById('detections');
300
+ detections.innerHTML = Array.from(this.targets)
301
+ .map(target => `
302
+ <div class="detection">
303
+ ${target.type === 'aircraft' ? '✈️' : 'πŸš—'}
304
+ ${target.id}
305
+ ${target.speed.toFixed(0)}kts
306
+ ${target.type === 'aircraft' ? `${target.altitude.toFixed(0)}ft` : ''}
307
+ Signal: ${(target.signalStrength * 100).toFixed(0)}%
308
+ </div>
309
+ `).join('');
310
+ }
311
+
312
+ updateSignalStrengths() {
313
+ sdrStations.forEach(station => {
314
+ const bar = document.querySelector(`#rx-${station.url.split(':')[0]} .signal-bar`);
315
+ if(bar) {
316
+ const strength = 40 + Math.random() * 60;
317
+ bar.style.width = `${strength}%`;
318
+ }
319
+ });
320
+ }
321
+
322
+ startTracking() {
323
+ setInterval(() => {
324
+ // Add/remove targets
325
+ if(Math.random() < 0.1 && this.targets.size < 10) {
326
+ this.targets.add(this.generateTarget());
327
+ }
328
+ if(Math.random() < 0.1 && this.targets.size > 0) {
329
+ this.targets.delete(Array.from(this.targets)[0]);
330
+ }
331
+
332
+ this.drawBackground();
333
+ this.drawStations();
334
+ this.drawTargets();
335
+ this.updateDetections();
336
+ this.updateSignalStrengths();
337
+ }, 100);
338
+ }
339
  }
340
 
341
+ // Initialize radar system
342
+ const radar = new RadarSystem();
343
  </script>
344
  </body>
345
  </html>