vs4vijay commited on
Commit
d329ea1
·
verified ·
1 Parent(s): 7eec6c7

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +98 -65
index.html CHANGED
@@ -3,8 +3,8 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>SkyWatch - Plane Tracker</title>
7
- <meta name="description" content="Track planes flying above your location in real-time">
8
  <meta name="theme-color" content="#1e40af">
9
  <link rel="manifest" href="/manifest.json">
10
  <script src="https://cdn.tailwindcss.com"></script>
@@ -187,7 +187,11 @@
187
  notifications: [],
188
  lastUpdated: null,
189
  currentPlane: null,
190
- deferredPrompt: null
 
 
 
 
191
  };
192
 
193
  // DOM Elements
@@ -276,22 +280,87 @@
276
  elements.upcomingPlanes.innerHTML = '';
277
  elements.upcomingPlanes.appendChild(elements.loadingPlanes);
278
  elements.apiStatus.textContent = 'API: Loading...';
 
 
 
 
279
 
280
  try {
281
- // In a real app, you would use the actual OpenSky Network API
282
- // For this demo, we'll use mock data
283
- // const response = await fetch(`https://opensky-network.org/api/states/all?lamin=${state.location.lat - 1}&lomin=${state.location.lon - 1}&lamax=${state.location.lat + 1}&lomax=${state.location.lon + 1}`);
284
- // const data = await response.json();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
 
286
- // Mock data for demonstration
287
- const mockPlanes = generateMockPlanes(state.location.lat, state.location.lon);
288
- state.planes = mockPlanes.states;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
 
290
  processPlaneData();
291
- elements.apiStatus.textContent = 'API: Online';
292
  elements.apiStatus.className = elements.apiStatus.className.replace('text-red-500', 'text-green-500');
293
  } catch (error) {
294
- console.error('Error fetching plane data:', error);
295
  elements.apiStatus.textContent = 'API: Offline';
296
  elements.apiStatus.className += ' text-red-500';
297
 
@@ -575,7 +644,7 @@
575
  // Extract airline code from callsign (first 3 letters usually)
576
  const airlineCode = callsign.substring(0, 3).toUpperCase();
577
 
578
- // Mock airline database
579
  const airlines = {
580
  'UAL': 'United Airlines',
581
  'AAL': 'American Airlines',
@@ -592,63 +661,27 @@
592
  'SIA': 'Singapore Airlines',
593
  'THY': 'Turkish Airlines',
594
  'UAE': 'Emirates',
595
- 'VIR': 'Virgin Atlantic'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
596
  };
597
 
598
  return airlines[airlineCode] || null;
599
  }
600
 
601
- // Generate mock plane data for demonstration
602
- function generateMockPlanes(userLat, userLon) {
603
- const now = Date.now() / 1000;
604
- const mockPlanes = [];
605
-
606
- // Generate 8-15 mock planes
607
- const planeCount = 8 + Math.floor(Math.random() * 7);
608
-
609
- for (let i = 0; i < planeCount; i++) {
610
- // Generate random position within 50km radius
611
- const distance = 0.5 + Math.random() * 50; // 0.5-50 km
612
- const bearing = Math.random() * 360;
613
-
614
- // Calculate position
615
- const R = 6371; // Earth radius in km
616
- const lat1 = userLat * Math.PI / 180;
617
- const lon1 = userLon * Math.PI / 180;
618
- const d = distance / R;
619
-
620
- const lat2 = Math.asin(Math.sin(lat1) * Math.cos(d) +
621
- Math.cos(lat1) * Math.sin(d) * Math.cos(bearing));
622
- const lon2 = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(d) * Math.cos(lat1),
623
- Math.cos(d) - Math.sin(lat1) * Math.sin(lat2));
624
-
625
- const planeLat = lat2 * 180 / Math.PI;
626
- const planeLon = lon2 * 180 / Math.PI;
627
-
628
- // Generate plane data
629
- const callsigns = ['UAL123', 'AAL456', 'DAL789', 'SWA101', 'JBU202', 'FDX303', 'UPS404', 'AFR505', 'BAW606', 'DLH707'];
630
- const callsign = callsigns[Math.floor(Math.random() * callsigns.length)];
631
-
632
- mockPlanes.push([
633
- Math.random().toString(36).substring(2, 10).toUpperCase(), // icao24
634
- callsign, // callsign
635
- null, // origin country
636
- now - Math.random() * 3600, // time position
637
- now - Math.random() * 60, // last contact
638
- planeLon, // longitude
639
- planeLat, // latitude
640
- 1000 + Math.random() * 35000, // altitude (ft)
641
- false, // on ground
642
- 200 + Math.random() * 500, // velocity (knots)
643
- Math.random() * 360, // heading
644
- -20 + Math.random() * 40, // vertical rate
645
- null, null, null, null, null, null
646
- ]);
647
- }
648
-
649
- return { states: mockPlanes };
650
- }
651
-
652
  // Load notifications from localStorage
653
  function loadNotifications() {
654
  const savedNotifications = localStorage.getItem('skywatch-notifications');
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SkyWatch - Real-time Plane Tracker</title>
7
+ <meta name="description" content="Track real planes flying above your location">
8
  <meta name="theme-color" content="#1e40af">
9
  <link rel="manifest" href="/manifest.json">
10
  <script src="https://cdn.tailwindcss.com"></script>
 
187
  notifications: [],
188
  lastUpdated: null,
189
  currentPlane: null,
190
+ deferredPrompt: null,
191
+ apiKeys: {
192
+ opensky: null, // OpenSky is free but rate limited
193
+ adsbexchange: null // ADSBExchange requires API key
194
+ }
195
  };
196
 
197
  // DOM Elements
 
280
  elements.upcomingPlanes.innerHTML = '';
281
  elements.upcomingPlanes.appendChild(elements.loadingPlanes);
282
  elements.apiStatus.textContent = 'API: Loading...';
283
+
284
+ if(!state.location) {
285
+ return;
286
+ }
287
 
288
  try {
289
+ // Calculate bounding box (1 degree = ~111km)
290
+ const range = 1; // ~111km radius
291
+ const bbox = [
292
+ state.location.lat - range,
293
+ state.location.lon - range,
294
+ state.location.lat + range,
295
+ state.location.lon + range
296
+ ];
297
+
298
+ console.log('---state', state);
299
+ console.log('---bbox', bbox);
300
+
301
+
302
+ // Try OpenSky Network API first (free but rate limited)
303
+ let response = await fetch(`https://opensky-network.org/api/states/all?lamin=${bbox[0]}&lomin=${bbox[1]}&lamax=${bbox[2]}&lomax=${bbox[3]}`);
304
+
305
+ if (!response.ok) {
306
+ // If OpenSky fails, try ADSBExchange (requires API key)
307
+ throw new Error('OpenSky API failed, trying ADSBExchange');
308
+ }
309
+
310
+ const data = await response.json();
311
+ state.planes = data.states || [];
312
+
313
+ if (state.planes.length === 0) {
314
+ // If no planes from OpenSky, try ADSBExchange
315
+ await getADSBExchangeData();
316
+ } else {
317
+ processPlaneData();
318
+ elements.apiStatus.textContent = 'API: OpenSky';
319
+ elements.apiStatus.className = elements.apiStatus.className.replace('text-red-500', 'text-green-500');
320
+ }
321
+ } catch (error) {
322
+ console.error('Error fetching plane data:', error);
323
+ // Fallback to ADSBExchange if OpenSky fails
324
+ await getADSBExchangeData();
325
+ }
326
+ }
327
+
328
+ // Fetch plane data from ADSBExchange API
329
+ async function getADSBExchangeData() {
330
+ try {
331
+ // ADSBExchange API (requires API key - this is a public demo key that may be rate limited)
332
+ const response = await fetch(`https://adsbexchange-com1.p.rapidapi.com/v2/lat/${state.location.lat}/lon/${state.location.lon}/dist/50/`, {
333
+ headers: {
334
+ 'X-RapidAPI-Key': 'your-rapidapi-key-here', // Replace with your RapidAPI key
335
+ 'X-RapidAPI-Host': 'adsbexchange-com1.p.rapidapi.com'
336
+ }
337
+ });
338
 
339
+ if (!response.ok) throw new Error('ADSBExchange API failed');
340
+
341
+ const data = await response.json();
342
+ // Convert ADSBExchange format to OpenSky-like format for consistency
343
+ state.planes = data.ac.map(plane => [
344
+ plane.hex, // icao24
345
+ plane.flight, // callsign
346
+ null, // origin country
347
+ null, // time position
348
+ null, // last contact
349
+ plane.lon, // longitude
350
+ plane.lat, // latitude
351
+ plane.altitude, // altitude (ft)
352
+ false, // on ground
353
+ plane.speed, // velocity (knots)
354
+ plane.track, // heading
355
+ plane.vrate, // vertical rate
356
+ null, null, null, null, null, null
357
+ ]);
358
 
359
  processPlaneData();
360
+ elements.apiStatus.textContent = 'API: ADSBExchange';
361
  elements.apiStatus.className = elements.apiStatus.className.replace('text-red-500', 'text-green-500');
362
  } catch (error) {
363
+ console.error('Error fetching ADSBExchange data:', error);
364
  elements.apiStatus.textContent = 'API: Offline';
365
  elements.apiStatus.className += ' text-red-500';
366
 
 
644
  // Extract airline code from callsign (first 3 letters usually)
645
  const airlineCode = callsign.substring(0, 3).toUpperCase();
646
 
647
+ // Airline database
648
  const airlines = {
649
  'UAL': 'United Airlines',
650
  'AAL': 'American Airlines',
 
661
  'SIA': 'Singapore Airlines',
662
  'THY': 'Turkish Airlines',
663
  'UAE': 'Emirates',
664
+ 'VIR': 'Virgin Atlantic',
665
+ 'RYR': 'Ryanair',
666
+ 'EZY': 'EasyJet',
667
+ 'WZZ': 'Wizz Air',
668
+ 'AFL': 'Aeroflot',
669
+ 'ANA': 'All Nippon Airways',
670
+ 'JAL': 'Japan Airlines',
671
+ 'CAL': 'China Airlines',
672
+ 'CPA': 'Cathay Pacific',
673
+ 'CES': 'China Eastern',
674
+ 'CSN': 'China Southern',
675
+ 'KAL': 'Korean Air',
676
+ 'MAS': 'Malaysia Airlines',
677
+ 'QTR': 'Qatar Airways',
678
+ 'SVA': 'Saudia',
679
+ 'THA': 'Thai Airways'
680
  };
681
 
682
  return airlines[airlineCode] || null;
683
  }
684
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
  // Load notifications from localStorage
686
  function loadNotifications() {
687
  const savedNotifications = localStorage.getItem('skywatch-notifications');