Zayeemk's picture
Rename static/app.js to static/js/app.js
6b2210f verified
// Flight Delay Prediction System - JavaScript
// Smooth scrolling
function scrollToSection(sectionId) {
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView({ behavior: 'smooth' });
}
}
// Initialize charts
let hourlyChart, seasonalChart, featureImportanceChart, predictionTrendsChart, airlinePerformanceChart, airportPerformanceChart;
// Load insights data
async function loadInsights() {
try {
const response = await fetch('/api/insights');
const data = await response.json();
if (data.error) {
console.error('Error loading insights:', data.error);
return;
}
// Update metrics
document.getElementById('delay-rate').textContent = data.delay_rate + '%';
document.getElementById('total-flights').textContent = data.total_flights.toLocaleString();
document.getElementById('avg-delay').textContent = data.avg_delay;
// Create charts with real data
await createHourlyChart();
await createSeasonalChart();
await createFeatureImportanceChart();
await createPredictionTrendsChart();
await createAirlinePerformanceChart();
await createAirportPerformanceChart();
} catch (error) {
console.error('Error fetching insights:', error);
}
}
// Create hourly delays chart
async function createHourlyChart() {
try {
const response = await fetch('/api/chart-data/hourly');
const data = await response.json();
if (data.error) {
console.error('Error loading hourly data:', data.error);
return;
}
const ctx = document.getElementById('hourly-chart').getContext('2d');
if (hourlyChart) {
hourlyChart.destroy();
}
hourlyChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels.map(h => h + ':00'),
datasets: [{
label: 'Delay Rate by Hour',
data: data.data,
backgroundColor: '#2F80ED',
borderColor: '#2F80ED',
borderWidth: 1,
borderRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Delays by Departure Hour',
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
},
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Delay Rate (%)',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
},
x: {
title: {
display: true,
text: 'Hour of Day',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
}
}
}
});
} catch (error) {
console.error('Error creating hourly chart:', error);
}
}
// Create seasonal delays chart
async function createSeasonalChart() {
try {
const response = await fetch('/api/chart-data/seasonal');
const data = await response.json();
if (data.error) {
console.error('Error loading seasonal data:', data.error);
return;
}
const ctx = document.getElementById('seasonal-chart').getContext('2d');
if (seasonalChart) {
seasonalChart.destroy();
}
seasonalChart = new Chart(ctx, {
type: 'pie',
data: {
labels: data.labels,
datasets: [{
data: data.data,
backgroundColor: ['#2F80ED', '#27AE60', '#56CCF2', '#F2994A'],
borderWidth: 2,
borderColor: '#fff',
borderRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom',
labels: {
color: '#1A2B3C',
padding: 20,
font: {
family: 'Inter'
}
}
},
title: {
display: true,
text: 'Delays by Season',
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
}
}
});
} catch (error) {
console.error('Error creating seasonal chart:', error);
}
}
// Create feature importance chart
async function createFeatureImportanceChart() {
try {
const response = await fetch('/api/chart-data/feature-importance');
const data = await response.json();
if (data.error) {
console.error('Error loading feature importance data:', data.error);
return;
}
const ctx = document.getElementById('feature-importance-chart').getContext('2d');
if (featureImportanceChart) {
featureImportanceChart.destroy();
}
featureImportanceChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: [{
label: 'Feature Importance',
data: data.data,
backgroundColor: '#2F80ED',
borderColor: '#2F80ED',
borderWidth: 1,
borderRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
indexAxis: 'y',
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Feature Importance',
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
},
scales: {
x: {
title: {
display: true,
text: 'Importance',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
},
y: {
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
}
}
}
});
} catch (error) {
console.error('Error creating feature importance chart:', error);
}
}
// Create prediction trends chart
async function createPredictionTrendsChart() {
try {
const response = await fetch('/api/chart-data/prediction-trends');
const data = await response.json();
if (data.error) {
console.error('Error loading prediction trends data:', data.error);
return;
}
const ctx = document.getElementById('prediction-trends-chart').getContext('2d');
if (predictionTrendsChart) {
predictionTrendsChart.destroy();
}
predictionTrendsChart = new Chart(ctx, {
type: 'line',
data: {
labels: data.labels,
datasets: [{
label: 'Prediction Confidence',
data: data.data,
borderColor: '#2F80ED',
backgroundColor: 'rgba(47, 128, 237, 0.1)',
borderWidth: 3,
fill: true,
tension: 0.4,
pointBackgroundColor: '#2F80ED',
pointBorderColor: '#fff',
pointBorderWidth: 2,
pointRadius: 5,
pointHoverRadius: 7
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Prediction Trends Over Time',
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
},
scales: {
y: {
beginAtZero: true,
max: 100,
title: {
display: true,
text: 'Confidence (%)',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
},
x: {
title: {
display: true,
text: 'Day',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
}
}
}
});
} catch (error) {
console.error('Error creating prediction trends chart:', error);
}
}
// Create airline performance chart
async function createAirlinePerformanceChart() {
try {
const response = await fetch('/api/chart-data/airline-performance');
const data = await response.json();
if (data.error) {
console.error('Error loading airline performance data:', data.error);
return;
}
const ctx = document.getElementById('airline-performance-chart').getContext('2d');
if (airlinePerformanceChart) {
airlinePerformanceChart.destroy();
}
airlinePerformanceChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.labels,
datasets: [{
label: 'Delay Rate by Airline',
data: data.data,
backgroundColor: '#2F80ED',
borderColor: '#2F80ED',
borderWidth: 1,
borderRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Airline Performance',
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
},
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Delay Rate (%)',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
},
x: {
title: {
display: true,
text: 'Airlines',
color: '#4A5D73',
font: {
family: 'Inter',
size: 14
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter',
size: 11
},
maxRotation: 45,
minRotation: 0,
autoSkip: false,
callback: function(value, index, values) {
const label = this.getLabelForValue(value);
if (label.length > 20) {
return label.substring(0, 18) + '...';
}
return label;
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
}
}
}
});
} catch (error) {
console.error('Error creating airline performance chart:', error);
}
}
// Create airport performance chart
async function createAirportPerformanceChart() {
try {
const response = await fetch('/api/chart-data/airport-performance');
const data = await response.json();
if (data.error) {
console.error('Error loading airport performance data:', data.error);
return;
}
const ctx = document.getElementById('airport-performance-chart').getContext('2d');
if (airportPerformanceChart) {
airportPerformanceChart.destroy();
}
// Prepare data for dual-axis chart
const airports = Object.keys(data.top_airports);
const delayRates = Object.values(data.delay_rates);
const flightVolumes = Object.values(data.top_airports);
airportPerformanceChart = new Chart(ctx, {
type: 'bar',
data: {
labels: airports,
datasets: [
{
label: 'Delay Rate (%)',
data: delayRates,
backgroundColor: '#EB5757',
borderColor: '#EB5757',
borderWidth: 1,
borderRadius: 4,
yAxisID: 'y'
},
{
label: 'Flight Volume',
data: flightVolumes,
backgroundColor: '#2F80ED',
borderColor: '#2F80ED',
borderWidth: 1,
borderRadius: 4,
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'bottom',
labels: {
color: '#1A2B3C',
padding: 20,
font: {
family: 'Inter'
}
}
},
title: {
display: true,
text: 'Airport Performance',
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
},
scales: {
y: {
type: 'linear',
display: true,
title: {
display: true,
text: 'Delay Rate (%)',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
},
y1: {
type: 'linear',
position: 'right',
title: {
display: true,
text: 'Flight Volume',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
display: false
}
},
x: {
title: {
display: true,
text: 'Airports',
color: '#4A5D73',
font: {
family: 'Inter',
size: 14
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter',
size: 11
},
maxRotation: 45,
minRotation: 0,
autoSkip: false,
callback: function(value, index, values) {
const label = this.getLabelForValue(value);
if (label.length > 25) {
return label.substring(0, 23) + '...';
}
return label;
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
}
}
}
});
} catch (error) {
console.error('Error creating airport performance chart:', error);
}
}
// Create prediction chart for specific prediction
async function createPredictionChart(predictionData) {
const ctx = document.getElementById('prediction-chart').getContext('2d');
if (window.predictionChart) {
window.predictionChart.destroy();
}
// Create gauge chart for prediction
const prediction = predictionData.prediction;
const probability = predictionData.probability;
window.predictionChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['On Time', 'Delayed'],
datasets: [{
data: [prediction === 0 ? 100 - probability : probability, prediction === 1 ? probability : 100 - probability],
backgroundColor: ['#27AE60', '#EB5757'],
borderWidth: 2,
borderColor: '#fff',
borderRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
cutout: '70%',
plugins: {
legend: {
display: true,
position: 'bottom',
labels: {
color: '#1A2B3C',
padding: 20,
font: {
family: 'Inter'
}
}
},
title: {
display: true,
text: `Flight Prediction - ${predictionData.status}`,
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
}
}
});
}
// Load airlines and airports for form
async function loadFormData() {
try {
// Load airlines
const airlinesResponse = await fetch('/api/airlines');
const airlinesData = await airlinesResponse.json();
const airlineSelect = document.getElementById('airline');
if (airlinesData.airlines && !airlinesData.error) {
airlinesData.airlines.forEach(airline => {
const option = document.createElement('option');
option.value = airline;
option.textContent = airline;
airlineSelect.appendChild(option);
});
}
// Load airports
const airportsResponse = await fetch('/api/airports');
const airportsData = await airportsResponse.json();
const originSelect = document.getElementById('origin');
const destinationSelect = document.getElementById('destination');
if (airportsData.airports && !airportsData.error) {
airportsData.airports.forEach(airport => {
const option1 = document.createElement('option');
option1.value = airport;
option1.textContent = airport;
originSelect.appendChild(option1);
const option2 = document.createElement('option');
option2.value = airport;
option2.textContent = airport;
destinationSelect.appendChild(option2);
});
}
// Add event listeners for automatic season calculation
const flightDateInput = document.getElementById('flight_date');
const originAirportSelect = document.getElementById('origin');
const seasonInput = document.getElementById('season');
// Function to update season based on date and origin
function updateSeason() {
const flightDate = flightDateInput.value;
const origin = originAirportSelect.value;
if (flightDate && origin) {
// Extract origin airport code for season calculation
const originCode = origin.split('(').pop()?.replace(')', '').trim() || origin.split()[0];
// Calculate season based on date and origin
const season = calculateSeasonFromDate(flightDate, originCode);
seasonInput.value = season;
}
}
flightDateInput.addEventListener('change', updateSeason);
originAirportSelect.addEventListener('change', updateSeason);
// Set default date to today
const today = new Date().toISOString().split('T')[0];
flightDateInput.value = today;
} catch (error) {
console.error('Error loading form data:', error);
}
}
// Calculate season based on date and origin airport
function calculateSeasonFromDate(dateStr, originAirport) {
try {
const date = new Date(dateStr);
const month = date.getMonth() + 1; // 1-12
// Major southern hemisphere airports
const southernAirports = ['SYD', 'MEL', 'BNE', 'ADL', 'PER', 'CBR', 'HBA', 'DRW', 'CNS', 'OOL'];
// Extract airport code
const originCode = originAirport.split('(').pop()?.replace(')', '').trim() || originAirport.split()[0];
const isSouthern = southernAirports.includes(originCode.toUpperCase());
if (isSouthern) {
// Southern hemisphere seasons are reversed
if ([12, 1, 2].includes(month)) return 'Summer';
if ([3, 4, 5].includes(month)) return 'Fall';
if ([6, 7, 8].includes(month)) return 'Winter';
return 'Spring'; // [9, 10, 11]
} else {
// Northern hemisphere seasons
if ([12, 1, 2].includes(month)) return 'Winter';
if ([3, 4, 5].includes(month)) return 'Spring';
if ([6, 7, 8].includes(month)) return 'Summer';
return 'Fall'; // [9, 10, 11]
}
} catch (error) {
console.error('Error calculating season:', error);
return 'Spring';
}
}
// Handle prediction form submission
document.getElementById('prediction-form').addEventListener('submit', async function(e) {
e.preventDefault();
console.log('=== FORM SUBMISSION STARTED ===');
const submitButton = this.querySelector('button[type="submit"]');
const originalText = submitButton.textContent;
// Get form values directly
const airline = document.getElementById('airline').value;
const origin = document.getElementById('origin').value;
const destination = document.getElementById('destination').value;
const departure_hour = document.getElementById('departure_hour').value;
const flight_date = document.getElementById('flight_date').value;
console.log('Form values:', { airline, origin, destination, departure_hour, flight_date });
// Validate form data
if (!airline || !origin || !destination || !departure_hour || !flight_date) {
alert('Please fill in all required fields.');
return;
}
// Show loading state
submitButton.textContent = 'Predicting...';
submitButton.disabled = true;
try {
// Create FormData exactly like the working test function
const formData = new FormData();
formData.append('airline', airline);
formData.append('origin', origin);
formData.append('destination', destination);
formData.append('departure_hour', departure_hour);
formData.append('flight_date', flight_date);
console.log('Sending prediction request...');
const response = await fetch('/api/predict', {
method: 'POST',
body: formData
});
console.log('Response status:', response.status);
if (!response.ok) {
const errorText = await response.text();
console.error('Server error:', errorText);
throw new Error(`Server error: ${response.status} - ${errorText}`);
}
const result = await response.json();
console.log('Prediction result:', result);
if (result.error) {
alert('Error: ' + result.error);
return;
}
// Display result directly on webpage
displayPredictionResult(result);
// Create prediction chart
try {
await createPredictionChart(result);
document.getElementById('prediction-chart-container').style.display = 'block';
} catch (chartError) {
console.error('Error creating prediction chart:', chartError);
}
// Create flight visualization chart
try {
await createFlightVisualizationChart(result);
document.getElementById('flight-visualization-container').style.display = 'block';
} catch (flightChartError) {
console.error('Error creating flight visualization chart:', flightChartError);
}
console.log('=== FORM SUBMISSION COMPLETED ===');
} catch (error) {
console.error('Error making prediction:', error);
alert('Error making prediction: ' + error.message + '. Please try again.');
} finally {
// Reset button
submitButton.textContent = originalText;
submitButton.disabled = false;
}
});
// Display prediction result
function displayPredictionResult(result) {
try {
console.log('Displaying prediction result:', result);
const resultDiv = document.getElementById('prediction-result');
const probabilityDiv = document.getElementById('result-probability');
const statusDiv = document.getElementById('result-status');
const descriptionDiv = document.getElementById('result-description');
if (!resultDiv || !probabilityDiv || !statusDiv || !descriptionDiv) {
console.error('Result display elements not found:', {
resultDiv: !!resultDiv,
probabilityDiv: !!probabilityDiv,
statusDiv: !!statusDiv,
descriptionDiv: !!descriptionDiv
});
return;
}
// Update result display
probabilityDiv.textContent = (result.probability || 0) + '%';
statusDiv.textContent = result.status || 'Unknown';
// Set color based on prediction
if (result.prediction === 1) {
probabilityDiv.className = 'result-probability result-delayed';
statusDiv.className = 'result-label result-delayed';
descriptionDiv.textContent = 'High probability of delay. Consider alternative flights or allow extra time.';
} else {
probabilityDiv.className = 'result-probability result-ontime';
statusDiv.className = 'result-label result-ontime';
descriptionDiv.textContent = 'Low probability of delay. Flight is likely to be on time.';
}
// Show result section
resultDiv.style.display = 'block';
console.log('Result displayed successfully');
// Scroll to result
setTimeout(() => {
resultDiv.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 100);
} catch (error) {
console.error('Error displaying prediction result:', error);
}
}
// Create flight visualization chart
async function createFlightVisualizationChart(predictionData) {
try {
const response = await fetch('/api/flight-visualization', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
airline: predictionData.airline,
origin: predictionData.origin,
destination: predictionData.destination,
probability: predictionData.probability,
season: predictionData.season
})
});
const data = await response.json();
if (data.error) {
console.error('Error loading flight visualization data:', data.error);
return;
}
const ctx = document.getElementById('flight-visualization-chart').getContext('2d');
if (window.flightVisualizationChart) {
window.flightVisualizationChart.destroy();
}
// Create combination chart with flight phases and risk factors
window.flightVisualizationChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.flight_phases,
datasets: [
{
label: 'Confidence Level',
data: data.phase_confidences,
backgroundColor: 'rgba(47, 128, 237, 0.8)',
borderColor: '#2F80ED',
borderWidth: 2,
borderRadius: 4,
yAxisID: 'y'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'top',
labels: {
color: '#1A2B3C',
font: {
family: 'Inter'
}
}
},
title: {
display: true,
text: `Flight Analysis: ${data.airline} - ${data.origin} to ${data.destination}`,
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
},
subtitle: {
display: true,
text: `Season: ${data.season} | Overall Delay Probability: ${data.overall_probability}%`,
color: '#4A5D73',
font: {
size: 14,
family: 'Inter'
}
}
},
scales: {
y: {
type: 'linear',
display: true,
position: 'left',
title: {
display: true,
text: 'Confidence (%)',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
},
max: 100
},
x: {
title: {
display: true,
text: 'Flight Phases',
color: '#4A5D73',
font: {
family: 'Inter'
}
},
ticks: {
color: '#4A5D73',
font: {
family: 'Inter'
}
},
grid: {
color: 'rgba(74, 93, 115, 0.1)'
}
}
}
}
});
// Create risk factors chart below
createRiskFactorsChart(data);
} catch (error) {
console.error('Error creating flight visualization chart:', error);
}
}
// Create risk factors chart
function createRiskFactorsChart(data) {
// Create a second chart for risk factors if it doesn't exist
const riskContainer = document.getElementById('flight-visualization-container');
// Check if risk chart already exists
if (document.getElementById('risk-factors-chart')) {
return;
}
// Create risk factors chart container
const riskChartDiv = document.createElement('div');
riskChartDiv.className = 'dashboard-card chart-container';
riskChartDiv.style.gridColumn = '1 / -1';
riskChartDiv.style.marginTop = '30px';
riskChartDiv.innerHTML = '<canvas id="risk-factors-chart"></canvas>';
riskContainer.appendChild(riskChartDiv);
const ctx = document.getElementById('risk-factors-chart').getContext('2d');
if (window.riskFactorsChart) {
window.riskFactorsChart.destroy();
}
window.riskFactorsChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: data.risk_factors,
datasets: [{
data: data.risk_values,
backgroundColor: [
'#EB5757', // Weather Risk - Red
'#F2994A', // Traffic Congestion - Orange
'#56CCF2', // Airport Delay History - Light Blue
'#27AE60', // Airline Performance - Green
'#2F80ED' // Time of Day - Blue
],
borderWidth: 2,
borderColor: '#fff',
borderRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: true,
position: 'bottom',
labels: {
color: '#1A2B3C',
padding: 20,
font: {
family: 'Inter'
}
}
},
title: {
display: true,
text: 'Risk Factors Analysis',
color: '#1A2B3C',
font: {
size: 16,
weight: 'bold',
family: 'Inter'
}
}
}
}
});
}
// Auto-update flight status
function updateFlightStatus() {
const onTimeElement = document.querySelector('.status-on-time').parentElement.querySelector('span');
const delayedElement = document.querySelector('.status-delayed').parentElement.querySelector('span');
// Simulate real-time updates
const onTimeRate = 75 + Math.random() * 10;
const delayedRate = 100 - onTimeRate;
onTimeElement.textContent = `On Time: ${onTimeRate.toFixed(1)}%`;
delayedElement.textContent = `Delayed: ${delayedRate.toFixed(1)}%`;
}
// Add parallax effect
window.addEventListener('scroll', function() {
const scrolled = window.pageYOffset;
const parallaxElements = document.querySelectorAll('.parallax-element');
parallaxElements.forEach(element => {
const speed = element.dataset.speed || 0.5;
element.style.transform = `translateY(${scrolled * speed}px)`;
});
// Add parallax to hero section
const heroSection = document.querySelector('.hero-section');
if (heroSection) {
heroSection.style.transform = `translateY(${scrolled * 0.3}px)`;
}
});
// Test function to debug prediction API
async function testPrediction() {
try {
console.log('Testing prediction API...');
// Test the test endpoint first
const testResponse = await fetch('/api/test');
const testData = await testResponse.json();
console.log('Test endpoint result:', testData);
// Test the prediction endpoint with sample data
const formData = new FormData();
formData.append('airline', 'Air India');
formData.append('origin', 'Indira Gandhi International Airport (DEL)');
formData.append('destination', 'Chatrapati Shivaji International Airport (BOM)');
formData.append('departure_hour', '10');
formData.append('flight_date', '2024-12-15');
console.log('Sending prediction request...');
const response = await fetch('/api/predict', {
method: 'POST',
body: formData
});
console.log('Response status:', response.status);
if (!response.ok) {
const errorText = await response.text();
console.error('Server error:', errorText);
alert('Server error: ' + response.status + ' - ' + errorText);
return;
}
const result = await response.json();
console.log('Prediction result:', result);
if (result.error) {
alert('Prediction error: ' + result.error);
} else {
alert('Prediction successful! Status: ' + result.status + ', Probability: ' + result.probability + '%');
}
} catch (error) {
console.error('Test error:', error);
alert('Test error: ' + error.message);
}
}
// Add smooth scroll behavior
document.addEventListener('DOMContentLoaded', function() {
// Load form data
loadFormData();
// Load insights
loadInsights();
// Update flight status every 5 seconds
setInterval(updateFlightStatus, 5000);
// Add smooth scroll behavior
document.documentElement.style.scrollBehavior = 'smooth';
// Add parallax class to elements
const heroTitle = document.querySelector('.hero-title');
const heroSubtitle = document.querySelector('.hero-subtitle');
const heroButtons = document.querySelector('.hero-buttons');
if (heroTitle) heroTitle.classList.add('parallax-element');
if (heroSubtitle) heroSubtitle.classList.add('parallax-element');
if (heroButtons) heroButtons.classList.add('parallax-element');
// Set different speeds for different elements
if (heroTitle) heroTitle.dataset.speed = '0.2';
if (heroSubtitle) heroSubtitle.dataset.speed = '0.3';
if (heroButtons) heroButtons.dataset.speed = '0.4';
});
// Add intersection observer for animations
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.style.opacity = '1';
entry.target.style.transform = 'translateY(0)';
}
});
}, observerOptions);
// Observe all cards for animation
document.addEventListener('DOMContentLoaded', function() {
const cards = document.querySelectorAll('.feature-card, .dashboard-card, .impact-card');
cards.forEach(card => {
card.style.opacity = '0';
card.style.transform = 'translateY(20px)';
card.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
observer.observe(card);
});
});