An easy-to-use platform for EEG experimentation in the classroom
at main 143 lines 3.9 kB view raw
1import * as lab from 'lab.js'; 2 3export function initMultitaskingResponseHandlers( 4 this: lab.flow.Loop<Record<string, unknown>> 5) { 6 if (!this.options.events) return; 7 8 this.options.events.keydown = (e: Event) => { 9 const { code } = e as unknown as { code: string }; 10 if (code === 'KeyQ') { 11 this.data.skipTraining = true; 12 this.end(); 13 } 14 15 if (code === 'ArrowLeft' || code === 'ArrowRight') { 16 const instructions = 17 document.querySelectorAll<HTMLElement>('div.instruction'); 18 let notFound = true; 19 instructions.forEach((i) => { 20 if (i.style.display === 'block' && notFound) { 21 const cur_id = parseInt(i.id.split('screen_')[1], 10); 22 let next_id; 23 if (code === 'ArrowLeft') { 24 next_id = cur_id - 1; 25 } 26 if (code === 'ArrowRight') { 27 next_id = cur_id + 1; 28 } 29 if (next_id > 0 && next_id <= 10) { 30 i.style.display = 'none'; 31 next_id = `screen_${next_id}`; 32 33 const nextElement = document.querySelector<HTMLElement>( 34 `#${next_id}` 35 ); 36 if (nextElement) { 37 nextElement.style.display = 'block'; 38 } 39 notFound = false; 40 } 41 } 42 }); 43 } 44 }; 45} 46 47export function initTasks(this: lab.flow.Loop<Record<string, unknown>>) { 48 function shuffle(a) { 49 let j; 50 let x; 51 for (let i = a.length - 1; i > 0; i--) { 52 j = Math.floor(Math.random() * (i + 1)); 53 x = a[i]; 54 a[i] = a[j]; 55 a[j] = x; 56 } 57 return a; 58 } 59 60 let tasksParameters: { 61 type: string; 62 dots: number; 63 form: string; 64 cor_response: string; 65 }[] = []; 66 const blocks: string[] = 67 this.parameters.block === 'mixed' 68 ? ['shape', 'filling'] 69 : [this.parameters.block, this.parameters.block]; 70 71 function trialConstructor( 72 block: string, 73 dots: number, 74 form: string, 75 cor_response: string 76 ) { 77 return { 78 type: block, 79 dots, 80 form, 81 cor_response, 82 }; 83 } 84 85 const numberBlocks = Math.ceil(this.parameters.num_trials / 4); 86 87 for (let i = 1; i <= numberBlocks; i++) { 88 for (const block of blocks) { 89 if (block === 'shape') { 90 tasksParameters = tasksParameters.concat([ 91 trialConstructor(block, 2, 'diamond', 'b'), 92 trialConstructor(block, 2, 'square', 'n'), 93 trialConstructor(block, 3, 'diamond', 'b'), 94 trialConstructor(block, 3, 'square', 'n'), 95 ]); 96 } else if (block === 'filling') { 97 tasksParameters = tasksParameters.concat([ 98 trialConstructor(block, 2, 'diamond', 'b'), 99 trialConstructor(block, 2, 'square', 'b'), 100 trialConstructor(block, 3, 'diamond', 'n'), 101 trialConstructor(block, 3, 'square', 'n'), 102 ]); 103 } 104 } 105 } 106 107 const tasksParametersShuffled = shuffle(tasksParameters); 108 // assign options values to parameters of this task 109 this.options.templateParameters = tasksParametersShuffled.slice( 110 0, 111 this.parameters.num_trials 112 ); 113} 114 115export function triggerEEGCallback(this: lab.core.Component) { 116 this.parameters.callbackForEEG( 117 // TODO: is this parameter ever handled? 118 this.parameters.cond === 'Switching' ? 1 : 2 119 ); 120 this.data.correct = 'empty'; 121} 122 123export function initTaskScreen(this: lab.core.Component) { 124 const { id } = this.options; 125 if (!id) return; 126 127 this.data.trial_number = 128 1 + parseInt(id.split('_')[id.split('_').length - 2], 10); 129 this.data.condition = this.parameters.cond; 130 this.data.reaction_time = this.state.duration; 131 132 if (this.state.response === this.parameters.cor_response) { 133 this.data.correct_response = true; 134 } else { 135 this.data.correct_response = false; 136 } 137 138 if (this.parameters.task === 'main') { 139 this.data.response_given = this.state.correct === 'empty' ? 'no' : 'yes'; 140 } else { 141 this.data.phase = 'practice'; 142 } 143}