`;
resultsHTML += `
`;
resultsAnalyzerEl.innerHTML = resultsHTML;
resultsAnalyzerEl.style.display = 'block';
}
/**
* Handles the analysis calculation process.
*/
function handleAnalysisCalculate() {
const inputs = getAnalyzerInputs();
if (!inputs) return;
if (!validateAnalyzerInputs(inputs)) {
if(resultsAnalyzerEl) resultsAnalyzerEl.style.display = 'none';
return;
}
const analysisResults = calculateInvestmentAnalysis(inputs);
displayAnalysisResults(analysisResults);
}
/**
* Generates and downloads a PDF of the analysis results.
*/
function generateAnalysisPdf() {
const inputs = getAnalyzerInputs();
if (!inputs) {
alert('Could not retrieve input data for PDF generation. Please calculate first.');
return;
}
if (!validateAnalyzerInputs(inputs)) {
alert('Invalid inputs. Please correct them before generating PDF.');
return;
}
const analysisData = calculateInvestmentAnalysis(inputs);
if (!analysisData) {
alert('Could not calculate results for PDF generation. Please try again.');
return;
}
const doc = new jsPDF();
const today = new Date();
const formattedDate = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
const title = `L1 vs. L2 Investment Analysis Report`;
doc.setFontSize(18);
doc.text(title, 14, 22);
doc.setFontSize(11);
doc.setTextColor(100);
doc.text(`Report Generated: ${formattedDate}`, 14, 30);
doc.text(`Investment Horizon: ${analysisData.horizonValue} ${analysisData.horizonUnit} (${analysisData.horizonInYears.toFixed(2)} years)`, 14, 36);
const headStyle = { fillColor: [79, 70, 229] }; // Indigo for header
const bodyStyle = { minCellHeight: 9, fontSize: 9 };
// Adjusted column widths
const colWidths = [59, 59, 59]; // Parameter, L1 Value, L2 Value. Original: [60,60,60]
const tableBody = [
['Protocol Name', analysisData.l1.name, analysisData.l2.name],
['Initial Investment ($)', `$${analysisData.l1.initialInvestment.toFixed(2)}`, `$${analysisData.l2.initialInvestment.toFixed(2)}`],
['Exp. Annual Growth (%)', `${(analysisData.l1.growthRate * 100).toFixed(2)}%`, `${(analysisData.l2.growthRate * 100).toFixed(2)}%`],
['Avg. Transaction Fee ($)', `$${analysisData.l1.avgTxFee.toFixed(2)}`, `$${analysisData.l2.avgTxFee.toFixed(2)}`],
['Est. Transactions/Month', `${analysisData.l1.txPerMonth}`, `${analysisData.l2.txPerMonth}`],
['--- RESULTS ---', '---', '---'], // Separator
['Gross Projected Value ($)', `$${analysisData.l1.grossFutureValue.toFixed(2)}`, `$${analysisData.l2.grossFutureValue.toFixed(2)}`],
['Total Transactions (Period)', `${analysisData.l1.totalTransactions}`, `${analysisData.l2.totalTransactions}`],
['Total Transaction Costs ($)', `$${analysisData.l1.totalTxCosts.toFixed(2)}`, `$${analysisData.l2.totalTxCosts.toFixed(2)}`],
['Net Projected Value ($)', `$${analysisData.l1.netFutureValue.toFixed(2)}`, `$${analysisData.l2.netFutureValue.toFixed(2)}`],
[{ content: 'Net Profit / Loss ($)', styles: { fontStyle: 'bold' } },
{ content: `$${analysisData.l1.netProfit.toFixed(2)}`, styles: { textColor: analysisData.l1.netProfit >= 0 ? [16, 185, 129] : [239, 68, 68] } },
{ content: `$${analysisData.l2.netProfit.toFixed(2)}`, styles: { textColor: analysisData.l2.netProfit >= 0 ? [16, 185, 129] : [239, 68, 68] } }],
[{ content: 'Profit Percentage (%)', styles: { fontStyle: 'bold' } },
{ content: `${analysisData.l1.profitPercentage.toFixed(2)}%`, styles: { textColor: analysisData.l1.netProfit >= 0 ? [16, 185, 129] : [239, 68, 68] } },
{ content: `${analysisData.l2.profitPercentage.toFixed(2)}%`, styles: { textColor: analysisData.l2.netProfit >= 0 ? [16, 185, 129] : [239, 68, 68] } }]
];
doc.autoTable({
startY: 45,
head: [['Parameter', analysisData.l1.name || 'Layer 1', analysisData.l2.name || 'Layer 2']],
body: tableBody,
theme: 'striped',
headStyles: headStyle,
styles: bodyStyle,
columnStyles: {
0: { fontStyle: 'bold', cellWidth: colWidths[0] },
1: { cellWidth: colWidths[1], halign: 'right' },
2: { cellWidth: colWidths[2], halign: 'right' }
},
didDrawCell: (data) => {
if (data.section === 'body' && data.row.index === 5) { // Separator row
doc.setFillColor(200, 200, 200); // Light gray
doc.rect(data.cell.x, data.cell.y, data.cell.width, data.cell.height, 'F');
// Optionally, make text bold or centered if it's a true title
if (data.column.index === 0) { // Only for the first cell of separator
doc.setTextColor(50,50,50);
doc.setFont(undefined, 'bold');
doc.text(data.cell.text[0], data.cell.x + data.cell.padding('left'), data.cell.y + data.cell.height / 1.5, {
baseline: 'middle'
});
}
}
}
});
const l1NetProfit = analysisData.l1.netProfit;
const l2NetProfit = analysisData.l2.netProfit;
let summaryText = "";
if (l1NetProfit > l2NetProfit) {
summaryText = `${analysisData.l1.name} shows a higher projected net profit by $${(l1NetProfit - l2NetProfit).toFixed(2)}.`;
} else if (l2NetProfit > l1NetProfit) {
summaryText = `${analysisData.l2.name} shows a higher projected net profit by $${(l2NetProfit - l1NetProfit).toFixed(2)}.`;
} else {
summaryText = `Both investments project similar net profits.`;
}
doc.setFontSize(11);
doc.text("Summary: " + summaryText, 14, doc.lastAutoTable.finalY + 15);
doc.save(`L1_vs_L2_Analysis_${formattedDate}.pdf`);
}
// Event listener for DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
investmentHorizonValueEl = document.getElementById('investmentHorizonValue');
investmentHorizonUnitEl = document.getElementById('investmentHorizonUnit');
l1NameEl = document.getElementById('l1Name');
l1InvestmentAmountEl = document.getElementById('l1InvestmentAmount');
l1GrowthRateEl = document.getElementById('l1GrowthRate');
l1AvgTxFeeEl = document.getElementById('l1AvgTxFee');
l1TxPerMonthEl = document.getElementById('l1TxPerMonth');
l2NameEl = document.getElementById('l2Name');
l2InvestmentAmountEl = document.getElementById('l2InvestmentAmount');
l2GrowthRateEl = document.getElementById('l2GrowthRate');
l2AvgTxFeeEl = document.getElementById('l2AvgTxFee');
l2TxPerMonthEl = document.getElementById('l2TxPerMonth');
errorAnalyzerEl = document.getElementById('errorAnalyzer');
resultsAnalyzerEl = document.getElementById('resultsAnalyzer');
const criticalElements = [
investmentHorizonValueEl, investmentHorizonUnitEl,
l1InvestmentAmountEl, l1GrowthRateEl, l1AvgTxFeeEl, l1TxPerMonthEl,
l2InvestmentAmountEl, l2GrowthRateEl, l2AvgTxFeeEl, l2TxPerMonthEl,
errorAnalyzerEl, resultsAnalyzerEl
];
if (criticalElements.some(el => !el)) {
console.error("One or more critical elements are missing from the DOM for the Analyzer.");
const body = document.querySelector('body');
if (body && errorAnalyzerEl && errorAnalyzerEl.style.display === 'none') {
errorAnalyzerEl.textContent = "Error: Calculator UI could not be fully initialized. Some fields may be missing. Please refresh.";
errorAnalyzerEl.style.display = 'block';
} else if (body && !errorAnalyzerEl) {
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.textContent = "Critical Error: Calculator UI initialization failed. Please refresh.";
errorDiv.style.display = 'block';
const container = document.querySelector('.calculator-container');
if (container) container.prepend(errorDiv); else body.prepend(errorDiv);
}
}
});