-
Notifications
You must be signed in to change notification settings - Fork 0
/
Documentation.html
1286 lines (1075 loc) · 85.4 KB
/
Documentation.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
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html><html><head><meta charset="utf-8"><title>README.md</title><style>.markdown-body hr:after,.markdown-body hr:before{display:table;content:""}.markdown-body ol,.markdown-body td,.markdown-body th,.markdown-body ul{padding:0}@font-face{font-family:octicons-anchor;src:url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format('woff')}.markdown-body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;color:#333;overflow:hidden;font-family:"Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif;font-size:16px;line-height:1.6;word-wrap:break-word}.markdown-body strong{font-weight:700}.markdown-body h1{margin:.67em 0}.markdown-body img{border:0}.markdown-body hr{-moz-box-sizing:content-box;box-sizing:content-box}.markdown-body input{color:inherit;margin:0;line-height:normal;font:13px/1.4 Helvetica,arial,freesans,clean,sans-serif,"Segoe UI Emoji","Segoe UI Symbol"}.markdown-body html input[disabled]{cursor:default}.markdown-body input[type=checkbox]{-moz-box-sizing:border-box;box-sizing:border-box;padding:0}.markdown-body *{-moz-box-sizing:border-box;box-sizing:border-box}.markdown-body a{background:0 0;color:#4183c4;text-decoration:none}.markdown-body a:active,.markdown-body a:hover{outline:0;text-decoration:underline}.markdown-body hr:after{clear:both}.markdown-body blockquote{margin:0}.markdown-body h1,.markdown-body h2{padding-bottom:.3em;border-bottom:1px solid #eee}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ol ol ol,.markdown-body ol ul ol,.markdown-body ul ol ol,.markdown-body ul ul ol{list-style-type:lower-alpha}.markdown-body dd{margin-left:0}.markdown-body .octicon{font:normal normal 16px octicons-anchor;line-height:1;display:inline-block;text-decoration:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.markdown-body .octicon-link:before{content:'\f05c'}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body .anchor{position:absolute;top:0;left:0;display:block;padding-right:6px;padding-left:30px;margin-left:-30px}.markdown-body .anchor:focus{outline:0}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{position:relative;margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{display:none;color:#000;vertical-align:middle}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{padding-left:8px;margin-left:-30px;text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{display:inline-block}.markdown-body h1{font-size:2.25em;line-height:1.2}.markdown-body h1 .anchor{line-height:1}.markdown-body h2{font-size:1.75em;line-height:1.225}.markdown-body h2 .anchor{line-height:1}.markdown-body h3{font-size:1.5em;line-height:1.43}.markdown-body h3 .anchor,.markdown-body h4 .anchor{line-height:1.2}.markdown-body h4{font-size:1.25em}.markdown-body h5 .anchor,.markdown-body h6 .anchor{line-height:1.1}.markdown-body h5{font-size:1em}.markdown-body h6{font-size:1em;color:#777}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:16px}.markdown-body hr{overflow:hidden;background:0 0;height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:16px}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body table{border-collapse:collapse;border-spacing:0;display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{max-width:100%;-moz-box-sizing:border-box;box-sizing:border-box}.markdown-body code{border-radius:3px}.markdown-body .pl-c{color:#969896}.markdown-body .pl-c1,.markdown-body .pl-mdh,.markdown-body .pl-mm,.markdown-body .pl-mp,.markdown-body .pl-mr,.markdown-body .pl-s1 .pl-v,.markdown-body .pl-s3,.markdown-body .pl-sc,.markdown-body .pl-sv{color:#0086b3}.markdown-body .pl-e,.markdown-body .pl-en{color:#795da3}.markdown-body .pl-s1 .pl-s2,.markdown-body .pl-smi,.markdown-body .pl-smp,.markdown-body .pl-stj,.markdown-body .pl-vo,.markdown-body .pl-vpf{color:#333}.markdown-body .pl-ent{color:#63a35c}.markdown-body .pl-k,.markdown-body .pl-s,.markdown-body .pl-st{color:#a71d5d}.markdown-body .pl-pds,.markdown-body .pl-s1,.markdown-body .pl-s1 .pl-pse .pl-s2,.markdown-body .pl-sr,.markdown-body .pl-sr .pl-cce,.markdown-body .pl-sr .pl-sra,.markdown-body .pl-sr .pl-sre,.markdown-body .pl-src{color:#df5000}.markdown-body .pl-mo,.markdown-body .pl-v{color:#1d3e81}.markdown-body .pl-id{color:#b52a1d}.markdown-body .pl-ii{background-color:#b52a1d;color:#f8f8f8}.markdown-body .pl-sr .pl-cce{color:#63a35c;font-weight:700}.markdown-body .pl-ml{color:#693a17}.markdown-body .pl-mh,.markdown-body .pl-mh .pl-en,.markdown-body .pl-ms{color:#1d3e81;font-weight:700}.markdown-body .pl-mq{color:teal}.markdown-body .pl-mi{color:#333;font-style:italic}.markdown-body .pl-mb{color:#333;font-weight:700}.markdown-body .pl-md,.markdown-body .pl-mdhf{background-color:#ffecec;color:#bd2c00}.markdown-body .pl-mdht,.markdown-body .pl-mi1{background-color:#eaffea;color:#55a532}.markdown-body .pl-mdr{color:#795da3;font-weight:700}.markdown-body kbd{display:inline-block;padding:3px 5px;font:11px Consolas,"Liberation Mono",Menlo,Courier,monospace;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:1px solid #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown-body .task-list-item{list-style-type:none}.markdown-body .task-list-item+.task-list-item{margin-top:3px}.markdown-body .task-list-item input{float:left;margin:.3em 0 .25em -1.6em;vertical-align:middle}.markdown-body :checked+.radio-label{z-index:1;position:relative;border-color:#4183c4}.hljs{display:block;overflow-x:auto;padding:.5em;background:#23241f;-webkit-text-size-adjust:none}.aspectj .hljs-function,.css .hljs-function .hljs-preprocessor,.css .hljs-rules,.css .hljs-value,.hljs,.hljs-pragma,.hljs-tag{color:#f8f8f2}.hljs-emphasis,.hljs-strong,.hljs-strongemphasis{color:#a8a8a2}.alias .hljs-keyword,.hljs-blockquote,.hljs-bullet,.hljs-hexcolor,.hljs-horizontal_rule,.hljs-literal,.hljs-number,.hljs-regexp{color:#ae81ff}.css .hljs-class,.hljs-class .hljs-title:last-child,.hljs-code,.hljs-tag .hljs-value,.hljs-title{color:#a6e22e}.hljs-link_url{font-size:80%}.hljs-strong,.hljs-strongemphasis{font-weight:700}.hljs-class .hljs-title:last-child,.hljs-emphasis,.hljs-strongemphasis,.hljs-typename{font-style:italic}.alias .hljs-keyword:first-child,.css .hljs-important,.css .hljs-tag,.css .unit,.hljs-attribute,.hljs-change,.hljs-flow,.hljs-function,.hljs-header,.hljs-keyword,.hljs-symbol,.hljs-symbol .hljs-string,.hljs-tag .hljs-title,.hljs-value,.hljs-winutils,.nginx .hljs-title,.ruby .hljs-class .hljs-keyword:first-child,.ruby .hljs-function .hljs-keyword,.tex .hljs-special{color:#f92672}.css .hljs-attribute,.hljs-aspect .hljs-keyword:first-child,.hljs-class .hljs-keyword:first-child,.hljs-constant,.hljs-function .hljs-keyword,.hljs-typename{color:#66d9ef}.hljs-aspect .hljs-title,.hljs-class .hljs-title,.hljs-params,.hljs-variable{color:#f8f8f2}.apache .hljs-cbracket,.apache .hljs-tag,.css .hljs-id,.django .hljs-filter .hljs-argument,.django .hljs-template_tag,.django .hljs-variable,.hljs-addition,.hljs-attr_selector,.hljs-built_in,.hljs-envvar,.hljs-link_label,.hljs-link_url,.hljs-prompt,.hljs-pseudo,.hljs-stream,.hljs-string,.hljs-subst,.hljs-type,.ruby .hljs-class .hljs-parent,.smalltalk .hljs-array,.smalltalk .hljs-class,.smalltalk .hljs-localvars,.tex .hljs-command{color:#e6db74}.apache .hljs-sqbracket,.hljs-annotation,.hljs-comment,.hljs-decorator,.hljs-deletion,.hljs-doctype,.hljs-javadoc,.hljs-pi,.hljs-shebang,.tex .hljs-formula{color:#75715e}.coffeescript .javascript,.javascript .xml,.php .xml,.tex .hljs-formula,.xml .css,.xml .hljs-cdata,.xml .javascript,.xml .php,.xml .vbscript{opacity:.5}.markdown-body {min-width: 200px;max-width: 790px;width: auto !important;margin: 0 auto;padding: 30px;}.markdown-body img {max-width: 100%;}</style></head><body><article class="markdown-body"><h1 id="top"> Online Bourdon Vos Test </h1>
<p>The Online Bourdon Vos Test (O-BVT) has transformed the Bourdon Vos Test (BVT; 1998) from a paper-and-pencil version to a web based test. The O-BVT & BVT measure continued attention in children aged 6 - 17. This is done by providing the participants with a sheet (BVT) or screen (O-BVT) containing 33 rows with 24 figures each (i.e. 792 figures). Each figure contains of either 3, 4, or 5 black dots. This is why the adult version (the Bourdon Wiersma Test) is also called the "Dot Cancellation Test". </p>
<p><strong>IF YOU WISH TO USE THE ONLINE BOURDON VOS TEST - PLEASE SEE THE <a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/README_USERS.pdf">USER MANUAL</a> FOR INSTRUCTIONS !</strong></p>
<p>This document contains information on the process behind creating the O-BVT in line with the requirements for the course "Programming The Next Step", which was given at the University of Amsterdam, the Netherlands, in 2017. For other software developers I recommend looking at the <a href="#design">Design</a> section as it contains examples of the code. Of course, all source files are accessible on GitHub: <a href="https://github.com/SHogenboom/BourdonVosTest">Bourdon Vos Test</a>. All files contain in-line comments.</p>
<h2> Content </h2>
<ul>
<li><a href="#requirements">Requirements</a><ul>
<li><a href="#scenario">Scenario</a></li>
<li><a href="#screenshots">Screenshots</a></li>
<li><a href="#taskflow">Task Flow</a><ul>
<li><a href="#taskflowuser">User</a></li>
<li><a href="#taskflowsoftware">Software</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#design">Design</a><ul>
<li><a href="#content">Content</a></li>
</ul>
</li>
<li><a href="#implementation">Implementation</a><ul>
<li><a href="#versioncontrol">Version Control</a></li>
<li><a href="#codingstyle">Coding Style</a></li>
<li><a href="#testing">Testing</a></li>
<li><a href="#documentation">Documentation</a></li>
<li><a href="#errorprovision">Error Provision</a></li>
</ul>
</li>
<li><a href="#verification">Verification</a><ul>
<li><a href="#alphatester">Alpha Testing</a></li>
<li><a href="#bugs">Bug Reporting</a></li>
</ul>
</li>
<li><a href="#development">Planned Developments</a>
+ </li>
<li><a href="#references">References</a><ul>
<li><a href="#bourdonvostest">Bourdon Vos Test</a></li>
<li><a href="#normgroup">Norm Groups</a></li>
</ul>
</li>
</ul>
<p><a href="#top"><em>top</em></a></p>
<h2 id="requirements"> Requirements </h2>
<h3 id="scenario"> Scenario </h3>
<p>The BVT is administered by an <code>Experiment Leader</code> to a child aged 6 - 17 with (un)diagnosed attention deficits. Therefore, the O-BVT serves two audiences: the <code>Experiment Leader</code> and the <code>Participant</code>. The <code>Participant</code> is merely pre-occupied with crossing out any figure that contains 4 dots (leaving 3 and 5 dot figures untouched). To do so, the <code>Participant</code> needs to comprehend how to perform the task while on the computer. The <code>Experiment Leader</code> aims to determine if the <code>Participant</code>'s continued attention levels matches that of his/her peers. Therefore, the <code>Experiment Leader</code> normally (in the BVT) has to instruct the <code>Participant</code>, record reaction times, and compute total scores. In the O-BVT, this will all be done by the software, thereby significantly decreasing the time and effort it costs an <code>Experiment Leader</code> to administer the Bourdon Vos paradigm. The <code>Experiment Leader</code> is only tasked with entering the <code>Participant</code>'s demographics. </p>
<p><a href="#top"><em>top</em></a></p>
<h3 id="screenshots"> Screenshots </h3>
<p><img src="https://github.com/SHogenboom/BourdonVosTest/blob/master/BourdonWiersma.png" alt="Screenshot Bourdon Vos Test"> </p>
<p><em>Screenshot of Bourdon Vos Test</em> </p>
<p><img src="https://github.com/SHogenboom/BourdonVosTest/blob/master/O-BVT.png" alt="Screenshot Online Bourdon Vos Test"> </p>
<p><em>Screenshot of Online Bourdon Vos Test</em><br>All figures with 4 dots are to be clicked (i.e. crossed out). When the participant has moved the mouse over a figure, this figure will turn grey. </p>
<p><a href="#top"><em>top</em></a></p>
<h3 id="taskflow"> Task Flow </h3>
<table>
<thead>
<tr>
<th style="text-align:center">Page</th>
<th style="text-align:center"><code>HTML</code></th>
<th style="text-align:center"><code>JavaScript</code></th>
<th style="text-align:center"><code>CSS</code></th>
<th style="text-align:center">Function</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">1</td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/index.html">index.html</a></td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/index.js">index.js</a></td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/bv_css.css">bv_css.css</a></td>
<td style="text-align:center">Demograhpics</td>
</tr>
<tr>
<td style="text-align:center">2</td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/bv_test_fixed.html">bv_test_fixed.html</a></td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/bv_combined.js">bv_combined.js</a></td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/bv_css.css">bv_css.css</a></td>
<td style="text-align:center">Practice Stimuli + Practice Line + Bourdon Vos Test</td>
</tr>
<tr>
<td style="text-align:center">3</td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/bv_results.html">bv_results.html</a></td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/bv_results_fixed.js">bv_results_fixed.js</a></td>
<td style="text-align:center"><a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/bv_css.css">bv_css.css</a></td>
<td style="text-align:center">Results</td>
</tr>
</tbody>
</table>
<p><em>Table of HTML pages presented in the O-BVT in the order they are displayed to the user. Supporting Javascript & CSS files per page. All links refer to the source file location on gitHub.</em> </p>
<h4 id="taskflowuser"> Task Flow User </h4>
<p><em>NOTE: all links refer to the JavaScript code documented in the <a href="#design">O-BVT Design</a> section.</em></p>
<p><strong>Experiment Leader</strong> follows instructions from the <a href="https://github.com/SHogenboom/BourdonVosTest/blob/master/README_USERS.pdf">User Manual</a> to start the O-BVT. The O-BVT starts with the index page to display <strong>Experiment Leader</strong> instructions & allows the <strong>Experiment Leader</strong> to enter the Participant's <a href="#demographics"><em>demographics</em></a>. The <strong>Experiment Leader</strong> then calls the <strong>Participant</strong> to the computer who will start the <a href="#practice"><em>practice</em></a> phase. Here, the <strong>Participant</strong> will be instructed on the possible stimuli and the mouse actions, then -similar to the BVT - the <strong>Participant</strong> completes a first row of the Bourdon Vos Test. After completing the practice phase, indicating that the <strong>Participant</strong> understands how to operate the computer and what is expected in the task, the <strong>Participant</strong> will continue on to the main phase: the <a href="#bvt"><em>Bourdon Vos Test</em></a>. When the <strong>Participant</strong> has finished the task, he/she will call the <strong>Experiment Leader</strong> again. The <strong>Experiment Leader</strong> then has to enter the pre-specified <a href="#password">password</a> in order to access the participant's <a href="#results"><em>results</em></a>.</p>
<h4 id="taskflowsoftware"> Task Flow Software </h4>
<p><em>NOTE: all links refer to the JavaScript code documented in the <a href="#design">O-BVT Design</a> section.</em></p>
<ol>
<li><strong>Display</strong> instructions to Experiment Leader</li>
<li><strong>Ask for & store</strong> Participant's <a href="#demographics">Demographics</a><ul>
<li>First Name</li>
<li>Last Name</li>
<li>Age</li>
<li>Gender</li>
</ul>
</li>
<li><strong>Store</strong> specified <a href="#password">Password</a> to prevent the results from being accessed by the Participants in the <a href="#results">Results</a> phase.</li>
<li><strong>Change interface</strong> from Experiment Leader interface to Participant interface</li>
<li><strong>Display</strong> Participant with instructions about the task</li>
<li><strong>Present</strong> <a href="#practice">Practice Trial</a> to Participant to familiarize with interface & operation<ul>
<li><strong>Store</strong> responses</li>
<li><strong>Loop until</strong> pp. crosses out all 4 dotted figures in 1 row of random figures</li>
<li><strong>Store</strong> amount of practice trials</li>
</ul>
</li>
<li><strong>Present</strong> <a href="#bvt">Bourdon Vos Test</a> to Participant<ul>
<li><strong>Create</strong> <a href="#stimuli">Stimuli</a></li>
<li><strong>Track</strong> <a href="#response">responses</a></li>
<li>Enable <strong>response visualizations</strong> to each figure (i.e. crossing out)</li>
<li><strong>Store</strong> reaction times per row & for total Bourdon Vos test</li>
</ul>
</li>
<li><strong>Change interface</strong> from Participant interface to Experiment Leader interface</li>
<li><strong>Validate</strong> pre-specified <a href="#password">Password</a> input<ul>
<li>if valid return results</li>
<li>if invalid retry or exit the O-BVT</li>
</ul>
</li>
<li><strong>Display</strong> <a href="#results">Results</a><ul>
<li><strong>Calculate</strong> absolute hits/misses/false alarms</li>
<li><strong>Calculate</strong> amount of figures not reviewed</li>
<li><strong>Display</strong> percentage of hits/misses/false alarms/not reviewed</li>
<li><strong>Calculate</strong> row reaction time</li>
<li><strong>Compare</strong> participant data to norm group data (based on age)</li>
</ul>
</li>
</ol>
<p><a href="#top"><em>top</em></a></p>
<h2 id="design"> Design </h2>
<p>This section provides context on the code that was used to create the Bourdon Vos Test from a more global perspective. Necessary elements of the code are discussed, however, changes in button text etc are not discussed. All code files are accessible on <a href="https://github.com/SHogenboom/BourdonVosTest">GitHub</a> and contain in-code comments for specifics. Relevant code snippets can be viewed by clicking the "> Code: ... " buttons </p>
<p><a href="#top"><em>top</em></a></p>
<h3 id="content"> Content </h3><br>
<ul>
<li><a href="#demographics">Demographics</a></li>
<li><a href="#password">Password Protect Results</a></li>
<li><a href="#practice">Practice Trial</a></li>
<li><a href="#bvt">Bourdon Vos Test</a><ul>
<li><a href="#stimuli">Stimuli</a></li>
<li><a href="#response">Response Actions</a></li>
</ul>
</li>
<li><a href="#results">Results</a> </li>
<li><a href="#internet">Function From Internet Sources</a></li>
</ul>
<p><a href="#top"><em>top</em></a></p>
<h3 id="demographics"> Demographics </h3>
<p>The experiment leader is asked to provide the participant's <code>FIRSTNAME</code>, <code>LASTNAME</code>, <code>GENDER</code>, and <code>AGE</code>. <code>FIRSTNAME</code>, <code>LASTNAME</code>, <code>GENDER</code> input is <strong>not validated</strong> because these are not used for any other reason than to address the participant at a later phase. <code>AGE</code> is <strong>validated</strong> against two criteria: 1) The input is a number, and 2) the participant is between 6 and 17 years old. This validation is important because norm group data is not available for other age groups. </p>
<p>The experiment leader is provided with a way out by clicking "cancel" in the prompt boxes. In doing so the experiment leader does not continue with the rest of the O-BVT. </p>
<details>
<summary> Code: Prompt Demographic Input </summary>
<p><br>
<code>javascript
const FIRSTNAME = window.prompt("First name: "); // ... enter pp. first name
if (FIRSTNAME != null) {
const LASTNAME = window.prompt("Last name: "); // ... enters pp. last name
if (LASTNAME != null) {
const GENDER = window.prompt("The participant is ... [Male/Female/Other]"); // ... enter pp gender [suggestions]
if (GENDER != null) {
const AGE = agePrompt();
if (AGE != null) {
// ENTER PASSWORD
document.getElementById("maintext").innerHTML =
("Thank you for entering the participant's demographics" +
"<br>" + "It is now time to call the participant." + "<br>" +
"Please press 'next' to display the participant instructions");
document.getElementById("button").innerHTML = "next"; // change button text
document.getElementById("button").onclick = function(){window.location.href = "bv_practice.html"};
// load practice window upon clicking the button
// store variables in temporary memory for acces later on
sessionStorage.setItem("FIRSTNAME", FIRSTNAME);
sessionStorage.setItem("LASTNAME", LASTNAME);
sessionStorage.setItem("AGE", AGE);
sessionStorage.setItem("RESULT_ACCES_PASSWORD", String(RESULT_ACCES_PASSWORD));
} else {
// finish task
document.getElementById("maintext").innerHTML =
"Thank you for viewing the online Bourdon Vos Test. Please contact [email protected] for any questions or comments regarding the test.";
document.getElementById("button").style.visibility = "hidden"; // no advance possible to task
} // END AGE IF
} else {
// finish task
document.getElementById("maintext").innerHTML =
"Thank you for viewing the online Bourdon Vos Test. Please contact [email protected] for any questions or comments regarding the test.";
document.getElementById("button").style.visibility = "hidden"; // no advance possible to task
} // END GENDER IF
} else {
// finish task
document.getElementById("maintext").innerHTML =
"Thank you for viewing the online Bourdon Vos Test. Please contact [email protected] for any questions or comments regarding the test.";
document.getElementById("button").style.visibility = "hidden"; // no advance possible to task
} // END lastname IF
} else {
// finish task
document.getElementById("maintext").innerHTML =
"Thank you for viewing the online Bourdon Vos Test. Please contact [email protected] for any questions or comments regarding the test.";
document.getElementById("button").style.visibility = "hidden"; // no advance possible to task
} // END firstname IF</code><br></p>
</details>
<hr>
<details> <summary> Code: Age Validation </summary> <p>
<code>javascript
function agePrompt () {
// GOAL: To determine whether the input for the participant demographics is a number and falls between the appropriate age range for the Bourdon Vos Test (6 - 17)
while (validated == "No") {
var AGE = parseFloat(window.prompt("The participant is ... years old: ")); // parseFloat to change numerical input from prompt to number instead of string
if (isNaN(AGE) == false) {
// number validation passed >> AGE is a number
// check if age falls within limits: 6 < age < 17, if not prompt for re-entry of demographics<br> if (AGE < 6 || AGE > 17) {
// pp age does not fall within age limit
window.alert("The participants age = " + AGE + ". The BVTest is only suited for children between 6 and 17 years");
// Re-enter participant age?
var reEnter = window.confirm(
"Do you wish to re-enter the participant's age?");
// Confirm or cancel pop-up box
// ... if confirmed reEnter == true, if canceld reEnter == false
if (reEnter == true) {
validated == "No"; // prompts re-entry and re-validation for age
} else {
// the experimenter did not want to re-enter the pp demographics
// reEnter == false
console.log("The experiment leader did not wish to re-enter the demographics")
document.getElementById("maintext").innerHTML =
"Thank you for viewing the online Bourdon Vos Test. Please contact [email protected] for any questions or comments regarding the test.";
document.getElementById("button").style.visibility = "hidden"; // no advance possible to task
} // END reEnter<br>
} else {
// participant age lies within age range
validated = "Yes"; // will discontinue the while loop
} // END age IF
} else {
// pp age = not a number
window.alert("The participant age you specified was not a number. Please enter the participant's age in numbers only")
// Re-enter participant age?
var reEnter = window.confirm(
"Do you wish to re-enter the participant's age?");
// Confirm or cancel pop-up box
// ... if confirmed reEnter == true, if canceld reEnter == false
console.log(reEnter);
if (reEnter == true) {
validated == "No"; // prompts re-entry and re-validation for age
} else {
// the experimenter did not want to re-enter the pp demographics
// reEnter == false
console.log("The experiment leader did not wish to re-enter the demographics")
document.getElementById("maintext").innerHTML =
"Thank you for viewing the online Bourdon Vos Test. Please contact [email protected] for any questions or comments regarding the test.";
document.getElementById("button").style.visibility = "hidden"; // no advance possible to task
validated == "Yes";
break;
} // END reEnter<br>
// var AGE = 0;
} // END number IF<br> } // END WHILE LOOP
return AGE;
} // END agePrompt FUNCTION</code>
</p> </details>
<hr>
<p><a href="#top"><em>top</em></a></p>
<h3 id="password"> Password Protect Results </h3>
<p>Both the Experiment Leader and the Participant use the same computer, therefore, the <em>results</em> are protected from being viewed by the participant through a password. When the Experiment Leader sets up the experiment by entering the participant demographics, he/she is also asked to specify a password. The default value is set to "password". </p>
<p><strong>WARNING</strong>
If the Experiment Leader forgets the password they previously specified, he/she will not be able to view the participant's results.</p>
<details><summary> Code: Prompt Password </summary><p>
<code>javascript
const RESULT_ACCES_PASSWORD =
window.prompt(("Please enter a password that will allow only you" +
" to access the participant's results after completion"), "password");</code>
</p></details>
<hr>
<p>The password that is entered by the Experiment Leader is stored in <code>sessionStorage</code> until it is recalled in the results section of the O-BVT. When the participant has completed the Bourdon Vos Test, the Experiment Leader is prompted to enter their personal password. The entered password is <strong>validated</strong> against the earlier given password. </p>
<details><summary> Code: Validate Password </summary><p>
<code>javascript
var passWord = String(window.prompt("Please enter the specified password to access the results"));
if (passWord == RESULT_ACCES_PASSWORD) {
window.alert("Correct password. These are the results: ")
// CALL FUNCTIONS TO DISPLAY RESULTS
} else {
var passwordReentry = window.confirm("This is not the correct password. Do you wish to try again?");
if (passwordReentry == true) {
displayResults(); // launch validation again
} else {
document.getElementById("maintext").innerHTML = (
"Thank you for using the online Bourdon Vos Test" + "<br>" +
"For questions and comments, please contact: [email protected]")
} // END re-entry of password IF
} // END password Comparison</code>
</p></details>
<hr>
<p><a href="#top"><em>top</em></a></p>
<h3 id="practice"> Practice Trials </h3>
<p>The participants is provided with two opportunities to become familiar with the upcoming task. Firstly, he/she is provided with the <code>practice.html</code> screen which shows 3 figures. The first figure contains 3 dots, the second 4 dots, and the third 5 dots. </p>
<details><summary> Code: Create Practice Figures </summary><p>
<code>javascript
function figureCreation(canvasID) {
// GOAL create three practice figures
var dots = (canvasID.replace("Canvas", ""));
// Delete "Canvas" from id to identify amount of dots
if (dots == 3) {
blackDot(10,10,5,canvasID);
blackDot(40,30,5,canvasID);
blackDot(10,50,5,canvasID);
} else if (dots == 4) {
blackDot(30,10,5,canvasID);
blackDot(10,50,5,canvasID);
blackDot(30,30,5,canvasID);
blackDot(50,50,5,canvasID);
} else if (dots == 5) {
blackDot(30,30,5,canvasID);
blackDot(10,50,5,canvasID);
blackDot(50,10,5,canvasID);
blackDot(50,50,5,canvasID);
blackDot(30,10,5,canvasID);
}
} // END figureCreation FUNCTION</code>
<em>NOTE</em> the blackDot function is explained in the <a href="#stimuli">stimuli</a> section
</p></details>
<hr>
<p>The participant is guided through the process of which figures to click (only those with 4 dots) and what to do if they made a mistake (i.e. how to make a correction). How the figures are made response active is discussed in <a href="#stimuli">here</a>.</p>
<details><summary> Code: Response Instructions </summary><p>
<code>javascript
if (index == 1 && clicks == 0) {
document.getElementById("maintext").innerHTML =
("Easy right? But what if you clicked a figure with 3 or 5 dots" +
" by accident? Try clicking a figure twice and see what happens")
warning = false;
} else if ((clicks == 1 && index == 0) || (clicks == 1 && index == 2)){
document.getElementById("maintext").innerHTML =
("Welldone! You are ready for the Bourdon Vos Test" +
"<br>" + "Please click 'Start the Test' to get going.")
document.getElementById("button").innerHTML = "Start the Test";
document.getElementById("button").style.visibility = "visible";
document.getElementById("button").onclick = function() {window.location.href = "bv_test_fixed.html"};
warning = false;
} else if (index != 1 && warning == true) {
document.getElementById("maintext").innerHTML =
("You should click the figure with 4 dots first!");
} // END display of new instructions</code>
</p></details>
<hr>
<p>Upon familiarization with all possible responses (i.e. 1 click = cross out, 2 clicks = correction) the participant is redirected to the actual practice phase of the BVT: a single line with random figures. Presentation of this practice line was programmed in the <code>bv_test_fixed.html</code> file as all necessary functions were already present there. </p>
<p><a href="#top"><em>top</em></a></p>
<h3 id="bvt"> Bourdon Vos Test </h3>
<p>In order to provide the participant with a functioning Bourdon Vos Test I had to create the <a href="#stimuli">stimuli</a> and allow for mouse actions (i.e. <a href="#response">response action</a>.</p>
<p><a href="#top"><em>top</em></a></p>
<h4 id="stimuli"> Stimulus Creation </h4>
<p>In order to create anything graphical on a webpage that is not an image, one has to create a <code>canvas</code> element. In the Bourdon Vos Test it is specified that there are 24 figures per row, and 33 rows. Therefore, depending on the window size, the canvasses are smaller or larger. It is assumed that computer screens are wider than they are high, thus only the maximum width has to be determined in order to create square canvasses</p>
<details><summary> Code: Determine Canvas Size </summary><p>
<code>javascript
function canvasSize() {
// GOAL: determine size of screen and adjust size of the presented stimuli to be as
// ... large as possible
// ASSUMPTION: Computer & Laptop screens are wider than they are high.
// ... Thus in order to create maximum sized squares, only the width needs to be taken into account.
// Determine current window size
var winWidth = (window.innerWidth - (2<em> outerBorder)); // available amount of pixels on the inside of the window
// Determine max canvas width
var canvasWidth = (winWidth / (stimuliColumns)); // -4 to allow for room for the borders between canvases & the side of the window
return canvasWidth;
} // END canvasSize FUNCTION</code>
</p></details>
<hr>
<p>After the maximum height and width of the canvasses are determined, an empty canvas is created and attached to an existing <code><div></code> HTML element. This function is repeated in the <code>stimuliPresentation</code> function to create the appropriate amount of canvasses as specified by the Bourdon Vos Test (24 figures x 33 rows = 792).</p>
<details><summary> Code: Create Empty Canvas </summary><p>
<code>javascript
function createCanvas (appendObject, canvasID, canvasHeight, canvasWidth, posLeft, posTop) {
// GOAL: create a new RESPONSIVE empty canvas
// appendObject: ID of the object to which the canvas should be appended <div id = "stimuli">
// canvasID: name you want to give to the created canvas
// canvasHeight: height of the canvas
// canvasWidth: width of the canvas
// posLeft: left side of the canvas should be placed on which X-coordinate (in pixels)
// posTop: top side of the canvas should be placed on which Y-coordinate (in pixels)
// CREATE CANVAS
var addCanvas = document.createElement('canvas'); // Create new canvas element
// ASSIGN PROPERTIES
addCanvas.id = canvasID; // .id to change on what is specified (itterates in stimulusPresentation function)
addCanvas.width = canvasWidth; // set canvasWidth (depending on screen size in canvasSize function)<br> addCanvas.height = canvasHeight; // set canvasHeight (depending on screen size in canvasSize function)
addCanvas.style.position = "absolute";
addCanvas.style.left = posLeft;
addCanvas.style.top = posTop;
// ASSIGN RESPONSE ACTIONS
addCanvas.onclick = function () {responseLogging() } ; // call upon responseLogging to track correct crossout and log hits/miss/mistakes
addCanvas.onmouseover = function () {canvasMouseOver()} ; //
addCanvas.onmouseout = function () {canvasMouseOut()} ;
// APPEND CANVAS TO EXISTING OBJECT
document.getElementById(appendObject).appendChild(addCanvas); // append newly created canvas to existing element
} // END createCanvas FUNCTION</code>
<em>NOTE</em> the variables are passed forward to this function in the main function <code>stimuliPresentation();</code>. Secondly, all response actions are stored in separate functions.
</p></details>
<hr>
<p>Once an empty canvas is created (or a screen full of empty canvasses) it is time to draw a dot figure on that canvas. To do so, first we have to determine how many 3, 4, and 5 dots figures there are, and randomize presentation order</p>
<details><summary> Code: Randomize 3/4/5 Dot Figures </summary><p>
<code>javascript
totalStimuli = stimuliColumns </em> stimuliRows;
// CREATE DOT ARRAY
// Create an array with 1/3 of totalStimuli containing "3", "4", or "5" > will represent amount of dots later on
for (i = 3; i < 6; i++) {
for (x = 1; x < ((totalStimuli / 3) + 1); x++) { // +1 because counter starts at 1
dotArray.push(i) // add the number (i) to the entire array
} // END 1/3 of figure LOOP
} // END create dot array LOOP
shuffleArray(dotArray); // shuffle content of dotArray to allow for random presentation order</code>
</p></details>
<hr>
<p>After knowing how many dots will be presented in each figure, it is key to determine where these dots can be drawn on the canvas. This is dependent on the canvas size. For this version of the O-BVT a 3x3 grid of dot placements was created. Future versions could increase this grid size to allow for more varied figures, similar to the figures in the BVT. </p>
<details><summary> Code: Create Position Grid </summary><p>
<code>javascript
function dotCoordinates (canvasID) {
// GOAL: create a combination of X & Y coordinates that match size of the canvas
// canvasID: id of canvas to be drawn on
// SET VARIABLES
var canvasWidth = (document.getElementById(canvasID).width - 6); // -6 to allow for 3px blank border where no circkel is drawn
var canvasHeight = (document.getElementById(canvasID).height - 6); // -6 to allow for 3px blank border where no circkel is drawn
var sizeCirckel = (canvasWidth / 11); // divide by 11 to allow blank spaces between the dots
// console.log(sizeCirckel);
arrayXpos = [];
arrayYpos = [];
// possible X positions
arrayXPos = []; // create empty array accesible outside function
for (q = 1; q < (3 + 1); q++) { // repeat X coordinates for all coordinates of Y
for (k = 1; k < (3 + 1); k++) { // positions for the amount of horizontalCirckles specified (+1 because k = 1)
var posX = ((3 <em> sizeCirckel) </em> k); // (should be changed depending on canvas & circkel size)
arrayXpos.push(posX); // append new position to array containing all X coordinates
} // END horizontal LOOP
} // END vertical LOOP
// window.alert(arrayXPos); // TEST
// possible Y positions
arrayYPos = []; // create empty array accesisble outside function
for (w = 1; w < (3 + 1); w++) { // repeat Y coordinates for all coordinates of X
for (l = 1; l < (3 + 1); l++) { // positions for the amount of verticalCirckles specified (+1 because l = 1)
var posY = ((3 <em> sizeCirckel) </em> l); // change depending on circkelSize
arrayYpos.push(posY); // append new position to array containing all Y position
} // END vertical LOOP
} // END horizontal LOOP
// window.alert(arrayYPos); // TEST
// sort so when paired with X creates unique XY coordinates
arrayYpos.sort();
// shuffle XY positions
indexArray = []; // create new Array for random indexing out of XY coordinate arrays
for (y = 1; y < 9; y++) { // create integers for each point in the grid (1 - 9)
indexArray.push(y); // append integer to indexArray
} // END for LOOP
shuffleArray(indexArray); // shuffle order of integers to allow for random indexing (i.e. dot placement)
return sizeCirckel;
} // END positionGrid FUNCTION</code>
</p></details>
<hr>
<p>We now have an empty canvas upon which we can draw a figure, we know how many dots should go on that figure, and we know all possible positions of a single dot. All that is left now is to draw a dot, and repeat that action for the appropriate amount of times.</p>
<details><summary> Code: Draw Figure </summary><p>
Draw Black Dot
<code>javascript
function blackDot (canvasID, posX, posY, sizeCirckel) {
// GOAL: draw a single black circkle
// canvasID: id of the canvas to be drawn on
// posX: X position of center circkel relative to canvas
// posY: Y position of center circkel relative to canvas
// sizeCirckel: size of circkel dependent on size of canvas
// CALL CANVAS
var c = document.getElementById(canvasID); // draw on prespecified canvas (see HTML)
var ctx = c.getContext("2d"); // unkown functionality but necessary
// DRAW CIRCKEL
ctx.beginPath(); // initialize drawing
ctx.fillstyle = "black"; // specify fill color = black
ctx.arc(posX,posY,sizeCirckel,0,2<em>Math.PI); // specification of shape to draw (in this case a circkle)
ctx.stroke(); // draw specified shape
ctx.closePath(); // to allow for other figures to be drawn
ctx.fill(); // execute
} // END blackDot FUNCTION</code>
Repeat appropriate amount of times
<code>javascript
// DRAW FIGURES ON CANVAS
var sizeCirckel = dotCoordinates (canvasID);
var dots = dotArray[(t-1)]; // -1 because index starts at 0
for (k = 0 ; k < dots; k++) {
var index = indexArray[k];<br> var posX = arrayXpos[index];
var posY = arrayYpos[index];
blackDot (canvasID, posX, posY, sizeCirckel)
} // END drawing figures LOOP</code>
</p></details>
<hr>
<p><a href="#top"><em>top</em></a></p>
<h4 id="response"> Response Actions </h4>
<p>The O-BVT requires the following response actions:</p>
<ol>
<li>1 Click = cross-out figure & 2 Clicks = correction </li>
<li>Record Hits/Misses/False Alarms</li>
<li>Reaction Times per Row</li>
</ol>
<p>I have also added the response action to change the background color of the figure when it is hovered over with the mouse. This way participants are more clear on where the mouse is, and thus which figure they are responding to. </p>
<p>All these functionalities were added to the figures (i.e. canvasses) as they were created. All functionalities are placed in the <code>.mouseout</code> function with a delay of 200 milliseconds. In other words: none of these responses are logged if you quickly scroll over the stimuli, they are only logged if you "hover" over a figure longer than 200 milliseconds: <code>if ((finishHover - startHover) > 200)</code>. </p>
<p><strong>NOTE</strong></p>
<p>Initially any response is coded, pushed to the relevant array, and stored in memory. The responses are not cleaned until the results section.</p>
<details><summary> Code: Mouse Click Actions </summary><p>
<code>javascript
function responseLogging () {
// SET VARIABLES
var currentID = event.currentTarget.id; // log id of event that triggered the function
var canvasWidth = document.getElementById(currentID).width; // determine canvas width
var canvasHeight = document.getElementById(currentID).height; // determine canvas height<br> var index = (currentID.replace("Canvas", ""))-1; // replace "Canvas" by nothing so unique number remains, -1 because index starts from 0
// DRAW RESPONSE
var clicks = clickArray[index];
if (clicks == 0) {
// canvas has not been clicked - draw line
var c=document.getElementById(currentID); // refer to correct canvas
var ctx=c.getContext("2d"); // unkown but necessary
imageData = ctx.getImageData(0,0,canvasWidth, canvasHeight); // store canvas picture as is
ctx.beginPath(); // start new drawing
ctx.moveTo(0,0); // determine starting position of line - constant
ctx.lineTo(canvasWidth,canvasHeight); // finish position of line - changes on canvas size specifiedin drawGrid function
ctx.lineWidth = 4; // size of the line to be drawn (should depend on circkle size)
ctx.strokeStyle = "#ff0000"; // color of line; red
ctx.stroke(); // initialize drawing
clickArray[index] = 1; // increment clicks to 1
} else if (clicks == 1) {
// second response, draw correction line
var c=document.getElementById(currentID); // refer to correct canvas
var ctx=c.getContext("2d"); // unkown but necessary
ctx.putImageData(imageData, 0,0); // reset previous picture (i.e. remove red line)
clickArray[index] = 2;
} else {
// do nothing, pictures should not be clicked more than twice
} // END clicks IF
} // END responseLogging FUNCTION</code>
</p></details>
<hr>
<details><summary> Code: Hit/Miss/False Alarm Coding </summary><p>
<code>javascript
// CODE RESPONSES (only cross out (click = 1) figures with 4 dots)
// responses: HIT (1), Miss (2), False Alarm (3)
// corrections: NO (0), YES (1)
if (amountDots == 3 || amountDots == 5) {
// do not click (click == 0) or correct mistake (click == 2) == HIT
if (clickArray[index] == 0) { // No click = CORRECT // NOTE: not coded because function only activated upon mouseclick
responseArray.push(1); // HIT
correctionArray.push(0); // NO
} else if (clickArray[index] == 1) { // 1 click == WRONG (only click figures with 4 dots)
responseArray.push(3); // FALSE ALARM
correctionArray.push(0); // NO
} else { // 2 clicks == CORRECTION
responseArray.push(1); // HIT
correctionArray.push(1); // YES
} // END click amount IF
} else { // amountDots == 4
if (clickArray[index] == 0) { // no click == WRONG // NOTE: not coded because function only activated upon mouseclick
responseArray.push(2); // MISS
correctionArray.push(0); // NO
} else if (clickArray[index] == 1) { // 1 click == CORRECT
responseArray.push(1); // HIT
correctionArray.push(0); // NO
} else { // 2 clicks == unjust correction aka WRONG
responseArray.push(2); // MISS
correctionArray.push(1); // YES
} // END click amount IF
} // END amountDots IF</code>
</p></details>
<hr>
<details><summary> Code: Reaction Time </summary><p>
<code>javascript
// STORE RESPONSE TIMES
responseTimeArray.push(currentTime()); // store current Time in responseTimeArray</code>
<em>NOTE</em> Reaction Times are initialy stored per canvas. In the results section the average row reaction time is calculated.
</p></details>
<hr>
<p>All responses are stored in <code>sessionStorage</code> memory to allow for calling in the results section of the O-BVT.</p>
<details><summary> Code: Store Data </summary><p>
<code>javascript
// startTime stored on window load
sessionStorage.setItem("finish", currentTime()); // store finish Time
sessionStorage.setItem("stimuliRows", stimuliRows); // store amount of rows containing stimuli
sessionStorage.setItem("stimuliCols", stimuliColumns); // store amount of columns containing stimuli
sessionStorage.setObj("ARRAY_MADE_RESPONSES", responseArray); // responses made
sessionStorage.setObj("ARRAY_MADE_CORRECTIONS", correctionArray); // corrections made
sessionStorage.setObj("ARRAY_CANVAS_RESPONSE_ORDER", responseOrderArray); // order in which responses were made
sessionStorage.setObj("ARRAY_N_DOTS", dotArray); // amount of dots in each figures
sessionStorage.setObj("ARRAY_RESPONSE_TIMES", responseTimeArray); // response times per canvas</code>
</p></details>
<hr>
<p><a href="#top"><em>top</em></a></p>
<h3 id="results"> Results </h3>
<p>Experiment Leaders cannot access the results section unless the correct <a href="#password">password</a> was entered. If the Experiment Leader does so, he/she will be provided with the Participant's scores and "Attention Age". "Attention Age" is calculated based on the participant's scores compared to the relevant norm group data. An "Attention Age" for accuracy and speed are provided. In addition to being able to view the data, the Experiment Leader is provided with the option to print the results.</p>
<p>First, all responses are cleaned so that only the last time a person clicked a canvas is used to calculate absolute scores.</p>
<details><summary> Code: Clean Responses </summary><p>
<code>javascript
function lastResponses () {
// GOAL: determine which response was made to which canvas
// ... and log if canvas was not responded to (i.e. not hovered over)
for (i = 0; i < ARRAY_N_DOTS.length; i++) { // loop for all canvases
var index = ARRAY_CANVAS_RESPONSE_ORDER.lastIndexOf(i);
if (index == -1) { // canvas was not responsed to
// var noResponse = noResponse + 1;
cleanedResponseArray.push(999);
cleanedCorrectionArray.push(999);
cleanedResponseTimeArray.push(999);
} else { // canvas was responded to
cleanedResponseArray.push(ARRAY_MADE_RESPONSES[index]);
cleanedCorrectionArray.push(ARRAY_MADE_CORRECTIONS[index]);
cleanedResponseTimeArray.push(ARRAY_RESPONSE_TIMES[index]);
} // END response made IF
} // END all canvases LOOP
} // END lastResponses FUNCTION</code>
</p></details>
<hr>
<p>Then, the total amount of hits, misses, and false alarms is coded & compared to the norm group data. </p>
<details><summary> Code: Accuracy Scores </summary><p>
Total amount of Hits, Misses, and False Alarms:
<code>javascript
function finalScore (cleanedResponseArray) {
// GOAL: calculate amount of hits, misses, and false alarms
// cleanedResponseArray: array with a response per canvas
// CODING: HIT (1), Miss (2), False Alarm (3)
// SET VARIABLES
var count = 0;
// LOOP RESPONSE OPTIONS<br> for (x = 1; x < 4; x++) { // only 3 possible response options
// LOOP ALL RESPONSES MADE
for (y = 0; y < (cleanedResponseArray.length + 1); y++) {
if (cleanedResponseArray[y] == x) { // if value is response option to be evaluated, increase count
count = count + 1;
} // END IF
} // END array LOOP
// window.alert(count);<br>
if (x == 1) {
var Hits = count;
} else if (x == 2) {
var Miss = count;
} else {
var FalseAlarms = count;
} // END IF<br>
count = 0;
return [Hits, Miss, FalseAlarms];
} // END possible responses LOOP
} // END finalScore FUNCTION</code>
Compare to norm group data:
<code>javascript
// ACCURACY
// FALSE ALARMS
if (falseAlarm > 4 ) {
if (falseAlarm > 12) {
// false alarms > 12 == -1
var faAge = Number(-1);
} else {
// false alarms between 4 & 12
var faAge = 0;
} // END IF [1]
} else {
// falseAlarms < 4 == accuracyAge + 1
var faAge = 1;
} // END falseAlarm IF [0]
accuracyAgeArray.push((AGE + faAge));
// CORRECTIONS
if (corrections == 0) {
var cAge = 1;
} else if (corrections < 3) {
var cAge = 0;
} else {
// corrections > 3
var cAge = (cAge-1);
} // END corrections IF
accuracyAgeArray.push((AGE + cAge));
// MISSES
if (miss > 0) {
var mAge = Number(-1);
} else {
// miss == 0
var mAge = 0;
} // END miss IF
accuracyAgeArray.push((AGE + mAge));
// TOTAL
accuracyAgeTotal = (AGE + (faAge + cAge + mAge));</code>
</p></details>
<hr>
<p>After determining the accuracy of the participants, it is also important to code how fast they were. To do so, first we had to calculate average row response times:</p>
<details><summary> Code: Average Row RT </summary><p>
<code>javascript
function calculateResponseTimes () {
// GOAL: to calculate the response time for each row
// ... and to calculate the average response time per row
deltaResponseTimeArray = [];
var canvasDeltaTime = 0;
rowRTArray = [];
// CALCULATE DELTA TIME FOR ALL CANVASSES
for (i = 0; i < cleanedResponseTimeArray.length; i++) {
var canvasTime = cleanedResponseTimeArray[i]; // identify reaction time per canvas
if (canvasTime == 999) {
// no response was made i.e. no reaction time
canvasDeltaTime = 0;
} else {
canvasDeltaTime = ((canvasTime - STARTTIME) / 10000); // calculate delta response time between start and that canvas
} // END valid time IF
deltaResponseTimeArray.push(canvasDeltaTime);
} // END FOR LOOP
var count = 0;
var previousRT = 0;
for (x = 0; x < STIMULI_ROWS; x++) {
// reset rowReactionTime
var rowRTTotal = 0;
if (x == 0) {
// first row reaction time
// totalRT = rowTotal
previousRT = 0;
// console.log("previousRT =" + previousRT);
} else {
previousRT = rowRTArray[(x-1)];
// console.log("previousRT =" + previousRT);
}
// CALCULATE ROW RT
// loop all stimuli columns
for (c = 0; c < STIMULI_COLS; c++) {
// window.alert(deltaResponseTimeArray[count]);
// console.log(deltaResponseTimeArray[count]);
var rowRTTotal = round((rowRTTotal + deltaResponseTimeArray[count]),2);
count = count + 1;
} // END stimuli col LOOP
// console.log("rowTTtotal = " + rowRTTotal);
// store total rowRT
if ((rowRTTotal == 0) || (isNaN(rowRTTotal) == true)) {
rowRT = ("-");
} else {
rowRT = round((rowRTTotal - previousRT),2); // extract previous row time because all times are delta with STARTTIME
} // END rowRTTotal IF
rowRTArray.push(rowRT);
} // END row LOOP
} // END calculateResponseTimes FUNCTION</code>
</p></details>
<hr>
<p>Then, these row reaction times (rowRT) had to be compared to the relevant norm group data.</p>
<details><summary> Code: Norm Group Data </summary><p>
<code>javascript
// SPEED NORMS [0] - [3]
// highter than [0] == -2
// between [0] & [1] == -1
// between [1] & [2] == 0
// between [2] & [3] == +1
// smaller than [3] == +2
const NORM_GROUP_DATA = {
normGroup6: [31.5 , 24.9 , 18.4 , 16.5],
normGroup7: [27.6 , 23.5 , 18.0 , 15.6],
normGroup8: [23.2 , 19.6 , 16.4 , 13.7],
normGroup9: [20.4 , 18.0 , 14.3 , 12.5],
normGroup10: [20.6 , 16.8 , 13.7 , 12.0],
normGroup11: [17.2 , 14.9 , 12.4 , 11.1],
normGroup12: [17.1 , 14.7 , 11.9 , 10.0],
normGroup13: [16.5 , 14.2 , 11.1 , 9.1],
normGroup14: [15.3 , 12.8 , 9.9 , 8.4],
normGroup15: [14.2 , 11.6 , 9.7 , 9.2],
normGroup16: [13.6 , 11.4 , 9.0 , 8.4],
normGroup17: [13.0 , 11.1 , 9.1 , 8.2],
} // END OBJECT</code>
<em>NOTE</em> from Bourdon Vos Manual (Vos, 1998)
</p></details>
<hr>
<details><summary> Code: Speed Scores </summary><p>
Identify relevant norm group
<code>javascript
// GOAL: select the appropriate normGroup variable for calculation of scores
for (i = 6; i < 18; i++) {
if (i == AGE) { // extract correct normgroup
var referenceData = "normGroup"+ i;
} // END IF
} // END FOR ALL AGES
var referenceData = NORM_GROUP_DATA[normGroup]; // access relevant normgroup data (all data stored below)</code>
Compare rowRT to norm group data
<code>javascript
// SPEED (per row)
for (x = 0; x < STIMULI_ROWS ; x++) {
// GOAL: compare row rt with norm group data
// extract row rt
var rowRT = rowRTArray[x];
// console.log(rowRT);
if ((isNaN(rowRT) == true) || (rowRT == 0)) {
// do nothing to attentionAge
attentionAge = "-";
// console.log("rowRT = NaN");
// console.log("attentionAgeArray = " + attentionAgeArray);
} else {
// console.log("rowRT = " + rowRT);
// comapre with norm group data
if (rowRT > referenceData[3]) { // referenceData[3] = lowest RT boundary
if (rowRT > referenceData[2]) {
if (rowRT > referenceData[1]) {
if (rowRT > referenceData[0]) {
// reaction time larger than upper RT boundary
attentionAge = (attentionAge - 2);
} else {
// reaction time between [1] & [0]
// attentionAge = calender age - 1
attentionAge = (attentionAge - 1);
} // END IF [1]
} else {
// reaction time between [2] & [1]
// attentionAge = calender age
attentionAge = attentionAge;
} // END IF [1]
} else {
// reaction time between [3] & [2]
// attentionAge = +1 calender age
attentionAge = (attentionAge + 1);
} // END IF [2]
} else {
// if reaction time lower than lowest RT boundary than no if's were met
// attentionAge = -2 calander age
attentionAge = (attentionAge + 2);
} // END IF [3]
} // END rowRT == 0 IF
attentionAgeArray.push(attentionAge);
} // END rt rows LOOP</code>
</p></details>
<hr>
<p>Once all scores were calculated, output tables of all the scores were created:</p>
<details><summary> Code: Output Tables </summary><p>
Output Accuracy
<code>javascript
"<table>" +
"<tr>" +
"<th>" + "" +
"<th>" + "Absolute Amounts" +
"<th>" + "Percentages" +
"<th>" + "Calender Age" +
"<th>" + "Accuracy Age" +
"</tr>" +
"<tr>" +
"<td>" + "Hits" +
"<td>" + hits +
"<td>" + percHits + " %" +
"<td>" + AGE +
"<td>" + "-" +
"</tr>" +
"<tr>" +
"<td>" + "Misses" +