No logs found for the selected date range.
';
document.getElementById('swfm-fatigue-indicator-label').textContent = 'N/A';
document.getElementById('swfm-fatigue-needle').style.transform = `rotate(-90deg)`;
Object.values(swfmChartInstances).forEach(chart => chart ? chart.destroy() : null);
return;
}
// Update Fatigue Indicator (based on latest log in range)
const latestLog = filteredLogs.length > 0 ? filteredLogs[filteredLogs.length - 1] : null;
const fatigueScore = swfmCalculateFatigueScore(latestLog);
const needleRotation = (fatigueScore / 100) * 180 - 90; // -90 (low) to +90 (high)
document.getElementById('swfm-fatigue-needle').style.transform = `rotate(${needleRotation}deg)`;
const indicatorLabelEl = document.getElementById('swfm-fatigue-indicator-label');
if (fatigueScore >= 70) { indicatorLabelEl.textContent = "High Fatigue Risk"; indicatorLabelEl.className = 'swfm-indicator-label fatigue-high';}
else if (fatigueScore >= 40) { indicatorLabelEl.textContent = "Moderate Fatigue"; indicatorLabelEl.className = 'swfm-indicator-label fatigue-moderate';}
else { indicatorLabelEl.textContent = "Low Fatigue / Good State"; indicatorLabelEl.className = 'swfm-indicator-label fatigue-low';}
// Prepare chart data
const stressData = filteredLogs.map(log => ({x: log.datetime, y: log.stressLevel}));
const energyData = filteredLogs.map(log => ({x: log.datetime, y: log.energyLevel}));
const sleepData = filteredLogs.map(log => ({x: log.datetime, y: log.sleepQuality}));
// Symptom frequency
let symptomCounts = {};
filteredLogs.forEach(log => {
[...log.physicalSymptoms, ...log.mentalSymptoms].forEach(symptom => {
symptomCounts[symptom] = (symptomCounts[symptom] || 0) + 1;
});
});
const sortedSymptoms = Object.entries(symptomCounts).sort((a,b) => b[1] - a[1]).slice(0,5); // Top 5
// Dashboard HTML (Chart Canvases)
document.getElementById('swfm-dashboard-display').innerHTML = `
Stress Level Over Time
Energy Level Over Time
Sleep Quality Over Time
Top Reported Symptoms
`;
// Render Charts
swfmRenderLineChart('swfm-stress-chart', stressData, 'Stress Level (1-5)', 'var(--danger-color)');
swfmRenderLineChart('swfm-energy-chart', energyData, 'Energy Level (1-5)', 'var(--success-color)');
swfmRenderLineChart('swfm-sleep-chart', sleepData, 'Sleep Quality (1-5)', 'var(--primary-color)');
swfmRenderBarChart('swfm-symptoms-chart', sortedSymptoms.map(s=>s[0]), sortedSymptoms.map(s=>s[1]), 'Symptom Frequency', 'var(--accent-color)');
// Generate Insights
const insightsListEl = document.getElementById('swfm-insights-list');
insightsListEl.innerHTML = ''; let insightsGenerated = 0;
if (filteredLogs.length > 0) {
const avgStress = filteredLogs.reduce((sum,l)=>sum+l.stressLevel,0)/filteredLogs.length;
const avgEnergy = filteredLogs.reduce((sum,l)=>sum+l.energyLevel,0)/filteredLogs.length;
const avgSleep = filteredLogs.reduce((sum,l)=>sum+l.sleepQuality,0)/filteredLogs.length;
const avgBreaks = filteredLogs.reduce((sum,l)=>sum+l.breaksTaken,0)/filteredLogs.length;
if(avgStress >= 4) { insightsListEl.innerHTML += `
Average stress level is high (${avgStress.toFixed(1)}/5). Consider stress management techniques or workload review.`; insightsGenerated++;}
if(avgEnergy <= 2) { insightsListEl.innerHTML += `
Average energy level is low (${avgEnergy.toFixed(1)}/5). Ensure sufficient rest, nutrition, and breaks.`; insightsGenerated++;}
if(avgSleep <= 2) { insightsListEl.innerHTML += `
Average sleep quality is poor (${avgSleep.toFixed(1)}/5). Prioritize sleep hygiene for better recovery and daytime energy.`; insightsGenerated++;}
if(avgBreaks < 2 && filteredLogs.some(l => l.workDuration > 4)) { insightsListEl.innerHTML += `
Average breaks taken is low (${avgBreaks.toFixed(1)}). Regular short breaks (5-10 min every hour) can significantly reduce fatigue during long work periods.`; insightsGenerated++;}
if(symptomCounts["Eye Strain"] && symptomCounts["Eye Strain"] > filteredLogs.length / 3) { insightsListEl.innerHTML += `
'Eye Strain' is frequently reported. Remember the 20-20-20 rule: every 20 minutes, look at something 20 feet away for 20 seconds. Ensure proper screen ergonomics.`; insightsGenerated++;}
if(symptomCounts["Headache"] && symptomCounts["Headache"] > filteredLogs.length / 3) { insightsListEl.innerHTML += `
'Headache' is frequently reported. Ensure proper hydration, screen brightness, and consider if stress or eye strain are contributing factors.`; insightsGenerated++;}
}
if(insightsGenerated === 0 && filteredLogs.length > 0) insightsListEl.innerHTML += `
Review your trend charts for personal patterns. Consistent logging helps identify what impacts your fatigue levels.`;
else if (filteredLogs.length === 0) insightsListEl.innerHTML += `
No data in the selected range to provide insights.`;
}
function swfmRenderLineChart(canvasId, dataPoints, label, color) { // dataPoints = [{x: Date, y: value}]
const ctx = document.getElementById(canvasId);
if (!ctx) return;
if (swfmChartInstances[canvasId]) swfmChartInstances[canvasId].destroy();
swfmChartInstances[canvasId] = new Chart(ctx.getContext('2d'), {
type: 'line',
data: { datasets: [{ label: label, data: dataPoints, borderColor: color, tension: 0.1, fill: false }] },
options: {
responsive: true, maintainAspectRatio: false,
scales: { x: { type: 'time', time: { unit: 'day', tooltipFormat: 'MMM dd, yyyy', displayFormats: {'day': 'MMM dd'} } },
y: { beginAtZero: false, suggestedMin: 1, suggestedMax: (label.includes('Sleep') || label.includes('Energy') || label.includes('Stress')) ? 5 : undefined, title: {display:true, text:label.split('(')[0].trim()}} }
}
});
}
function swfmRenderBarChart(canvasId, labels, data, chartLabel, color) {
const ctx = document.getElementById(canvasId);
if (!ctx) return;
if (swfmChartInstances[canvasId]) swfmChartInstances[canvasId].destroy();
swfmChartInstances[canvasId] = new Chart(ctx.getContext('2d'), {
type: 'bar',
data: { labels: labels, datasets: [{ label: chartLabel, data: data, backgroundColor: color }] },
options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { beginAtZero: true, title: {display:true, text:"Frequency"} } } }
});
}
// PDF Download
function swfmDownloadPDF() {
const dashboardDisplayElement = document.getElementById('swfm-dashboard-display');
if (!dashboardDisplayElement || dashboardDisplayElement.innerHTML.includes("Log check-ins") || swfmFatigueLogs.length === 0) {
alert("Please log some data and analyze trends first."); return;
}
const analysisStartDate = document.getElementById('swfm-analysis-start-date').value;
const analysisEndDate = document.getElementById('swfm-analysis-end-date').value;
const fatigueIndicatorLabel = document.getElementById('swfm-fatigue-indicator-label').textContent;
const fatigueNeedleTransform = document.getElementById('swfm-fatigue-needle').style.transform;
let pdfHTML = `
Work Fatigue Monitor Report
`;
pdfHTML += `
Analysis Period: ${analysisStartDate} to ${analysisEndDate}
`;
pdfHTML += `
Current Fatigue Indicator
`;
const chartsToInclude = [
{instance: swfmChartInstances['swfm-stress-chart'], title: "Stress Level Over Time"},
{instance: swfmChartInstances['swfm-energy-chart'], title: "Energy Level Over Time"},
{instance: swfmChartInstances['swfm-sleep-chart'], title: "Sleep Quality Over Time"},
{instance: swfmChartInstances['swfm-symptoms-chart'], title: "Top Reported Symptoms"}
];
chartsToInclude.forEach(chartInfo => {
if(chartInfo.instance){
pdfHTML += `
`;
}
});
const insightsContent = document.getElementById('swfm-insights-list').outerHTML;
if(insightsContent) pdfHTML += `
Key Insights & Recommendations
${insightsContent}`;
const filteredLogsForPDF = swfmFatigueLogs.filter(log => {
const logDateOnly = log.datetime.toISOString().split('T')[0];
return logDateOnly >= analysisStartDate && logDateOnly <= analysisEndDate;
});
if (filteredLogsForPDF.length > 0) {
pdfHTML += `
Detailed Log (${analysisStartDate} to ${analysisEndDate})
`;
pdfHTML += `
| Date | Work(h) | Brk | Stress | Energy | Sleep | Symptoms | Notes |
`;
filteredLogsForPDF.forEach(log => {
const symptomsSummary = [...log.physicalSymptoms, ...log.mentalSymptoms];
pdfHTML += `
| ${log.datetime.toLocaleString([],{dateStyle:'short',timeStyle:'short'})} | ${log.workDuration.toFixed(1)} | ${log.breaksTaken} |
${log.stressLevel} | ${log.energyLevel} | ${log.sleepQuality} |
${symptomsSummary.length > 0 ? symptomsSummary.join(', ').substring(0,30)+'...' : 'None'} |
${log.notes.substring(0,30)}${log.notes.length > 30 ? '...' : ''} |
`;
});
pdfHTML += `
`;
}
const pdfContainer = document.getElementById('swfm-report-content-for-pdf');
pdfContainer.innerHTML = pdfHTML;
// Manually apply gradient to gauge for PDF because CSS gradients in html2pdf are tricky
const gaugePdf = pdfContainer.querySelector('.swfm-indicator-gauge');
if(gaugePdf) {
const c = getComputedStyle(document.documentElement);
gaugePdf.style.backgroundImage = `linear-gradient(to right, ${c.getPropertyValue('--success-color')}, ${c.getPropertyValue('--warning-color')}, ${c.getPropertyValue('--danger-color')})`;
}
const opt = {
margin: [0.5, 0.4, 0.5, 0.4], filename: `Work_Fatigue_Report_${analysisStartDate}_to_${analysisEndDate}.pdf`,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2, useCORS: true, logging: false, scrollX:0, scrollY: -window.scrollY, windowWidth: pdfContainer.scrollWidth + 100 },
jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' },
pagebreak: { mode: ['avoid-all', 'css', 'legacy'] }
};
html2pdf().from(pdfContainer).set(opt).save().then(() => {
pdfContainer.innerHTML = '';
}).catch(err => {
console.error("Error generating PDF:", err);
pdfContainer.innerHTML = '';
alert("An error occurred while generating the PDF. Check console for details.");
});
}