No gating steps defined.
';
}
appState.gatingSteps.forEach(function(step) {
var item = document.createElement('div');
item.className = 'gsd-step-list-item';
item.innerHTML = `
Step ${step.id}: ${step.popId} from ${step.parent}
`;
stepsListDiv.appendChild(item);
});
// Add remove listeners
stepsListDiv.querySelectorAll('.gsd-remove-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var id = parseInt(btn.dataset.id);
appState.gatingSteps = appState.gatingSteps.filter(function(s) { return s.id !== id; });
saveState();
renderConfigTab();
});
});
}
addStepBtn.addEventListener('click', function() {
var popId = popIdInput.value.trim();
var parentPop = parentPopInput.value.trim();
var markers = markersInput.value.trim();
var gateType = gateTypeSelect.value;
var logicDesc = logicDescInput.value.trim();
if (!popId || !parentPop || !markers || !logicDesc) {
alert("Please fill in Population ID, Parent, Markers, and Logic Description.");
return;
}
var newStep = {
id: Date.now(),
popId: popId,
parent: parentPop,
markers: markers,
type: gateType,
logic: logicDesc
};
appState.gatingSteps.push(newStep);
appState.gatingSteps.sort(function(a, b) { return a.id - b.id; }); // Sort by creation time
saveState();
renderConfigTab();
// Clear inputs
popIdInput.value = '';
parentPopInput.value = '';
markersInput.value = '';
logicDescInput.value = '';
gateTypeSelect.value = 'Scatter';
});
// Update button action
updateBtn.addEventListener("click", function() {
// Update metadata from form
appState.metadata.project = projectNameInput.value;
appState.metadata.experimenter = experimenterInput.value;
appState.metadata.instrument = instrumentInput.value;
appState.metadata.sampleType = sampleTypeInput.value;
saveState();
renderDashboardTab();
showTab(1); // Switch to Dashboard
});
// --- Core Logic: Dashboard Rendering ---
function renderDashboardTab() {
// Render titles
projectTitleDisplay.textContent = `Gating Strategy Document - ${appState.metadata.project}`;
// Render metadata table
metadataBody.innerHTML = `
| Project Name | ${appState.metadata.project} |
| Experimenter/Analyst | ${appState.metadata.experimenter} |
| Instrument Model | ${appState.metadata.instrument} |
| Sample Type | ${appState.metadata.sampleType} |
|---|
`;
// Render strategy table
strategyTableBody.innerHTML = '';
if (appState.gatingSteps.length === 0) {
strategyTableBody.innerHTML = '
| No gating steps defined. |
';
return;
}
appState.gatingSteps.forEach(function(step, index) {
var stepNum = index + 1;
strategyTableBody.innerHTML += `
| ${stepNum} |
${step.popId} |
${step.parent} |
${step.markers} |
${step.type} |
${step.logic} |
`;
});
}
// --- PDF Download ---
pdfBtn.addEventListener("click", function() {
var jsPDF = window.jspdf.jsPDF;
var projectSlug = appState.metadata.project.replace(/[^a-zA-Z0-9\s]/g, '').replace(/\s/g, '_').substring(0, 30) || 'Gating_Strategy';
var fileName = `${projectSlug}_Strategy_Document.pdf`;
// Temporarily adjust minimum width for better PDF quality capture
var tableContainer = document.getElementById('gsd-strategy-table-container');
var originalMinWidth = tableContainer.style.minWidth;
tableContainer.style.minWidth = '1000px';
html2canvas(exportArea, {
scale: 2,
useCORS: true,
backgroundColor: '#ffffff'
}).then(function(canvas) {
// Restore original minWidth
tableContainer.style.minWidth = originalMinWidth;
var imgData = canvas.toDataURL('image/png');
var doc = new jsPDF({
orientation: 'l', // Landscape is better for wide tables
unit: 'pt',
format: 'a4'
});
var pdfWidth = doc.internal.pageSize.getWidth();
var pdfHeight = doc.internal.pageSize.getHeight();
var imgProps = doc.getImageProperties(imgData);
var imgWidth = imgProps.width;
var imgHeight = imgProps.height;
var margin = 40;
var usableWidth = pdfWidth - (2 * margin);
var ratio = usableWidth / imgWidth;
var scaledHeight = imgHeight * ratio;
var usablePageHeight = pdfHeight - (2 * margin);
var heightLeft = scaledHeight;
var position = 0;
while (heightLeft > 0) {
// Add content with appropriate vertical offset for pagination
doc.addImage(imgData, 'PNG', margin, position + margin, usableWidth, scaledHeight);
heightLeft -= usablePageHeight;
position -= usablePageHeight;
if (heightLeft > 0) {
doc.addPage();
}
}
doc.save(fileName);
}).catch(function(err) {
tableContainer.style.minWidth = originalMinWidth; // Restore on error
console.error("GSD PDF Error:", err);
// alert("An error occurred while generating the PDF."); // Per spec
});
});
// --- Initial Load ---
loadState();
renderConfigTab();
renderDashboardTab();
showTab(0);
});