kolaslab commited on
Commit
5921982
Β·
verified Β·
1 Parent(s): ab7c1ca

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +138 -183
index.html CHANGED
@@ -276,197 +276,152 @@
276
  // ... [이전에 μ •μ˜λœ λ‚˜λ¨Έμ§€ μŠ€ν…Œμ΄μ…˜λ“€λ„ 포함]
277
  ];
278
 
279
- class RadarSystem {
280
- constructor() {
281
- this.canvas = document.getElementById('map');
282
- this.ctx = this.canvas.getContext('2d');
283
- this.targets = new Set();
284
- this.signalLines = new Set();
285
- this.setupWorldMap();
286
- this.setupCanvas();
287
- this.renderReceivers();
288
- this.startTracking();
289
-
290
- window.addEventListener('resize', this.handleResize.bind(this));
291
- }
292
-
293
-
294
- setupWorldMap() {
295
- this.worldMap = L.map('world-map', {
296
- center: [20, 0],
297
- zoom: 2,
298
- zoomControl: true,
299
- dragging: true,
300
- scrollWheelZoom: true,
301
- doubleClickZoom: true
302
- });
303
-
304
- L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
305
- attribution: 'Β© OpenStreetMap contributors'
306
- }).addTo(this.worldMap);
307
-
308
- // 각 SDR μŠ€ν…Œμ΄μ…˜μ— 마컀 μΆ”κ°€
309
- sdrStations.forEach(station => {
310
- const marker = L.circle([station.location[0], station.location[1]], {
311
- color: '#0f0',
312
- fillColor: '#0f0',
313
- fillOpacity: 0.5,
314
- radius: 50000
315
- }).addTo(this.worldMap);
316
-
317
- marker.bindPopup(`
318
- <div style="color: black;">
319
- <strong>${station.name}</strong><br>
320
- πŸ“‘ ${station.url}<br>
321
- πŸ“» ${station.frequency}<br>
322
- Range: ${station.range}km
323
- </div>
324
- `);
325
- });
326
- }
327
-
328
- setupCanvas() {
329
- const container = document.getElementById('map-container');
330
- this.canvas.width = container.offsetWidth;
331
- this.canvas.height = container.offsetHeight;
332
- }
333
-
334
- handleResize() {
335
- const container = document.getElementById('map-container');
336
- this.canvas.width = container.offsetWidth;
337
- this.canvas.height = container.offsetHeight;
338
- this.worldMap.invalidateSize();
339
- }
340
-
341
- renderReceivers() {
342
- const container = document.getElementById('receivers');
343
- container.innerHTML = sdrStations.map(station => `
344
- <div class="receiver" id="rx-${station.url.split(':')[0]}">
345
- <div class="status">
346
- <div class="led ${station.active ? 'active' : 'inactive'}"></div>
347
- <strong>${station.name}</strong>
348
- </div>
349
- <div>πŸ“‘ ${station.url}</div>
350
- <div>πŸ“» ${station.frequency}</div>
351
- <div>πŸ“ ${station.location.join(', ')}</div>
352
- <div>Range: ${station.range}km</div>
353
- <div class="signal-strength">
354
- <div class="signal-bar"></div>
355
- </div>
356
- </div>
357
- `).join('');
358
- }
359
-
360
- generateTarget() {
361
- const station = sdrStations[Math.floor(Math.random() * sdrStations.length)];
362
- const range = 5;
363
- return {
364
- type: Math.random() > 0.7 ? 'aircraft' : 'vehicle',
365
- position: {
366
- lat: station.location[0] + (Math.random() - 0.5) * range,
367
- lon: station.location[1] + (Math.random() - 0.5) * range
368
- },
369
- speed: Math.random() * 100 + 50,
370
- heading: Math.random() * 360,
371
- station: station
372
- };
373
- }
374
 
375
- updateTargets() {
376
- if (Math.random() < 0.1 && this.targets.size < 10) {
377
- const newTarget = this.generateTarget();
378
- this.targets.add(newTarget);
379
-
380
- const targetMarker = L.circle([newTarget.position.lat, newTarget.position.lon], {
381
- color: newTarget.type === 'aircraft' ? '#ff0' : '#f00',
382
- fillColor: newTarget.type === 'aircraft' ? '#ff0' : '#f00',
383
- fillOpacity: 0.5,
384
- radius: 20000
385
- }).addTo(this.worldMap);
386
-
387
- newTarget.marker = targetMarker;
388
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
 
390
- this.targets.forEach(target => {
391
- const rad = target.heading * Math.PI / 180;
392
- target.position.lat += Math.cos(rad) * target.speed * 0.00001;
393
- target.position.lon += Math.sin(rad) * target.speed * 0.00001;
394
-
395
- if (target.marker) {
396
- target.marker.setLatLng([target.position.lat, target.position.lon]);
397
- }
398
-
399
- const distance = this.calculateDistance(
400
- target.position.lat,
401
- target.position.lon,
402
- target.station.location[0],
403
- target.station.location[1]
404
- );
405
-
406
- if (distance > target.station.range) {
407
- if (target.marker) {
408
- this.worldMap.removeLayer(target.marker);
409
- }
410
- this.targets.delete(target);
411
- }
412
- });
413
- }
414
 
415
- calculateDistance(lat1, lon1, lat2, lon2) {
416
- const R = 6371;
417
- const dLat = (lat2 - lat1) * Math.PI / 180;
418
- const dLon = (lon2 - lon1) * Math.PI / 180;
419
- const a =
420
- Math.sin(dLat/2) * Math.sin(dLat/2) +
421
- Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
422
- Math.sin(dLon/2) * Math.sin(dLon/2);
423
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
424
- return R * c;
425
  }
426
 
427
- addDetection(target) {
428
- const container = document.getElementById('detections');
429
- const detection = document.createElement('div');
430
- detection.className = 'detection';
431
- detection.innerHTML = `
432
- ${target.type === 'aircraft' ? '✈️' : 'πŸš—'} Signal detected at
433
- ${target.position.lat.toFixed(4)}, ${target.position.lon.toFixed(4)}
434
- <br>Speed: ${target.speed.toFixed(1)} km/h
435
- <br>Heading: ${target.heading.toFixed(1)}Β°
436
- <br>Station: ${target.station.name}
437
- `;
438
- container.insertBefore(detection, container.firstChild);
439
-
440
- if (container.children.length > 5) {
441
- container.removeChild(container.lastChild);
442
- }
443
 
444
- const receiver = document.getElementById(`rx-${target.station.url.split(':')[0]}`);
445
- if (receiver) {
446
- const signalBar = receiver.querySelector('.signal-bar');
447
- if (signalBar) {
448
- signalBar.style.width = `${Math.random() * 40 + 60}%`;
449
- }
450
  }
451
-
452
- this.addSignalLine(target);
453
- }
454
-
455
- addSignalLine(target) {
456
- const stationLatLng = L.latLng(target.station.location[0], target.station.location[1]);
457
- const targetLatLng = L.latLng(target.position.lat, target.position.lon);
458
-
459
- const line = L.polyline([stationLatLng, targetLatLng], {
460
- color: '#0f0',
461
- weight: 2,
462
- opacity: 0.6,
463
- dashArray: '5, 10'
464
- }).addTo(this.worldMap);
465
-
466
- setTimeout(() => {
467
- this.worldMap.removeLayer(line);
468
- }, 2000);
469
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
 
471
  startTracking() {
472
  setInterval(() => {
 
276
  // ... [이전에 μ •μ˜λœ λ‚˜λ¨Έμ§€ μŠ€ν…Œμ΄μ…˜λ“€λ„ 포함]
277
  ];
278
 
279
+ class RadarSystem {
280
+ constructor() {
281
+ this.canvas = document.getElementById('map');
282
+ this.ctx = this.canvas.getContext('2d');
283
+ this.targets = new Set();
284
+ this.signalLines = new Set();
285
+ this.setupWorldMap();
286
+ this.setupCanvas();
287
+ this.renderReceivers();
288
+ this.startTracking();
289
+
290
+ window.addEventListener('resize', this.handleResize.bind(this));
291
+ }
292
+
293
+ setupWorldMap() {
294
+ // 지도 μ΄ˆκΈ°ν™” μ„€μ • μˆ˜μ •
295
+ this.worldMap = L.map('world-map', {
296
+ center: [30, 0],
297
+ zoom: 3,
298
+ minZoom: 2,
299
+ maxZoom: 18,
300
+ zoomControl: true,
301
+ dragging: true,
302
+ scrollWheelZoom: true,
303
+ doubleClickZoom: true
304
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
 
306
+ // 타일 λ ˆμ΄μ–΄ μŠ€νƒ€μΌ μˆ˜μ •
307
+ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
308
+ attribution: 'Β© OpenStreetMap contributors',
309
+ noWrap: false,
310
+ bounds: [[-90, -180], [90, 180]]
311
+ }).addTo(this.worldMap);
312
+
313
+ // 쀌 컨트둀 μœ„μΉ˜ μ‘°μ •
314
+ L.control.zoom({
315
+ position: 'topright'
316
+ }).addTo(this.worldMap);
317
+
318
+ // SDR μŠ€ν…Œμ΄μ…˜ 마컀 μΆ”κ°€
319
+ sdrStations.forEach(station => {
320
+ // μŠ€ν…Œμ΄μ…˜ 마컀
321
+ const stationMarker = L.circleMarker([station.location[0], station.location[1]], {
322
+ radius: 8,
323
+ color: '#0f0',
324
+ fillColor: '#0f0',
325
+ fillOpacity: 0.5,
326
+ weight: 2
327
+ }).addTo(this.worldMap);
328
+
329
+ // λ²”μœ„ 원
330
+ L.circle([station.location[0], station.location[1]], {
331
+ radius: station.range * 1000, // kmλ₯Ό m둜 λ³€ν™˜
332
+ color: '#0f0',
333
+ fillColor: '#0f0',
334
+ fillOpacity: 0.1,
335
+ weight: 1
336
+ }).addTo(this.worldMap);
337
+
338
+ // νŒμ—… 정보
339
+ stationMarker.bindPopup(`
340
+ <div style="color: black;">
341
+ <strong>${station.name}</strong><br>
342
+ πŸ“‘ ${station.url}<br>
343
+ πŸ“» ${station.frequency}<br>
344
+ Range: ${station.range}km
345
+ </div>
346
+ `);
347
+ });
348
+ }
349
+
350
+ generateTarget() {
351
+ const station = sdrStations[Math.floor(Math.random() * sdrStations.length)];
352
+ const range = station.range / 100; // λ²”μœ„ μ‘°μ •
353
+ return {
354
+ type: Math.random() > 0.7 ? 'aircraft' : 'vehicle',
355
+ position: {
356
+ lat: station.location[0] + (Math.random() - 0.5) * range,
357
+ lon: station.location[1] + (Math.random() - 0.5) * range
358
+ },
359
+ speed: Math.random() * 100 + 50,
360
+ heading: Math.random() * 360,
361
+ station: station
362
+ };
363
+ }
364
+
365
+ updateTargets() {
366
+ if (Math.random() < 0.1 && this.targets.size < 10) {
367
+ const newTarget = this.generateTarget();
368
+ this.targets.add(newTarget);
369
+
370
+ // νƒ€κ²Ÿ 마컀 μŠ€νƒ€μΌ μˆ˜μ •
371
+ const targetMarker = L.circleMarker([newTarget.position.lat, newTarget.position.lon], {
372
+ radius: 5,
373
+ color: newTarget.type === 'aircraft' ? '#ff0' : '#f00',
374
+ fillColor: newTarget.type === 'aircraft' ? '#ff0' : '#f00',
375
+ fillOpacity: 0.8,
376
+ weight: 2
377
+ }).addTo(this.worldMap);
378
+
379
+ newTarget.marker = targetMarker;
380
+ }
381
 
382
+ this.targets.forEach(target => {
383
+ const rad = target.heading * Math.PI / 180;
384
+ target.position.lat += Math.cos(rad) * target.speed * 0.00001;
385
+ target.position.lon += Math.sin(rad) * target.speed * 0.00001;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
 
387
+ if (target.marker) {
388
+ target.marker.setLatLng([target.position.lat, target.position.lon]);
 
 
 
 
 
 
 
 
389
  }
390
 
391
+ const distance = this.calculateDistance(
392
+ target.position.lat,
393
+ target.position.lon,
394
+ target.station.location[0],
395
+ target.station.location[1]
396
+ );
 
 
 
 
 
 
 
 
 
 
397
 
398
+ if (distance > target.station.range) {
399
+ if (target.marker) {
400
+ this.worldMap.removeLayer(target.marker);
 
 
 
401
  }
402
+ this.targets.delete(target);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403
  }
404
+ });
405
+ }
406
+
407
+ addSignalLine(target) {
408
+ const stationLatLng = L.latLng(target.station.location[0], target.station.location[1]);
409
+ const targetLatLng = L.latLng(target.position.lat, target.position.lon);
410
+
411
+ // μ‹ ν˜Έμ„  μŠ€νƒ€μΌ μˆ˜μ •
412
+ const line = L.polyline([stationLatLng, targetLatLng], {
413
+ color: '#0f0',
414
+ weight: 2,
415
+ opacity: 0.8,
416
+ dashArray: '5, 10',
417
+ className: 'signal-line'
418
+ }).addTo(this.worldMap);
419
+
420
+ // μ‹ ν˜Έμ„  μ• λ‹ˆλ©”μ΄μ…˜
421
+ setTimeout(() => {
422
+ this.worldMap.removeLayer(line);
423
+ }, 2000);
424
+ }
425
 
426
  startTracking() {
427
  setInterval(() => {