Housing Affordability & Mortgage Stress Index (Conceptual Calculator)
Your Financial Profile
$
$
e.g., car loans, student loans, credit card minimums.
$
Housing & Mortgage Goals
$
$
%
Estimated Monthly Housing Expenses
$
$
$
$
Consider PMI if down payment is less than 20%.
Housing Affordability & Mortgage Stress Analysis
Analysis results will appear here.
Conceptual Mortgage Stress Index
-
This index is based on common DTI ratio guidelines. Green (Comfortable), Yellow (Manageable), Orange (Stressed), Red (Severely Stressed).
Based on 28% front-end DTI, your current down payment, and loan terms. This is a simplified estimate.
Est. Max Affordable House Price: ${hamsi_formatCurrency(r.maxAffordableHousePrice_28_conceptual)}
`;
// Stress Meter
stressLevelText.textContent = r.stressLevel;
stressLevelText.className = r.stressClass; // Apply class for color
const meterBar = document.createElement('div');
meterBar.className = 'hamsi_stress_meter_bar';
// Score 0 (Comfortable) -> up to 25% width
// Score 1 (Manageable) -> up to 50% width
// Score 2 (Stressed) -> up to 75% width
// Score 3 (Severe) -> up to 100% width
const meterWidths = [25, 50, 75, 100]; // Cumulative % widths for each level
const meterLevels = ['low', 'manageable', 'stressed', 'severe'];
const meterLabels = ['Comfortable', 'Manageable', 'Stressed', 'Severe'];
let currentMeterFilled = 0;
if(r.stressScore !== undefined) { // Check if stressScore is defined
const targetFill = meterWidths[r.stressScore];
const segment = document.createElement('div');
segment.className = `hamsi_stress_meter_segment ${meterLevels[r.stressScore]}`;
segment.style.width = `${targetFill}%`;
// segment.textContent = meterLabels[r.stressScore]; // Optional text on bar
meterBar.appendChild(segment);
currentMeterFilled = targetFill;
}
// Fill remaining transparently or with a base color
if(currentMeterFilled < 100){
const remainingSegment = document.createElement('div');
remainingSegment.style.width = `${100-currentMeterFilled}%`;
// No background for remaining, or a very light grey
meterBar.appendChild(remainingSegment);
}
stressMeterContainer.innerHTML = ''; // Clear previous
stressMeterContainer.appendChild(meterBar);
// Labels for meter (optional, can be complex to align perfectly with dynamic bar)
// const meterLabelsDiv = document.createElement('div');
// meterLabelsDiv.className = 'hamsi_stress_meter_labels';
// meterLabelsDiv.innerHTML = `LowModHighSevere`;
// stressMeterContainer.appendChild(meterLabelsDiv);
const pdfBtn = document.getElementById('hamsi_downloadPdfButton');
if(pdfBtn) pdfBtn.style.display = 'block';
}
// --- PDF Generation ---
function hamsi_downloadPDF() {
if (!hamsi_results) { alert("Please calculate results first."); return; }
if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') {
alert('Core PDF library (jsPDF) is not loaded.'); console.error('jsPDF library not found.'); return;
}
const { jsPDF: JSPDF } = window.jspdf;
const doc = new JSPDF();
if (typeof doc.autoTable !== 'function') {
alert('PDF Table plugin (jsPDF-AutoTable) is not loaded correctly. Tables in PDF may be missing.');
console.error('doc.autoTable is not a function. jsPDF-AutoTable plugin error.');
}
let y = 15; const m = 15; const cw = doc.internal.pageSize.getWidth() - (2 * m);
const i = hamsi_results.inputs;
const r = hamsi_results.calculations;
function addLine(text, size, style = 'normal', indent = 0, spacing = 2.5) {
if (y > 275) { doc.addPage(); y = m; }
doc.setFontSize(size); doc.setFont(undefined, style);
const lines = doc.splitTextToSize(text, cw - indent); doc.text(lines, m + indent, y);
y += (lines.length * (size * 0.35)) + spacing;
}
addLine(`Housing Affordability & Mortgage Stress Report`, 16, 'bold', 0, 5);
addLine(`Assessment Date: ${new Date().toLocaleDateString()}`, 9, 'italic', 0, 5);
addLine("Input Summary:", 12, 'bold', 0, 3);
let inputData = [
["Gross Annual Income:", hamsi_formatCurrency(i.grossAnnualIncome)],
["Total Monthly Debts (Non-Housing):", hamsi_formatCurrency(i.monthlyDebts)],
["Target Property Price:", hamsi_formatCurrency(i.propertyPrice)],
["Down Payment Amount:", `${hamsi_formatCurrency(i.downPaymentAmount)} (${hamsi_formatPercent((i.downPaymentAmount/i.propertyPrice)*100 || 0)})`],
["Loan Interest Rate:", hamsi_formatPercent(i.loanInterestRate)],
["Loan Term:", `${i.loanTerm} years`],
["Annual Property Taxes:", hamsi_formatCurrency(i.annualPropertyTaxes)],
["Annual Home Insurance:", hamsi_formatCurrency(i.annualHomeInsurance)],
["Monthly HOA Fees:", hamsi_formatCurrency(i.monthlyHOA)],
["Monthly PMI:", hamsi_formatCurrency(i.monthlyPMI)],
];
if (typeof doc.autoTable === 'function') {
doc.autoTable({ startY: y, body: inputData, theme: 'plain', styles: {fontSize: 9, cellPadding: 1.2}, columnStyles: {0:{fontStyle:'bold'}}});
y = doc.lastAutoTable.finalY + 6;
} else {
inputData.forEach(row => addLine(`${row[0]} ${row[1]}`, 9)); y += 5;
}
addLine("Affordability Analysis:", 12, 'bold', 0, 3);
let analysisData = [
["Gross Monthly Income:", hamsi_formatCurrency(r.grossMonthlyIncome)],
["Est. Monthly Mortgage (P&I):", hamsi_formatCurrency(r.monthlyPI)],
["Est. Monthly Taxes & Insurance (T&I):", hamsi_formatCurrency(r.monthlyTaxes + r.monthlyInsurance)],
["Est. Total Monthly Housing (PITI + HOA + PMI):", hamsi_formatCurrency(r.totalPITI_HOA_PMI)],
["Front-End DTI (Housing/Income):", hamsi_formatPercent(r.frontEndDTI)],
["Back-End DTI (Total Debts/Income):", hamsi_formatPercent(r.backEndDTI)],
["Conceptual Max Affordable House Price (28% DTI):", hamsi_formatCurrency(r.maxAffordableHousePrice_28_conceptual)],
];
if (typeof doc.autoTable === 'function') {
doc.autoTable({ startY: y, body: analysisData, theme: 'plain', styles: {fontSize: 9, cellPadding: 1.2}, columnStyles: {0:{fontStyle:'bold'}}});
y = doc.lastAutoTable.finalY + 6;
} else {
analysisData.forEach(row => addLine(`${row[0]} ${row[1]}`, 9)); y += 5;
}
addLine(`Mortgage Stress Index: ${r.stressLevel}`, 14, 'bold', 0, 5);
let stressDesc = "";
if(r.stressScore === 0) stressDesc = "Housing costs appear comfortable relative to income.";
else if(r.stressScore === 1) stressDesc = "Housing costs are manageable, but monitor budget closely.";
else if(r.stressScore === 2) stressDesc = "Housing costs indicate potential financial stress. Careful budgeting is essential.";
else stressDesc = "Housing costs are at a severely stressed level, indicating high financial risk.";
addLine(stressDesc, 10);
y += 7;
addLine("Disclaimer: This is a conceptual calculator for informational purposes only and not financial advice. DTI benchmarks can vary. Consult with a financial advisor.", 7, 'italic');
doc.save(`Housing_Affordability_Stress_Report.pdf`);
}