U.S. Leading Economic Indicators Dashboard
The Conference Board LEI for the U.S.
The Leading Economic Index provides an early indication of significant turning points in the business cycle.
Average Weekly Initial Claims for Unemployment Insurance (U.S.)
An indicator of layoffs and labor market health. A lower number is generally positive.
S&P 500 Index
A market-capitalization-weighted index of the 500 largest U.S. publicly traded companies; a key benchmark for U.S. stock market performance.
ISM Manufacturing PMI (Purchasing Managers' Index)
An indicator of the economic health of the manufacturing sector. A reading above 50 percent indicates that the manufacturing economy is generally expanding.
No data available.
'; return; } const latest = data[data.length - 1]; const previous = data.length > 1 ? data[data.length - 2] : null; let changeHtml = ''; if (previous) { const change = latest.value - previous.value; const percentChange = previous.value !== 0 ? (change / previous.value) * 100 : 0; const changeColor = change >= 0 ? 'green' : 'red'; const arrow = change >= 0 ? 'â–²' : 'â–¼'; changeHtml = `Change (MoM): ${arrow} ${Math.abs(change).toLocaleString(undefined, {minimumFractionDigits: unit==='$'?2:0, maximumFractionDigits: 2})} ${previous.value !== 0 ? '('+percentChange.toFixed(2)+'%)' : '(N/A)'}
`; } container.innerHTML = `Latest (${latest.date}): ${latest.value.toLocaleString(undefined, {minimumFractionDigits: unit==='$'?2:0, maximumFractionDigits: 2})} ${unit && unit !== '$' ? unit : ''}
${changeHtml} `; } // --- Create/Update Charts Function --- function renderCharts(monthsToShow) { if (typeof Chart === 'undefined') return; // Don't render if Chart.js not loaded const datasets = { leiCompositeChart: { data: allData.cbLei, label: 'CB LEI Value', color: 'rgb(54, 162, 235)', unit: 'Index Value', figuresId: 'leiCompositeKeyFigures' }, unemploymentClaimsChart: { data: allData.unemployment, label: 'Initial Claims', color: 'rgb(255, 159, 64)', unit: 'Number of Claims', figuresId: 'unemploymentClaimsKeyFigures' }, sp500Chart: { data: allData.sp500, label: 'S&P 500 Index', color: 'rgb(75, 192, 192)', unit: 'Index Points', figuresId: 'sp500KeyFigures' }, pmiChart: { data: allData.pmi, label: 'ISM PMI', color: 'rgb(153, 102, 255)', unit: 'Index Value (Above 50 = Expansion)', figuresId: 'pmiKeyFigures' } }; for (const chartId in datasets) { const config = datasets[chartId]; const slicedData = config.data.slice(-monthsToShow); if (charts[chartId]) charts[chartId].destroy(); const canvasElement = document.getElementById(chartId.replace('Chart', 'Chart')); // e.g. leiCompositeChart if (canvasElement) { charts[chartId] = new Chart( canvasElement.getContext('2d'), getChartConfig(slicedData, config.label, config.color, config.unit) ); updateKeyFigures(config.figuresId, slicedData); } else { console.warn(`Canvas element for ${chartId} not found.`); } } } // --- Tab Management --- const tabLinksNodeList = document.querySelectorAll('.lei-tab-link'); const tabContentsNodeList = document.querySelectorAll('.lei-tab-content'); const tabIds = Array.from(tabLinksNodeList).map(link => link.id.replace('leiTabBtn_', '')); window.openLeiTab = function(event, tabName) { tabContentsNodeList.forEach(tab => { if(tab) tab.style.display = 'none'; }); tabLinksNodeList.forEach(link => { if(link) link.classList.remove('active'); }); const currentTabContent = document.getElementById(tabName); if (currentTabContent) currentTabContent.style.display = 'block'; const activeTabButton = document.getElementById('leiTabBtn_' + tabName); if (activeTabButton) { activeTabButton.classList.add('active'); } else if (event && event.currentTarget) { // Fallback to event target if ID method fails event.currentTarget.classList.add('active'); } updateNavigationButtons(); } const prevTabButton = document.getElementById('leiPrevTabButton'); const nextTabButton = document.getElementById('leiNextTabButton'); function getCurrentTabIndex() { const activeTab = document.querySelector('.lei-tab-link.active'); if (!activeTab) return -1; const activeTabId = activeTab.id.replace('leiTabBtn_', ''); return tabIds.indexOf(activeTabId); } window.navigateLeiTabs = function(direction) { let currentIndex = getCurrentTabIndex(); if (currentIndex === -1 && tabIds.length > 0) currentIndex = 0; // Default to first if none active let newIndex; if (direction === 'next') { newIndex = (currentIndex + 1) % tabIds.length; } else { newIndex = (currentIndex - 1 + tabIds.length) % tabIds.length; } const newTabButton = document.getElementById('leiTabBtn_' + tabIds[newIndex]); if (newTabButton) { openLeiTab({currentTarget: newTabButton}, tabIds[newIndex]); } } function updateNavigationButtons() { if (!prevTabButton || !nextTabButton) return; let currentIndex = getCurrentTabIndex(); const disableNav = tabIds.length <= 1; prevTabButton.disabled = disableNav; // For circular, always enabled if > 1 tab nextTabButton.disabled = disableNav; // For circular, always enabled if > 1 tab // If non-circular preferred: // prevTabButton.disabled = (currentIndex <= 0); // nextTabButton.disabled = (currentIndex >= tabIds.length - 1); } // --- Event Listeners --- const timeRangeSelector = document.getElementById('leiTimeRangeSelector'); if (timeRangeSelector) { timeRangeSelector.addEventListener('change', function() { currentVisibleMonths = parseInt(this.value); renderCharts(currentVisibleMonths); }); } const pdfDownloadButton = document.getElementById('leiPdfDownloadButton'); if (pdfDownloadButton) { pdfDownloadButton.addEventListener('click', function() { const button = this; const originalButtonText = button.textContent; if (typeof html2canvas === 'undefined' || typeof window.jspdf === 'undefined') { console.error("PDF generation libraries (html2canvas or jsPDF) not loaded."); alert("Error: PDF libraries not found. PDF cannot be generated."); return; } const { jsPDF } = window.jspdf; const dashboardContentToPrint = document.getElementById('leiDashboardPdfContent'); if (!dashboardContentToPrint) { console.error("PDF content area ('leiDashboardPdfContent') not found."); alert("Error: Could not find content to generate PDF."); return; } button.textContent = 'Generating PDF...'; button.disabled = true; // Temporarily disable active chart animations for capture let activeChartInstance, originalChartAnimationSettings; const activeTabLink = document.querySelector('.lei-tab-link.active'); const activeTabContentId = activeTabLink ? activeTabLink.id.replace('leiTabBtn_', '') : null; if (activeTabContentId && typeof Chart !== 'undefined') { const chartInstanceKey = chartKeyMap[activeTabContentId]; activeChartInstance = charts[chartInstanceKey]; if (activeChartInstance && activeChartInstance.options && activeChartInstance.options.animation) { originalChartAnimationSettings = { ...activeChartInstance.options.animation }; activeChartInstance.options.animation.duration = 0; // Disable duration activeChartInstance.update('quiet'); // Update chart without triggering new animations } else if (activeChartInstance && Chart.defaults.animation) { // Fallback if not on instance originalChartAnimationSettings = { duration: initialChartJsAnimationDuration }; // Store global default if (activeChartInstance.options) { // Ensure options exist activeChartInstance.options.animation = { duration: 0 }; activeChartInstance.update('quiet'); } } } // Use a timeout to ensure chart has re-rendered without animation setTimeout(() => { html2canvas(dashboardContentToPrint, { scale: 2, useCORS: true, logging: false, backgroundColor: '#ffffff', onclone: (documentClone) => { const activeTabId = document.querySelector('.lei-tab-link.active').id.replace('leiTabBtn_', ''); const clonedContents = documentClone.querySelectorAll('.lei-tab-content'); clonedContents.forEach(tc => { tc.style.display = (tc.id === activeTabId) ? 'block' : 'none'; }); // Ensure any specific styles for PDF render are applied on the clone if needed } }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'px', format: [canvas.width, canvas.height] }); pdf.addImage(imgData, 'PNG', 0, 0, canvas.width, canvas.height); pdf.save('LEI_Dashboard_Report.pdf'); }).catch(error => { console.error("Error generating PDF: ", error); alert("Sorry, an error occurred while generating the PDF."); }).finally(() => { button.textContent = originalButtonText; button.disabled = false; // Restore chart animations if (activeChartInstance && originalChartAnimationSettings && activeChartInstance.options) { activeChartInstance.options.animation = originalChartAnimationSettings; activeChartInstance.update('quiet'); } }); }, 250); // 250ms delay for chart render after animation turned off. Adjust if needed. }); } // --- Initial Setup --- if (timeRangeSelector) currentVisibleMonths = parseInt(timeRangeSelector.value); const firstTabButton = document.getElementById('leiTabBtn_LEI_Composite'); if(firstTabButton){ openLeiTab({currentTarget: firstTabButton}, 'LEI_Composite'); } else if (tabLinksNodeList.length > 0 && tabIds.length > 0) { // Fallback to first available tab openLeiTab({currentTarget: tabLinksNodeList[0]}, tabIds[0]); } renderCharts(currentVisibleMonths); updateNavigationButtons(); });