Avg Conv. Rate
${totals.convRate.toFixed(2)}%
Overall ROAS
${totals.roas.toFixed(2)}x
| Channel | Clicks | Sales | Conv. Rate |
Revenue | Cost | CPA | ROAS |
${tableRows}
`;
Object.values(charts).forEach(chart => chart.destroy());
charts.revenue = new Chart(document.getElementById('revenueChart'), {
type: 'bar',
data: {
labels: channels,
datasets: [{ label: 'Revenue', data: channels.map(c => analysis[c].revenue), backgroundColor: colors }]
},
options: { plugins: { legend: { display: false } }, responsive: true, maintainAspectRatio: true }
});
charts.conversions = new Chart(document.getElementById('conversionsChart'), {
type: 'doughnut',
data: {
labels: channels,
datasets: [{ label: 'Conversions', data: channels.map(c => analysis[c].sales), backgroundColor: colors }]
},
options: { responsive: true, maintainAspectRatio: true }
});
document.getElementById('download-pdf-btn').addEventListener('click', handlePdfDownload);
lucide.createIcons();
}
async function handlePdfDownload() {
if (!lastResults) return;
const { jsPDF } = window.jspdf;
const { analysis } = lastResults;
// Populate PDF container
document.getElementById('pdf-generation-date').textContent = new Date().toLocaleDateString();
const totals = {
clicks: Object.values(analysis).reduce((s, c) => s + c.clicks, 0),
sales: Object.values(analysis).reduce((s, c) => s + c.sales, 0),
revenue: Object.values(analysis).reduce((s, c) => s + c.revenue, 0),
cost: Object.values(analysis).reduce((s, c) => s + c.cost, 0),
};
totals.convRate = totals.clicks > 0 ? (totals.sales / totals.clicks) * 100 : 0;
document.getElementById('pdf-summary').innerHTML = `
$${totals.revenue.toFixed(2)}
Total Revenue
${totals.sales}
Total Conversions
${totals.convRate.toFixed(2)}%
Avg. Conv. Rate
$${(totals.cost / totals.sales).toFixed(2)}
Avg. CPA
`;
const tableHtml = `
| Channel | Clicks | Sales |
Revenue | CPA | ROAS |
${Object.keys(analysis).map(channel => {
const data = analysis[channel];
return `
| ${channel} | ${data.clicks} | ${data.sales} |
$${data.revenue.toFixed(2)} | $${data.cpa.toFixed(2)} | ${data.roas.toFixed(2)}x |
`}).join('')}
`;
document.getElementById('pdf-main-table').innerHTML = tableHtml;
document.getElementById('pdf-chart-revenue').src = charts.revenue.toBase64Image();
document.getElementById('pdf-chart-conversions').src = charts.conversions.toBase64Image();
try {
const canvas = await html2canvas(document.getElementById('pdf-content'), { scale: 2 });
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const imgProps = pdf.getImageProperties(imgData);
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
pdf.save('Marketing_Attribution_Report.pdf');
} catch (e) {
console.error("PDF generation failed:", e);
alert("An error occurred generating the PDF.");
}
}
// --- Event Listeners ---
tabs.forEach((tab, index) => tab.btn.addEventListener('click', () => switchTab(index)));
prevBtn.addEventListener('click', () => switchTab(currentTab - 1));
nextBtn.addEventListener('click', () => switchTab(currentTab + 1));
analyzeBtn.addEventListener('click', handleAnalysis);
// --- Initialization ---
clickDataInput.value = sampleClickData;
salesDataInput.value = sampleSalesData;
costDataInput.value = sampleCostData;
switchTab(0);
updateNavButtons();
lucide.createIcons();
});