···2626import researchQuestionImage from '../../assets/common/ResearchQuestion2.png';
2727import methodsImage from '../../assets/common/Methods2.png';
2828import hypothesisImage from '../../assets/common/Hypothesis2.png';
2929+import { loadTimeline } from '../../utils/jspsych/functions';
29303031const CUSTOM_STEPS = {
3132 OVERVIEW: 'OVERVIEW',
3232- STIMULI: 'STIMULI',
3333 PARAMETERS: 'PARAMETERS',
3434 PREVIEW: 'PREVIEW'
3535};
3636+3737+// const CUSTOM_STEPS = {
3838+// OVERVIEW: 'OVERVIEW',
3939+// STIMULI: 'STIMULI',
4040+// PARAMETERS: 'PARAMETERS',
4141+// PREVIEW: 'PREVIEW'
4242+// };
36433744const FIELDS = {
3845 QUESTION: 'Research Question',
···8693 this.handleEEGEnabled = this.handleEEGEnabled.bind(this);
8794 if (isNil(props.params)) {
8895 props.experimentActions.loadDefaultTimeline();
8989- }
9696+ };
9797+ this.endPreview = this.endPreview.bind(this);
9898+ }
9999+100100+ endPreview() {
101101+ this.setState({ isPreviewing: false });
90102 }
9110392104 handleStepClick(step: string) {
···107119 this.props.history.push(SCREENS.COLLECT.route);
108120 }
109121110110- handlePreview() {
122122+ handlePreview(e) {
123123+ e.target.blur();
111124 this.setState({ isPreviewing: !this.state.isPreviewing });
112125 }
113126···163176 className={styles.contentGrid}
164177 >
165178 <Grid.Column stretched verticalAlign="middle">
166166- <Segment basic>
167167- <Header as="h1">Image Duration</Header>
168168- <p>
169169- Select the trial duration. This determines the amount of time
170170- each image will be displayed during the experiment.
171171- </p>
172172- </Segment>
173173- <Segment basic>
174174- <ParamSlider
175175- label="Image Duration (seconds)"
176176- value={this.state.params.trialDuration}
177177- onChange={value =>
178178- this.setState({
179179- params: { ...this.state.params, trialDuration: value }
180180- })
181181- }
182182- />
183183- </Segment>
184184- </Grid.Column>
185185- <Grid.Column stretched verticalAlign="middle">
186186- <Segment basic>
187187- <Header as="h1">Time Interval</Header>
188188- <p>
189189- Select the inter-trial interval duration. This is the amount
190190- of time between trials measured from the end of one trial to
191191- the start of the next one.
192192- </p>
193193- </Segment>
194194- <Segment basic>
195195- <ParamSlider
196196- label="ITI Duration (seconds)"
197197- value={this.state.params.iti}
198198- onChange={value =>
199199- this.setState({
200200- params: { ...this.state.params, iti: value }
201201- })
202202- }
203203- />
204204- </Segment>
205205- </Grid.Column>
206206- <Grid.Column stretched verticalAlign="middle">
207207- <Segment basic>
208208- <Header as="h1">Progress Bar</Header>
209209- <p>
210210- This will display a small progress bar at the top of the
211211- experiment window
212212- </p>
213213- </Segment>
214214- <Segment basic>
215215- <Checkbox
216216- checked={this.props.params.showProgessBar}
217217- label="Enable progress bar"
218218- onChange={this.handleProgressBar}
219219- />
220220- </Segment>
221179 <Segment basic>
222180 <Header as="h1">EEG Enabled</Header>
223181 <p>EEG data collection will be enabled for this experiment</p>
···237195 <Grid relaxed padded className={styles.contentGrid}>
238196 <Grid.Column
239197 stretched
240240- width={6}
198198+ width={12}
241199 textAlign="right"
242242- verticalAlign="top"
200200+ verticalAlign="middle"
243201 className={styles.jsPsychColumn}
244202 >
245203 <PreviewExperimentComponent
246246- params={this.state.params}
247247- mainTimeline={this.props.mainTimeline}
248248- trials={this.props.trials}
249249- timelines={this.props.timelines}
204204+ {...loadTimeline(this.props.paradigm)}
250205 isPreviewing={this.state.isPreviewing}
206206+ onEnd={this.endPreview}
207207+ type={this.props.type}
208208+ paradigm={this.props.paradigm}
251209 />
252210 </Grid.Column>
253253- <Grid.Column width={6} verticalAlign="middle">
211211+ <Grid.Column width={4} verticalAlign="middle">
254212 <Segment basic>
255213 <Form>
256214 <Form.TextArea
···269227 </Segment>
270228 <PreviewButton
271229 isPreviewing={this.state.isPreviewing}
272272- onClick={this.handlePreview}
230230+ onClick={(e) => this.handlePreview(e)}
273231 />
274232 </Grid.Column>
275233 </Grid>
···377335 );
378336 }
379337}
338338+339339+// <Grid.Column stretched verticalAlign="middle">
340340+// <Segment basic>
341341+// <Header as="h1">Image Duration</Header>
342342+// <p>
343343+// Select the trial duration. This determines the amount of time
344344+// each image will be displayed during the experiment.
345345+// </p>
346346+// </Segment>
347347+// <Segment basic>
348348+// <ParamSlider
349349+// label="Image Duration (seconds)"
350350+// value={this.state.params.trialDuration}
351351+// onChange={value =>
352352+// this.setState({
353353+// params: { ...this.state.params, trialDuration: value }
354354+// })
355355+// }
356356+// />
357357+// </Segment>
358358+// </Grid.Column>
359359+// <Grid.Column stretched verticalAlign="middle">
360360+// <Segment basic>
361361+// <Header as="h1">Time Interval</Header>
362362+// <p>
363363+// Select the inter-trial interval duration. This is the amount
364364+// of time between trials measured from the end of one trial to
365365+// the start of the next one.
366366+// </p>
367367+// </Segment>
368368+// <Segment basic>
369369+// <ParamSlider
370370+// label="ITI Duration (seconds)"
371371+// value={this.state.params.iti}
372372+// onChange={value =>
373373+// this.setState({
374374+// params: { ...this.state.params, iti: value }
375375+// })
376376+// }
377377+// />
378378+// </Segment>
379379+// </Grid.Column>
380380+381381+382382+// <Segment basic>
383383+// <Header as="h1">Progress Bar</Header>
384384+// <p>
385385+// This will display a small progress bar at the top of the
386386+// experiment window
387387+// </p>
388388+// </Segment>
389389+// <Segment basic>
390390+// <Checkbox
391391+// checked={this.props.params.showProgessBar}
392392+// label="Enable progress bar"
393393+// onChange={this.handleProgressBar}
394394+// />
395395+// </Segment>
+8-2
app/utils/jspsych/functions.js
···1010import { buildStroopTimeline } from './timelines/stroop';
1111import { buildMultiTimeline } from './timelines/multi';
1212import { buildSearchTimeline } from './timelines/search';
1313+import { buildCustomLine } from './timelines/custom';
13141415import {
1516 MainTimeline,
···3435const outlet = lsl.create_outlet(info, 0, 360);
35363637// loads a normalized timeline for the default experiments with specific callback fns
3737-export const loadTimeline = (type: EXPERIMENTS) => {
3838+export const loadTimeline = (paradigm: EXPERIMENTS) => {
3939+ console.log('paradigm', paradigm)
3840 let timeline;
3939- switch (type) {
4141+ switch (paradigm) {
4042 case EXPERIMENTS.P300:
4143 timeline = buildOddballTimeline();
4244 break;
···59616062 case EXPERIMENTS.SEARCH:
6163 timeline = buildSearchTimeline();
6464+ break;
6565+6666+ case EXPERIMENTS.CUSTOM:
6767+ timeline = buildN170Timeline();
6268 break;
63696470 default:
+72
app/utils/jspsych/timelines/custom.js
···11+import * as path from 'path';
22+import { EVENTS } from '../../../constants/constants';
33+44+// Default directories containing stimuli
55+const rootFolder = __dirname; // Note: there's a weird issue where the fs readdir function reads from BrainWaves dir
66+77+const facesDir = path.join(rootFolder, 'assets', 'face_house', 'faces');
88+const housesDir = path.join(rootFolder, 'assets', 'face_house', 'houses');
99+const fixation = path.join(rootFolder, 'assets', 'common', 'fixationcross.png');
1010+1111+export const buildCustomLine = () => ({
1212+ overview:
1313+ 'Here is the placeholder for the overview of the Visual Search task',
1414+ background: 'Here is the background of the Visual Search task',
1515+ background_title: `Title`,
1616+ protocol: 'Here is the protocol of the Visual Search task',
1717+ params: {
1818+ trialDuration: 1000,
1919+ nbTrials: 150,
2020+ iti: 500,
2121+ jitter: 200,
2222+ sampleType: 'with-replacement',
2323+ pluginName: 'callback-image-display',
2424+ intro:
2525+ 'You will see the visual search task. Press 1 when a face appears and 9 for a house. Press any key to continue',
2626+ showProgressBar: false,
2727+ stimulus1: {
2828+ dir: facesDir,
2929+ title: 'Face',
3030+ type: EVENTS.STIMULUS_1,
3131+ response: '1'
3232+ },
3333+ stimulus2: {
3434+ dir: housesDir,
3535+ title: 'House',
3636+ type: EVENTS.STIMULUS_2,
3737+ response: '9'
3838+ }
3939+ },
4040+ mainTimeline: ['intro', 'faceHouseTimeline', 'end'], // array of trial and timeline ids
4141+ trials: {
4242+ intro: {
4343+ type: 'callback-html-display',
4444+ id: 'intro',
4545+ post_trial_gap: 1000
4646+ },
4747+ end: {
4848+ id: 'end',
4949+ type: 'callback-html-display',
5050+ stimulus: 'Thanks for participating. Press any key to continue',
5151+ response_ends_trial: true,
5252+ post_trial_gap: 500
5353+ }
5454+ },
5555+ timelines: {
5656+ faceHouseTimeline: {
5757+ id: 'faceHouseTimeline',
5858+ timeline: [
5959+ {
6060+ id: 'interTrial',
6161+ type: 'callback-image-display',
6262+ stimulus: fixation,
6363+ response_ends_trial: false
6464+ },
6565+ {
6666+ id: 'trial',
6767+ response_ends_trial: false
6868+ }
6969+ ]
7070+ }
7171+ }
7272+});
+1-1
app/utils/jspsych/timelines/multi.js
···2121 sampleType: 'with-replacement',
2222 pluginName: 'callback-image-display',
2323 intro:
2424- 'You will see the multi-tasking test. Press 1 when a face appears and 9 for a house. Press any key to continue',
2424+ 'You will see the multi-tasking test. Press any key to continue',
2525 showProgressBar: false,
2626 stimulus1: {
2727 dir: facesDir,