Avg. Days on Market
${avgDom.toFixed(1)}
Total New Listings
${totalListings.toLocaleString('en-US')}
`;
}
function renderCharts() {
const labels = marketData.map(d => d.period);
const chartConfigs = {
salePriceChart: {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Median Sale Price',
data: marketData.map(d => d.price),
borderColor: 'rgb(59, 130, 246)',
backgroundColor: 'rgba(59, 130, 246, 0.5)',
tension: 0.1
}]
}
},
salesVolumeChart: {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Homes Sold',
data: marketData.map(d => d.sold),
backgroundColor: 'rgba(22, 163, 74, 0.7)'
}]
}
},
marketMetricsChart: {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Median Days on Market',
data: marketData.map(d => d.dom),
borderColor: 'rgb(234, 88, 12)',
backgroundColor: 'rgba(234, 88, 12, 0.5)',
yAxisID: 'y'
}, {
label: 'New Listings',
data: marketData.map(d => d.listings),
borderColor: 'rgb(147, 51, 234)',
backgroundColor: 'rgba(147, 51, 234, 0.5)',
yAxisID: 'y1'
}]
},
options: {
scales: {
y: { type: 'linear', display: true, position: 'left' },
y1: { type: 'linear', display: true, position: 'right', grid: { drawOnChartArea: false } }
}
}
}
};
for (const chartId in chartConfigs) {
const ctx = document.getElementById(chartId);
if (!ctx) continue;
if (chartInstances[chartId]) {
chartInstances[chartId].destroy();
}
chartInstances[chartId] = new Chart(ctx, chartConfigs[chartId]);
}
}
// --- PDF DOWNLOAD FUNCTION ---
function downloadPDF() {
const { jsPDF } = window.jspdf;
const pdfContent = document.getElementById('pdf-container');
const pdfTitle = document.getElementById('pdf-title');
if (!pdfContent || !pdfTitle) return;
pdfTitle.style.display = 'block'; // Show title for PDF
html2canvas(pdfContent, { scale: 2 }).then(canvas => {
pdfTitle.style.display = 'none'; // Hide title again
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({
orientation: 'l', // landscape
unit: 'mm',
format: 'a4'
});
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const imgProps = pdf.getImageProperties(imgData);
const imgWidth = pdfWidth - 20;
const imgHeight = (imgProps.height * imgWidth) / imgProps.width;
if (imgHeight > pdfHeight - 20) {
alert("Content is too long for a single PDF page. Consider reducing the number of data points for a better export.");
return;
}
pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight);
pdf.save('Real-Estate-Trend-Analysis.pdf');
});
}
// --- INITIALIZATION ---
if (addRowBtn) addRowBtn.addEventListener('click', addRow);
if (applyChangesBtn) applyChangesBtn.addEventListener('click', applyChanges);
if (downloadPdfBtn) downloadPdfBtn.addEventListener('click', downloadPDF);
renderDataTable();
renderDashboard();
showTab(0);
});