`;
document.getElementById('data-config-input').value = JSON.stringify(correlationData, null, 2);
document.getElementById('update-dashboard-btn').addEventListener('click', handleUpdateDashboard);
};
// --- CHART RENDERING ---
const renderChartsForTab = (tabId) => {
if (tabId !== 'dashboard') return;
destroyCharts();
const data = [];
for (let i = 0; i < correlationData.labels.length; i++) {
for (let j = 0; j < correlationData.labels.length; j++) {
data.push({
x: correlationData.labels[i],
y: correlationData.labels[j],
v: correlationData.matrix[i][j]
});
}
}
// Function to map a value from -1 to 1 to a color from red to green
const valueToColor = (value) => {
const r = value < 0 ? 214 + 41 * value : 247 - (201 * value);
const g = value < 0 ? 39 + 208 * value : 247 - (147 * value);
const b = value < 0 ? 40 + 208 * value : 247 - (215 * value);
return `rgb(${r}, ${g}, ${b})`;
};
chartInstances.matrix = new Chart(document.getElementById('matrix-chart').getContext('2d'), {
type: 'matrix',
data: {
datasets: [{
label: 'Correlation',
data: data,
backgroundColor: (ctx) => valueToColor(ctx.raw.v),
borderColor: 'rgba(255, 255, 255, 0.5)',
borderWidth: 1,
width: ({chart}) => (chart.chartArea || {}).width / correlationData.labels.length - 1,
height: ({chart}) => (chart.chartArea || {}).height / correlationData.labels.length - 1,
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: false
},
tooltip: {
callbacks: {
title: () => '',
label: (ctx) => [
`X: ${ctx.raw.x}`,
`Y: ${ctx.raw.y}`,
`Correlation: ${ctx.raw.v.toFixed(2)}`
]
}
}
},
scales: {
x: {
type: 'category',
labels: correlationData.labels,
ticks: {
display: true
},
grid: {
display: false
}
},
y: {
type: 'category',
labels: correlationData.labels,
offset: true,
ticks: {
display: true
},
grid: {
display: false
}
}
}
}
});
};
// --- NAVIGATION & EVENT HANDLING ---
const showTab = (tabIndex) => {
currentTab = tabIndex;
const tabId = tabs[tabIndex];
document.querySelectorAll('.tab-pane').forEach(pane => pane.classList.add('hidden'));
document.getElementById(`${tabId}-tab`).classList.remove('hidden');
document.querySelectorAll('.tab-btn').forEach(btn => btn.classList.remove('active'));
document.querySelector(`.tab-btn[data-tab='${tabId}']`).classList.add('active');
prevBtn.style.visibility = (currentTab === 0) ? 'hidden' : 'visible';
nextBtn.style.visibility = (currentTab >= tabs.length - 2) ? 'hidden' : 'visible';
downloadPdfBtn.style.visibility = (tabId === 'config') ? 'hidden' : 'visible';
if (tabId === 'dashboard') {
renderDashboardTab();
}
};
tabNavigation.addEventListener('click', (e) => {
if (e.target.matches('.tab-btn')) {
const tabId = e.target.dataset.tab;
const tabIndex = tabs.indexOf(tabId);
showTab(tabIndex);
}
});
nextBtn.addEventListener('click', () => {
if (currentTab < tabs.length - 1) showTab(currentTab + 1);
});
prevBtn.addEventListener('click', () => {
if (currentTab > 0) showTab(currentTab - 1);
});
const handleUpdateDashboard = () => {
const configInput = document.getElementById('data-config-input');
const errorDiv = document.getElementById('json-error');
const errorMessage = document.getElementById('json-error-message');
try {
const newData = JSON.parse(configInput.value);
// Basic validation
if (!newData.labels || !newData.matrix || newData.labels.length !== newData.matrix.length) {
throw new Error("Invalid data structure. 'labels' and 'matrix' must exist, and the matrix must be square.");
}
correlationData = newData;
errorDiv.classList.add('hidden');
renderDashboardTab();
alert('Dashboard updated successfully!');
showTab(0);
} catch (error) {
errorMessage.textContent = 'Invalid JSON format. ' + error.message;
errorDiv.classList.remove('hidden');
}
};
// --- PDF GENERATION ---
downloadPdfBtn.addEventListener('click', () => {
const { jsPDF } = window.jspdf;
const pdfContainer = document.getElementById('pdf-content-container');
const activeTabElement = document.getElementById('dashboard-tab');
if (!pdfContainer || !activeTabElement) return;
const clone = activeTabElement.cloneNode(true);
pdfContainer.innerHTML = '';
pdfContainer.appendChild(clone);
html2canvas(pdfContainer, { scale: 2, useCORS: true, logging: false, width: pdfContainer.scrollWidth, height: pdfContainer.scrollHeight })
.then(canvas => {
const imgData = canvas.toDataURL('image/png');
const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const imgWidth = canvas.width;
const imgHeight = canvas.height;
const ratio = imgWidth / imgHeight;
let finalImgHeight = pdfWidth / ratio;
let heightLeft = finalImgHeight;
let position = 0;
pdf.text(`Correlation Matrix Report`, 40, 40);
pdf.addImage(imgData, 'PNG', 0, 60, pdfWidth, finalImgHeight);
heightLeft -= (pdfHeight - 60);
while (heightLeft > 0) {
position = heightLeft - finalImgHeight;
pdf.addPage();
pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, finalImgHeight);
heightLeft -= pdfHeight;
}
pdf.save(`Correlation_Matrix_Report.pdf`);
pdfContainer.innerHTML = '';
}).catch(err => {
console.error("PDF generation failed:", err);
alert("Sorry, there was an error creating the PDF.");
});
});
// --- INITIALIZATION ---
createTabs();
renderAllTabs();
showTab(0);
});
