`;
}
function renderComparison() {
// Render Table
const tableContainer = document.getElementById('comparison-table-container');
const headers = ['Metric', ...comparisonList.map(t => `
${t}`)];
const rows = [
['Name', ...comparisonList.map(t => MOCK_FUND_DATA[t].name)],
['Expense Ratio', ...comparisonList.map(t => `${MOCK_FUND_DATA[t].expRatio.toFixed(2)}%`)],
['YTD Return', ...comparisonList.map(t => `${MOCK_FUND_DATA[t].returns.ytd}%`)],
['1-Year Return', ...comparisonList.map(t => `${MOCK_FUND_DATA[t].returns['1y']}%`)],
['3-Year Return', ...comparisonList.map(t => `${MOCK_FUND_DATA[t].returns['3y']}%`)],
['5-Year Return', ...comparisonList.map(t => `${MOCK_FUND_DATA[t].returns['5y']}%`)]
];
tableContainer.innerHTML = `
${headers.map(h => `| ${h} | `).join('')}
${rows.map(row => `${row.map((cell, i) => `| ${cell} | `).join('')}
`).join('')}
`;
// Render Chart
const ctx = document.getElementById('growth-chart').getContext('2d');
const datasets = comparisonList.map((ticker, i) => ({
label: ticker,
data: MOCK_FUND_DATA[ticker].growth,
borderColor: CHART_COLORS[i % CHART_COLORS.length],
tension: 0.1
}));
if (growthChart) growthChart.destroy();
growthChart = new Chart(ctx, {
type: 'line',
data: { labels: ['Start', 'Year 1', 'Year 2', 'Year 3', 'Year 4', 'Year 5'], datasets },
options: { responsive: true, maintainAspectRatio: false, scales: { y: { ticks: { callback: v => `$${v.toLocaleString()}` } } } }
});
}
// --- PDF GENERATION ---
async function generatePdfReport() {
downloadPdfBtn.disabled = true;
downloadPdfBtn.textContent = 'Generating...';
const renderFundCard = (ticker) => {
const data = MOCK_FUND_DATA[ticker];
return `
${ticker} - ${data.name}
| Expense Ratio | ${data.expRatio.toFixed(2)}% |
| YTD Return | ${data.returns.ytd}% |
| 1-Year Return | ${data.returns['1y']}% |
| 3-Year Return | ${data.returns['3y']}% |
| 5-Year Return | ${data.returns['5y']}% |
`;
};
const reportHtml = `
Fund Overview
${comparisonList.map(renderFundCard).join('')}
Growth of $10,000 Over 5 Years
`;
const pdfTemplate = document.getElementById('pdf-template');
pdfTemplate.innerHTML = reportHtml;
pdfTemplate.classList.remove('invisible');
// Render charts on hidden canvases
comparisonList.forEach(ticker => {
const data = MOCK_FUND_DATA[ticker].allocation;
new Chart(document.getElementById(`pdf-chart-${ticker}`), { type: 'doughnut', data: { labels: Object.keys(data), datasets: [{ data: Object.values(data), backgroundColor: ['#3b82f6', '#14b8a6', '#64748b'] }] }, options: { animation: { duration: 0 }, plugins: { legend: { display: false } } } });
});
new Chart(document.getElementById('pdf-growth-chart'), { type: 'line', data: growthChart.data, options: { animation: { duration: 0 }, maintainAspectRatio: false, scales: { y: { ticks: { callback: v => `$${v.toLocaleString()}` } } } } });
setTimeout(async () => {
try {
const { jsPDF } = window.jspdf;
const pdf = new jsPDF({ orientation: 'p', unit: 'pt', format: 'a4' });
const pages = pdfTemplate.querySelectorAll('.pdf-page');
for (let i = 0; i < pages.length; i++) {
const canvas = await html2canvas(pages[i], { scale: 2 });
const imgData = canvas.toDataURL('image/png');
const pdfWidth = pdf.internal.pageSize.getWidth(), pdfHeight = (canvas.height * pdfWidth) / canvas.width;
if (i > 0) pdf.addPage();
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
}
pdf.save('Mutual_Fund_Comparison.pdf');
} catch (e) { console.error('PDF Generation Error:', e); } finally {
downloadPdfBtn.disabled = false;
downloadPdfBtn.textContent = 'Download Comparison Report';
pdfTemplate.classList.add('invisible');
pdfTemplate.innerHTML = '';
}
}, 500);
}
// --- EVENT LISTENERS ---
addBtn.addEventListener('click', addFund);
document.getElementById('selected-funds-list').addEventListener('click', e => {
if (e.target.classList.contains('remove-fund-btn')) removeFund(e.target.dataset.ticker);
});
downloadPdfBtn.addEventListener('click', generatePdfReport);
// --- INITIALIZATION ---
switchTab(0);
renderSelectedFunds();
});