Key Factors Influencing Forecast:
${category}
`;
for (const key in appData[category]) {
formHtml += createFormGroup(key, appData[category][key], category);
}
formHtml += '
';
content.innerHTML = formHtml;
}
tabContentsContainer.appendChild(content);
tabContents.push(content);
});
updateTabs();
calculateAll();
setupEventListeners();
}
function calculateAll() {
const market = appData['Market Data'];
const econ = appData['Economic Indicators'];
let trendScore = 0;
const factors = [];
// Inventory
const inventory = parseFloat(market.inventory_months.value) || 0;
if (inventory < 3) { trendScore += 2; factors.push('Low inventory is supporting prices.'); }
else if (inventory > 6) { trendScore -= 2; factors.push('High inventory suggests a buyer\'s market.'); }
// Days on Market
const dom = parseFloat(market.days_on_market.value) || 0;
if (dom < 30) { trendScore += 1; factors.push('Homes selling quickly, indicating strong demand.'); }
else if (dom > 90) { trendScore -= 1; factors.push('Slowing sales pace may lead to price drops.'); }
// Interest Rates
const interest = parseFloat(econ.interest_rate.value) || 0;
if (interest > 7) { trendScore -= 2; factors.push('High mortgage rates are a major headwind for prices.'); }
else if (interest < 5) { trendScore += 2; factors.push('Low mortgage rates are stimulating demand.'); }
// Unemployment
const unemployment = parseFloat(econ.unemployment_rate.value) || 0;
if (unemployment > 5) { trendScore -= 2; factors.push('High unemployment threatens housing stability.'); }
else if (unemployment < 4) { trendScore += 1; factors.push('Strong employment supports the housing market.'); }
updateDashboard(trendScore, factors);
}
function updateDashboard(score, factors) {
const forecastTextEl = document.getElementById('trend-forecast-text');
const factorsList = document.getElementById('key-factors-list');
let forecast = '';
let color = '';
if (score > 2) { forecast = 'Strong Growth'; color = '#16a34a'; }
else if (score > 0) { forecast = 'Modest Growth'; color = '#22c55e'; }
else if (score === 0) { forecast = 'Stable / Flat'; color = '#6b7280'; }
else if (score >= -2) { forecast = 'Cooling / Modest Decline'; color = '#f97316'; }
else { forecast = 'Significant Decline'; color = '#ef4444'; }
forecastTextEl.textContent = forecast;
forecastTextEl.style.color = color;
factorsList.innerHTML = '';
factors.forEach(f => {
const li = document.createElement('li');
li.textContent = f;
factorsList.appendChild(li);
});
generateChart(score);
}
function generateChart(score) {
const basePrice = parseFloat(appData['Market Data'].median_home_price.value) || 450000;
const annualGrowthRate = (score * 1.5) / 100; // Simplified conversion of score to growth rate
const quarterlyGrowthRate = annualGrowthRate / 4;
const labels = [];
const data = [];
let currentPrice = basePrice;
for (let i = 0; i <= 8; i++) { // 8 quarters = 24 months
labels.push(`Q${(i % 4) + 1} '${25 + Math.floor(i/4)}`);
data.push(currentPrice);
currentPrice *= (1 + quarterlyGrowthRate);
}
const ctx = document.getElementById('trend-chart').getContext('2d');
if (trendChart) trendChart.destroy();
trendChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Median Home Price',
data: data,
borderColor: '#0ea5e9',
backgroundColor: 'rgba(14, 165, 233, 0.1)',
fill: true,
tension: 0.3
}]
},
options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { y: { ticks: { callback: (v) => '$' + (v/1000) + 'k' } } } }
});
}
function updateTabs() {
tabs.forEach((tab, i) => tab.classList.toggle('active', i === currentTabIndex));
tabContents.forEach((c, i) => c.classList.toggle('active', i === currentTabIndex));
prevBtn.disabled = currentTabIndex === 0;
nextBtn.disabled = currentTabIndex === tabs.length - 1;
prevBtn.classList.toggle('opacity-50', currentTabIndex === 0);
nextBtn.classList.toggle('opacity-50', currentTabIndex === tabs.length - 1);
}
function setupEventListeners() {
tabsContainer.addEventListener('click', (e) => { if (e.target.classList.contains('tab')) { currentTabIndex = parseInt(e.target.dataset.index); updateTabs(); } });
prevBtn.addEventListener('click', () => { if (currentTabIndex > 0) { currentTabIndex--; updateTabs(); } });
nextBtn.addEventListener('click', () => { if (currentTabIndex < tabs.length - 1) { currentTabIndex++; updateTabs(); } });
tabContentsContainer.addEventListener('input', (e) => {
if (e.target.tagName === 'INPUT') {
const category = e.target.dataset.category;
const key = e.target.dataset.key;
if (appData[category] && appData[category][key]) {
appData[category][key].value = e.target.value;
calculateAll();
}
}
});
document.getElementById('pdf-download-btn').addEventListener('click', generatePdf);
}
function generatePdf() {
const { jsPDF } = jspdf;
const pdf = new jsPDF();
const dashboardContent = document.querySelector('#Dashboard-content');
pdf.setFontSize(22);
pdf.text("Housing Market Forecast", 105, 20, { align: 'center' });
html2canvas(dashboardContent, { scale: 2 }).then(canvas => {
const imgData = canvas.toDataURL('image/png');
const { width, height } = pdf.internal.pageSize;
const imgHeight = canvas.height * width / canvas.width;
pdf.addImage(imgData, 'PNG', 15, 30, width - 30, imgHeight * ((width - 30) / width));
pdf.save('market-forecast.pdf');
});
}
initialize();
});
