Psychophysics Experiment Stimulus File

Psychophysics Experiment Stimulus File Generator

Generated Trial List (Editable)

Configure your experiment in the "Experiment Configuration" tab and click "Generate Trial List."

Experiment Parameters

Stimulus Levels (Method of Constant Stimuli)

The tool will generate **${document.getElementById('psf-config-levels')?.value || 7}** equally spaced values between **${document.getElementById('psf-config-start')?.value || 100}** and **${document.getElementById('psf-config-end')?.value || 200}**, and present them in random order.

No trials generated. Click the 'Generate Trial List' button to create a list.

"; return; } const table = document.createElement('table'); table.className = "psf-dash-table"; // Header table.innerHTML = ` Trial # Stimulus Value (${configStimulusType.value}) Target Response Notes Action `; const tbody = table.querySelector('tbody'); // Rows trialData.forEach((trial) => { const tr = document.createElement('tr'); tr.dataset.id = trial.id; tr.innerHTML = ` ${trial.id} `; tbody.appendChild(tr); }); dashboardList.appendChild(table); // Attach input listeners for live updates to the master state array setupDashboardListeners(); } /** * Attaches listeners to the newly created table elements */ function setupDashboardListeners() { const table = dashboardList.querySelector('.psf-dash-table'); if (!table) return; // Listen for changes in inputs (value, target, notes) table.querySelectorAll('input').forEach(input => { input.addEventListener('change', handleDashboardInput); input.addEventListener('keyup', handleDashboardInput); }); // Listen for removal clicks table.querySelectorAll('button[data-action="remove"]').forEach(button => { button.addEventListener('click', handleDashboardRemove); }); } /** * Handles live updates to the master `trialData` array */ function handleDashboardInput(e) { const row = e.target.closest("tr"); if (!row) return; const trialId = parseInt(row.dataset.id); const trial = trialData.find(t => t.id === trialId); if (!trial) return; // Update the specific field if (e.target.classList.contains('psf-dash-value')) { trial.value = parseFloat(e.target.value); } else if (e.target.classList.contains('psf-dash-target')) { trial.target = e.target.value; } else if (e.target.classList.contains('psf-dash-notes')) { trial.notes = e.target.value; } // Optional: console.log(trialData); // Check state update } /** * Handles removing a trial directly from the dashboard */ function handleDashboardRemove(e) { const row = e.target.closest("tr"); if (!row) return; const trialId = parseInt(row.dataset.id); // Remove from master array trialData = trialData.filter(t => t.id !== trialId); // Re-index the remaining trials (important for psychophysics) trialData.forEach((t, index) => { t.id = index + 1; }); renderDashboard(); // Re-render to update trial numbers } /** * Generates a PDF report from the dashboard data */ function downloadPDF() { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF.autoTable === 'undefined') { alert("Error: PDF libraries could not be loaded. Please try again."); return; } if (trialData.length === 0) { alert("Checklist is empty. Please generate a trial list first."); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF("p", "pt", "a4"); const margin = 40; let yPos = margin; const tableHead = [ ["Trial #", configStimulusType.value, "Target Response", "Notes"] ]; const tableBody = []; // Get data from the *current* master state (which reflects dashboard edits) trialData.forEach((trial) => { tableBody.push([ trial.id, trial.value, trial.target, trial.notes ]); }); doc.setFontSize(18); doc.text(`Stimulus File: ${configTitle.value}`, margin, yPos); yPos += 30; const tableOptions = { startY: yPos, head: tableHead, body: tableBody, theme: 'striped', headStyles: { fillColor: [0, 115, 230], // Blue textColor: [255, 255, 255], }, columnStyles: { 0: { cellWidth: 50 }, 1: { cellWidth: 100 }, 2: { cellWidth: 120 }, 3: { cellWidth: 'auto' }, }, styles: { fontSize: 9, cellPadding: 4, overflow: 'linebreak' }, margin: { left: margin, right: margin } }; doc.autoTable(tableOptions); yPos = doc.autoTable.previous.finalY + 25; // Update yPos doc.save("Psychophysics_Stimulus_File.pdf"); } /** * Helper to escape HTML */ function escapeHTML(str) { if (!str) return ""; return str .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } // --- 4. INITIALIZATION & EVENT LISTENERS --- // Tab Listeners tabButtons.forEach((btn) => { btn.addEventListener("click", () => showTab(btn.dataset.target)); }); navButtons.forEach((btn) => { btn.addEventListener("click", () => showTab(btn.dataset.target)); }); // Config Tab Listeners if (generateBtn) { generateBtn.addEventListener("click", handleGenerate); } // Dashboard Tab Listeners if (pdfBtn) { pdfBtn.addEventListener("click", downloadPDF); } // Initial State showTab("psf-tab-dashboard"); });
Scroll to Top