jsPsych/plugins/jspsych-visual-search-circle.js
mariansauter d30dac1dbe allow timing_max_search = 0
I added the possibility that the timing_max_search equals 0 so that the search display is not shown at all (circumventing setTimeout)

This might be very specifically handy for my purpose, because I can use the same plugin to show my probe at the fixation stimulus place before the actual search display. In any case, this change does not hurt and just allows timing_max_search = 0 to work
2015-02-11 23:28:29 +01:00

218 lines
7.3 KiB
JavaScript

/**
*
* jspsych-visual-search-circle
* Josh de Leeuw
*
* display a set of objects, with or without a target, equidistant from fixation
* subject responds to whether or not the target is present
*
* based on code written for psychtoolbox by Ben Motz
*
* requires Snap.svg library (snapsvg.io)
*
* documentation: docs.jspsych.org
*
**/
(function($) {
jsPsych["visual-search-circle"] = (function() {
var plugin = {};
plugin.create = function(params) {
var trials = new Array(params.target_present.length);
for (var i = 0; i < trials.length; i++) {
trials[i] = {};
trials[i].target_present = params.target_present[i];
trials[i].set_size = params.set_size[i];
trials[i].target = params.target;
trials[i].foil = params.foil;
trials[i].fixation_image = params.fixation_image;
trials[i].target_size = params.target_size || [50, 50];
trials[i].fixation_size = params.fixation_size || [16, 16];
trials[i].circle_diameter = params.circle_diameter || 250;
trials[i].target_present_key = params.target_present_key || 74;
trials[i].target_absent_key = params.target_absent_key || 70;
trials[i].timing_max_search = (typeof params.timing_max_search === 'undefined') ? -1 : params.timing_max_search;
trials[i].timing_fixation = (typeof params.timing_fixation === 'undefined') ? 1000 : params.timing_fixation;
}
return trials;
};
plugin.trial = function(display_element, trial) {
trial = jsPsych.pluginAPI.normalizeTrialVariables(trial);
// screen information
var screenw = display_element.width();
var screenh = display_element.height();
var centerx = screenw / 2;
var centery = screenh / 2;
// circle params
var diam = trial.circle_diameter; // pixels
var radi = diam / 2;
var paper_size = diam + trial.target_size[0];
// stimuli width, height
var stimh = trial.target_size[0];
var stimw = trial.target_size[1];
var hstimh = stimh / 2;
var hstimw = stimw / 2;
// fixation location
var fix_loc = [Math.floor(paper_size / 2 - trial.fixation_size[0] / 2), Math.floor(paper_size / 2 - trial.fixation_size[1] / 2)];
// possible stimulus locations on the circle
var display_locs = [];
var possible_display_locs = trial.set_size;
var random_offset = Math.floor(Math.random()*360);
for(var i = 0; i < possible_display_locs; i++){
display_locs.push([
Math.floor(paper_size / 2 + (cosd(random_offset + (i * (360/possible_display_locs))) * radi) - hstimw),
Math.floor(paper_size / 2 - (sind(random_offset + (i * (360/possible_display_locs))) * radi) - hstimh)
]);
}
// get target to draw on
display_element.appent($('<svg id="jspsych-visual-search-circle-svg" width='+paper_size+' height='+paper_size+'></svg>'))
var paper = Snap('#jspsych-visual-search-circle-svg');
show_fixation();
function show_fixation() {
// show fixation
var fixation = paper.image(trial.fixation_image, fix_loc[0], fix_loc[1], trial.fixation_size[0], trial.fixation_size[1]);
// wait
setTimeout(function() {
// after wait is over
show_search_array();
}, trial.timing_fixation);
}
function show_search_array() {
var search_array_images = [];
for (var i = 0; i < display_locs.length; i++) {
var which_image = (i == 0 && trial.target_present) ? trial.target : trial.foil;
var img = paper.image(which_image, display_locs[i][0], display_locs[i][1], trial.target_size[0], trial.target_size[1]);
search_array_images.push(img);
}
var trial_over = false;
var after_response = function(info){
trial_over = true;
var correct = 0;
if (info.key == trial.target_present_key && trial.target_present ||
info.key == trial.target_absent_key && !trial.target_present) {
correct = 1;
}
clear_display();
end_trial(info.rt, correct, info.key);
}
var valid_keys = [trial.target_present_key, trial.target_absent_key];
key_listener = jsPsych.pluginAPI.getKeyboardResponse(after_response, valid_keys, 'date',false);
+ if (trial.timing_max_search > -1) {
if(trial.timing_max_search == 0){
if (!trial_over) {
jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);
trial_over = true;
var rt = -1;
var correct = 0;
var key_press = -1;
clear_display();
end_trial(rt, correct, key_press);
}
}
setTimeout(function() {
if (!trial_over) {
jsPsych.pluginAPI.cancelKeyboardResponse(key_listener);
trial_over = true;
var rt = -1;
var correct = 0;
var key_press = -1;
clear_display();
end_trial(rt, correct, key_press);
}
}, trial.timing_max_search);
}
function clear_display() {
paper.clear();
}
}
function end_trial(rt, correct, key_press) {
// data saving
var trial_data = {
correct: correct,
rt: rt,
key_press: key_press,
locations: JSON.stringify(display_locs),
target_present: trial.target_present,
set_size: trial.set_size
};
// this line merges together the trial_data object and the generic
// data object (trial.data), and then stores them.
jsPsych.data.write($.extend({}, trial_data, trial.data));
// go to next trial
if(trial.timing_post_trial > 0){
setTimeout(function() {
jsPsych.finishTrial();
}, trial.timing_post_trial);
} else {
jsPsych.finishTrial();
}
}
};
// helper function for determining stimulus locations
function cosd(num) {
return Math.cos(num / 180 * Math.PI);
}
function sind(num) {
return Math.sin(num / 180 * Math.PI);
}
return plugin;
})();
})(jQuery);