${interpretation.status}: ${interpretation.text}
`;
container.appendChild(card);
}
updateOverallHealth(overallScore / Object.keys(indicators).length);
}
function updateOverallHealth(avgScore) {
const healthScoreText = document.getElementById('health-score-text');
const healthSummary = document.getElementById('health-summary');
if (avgScore > 1.5) {
healthScoreText.textContent = "Strong";
healthScoreText.className = 'text-4xl font-bold text-emerald-600 mt-2';
healthSummary.textContent = "The economy shows strong signs of expansion. Most key indicators are positive, suggesting robust growth and high confidence.";
} else if (avgScore > 0.5) {
healthScoreText.textContent = "Moderate";
healthScoreText.className = 'text-4xl font-bold text-amber-600 mt-2';
healthSummary.textContent = "The economic picture is mixed but generally positive. Growth is steady, but some areas may show signs of slowing or require monitoring.";
} else {
healthScoreText.textContent = "Weak";
healthScoreText.className = 'text-4xl font-bold text-red-600 mt-2';
healthSummary.textContent = "Indicators suggest economic weakness or a potential downturn. Caution is advised as consumer and business activity may be contracting.";
}
}
function calculateIndicatorScore(key, value) {
const i = indicators[key];
if (key === 'unemployment') { // Lower is better
if (value < i.thresholds.low) return 2;
if (value < i.thresholds.moderate) return 1;
return 0;
}
if (key === 'inflation') { // Ideal range
if (value >= i.thresholds.low && value <= i.thresholds.ideal) return 2;
if (value > i.thresholds.ideal && value <= i.thresholds.high) return 1;
return 0;
}
// Higher is better for others
if (value >= i.thresholds.moderate) return 2;
if (value >= i.thresholds.weak) return 1;
return 0;
}
function getStatusColor(key, value) {
const score = calculateIndicatorScore(key, value);
if (score === 2) return { text: 'text-emerald-600', border: 'border-emerald-500', bg: '#10B981' };
if (score === 1) return { text: 'text-amber-600', border: 'border-amber-500', bg: '#F59E0B' };
return { text: 'text-red-600', border: 'border-red-500', bg: '#EF4444' };
}
// --- CHARTING ---
function renderGaugeCharts() {
const container = document.getElementById('gauge-charts-container');
container.innerHTML = ''; // Clear previous charts
for(const key in indicators) {
const i = indicators[key];
const div = document.createElement('div');
div.className = 'bg-white p-4 rounded-lg shadow-lg text-center';
const canvasId = `${key}-gauge`;
div.innerHTML = `
${i.name}
`;
container.appendChild(div);
if (gaugeCharts[key]) {
gaugeCharts[key].destroy(); // Destroy old instance
}
createGaugeChart(key);
}
}
function createGaugeChart(key) {
const ctx = document.getElementById(`${key}-gauge`)?.getContext('2d');
if (!ctx) return;
const i = indicators[key];
const value = i.value;
const color = getStatusColor(key, value).bg;
let max = Math.max(...Object.values(i.thresholds)) * 1.25;
if (key === 'cci') max = 150;
gaugeCharts[key] = new Chart(ctx, {
type: 'doughnut',
data: {
datasets: [{
data: [value, max - value],
backgroundColor: [color, '#e2e8f0'],
borderWidth: 0,
}]
},
options: {
rotation: -90,
circumference: 180,
cutout: '70%',
responsive: true,
plugins: {
tooltip: { enabled: false }
}
}
});
}
// --- TAB NAVIGATION ---
function updateActiveTab() {
tabPanels.forEach((panel, index) => panel.classList.toggle('hidden', index !== currentTabIndex));
tabs.forEach((tab, index) => {
tab.classList.toggle('tab-btn-active', index === currentTabIndex);
tab.classList.toggle('tab-btn-inactive', index !== currentTabIndex);
tab.classList.toggle('border-teal-600', index === currentTabIndex);
tab.classList.toggle('border-transparent', index !== currentTabIndex);
});
updateNavButtons();
// Re-render charts only when switching to their tab to ensure they are visible
if (tabs[currentTabIndex].dataset.tab === 'visuals') {
renderGaugeCharts();
}
}
function updateNavButtons() {
if (prevBtn) prevBtn.disabled = currentTabIndex === 0;
if (nextBtn) nextBtn.disabled = currentTabIndex === tabs.length - 1;
prevBtn?.classList.toggle('opacity-50', prevBtn?.disabled);
nextBtn?.classList.toggle('opacity-50', nextBtn?.disabled);
}
function navigateNext() { if (currentTabIndex < tabs.length - 1) { currentTabIndex++; updateActiveTab(); } }
function navigatePrev() { if (currentTabIndex > 0) { currentTabIndex--; updateActiveTab(); } }
// --- PDF DOWNLOAD ---
function downloadPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const primaryColor = '#0d9488'; // Teal-600
const today = new Date().toLocaleDateString('en-US');
// --- Page Header ---
const addHeader = (title) => {
doc.setFillColor(primaryColor);
doc.rect(0, 0, 210, 25, 'F');
doc.setFontSize(22);
doc.setTextColor('#FFFFFF');
doc.setFont('helvetica', 'bold');
doc.text(title, 105, 16, { align: 'center' });
};
const addFooter = (pageNum) => {
doc.setFontSize(9);
doc.setTextColor('#64748b'); // slate-500
doc.text(`Page ${pageNum} | Economic Briefing | Generated on ${today}`, 105, 290, { align: 'center' });
};
// --- Page 1: Summary ---
addHeader('Economic Briefing Report');
const avgScore = Object.values(indicators).reduce((acc, i, index, arr) => {
const key = Object.keys(indicators)[index];
return acc + calculateIndicatorScore(key, i.value);
}, 0) / Object.keys(indicators).length;
const healthStatus = avgScore > 1.5 ? 'Strong' : avgScore > 0.5 ? 'Moderate' : 'Weak';
const healthSummary = document.getElementById('health-summary').textContent;
doc.setFontSize(18);
doc.setTextColor('#1e293b'); // slate-800
doc.text('Overall Economic Health:', 14, 40);
doc.setFontSize(26);
doc.setTextColor(primaryColor);
doc.text(healthStatus, 75, 40);
doc.setFontSize(11);
const splitSummary = doc.splitTextToSize(healthSummary, 182);
doc.text(splitSummary, 14, 52);
doc.autoTable({
startY: 70,
head: [['Indicator', 'Value', 'Status', 'Interpretation']],
body: Object.entries(indicators).map(([key, i]) => {
const interpretation = i.interpretation(i.value);
return [
i.name,
`${i.value}${i.name.includes('%') ? '%' : ''}`,
interpretation.status,
interpretation.text
];
}),
theme: 'grid',
headStyles: { fillColor: primaryColor },
didParseCell: function (data) {
if (data.section === 'body' && data.column.index === 2) {
const key = Object.keys(indicators)[data.row.index];
const score = calculateIndicatorScore(key, indicators[key].value);
if (score === 2) data.cell.styles.textColor = '#059669';
if (score === 1) data.cell.styles.textColor = '#d97706';
if (score === 0) data.cell.styles.textColor = '#dc2626';
}
}
});
addFooter(1);
// --- Page 2: Visuals ---
doc.addPage();
addHeader('Indicator Visuals');
let y = 35;
let x = 15;
const chartPromises = Object.keys(indicators).map(key => {
const canvas = document.getElementById(`${key}-gauge`);
return canvas.toDataURL('image/jpeg', 0.8);
});
Promise.all(chartPromises).then(images => {
images.forEach((imgData, index) => {
doc.addImage(imgData, 'JPEG', x, y, 60, 30);
doc.setFontSize(10);
doc.setTextColor('#1e293b');
doc.text(indicators[Object.keys(indicators)[index]].name, x + 30, y + 38, { align: 'center' });
x += 65;
if ((index + 1) % 3 === 0) {
x = 15;
y += 55;
}
});
addFooter(2);
doc.save(`Economic_Briefing_${today.replace(/\//g, '-')}.pdf`);
});
}
// --- RUN INITIALIZATION ---
initialize();
});