-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjspsych_example.html
173 lines (156 loc) · 7 KB
/
jspsych_example.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/[email protected]"></script>
<script src="https://unpkg.com/@jspsych/[email protected]"></script>
<script src="https://unpkg.com/@jspsych/[email protected]"></script>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/jspsych.css" />
</head>
<body>
</body>
<script>
// Get URL parameters
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
let url_launch_token = urlParams.get('launch_token'); // Single-use launch token
const url_pid = urlParams.get('anonymous_id') // Participant ID
// If there is no launch_token provided, assume that this is a preview
if (url_launch_token == "" || url_launch_token == null || url_launch_token == undefined) {
url_launch_token = "00000000-0000-4000-B000-000000000000"; // reserved preview token
}
/* Initialize jsPsych */
var jsPsych = initJsPsych({
use_webaudio: false,
on_finish: function () {
//jsPsych.data.displayData('csv');
window.location = "https://qa.terracotta.education/integrations?launch_token=" + url_launch_token + "&score=1";
}
});
/* Add the URL parameters to the jsPsych data */
jsPsych.data.addProperties({
pid: url_pid,
launch_token: url_launch_token
});
/* Session variables */
var timeline = [];
var n_back_set = ['Z', 'X', 'C', 'V', 'B', 'N'];
var sequence = [];
var how_many_back = 2;
var sequence_length = 12;
/* Instructions #1 */
var instructions_1 = {
type: jsPsychHtmlButtonResponse,
stimulus: '<div style="width: 800px;">' +
'<h2>Visual <i>N</i>-Back Task Demonstration</h2>' +
'<p>This will test your ability to hold information in short-term, temporary memory. This is called working memory.</p>' +
'</div>',
choices: ["Continue"]
}
timeline.push(instructions_1);
/* Instructions #2 */
var instructions_2 = {
type: jsPsychHtmlButtonResponse,
stimulus: '<div style="width: 800px;">' +
'<p>You will see a sequence of letters presented one at a time. Your task is to determine if the letter on the screen matches ' +
'the letter that appeared two letters before.</p>' +
'<h4>If the letters match, press the M key.</h4>' +
'<p>For example, if you saw the sequence X, C, V, B, V, X you would press the M key when the second V appeared on the screen.</p>' +
'<h4>Do not press any key when there is not a match.</h4>' +
'</div>',
choices: ["Continue"]
}
timeline.push(instructions_2);
/* Instructions #3 */
var instructions_3 = {
type: jsPsychHtmlKeyboardResponse,
stimulus: '<div style="width: 800px;">' +
'<p>The sequence will begin on the next screen.</p>' +
'<p>Remember: press the M key if the letter on the screen matches the letter that appeared two letters ago.</p>' +
'<p>When you are ready to begin, press the M key to begin</p>' +
'</div>',
choices: ["M"],
post_trial_gap: 1000
}
timeline.push(instructions_3);
/* N Back sequence trials */
var n_back_trial = {
type: jsPsychHtmlKeyboardResponse,
/* Stimulus logic:
- if the current length of the stimulus is less than 2, then just grab random letter
- otherwise,
- if timelinevariable says match==true then draw the stim from two steps back
- else, draw two letters, and if the first matches, take the second */
stimulus: function () {
if (sequence.length < how_many_back) {
var letter = jsPsych.randomization.sampleWithoutReplacement(n_back_set, 1)[0]
} else {
if (jsPsych.timelineVariable('match', true) == true) {
var letter = sequence[sequence.length - how_many_back];
} else {
var possible_letters = jsPsych.randomization.sampleWithoutReplacement(n_back_set, 2);
if (possible_letters[0] != sequence[sequence.length - how_many_back]) {
var letter = possible_letters[0];
} else {
var letter = possible_letters[1];
}
}
}
sequence.push(letter);
return '<span style="font-size: 96px; font-weight: bold;">' + letter + '</span>'
},
choices: ['M'],
trial_duration: 1500,
response_ends_trial: false, // responding doesn't end the trial
post_trial_gap: 500,
on_finish: function (data) {
if (jsPsych.timelineVariable('match', true)) {
data.phase = "test";
data.match = true;
data.correct = (data.response != null);
} else {
data.phase = "test";
data.match = false;
data.correct = (data.response === null);
}
}
}
/* For any n_back_trial, match is either true or false */
var n_back_trials = [
{ match: true },
{ match: false }
]
/* Make a sequence out of the n-back trials, randomly sampling whether it matches */
var n_back_sequence = {
timeline: [n_back_trial],
timeline_variables: n_back_trials,
sample: {
type: 'with-replacement',
size: sequence_length,
weights: [1, 2] // aims for twice as many non-matches as matches
}
}
/* Push those n-back trials into the timeline */
timeline.push(n_back_sequence);
/* Present feedback */
var feedback = {
type: jsPsychHtmlButtonResponse,
stimulus: function () {
var test_trials = jsPsych.data.get().filter({ phase: 'test' }).last(sequence_length - 2);
var n_match = test_trials.filter({ match: true }).count();
var n_nonmatch = test_trials.filter({ match: false }).count();
var n_correct = test_trials.filter({ match: true, correct: true }).count();
var false_alarms = test_trials.filter({ match: false, correct: false }).count();
var html = "<div style='width:800px;'>" +
"<p>All done!</p>" +
"<p>You correctly identified " + n_correct + " of the " + n_match + " matching items.</p>" +
"<p>You incorrectly identified " + false_alarms + " of the " + n_nonmatch + " non-matching items as matches.</p>" +
"<p>Click the button below to finish the activity, and have your credit sent to the gradebook.</p>"
return html;
},
choices: ["Continue"]
}
timeline.push(feedback);
/* Run the timeline, baby! */
jsPsych.run(timeline);
</script>
</html>