Debt Snowball Budgeting Calculator

Your Debts

List all your debts below. The calculator will automatically order them by balance for the snowball method.

Extra Monthly Payment

Your Debt Snowball Payoff Plan

Calculating your plan...

Total Amount Paid: $${data.totalAmountPaid.toFixed(2)}

`; let tableHTML = `

Debt Payoff Order & Details

`; data.payoffDetails.forEach(debt => { tableHTML += ``; }); tableHTML += `
Order Debt Name Starting Balance Payoff Month # Est. Payoff Date Total Paid to Debt Total Interest on Debt
${debt.order} ${debt.name} $${debt.originalBalance.toFixed(2)} ${debt.payoffMonthNum} ${debt.payoffDate} $${debt.totalPaidToDebt.toFixed(2)} $${debt.totalInterestOnDebt.toFixed(2)}
`; tableContainer.innerHTML = tableHTML; // Populate hidden monthly log for PDF let logText = ""; data.monthlyLog.forEach(monthEntry => { logText += `Month ${monthEntry.month}:\n`; logText += ` Total Paid: $${monthEntry.totalPaymentThisMonth.toFixed(2)}, Total Interest: $${monthEntry.totalInterestThisMonth.toFixed(2)}\n`; monthEntry.payments.forEach(p => { logText += ` - ${p.name}: Paid $${p.payment.toFixed(2)} (Interest: $${p.interest.toFixed(2)}, Principal: $${p.principal.toFixed(2)}), New Bal: $${p.endBalance}\n`; }); monthEntry.events.forEach(event => logText += ` EVENT: ${event}\n`); logText += "\n"; }); logContainer.textContent = logText; } function downloadSnowballPdf() { if (!snowballPlanData || Object.keys(snowballPlanData).length === 0) { alert("Please calculate a plan first."); return; } if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('PDF generation library (jsPDF) is not loaded.'); return; } const jsPDFConstructor = window.jspdf.jsPDF; const doc = new jsPDFConstructor(); if (typeof doc.autoTable !== 'function') { alert('jsPDF AutoTable plugin not loaded.'); return; } const data = snowballPlanData; const primaryColor = '#007bff'; const textColor = '#212529'; const tableHeaderColor = '#e9ecef'; let yPos = 22; doc.setFontSize(18); doc.setTextColor(primaryColor); doc.text("Debt Snowball Payoff Plan", 14, yPos); yPos += 8; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Report Date: ${new Date().toLocaleDateString()}`, 14, yPos); yPos += 10; // Initial Inputs Summary doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Initial Debt Summary", 14, yPos); yPos += 6; const initialDebtsBody = data.initialDebts.map(d => [ d.name, `$${d.balance.toFixed(2)}`, `$${d.minPayment.toFixed(2)}`, `${d.annualRate.toFixed(1)}%` ]); doc.autoTable({ startY: yPos, theme: 'grid', head: [['Debt Name', 'Balance', 'Min. Payment', 'Rate']], body: initialDebtsBody, headStyles: { fillColor: tableHeaderColor, textColor: textColor, fontStyle: 'bold' }, styles: { fontSize: 9 } }); yPos = doc.lastAutoTable.finalY + 5; doc.setFontSize(10); doc.setTextColor(textColor); doc.text(`Extra Monthly Payment: $${data.extraMonthlyPayment.toFixed(2)}`, 14, yPos); yPos += 10; // Overall Payoff Summary const years = Math.floor(data.totalMonths / 12); const remainingMonths = data.totalMonths % 12; let timeToDebtFree = ""; if (years > 0) timeToDebtFree += `${years} year${years > 1 ? 's' : ''}`; if (remainingMonths > 0) timeToDebtFree += `${years > 0 ? ' and ' : ''}${remainingMonths} month${remainingMonths > 1 ? 's' : ''}`; if (timeToDebtFree === "") timeToDebtFree = "0 months"; doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Overall Payoff Summary", 14, yPos); yPos += 6; doc.autoTable({ startY: yPos, theme: 'grid', body: [ ['Time to Debt-Free:', `${timeToDebtFree} (${data.totalMonths} months)`], ['Total Initial Debt Principal:', `$${data.totalInitialPrincipal.toFixed(2)}`], ['Total Interest Paid:', `$${data.totalInterestPaid.toFixed(2)}`], ['Total Amount Paid:', `$${data.totalAmountPaid.toFixed(2)}`] ], styles: { fontSize: 9 }, columnStyles: { 0: { fontStyle: 'bold' } } }); yPos = doc.lastAutoTable.finalY + 10; // Debt Payoff Details Table doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Debt Payoff Order & Details", 14, yPos); yPos += 6; const payoffDetailsBody = data.payoffDetails.map(d => [ d.order, d.name, `$${d.originalBalance.toFixed(2)}`, d.payoffMonthNum, d.payoffDate, `$${d.totalPaidToDebt.toFixed(2)}`, `$${d.totalInterestOnDebt.toFixed(2)}` ]); doc.autoTable({ startY: yPos, theme: 'grid', head: [['Order', 'Debt Name', 'Start Bal.', 'Payoff Month #', 'Est. Payoff Date', 'Total Paid', 'Total Interest']], body: payoffDetailsBody, headStyles: { fillColor: tableHeaderColor, textColor: textColor, fontStyle: 'bold' }, styles: { fontSize: 8, cellPadding: 1.5 } }); yPos = doc.lastAutoTable.finalY + 10; // Monthly Log (simplified for PDF to avoid excessive length) doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Monthly Payment Log Summary", 14, yPos); yPos += 6; doc.setFontSize(8); doc.setTextColor(textColor); const logLines = document.getElementById('monthlyLogContent').textContent.split('\n'); let currentLine = 0; const maxLinesPerPage = 50; // Adjust as needed function addLogPage() { if (currentLine > 0) doc.addPage(); // Add new page if not the first log page yPos = 20; // Reset yPos for new page doc.setFontSize(12); doc.setTextColor(primaryColor); doc.text("Monthly Payment Log Summary (Continued)", 14, yPos); yPos += 6; doc.setFontSize(8); doc.setTextColor(textColor); } for(let i=0; i < logLines.length; i++){ if( (i % maxLinesPerPage === 0 && i > 0) || yPos > 270) { // Check yPos for overflow too addLogPage(); } if (logLines[i].trim() !== "") { // Avoid empty lines if any doc.text(logLines[i], 14, yPos); yPos += 3.5; // Adjust line height } currentLine++; } doc.save("Debt_Snowball_Plan.pdf"); }
Scroll to Top