/**
* jspsych-webgazer-calibrate
* Josh de Leeuw
**/
jsPsych.plugins["webgazer-calibrate"] = (function() {
var plugin = {};
plugin.info = {
name: 'webgazer-calibrate',
description: '',
parameters: {
calibration_points: {
type: jsPsych.plugins.parameterType.INT,
default: [[10,10], [10,50], [10,90], [50,10], [50,50], [50,90], [90,10], [90,50], [90,90]]
},
repetitions_per_point: {
type: jsPsych.plugins.parameterType.INT,
default: 1
},
randomize_calibration_order: {
type: jsPsych.plugins.parameterType.BOOL,
default: false
},
time_to_saccade: {
type: jsPsych.plugins.parameterType.INT,
default: 1000
},
time_per_point: {
type: jsPsych.plugins.parameterType.STRING,
default: 2000
}
}
}
// provide options for calibration routines?
// dot clicks?
// track a dot with mouse?
// then a validation phase of staring at the dot in different locations?
plugin.trial = function(display_element, trial) {
var html = `
`
display_element.innerHTML = html;
jsPsych.extensions['webgazer'].showVideo();
jsPsych.extensions['webgazer'].resume();
//jsPsych.extensions['webgazer'].resume();
var wg_container = display_element.querySelector('#webgazer-calibrate-container');
show_video_detect_message();
function show_video_detect_message(){
wg_container.innerHTML = ""+
"
To start, you need to position your head so that the webcam has a good view of your eyes.
"+
"
Use the video in the upper-left corner as a guide. Center your face in the box.
"+
"
When your face is centered in the box and the box turns green, you can click to continue.
"+
"
"
// "
Quality of detection:
"+
// "
"+
"
"
var observer = new MutationObserver(face_detect_event_observer);
observer.observe(document, {
attributes: true,
attributeFilter: ['style'],
subtree: true
});
document.querySelector('#jspsych-wg-cont').addEventListener('click', function(){
observer.disconnect();
show_begin_calibrate_message();
})
// function waitForFace(){
// var score = check_face_score();
// //wg_container.querySelector('#video-detect-quality-inner').style.width = (score*100) + "%"
// if(score){
// document.querySelector('#jspsych-wg-cont').disabled = false;
// } else {
// requestAnimationFrame(waitForFace);
// }
// }
// requestAnimationFrame(waitForFace);
}
function face_detect_event_observer(mutationsList, observer){
if(mutationsList[0].target == document.querySelector('#webgazerFaceFeedbackBox')){
if(mutationsList[0].type == 'attributes' && mutationsList[0].target.style.borderColor == "green"){
document.querySelector('#jspsych-wg-cont').disabled = false;
}
if(mutationsList[0].type == 'attributes' && mutationsList[0].target.style.borderColor == "red"){
document.querySelector('#jspsych-wg-cont').disabled = true;
}
}
}
function show_begin_calibrate_message(){
jsPsych.extensions['webgazer'].hideVideo();
wg_container.innerHTML = ""+
"
Great! Now the eye tracker will be calibrated to translate the image of your eyes from the webcam to a location on your screen.
"+
"
To do this, you need to look at a series of dots.
"+
"
Keep your head still, and focus on each dot as quickly as possible. Keep your gaze fixed on the dot for as long as it is on the screen.
"+
"
"+
"
"
document.querySelector('#begin-calibrate-btn').addEventListener('click', function(){
calibrate();
});
}
var reps_completed = 0;
var points_completed = -1;
var cal_points = null;
function calibrate(){
jsPsych.extensions['webgazer'].resume();
next_calibration_round();
}
function next_calibration_round(){
if(trial.randomize_calibration_order){
cal_points = jsPsych.randomization.shuffle(trial.calibration_points);
} else {
cal_points = trial.calibration_points;
}
points_completed = -1;
next_calibration_point();
}
function next_calibration_point(){
points_completed++;
if(points_completed == cal_points.length){
reps_completed++;
if(reps_completed == trial.repetitions_per_point){
calibration_done();
} else {
next_calibration_round();
}
} else {
var pt = cal_points[points_completed];
calibration_display_gaze_only(pt);
}
}
function calibration_display_gaze_only(pt){
var pt_html = ''
wg_container.innerHTML = pt_html;
var pt_dom = wg_container.querySelector('#calibration-point');
var br = pt_dom.getBoundingClientRect();
var x = br.left + br.width / 2;
var y = br.top + br.height / 2;
var pt_start_cal = performance.now() + trial.time_to_saccade;
var pt_finish = performance.now() + trial.time_to_saccade + trial.time_per_point;
requestAnimationFrame(function watch_dot(){
if(performance.now() > pt_start_cal){
jsPsych.extensions['webgazer'].calibratePoint(x,y,'click');
}
if(performance.now() < pt_finish){
requestAnimationFrame(watch_dot);
} else {
next_calibration_point();
}
})
// jsPsych.pluginAPI.setTimeout(function(){
// pt_dom.style.backgroundColor = "#fff";
// pt_dom.addEventListener('click', function(){
// next_calibration_point();
// });
// }, Math.random()*(trial.maximum_dot_change_delay-trial.minimum_dot_change_delay)+trial.minimum_dot_change_delay);
}
function calibration_done(){
wg_container.innerHTML = "";
end_trial();
}
// function to end trial when it is time
function end_trial() {
jsPsych.extensions['webgazer'].pause();
jsPsych.extensions['webgazer'].hidePredictions();
jsPsych.extensions['webgazer'].hideVideo();
// kill any remaining setTimeout handlers
jsPsych.pluginAPI.clearAllTimeouts();
// gather the data to store for the trial
var trial_data = {
};
// clear the display
display_element.innerHTML = '';
// move on to the next trial
jsPsych.finishTrial(trial_data);
};
};
return plugin;
})();