-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.html
491 lines (455 loc) · 27 KB
/
index.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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
<!DOCTYPE html>
<html>
<head>
<!-- jspsych plugins-->
<title>Squares</title>
<script src="js/jquery-2.1.1.min.js"></script>
<script src="js/jspsych.js"></script>
<script src="plugins/jspsych-resize.js"></script>
<script src="plugins/jspsych-html-keyboard-response.js"></script>
<script src="plugins/jspsych-instructions.js"></script>
<script src="plugins/jspsych-survey-text.js"></script>
<script src="plugins/jspsych-survey-multi-choice.js"></script>
<script src="plugins/jspsych-fullscreen.js"></script>
<script src="plugins/jspsych-html-button-response.js"></script>
<script src="plugins/jspsych-html-slider-response.js"></script>
<!-- css-->
<link href="css/my_exp.css" rel="stylesheet" type="text/css">
<link href="css/jspsych.css" rel="stylesheet" type="text/css">
</head>
<body>
<script>
/*full screen */
var enter_fullscreen = {
type: "fullscreen",
fullscreen_mode: true
}
/*this part defines the css properties dynamicaly according to the window_screen_size
each of the 12 locations is determined here according to the required visual angle in pixels */
var root = document.documentElement;
var vis_angle_px = 105
var square_width = 51.4
root.style.setProperty('--top_middle', window.screen.height / 2 + "px");
root.style.setProperty('--left_middle', window.screen.width / 2 - (square_width / 2) + "px");
root.style.setProperty('--top_a', window.screen.height / 2 - vis_angle_px + "px");
root.style.setProperty('--left_a', window.screen.width / 2 - vis_angle_px + "px");
root.style.setProperty('--top_b', window.screen.height / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--left_b', window.screen.width / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--top_c', window.screen.height / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--left_c', window.screen.width / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--top_d', window.screen.height / 2 - vis_angle_px + "px");
root.style.setProperty('--right_d', window.screen.width / 2 - vis_angle_px + "px");
root.style.setProperty('--top_e', window.screen.height / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--right_e', window.screen.width / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--top_f', window.screen.height / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--right_f', window.screen.width / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--bottom_g', window.screen.height / 2 - vis_angle_px + "px");
root.style.setProperty('--right_g', window.screen.width / 2 - vis_angle_px + "px");
root.style.setProperty('--bottom_h', window.screen.height / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--right_h', window.screen.width / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--bottom_i', window.screen.height / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--right_i', window.screen.width / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--bottom_j', window.screen.height / 2 - vis_angle_px + "px");
root.style.setProperty('--left_j', window.screen.width / 2 - vis_angle_px + "px");
root.style.setProperty('--bottom_k', window.screen.height / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--left_k', window.screen.width / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--bottom_l', window.screen.height / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--left_l', window.screen.width / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--upper1', window.screen.height / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--upper2', window.screen.height / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--upper3', window.screen.height / 2 - vis_angle_px + "px");
root.style.setProperty('--lower1', window.screen.height / 2 - 3 * vis_angle_px + "px");
root.style.setProperty('--lower2', window.screen.height / 2 - 2 * vis_angle_px + "px");
root.style.setProperty('--lower3', window.screen.height / 2 - vis_angle_px + "px");
/*----------------------------------------------------
Variabels for squares game
------------------------------------------------------*/
/*randomly assigning the mapping of the response-keys to be ks or sk */ //cr: what does it mean? ks? sk?
mapping = jsPsych.randomization.sampleWithoutReplacement(['sk', 'ks'], 1)[0];
/* getting the images to display */
var change_detection_images = ['images/squares/black.png', 'images/squares/blue.png', 'images/squares/brown.png', 'images/squares/cyan.png', 'images/squares/green.png', 'images/squares/magenta.png', 'images/squares/orange.png', 'images/squares/red.png', 'images/squares/yellow.png']
/* setting the locations to randomize from */
var locations = ["<img class='a' src=", "<img class='b' src=", "<img class='c' src=", "<img class='d' src=", "<img class='e' src=", "<img class='f' src=", "<img class='g' src=", "<img class='h' src=", "<img class='i' src=", "<img class='j' src=", "<img class='k' src=", "<img class='l' src=",]
var locations_setsize1 = ["<img class='upper1' src=", "<img class='upper2' src=", "<img class='upper3' src=", "<img class='lower1' src=", "<img class='lower2' src=", "<img class='lower3' src="]
var subjectNumber = {type: 'survey-text',
questions:[{prompt: 'אנא הכנס מספר נבדק', placeholder: '1234', required: true, name:'subject'}]
}
var sessionNumber = {type: 'survey-text',
questions:[{prompt: 'אנא הכנס מספר סשן', placeholder: '1', required: true, name:'session'}]
}
/*subject number and time for csv saving*/
//var subN = "001"
var date = Date.now();
/*----------------------------------------------------
Functions for squares game
------------------------------------------------------*/
//This function decides on a random location for the test square
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
//This function picks random squares to show
function get_squares(images, number_of_images) {
return jsPsych.randomization.sampleWithoutReplacement(change_detection_images, number_of_images)
}
/*This function picks the locations in which the squares will be shown
It also takes care of equally randomizing the different quadrants */
function get_locations(locations_arr, number_of_images, locations_arr1) {
random_locations = [];
if (number_of_images == 1) {
return jsPsych.randomization.sampleWithoutReplacement(locations_arr1, 1)
}
for (var i = 0; i < 4; i++) {
random_2_locations = jsPsych.randomization.sampleWithoutReplacement(locations_arr.slice(i * 3, i * 3 + 3), 2)
random_locations.push(random_2_locations[0])
if (number_of_images > 4) {
random_locations.push(random_2_locations[1])
}
}
return random_locations
}
/*This function combines the squares and the locations that were randomly chosen */
function generate_random_squares(condition) {
number_of_images = parseInt(condition[0])
change_detection_images = jsPsych.randomization.shuffle(change_detection_images)
current_locations = get_locations(locations, number_of_images, locations_setsize1)
squares = '';
for (index = 0; index < number_of_images; index++) {
squares += current_locations[index] + change_detection_images[index] + ">"
}
return squares + fixation;
}
var condition_squares_exp = jsPsych.randomization.sampleWithoutReplacement(['4same', '4diff', '8same', '8diff'], 1)[0]
var fixation = '<div class="fixation">+</div>'
/*This function downloads the data locally */
function download_csv(csv,subN) {
var hiddenElement = document.createElement('a');
file_name = "WM_visual_array_" + subN + "_" + date.toString() + ".csv"
hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
hiddenElement.target = '_blank';
hiddenElement.download = file_name;
hiddenElement.click();
}
/*----------------------------------------------------
Timeline for squares starts
------------------------------------------------------*/
var timeline = [];
timeline.push(enter_fullscreen)
timeline.push(subjectNumber)
timeline.push(sessionNumber)
/*----------------------------------------------------
Start instructions variabels
------------------------------------------------------*/
var instructions_squares = {
type: "instructions",
pages: ["The experiment will have two parts, we will now learn the first one, called the <b>'squares game'</b>.",
"We will now provide instructions regarding the squares game. <b>Please read them carefully.</b>",
"Feel free to <b>go back and forth between the screens using the arrows</b> (Left=previous, Right=next) or the buttons below."
, "At the end of the instructions, <b>we will ask you to complete a short quiz about them</b>, to make sure everything is well understood."
, "In this part of the experiment, you will see a plus in the middle of the screen." +
"<p> We would like you to <b>focus on the plus whenever it appears</b>.</p> " + "<img src='images/fixation.png'>",
"<p> Then, 4 or 8 colored 'memory' squares will appear on the screen. <b>You need to remember the colors and locations of all of the squares</b>.</p>" +
"<img src='images/squares/example1.png'>",
"<p> Right afterward, the 'memory' squares will disappear and instead, one 'test' square will show up in a place where one of the squares was previously displayed.</p>" +
"<p> Your goal is to <b>identify whether the new 'test' square is in the same or different color as the one previously displayed in this location</b>.</p>" +
"<p> You need to press <b>'" + mapping[0] + "'</b> if you think the color is the <b>same</b> as the color of the square previously appearing in this location.</p>" +
"<img src='images/squares/example2.png'>",
"<p> You need to press <b>'" + mapping[1] + "'</b> if you think the color is <b>different</b> than the color of the square previously appearing in this location.</p>" +
"<img src='images/squares/example3.png'>", "<p> We will now ask you to complete a short quiz to make sure that you understood the instructions."],
show_clickable_nav: true,
};
var Q1_square_options = ["2 or 4", "4 or 6", "4 or 8"];
var Q2_square_options = ["True", "False"];
var Q3_square_options = ["Click on it", "Press the LEFT or RIGHT arrow keys", "Press the ‘" + mapping[0] + "’ or ‘" + mapping[1] + "’ key."];
var Q4_square_options = ["The plus appearing in the middle of the screen", "The colors and locations of the 'memory' squares", "The color and location of the single 'test' square"];
var Q5_square_options = ["To tell if the 'test' square is in the same color as the square previously appearing in this location", "To tell if a square previously appeared in the location of the shown square"];
var instructions_test_squares = {
type: 'survey-multi-choice',
questions: [
{ prompt: "How many squares will be initially shown?", name: 'set_size', correct: '4 or 8', options: Q1_square_options, required: true },
{ prompt: "The single square will appear after the squares will disappear ", name: 'steps', correct: 'True', options: Q2_square_options, required: true },
{ prompt: "How do you choose if a square is same or different?", name: 'choose_square', correct: "Press the ‘" + mapping[0] + "’ or ‘" + mapping[1] + "’ key.", options: Q3_square_options, required: true },
{ prompt: "What should you try to remember?", name: 'remember', correct: "The colors and locations of the 'memory' squares", options: Q4_square_options, required: true },
{ prompt: "What is your task?", name: 'task', correct: "To tell if the 'test' square is in the same color as the square previously appearing in this location", options: Q5_square_options, required: true },
],
data: { trial_name: 'test_squares' }
};
var if_trial_squares = {
type: 'html-button-response',
stimulus: "<p>Sorry. You made a mistake.<br>"
+ "Let’s go back to the instructions. "
+ "Please read them carefully before submitting your answers. <br>"
+ "Thank you!",
choices: ['Back to instructions']
}
/* the to_repeat variable defined whether the quiz is to be repeate*/
var to_repeat_squares;
var check_answers = {
timeline: [if_trial_squares],
conditional_function: function () {
// get the data from the previous trial,
// and check which key was pressed
to_repeat_squares = false;
var responses_to_test_square = JSON.parse(jsPsych.data.get().filter({ trial_type: 'survey-multi-choice' }).last(1).select('responses').values[0])
for (i = 0; i < instructions_test_squares.questions.length; i++) {
current_name = instructions_test_squares.questions[i].name;
current_correct = instructions_test_squares.questions[i].correct
if (current_correct != responses_to_test_square[current_name]) {
to_repeat_squares = true;
return to_repeat_squares
}
else {
to_repeat_squares = false;
}
}
return to_repeat_squares
}
}
var instructions_squares_loop = {
timeline: [instructions_squares, instructions_test_squares, check_answers],
loop_function: function () {
if (to_repeat_squares == true) {
return true;
} else {
return false;
}
}
}
/*----------------------------------------------------
Start practice part
------------------------------------------------------*/
var current_squares_practice_trial = 0;
var current_locations = null; // set up a global variable
var condition_squares_practice = jsPsych.randomization.sampleWithoutReplacement(['1same', '1diff'], 1)[0] //this makes sure that the subject will have at least one set_size1 trial in practice
var start_practice_squares = {
type: 'html-keyboard-response',
stimulus: "<p> We will now start some practice trials.<br> <b>The practice trials will also include some trials in which you will need to remember only one square to make sure you understood the instructions.</b> <br> You may already want to be ready with your fingers on '<b>s'</b> and <b>'k'</b>. <br><img class=keyboard src='images/keyboard.png'> <br> <u>Please try to be as accurate as possible for the experiment to succeed.</u> <br><br><b>Press any key to begin</b></u>",
post_trial_gap: 1000,
/*removes cursor from screen*/
on_finish: function () { document.querySelector('head').insertAdjacentHTML('beforeend', '<style id="cursor-toggle"> html { cursor: none; } </style>') },
}
var fixation_memory = {
type: 'html-keyboard-response',
stimulus: fixation,
choices: jsPsych.NO_KEYS,
trial_duration: 1000,
}
var memory_practice = {
type: "html-keyboard-response",
stimulus: function () { return generate_random_squares(condition_squares_practice) },
choices: jsPsych.NO_KEYS,
trial_duration: 200,
data: {
block_type: 'practice', trial_name: 'memory', trial_num: function () { return current_squares_practice_trial },
set_size: function () {
return condition_squares_practice[0]
}
}
}
var fixation_retention = {
type: 'html-keyboard-response',
stimulus: fixation,
choices: jsPsych.NO_KEYS,
trial_duration: 900
}
var test_practice = {
type: "html-keyboard-response",
stimulus: function () {
rand_num = getRandomInt(number_of_images)
if (condition_squares_practice[1] == 's') { /* it is the same condition */
square = current_locations[rand_num] + change_detection_images[rand_num] + ">"
}
else { /* it is different condition */
square = current_locations[rand_num] + jsPsych.randomization.sampleWithoutReplacement(change_detection_images.slice(number_of_images), 1) + ">"
}
return square + fixation
},
choices: ['s', 'k'],
trial_duration: 6000,
data: {
block_type: 'practice', trial_name: 'test', trial_num: function () { return current_squares_practice_trial },
correct_response: function () {
if (condition_squares_practice[1] == 's') { //it is same condition //cr: is it work with 'S'? should it work with capsLock? or it is case sensitive?
key_press_num = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(mapping[0])
}
else {
key_press_num = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(mapping[1])
}
return key_press_num
},
set_size: function () {
return condition_squares_practice[0]
}
},
on_finish: function (data) { //cr: im not sure if those names that start with numbers are legal
condition_squares_practice = jsPsych.randomization.sampleWithoutReplacement(['1same', '1diff', '4same', '4diff', '8same', '8diff'], 1)[0] //now everything could be
var correct = false;
if (data.correct_response == data.key_press) {
correct = true;
}
else if (data.key_press == null) {
correct = null;
}
data.accuracy = correct;
current_squares_practice_trial += 1;
}
}
var feedback_squares = {
type: 'html-keyboard-response',
stimulus: function () {
feedback_text = 'incorrect'
last_trial_correct = jsPsych.data.getLastTrialData().values()[0].accuracy;
if (last_trial_correct == true) {
feedback_text = 'correct'
}
else if (last_trial_correct == null) {
feedback_text = 'Please respond faster'
}
return feedback_text
},
choices: jsPsych.NO_KEYS,
trial_duration: 500
}
var demo_procedure_squares = {
timeline: [fixation_memory, memory_practice, fixation_retention, test_practice, feedback_squares],
repetitions: 5 //3.5sec per trial*15 =52.5sec
}
var if_trial_practice_squares = {
on_start: function () {
if (document.querySelector('#cursor-toggle') != null) {
document.querySelector('#cursor-toggle').remove()
}
},
type: 'html-button-response',
stimulus: "<p>Sorry. You made too many mistakes.<br>"
+ "Let’s do the practice session once again. <br>"
+ "Thank you!",
choices: ['Back to practice']
}
var to_repeat_practice_squares;
var check_accuracy = {
timeline: [if_trial_practice_squares],
conditional_function: function () {
/* Get the data from the previous trial,and calculate accuracy
If the participant wasn't perfect in the trials with set_size 1 - we will repeat.*/
to_repeat_practice_squares = false;
var correct_prac_square = jsPsych.data.getLastTimelineData().filter({ block_type: 'practice', trial_name: 'test', set_size: '1' }).select('accuracy').sum()
var total_prac_square = jsPsych.data.getLastTimelineData().filter({ block_type: 'practice', trial_name: 'test', set_size: '1' }).select('accuracy').count()
var prac_square_accuracy = correct_prac_square / total_prac_square;
if (prac_square_accuracy != 1) {
to_repeat_practice_squares = true;
return to_repeat_practice_squares
}
else {
to_repeat_practice_squares = false;
}
return to_repeat_practice_squares
}
}
var practice_squares_loop = {
timeline: [start_practice_squares, demo_procedure_squares, check_accuracy],
loop_function: function () {
if (to_repeat_practice_squares == true) {
return true;
} else {
return false;
}
}
}
/*Start exp part of squares game*/
var start_exp_squares = {
type: 'html-keyboard-response',
stimulus: '<p>Good Job! <br> You have finished the practice trials.<br> We will now start the real experiment. Please try to be as accurate as possible. <br> <br> <b> Press any key to begin</p>'
};
var current_squares_exp_trial = 0;
var memory = {
type: "html-keyboard-response",
stimulus: function () { return generate_random_squares(condition_squares_exp) },
choices: jsPsych.NO_KEYS,
trial_duration: 200,
data: {
block_type: 'exp', trial_name: 'memory', trial_num: function () { return current_squares_exp_trial }
}
}
var test = {
type: "html-keyboard-response",
stimulus: function () {
rand_num = getRandomInt(number_of_images)
if (condition_squares_exp[1] == 's') { /* it is the same condition */
square = current_locations[rand_num] + change_detection_images[rand_num] + ">"
}
else { /* it is different condition */
square = current_locations[rand_num] + jsPsych.randomization.sampleWithoutReplacement(change_detection_images.slice(number_of_images), 1) + ">"
}
return square + fixation
},
choices: ['s', 'k'],
trial_duration: 6000,
data: {
block_type: 'exp', trial_name: 'test_squares', mapping: mapping, trial_num: function () { return current_squares_exp_trial },
correct_response: function () {
if (condition_squares_exp[1] == 's') { //it is same condition
key_press_num = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(mapping[0])
}
else {
key_press_num = jsPsych.pluginAPI.convertKeyCharacterToKeyCode(mapping[1])
}
return key_press_num
},
set_size: function () {
return condition_squares_exp[0]
},
condition: function () {
return condition_squares_exp[1]
}
},
on_finish: function (data) {
condition_squares_exp = jsPsych.randomization.sampleWithoutReplacement(['4same', '4diff', '8same', '8diff'], 1)[0]
var correct = false;
if (data.correct_response == data.key_press) {
correct = true;
}
else if (data.key_press == null) {
correct = null;
}
data.accuracy = correct;
current_squares_exp_trial += 1;
}
}
/*Finish exp part of squares game*/
var finish_exp_squares = {
type: 'html-keyboard-response',
stimulus: '<p>Good Job! <br> You have finished the squares game.<br> We will now move on to the next test. Good luck! <br> <br> <b> Press any key to continue</p>'
};
var test_procedure_squares = {
timeline: [fixation_memory, memory, fixation_retention, test, feedback_squares],
repetitions: 120 //3.5sec per trial per 120 trials= 420sec
}
var full_procedure_squares = {
//timeline: [practice_squares_loop, start_exp_squares, test_procedure_squares, finish_exp_squares]
timeline: [instructions_squares_loop, practice_squares_loop, start_exp_squares, test_procedure_squares, finish_exp_squares]
} //instructions takes 60sec total
timeline.push(full_procedure_squares)
/*----------------------------------------------------
Define init for the whole experiment
------------------------------------------------------*/
jsPsych.init({
timeline: timeline,
preload_images: change_detection_images,
show_preload_progress_bar: true,
on_finish: function () {
/*calculate accuracy */
var correct_test_squares = jsPsych.data.get().filter({ block_type: 'exp', trial_name: 'test_squares' }).select('accuracy').sum()
var total_test_squares = jsPsych.data.get().filter({ block_type: 'exp', trial_name: 'test_squares' }).select('accuracy').count()
var test_squares_accuracy = correct_test_squares / total_test_squares;
localStorage.squares_accuracy = test_squares_accuracy;
var subNum = JSON.parse(jsPsych.data.get().filter({trial_index: 1}).select('responses').values[0])['subject']
var sessionNumber = JSON.parse(jsPsych.data.get().filter({trial_index: 2}).select('responses').values[0])['session']
jsPsych.data.addProperties({subject:subNum})
jsPsych.data.addProperties({session:sessionNumber})
/*get data */
download_csv(jsPsych.data.get().csv(),subNum)
}
});
</script>
</body>
</html>