/* * plugin for jsPsych based in Qisheng Li 11/2019. /// https://github.com/QishengLi/virtual_chinrest Modified by Gustavo Juantorena 08/2020 // https://github.com/GEJ1 Contributions from Peter J. Kohler: https://github.com/pjkohler */ jsPsych.plugins['virtual-chinrest'] = (function() { var plugin = {}; plugin.info = { name: "virtual-chinrest", parameters: { viewing_distance_cm: { type: jsPsych.plugins.parameterType.INT, default: 0 }, cardWidth_px: { type: jsPsych.plugins.parameterType.INT, default: 0 }, pixels_per_unit: { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Pixels per unit', default: 100, description: 'After the scaling factor is applied, this many pixels will equal one unit of measurement.' }, blindspot_reps: { type: jsPsych.plugins.parameterType.INT, pretty_name: 'Blindspot measurement repetitions', default: 5, description: 'How many times to measure the blindspot location' }, prompt_card: { type: jsPsych.plugins.parameterType.STRING, default: ' Let’s find out how big your monitor is! '+ '

Please use any credit card that you have available.
' + 'It can also be a grocery store membership card,
'+ 'your drivers license or anything else of the same format.
'+ 'Place your card flat onto the screen, and adjust the slider below to match its size.

'+ '

If you do not have access to a real card
'+ 'you can use a ruler to measure the image width to 3.37 inches or 85.6 mm.
' }, prompt_blindspot: { type: jsPsych.plugins.parameterType.STRING, default: 'Now, let’s quickly test how far away you are sitting.'+ '

You might know that vision tests at a doctor’s practice often involve chinrests.
'+ 'The doctor basically asks you to sit away from a screen in a specific distance.
'+ 'We do this here with a “virtual chinrest”.


'+ 'Instructions'+ '
'+ '
  1. Put your finger on space bar on the keyboard.
  2. '+ '
  3. Close your right eye. (Tips: it might be easier to cover your right eye by hand!)
  4. '+ '
  5. Using your left eye, focus on the black square.
  6. '+ '
  7. Click the button below to start the animation of the red ball. The red ball '+ 'will disappear as it moves from right to left. Press the “Space” key as soon as the ball disappears from your eye sight.
  8. '+ '

' }, card_path: { type: jsPsych.plugins.parameterType.STRING, default: "img/card.png" } } } // Get screen size var w = window.innerWidth; var h = window.innerHeight; const screen_size_px = [] screen_size_px.push(w) screen_size_px.push('x') screen_size_px.push(h) let trial_data = { "card_width_mm": 85.60, //card dimension: 85.60 × 53.98 mm (3.370 × 2.125 in) }; let config_data = { "ball_pos": [], "slider_clck": false } plugin.trial = function(display_element, trial) { const start_time = performance.now(); console.log(trial) pagesize_content = '


'+ trial.prompt_card + '
'+ '

'+ ''+ '

'+ '
'+ '
' blindspot_content = '' display_element.innerHTML = '
'+ pagesize_content + blindspot_content + '
' /*// create html for display var html = "






"; // html += "

Let’s find out what your monitor size is (click to go into
full screen mode
).

"; html += "

Please use any credit card that you have available (it can also be a grocery store membership card, your drivers license, or anything that is of the same format), hold it onto the screen, and adjust the slider below to its size.

"; html += "

(If you don't have access to a real card, you can use a ruler to measure image width to 3.37inch or 85.6mm, or make your best guess!)

"; html += "Make sure you put the card onto your screen."; html += '
'; html += "
"; html += '


'; html +='
'; html += '"; // render display_element.innerHTML = html; */ //Event listeners for buttons display_element.querySelector('#blind_spot').addEventListener('click', function(){ configureBlindSpot() }) display_element.querySelector('#start_ball').addEventListener('click', function(){ animateBall() }) display_element.querySelector('#proceed').addEventListener('click', function(){ // finish trial display_element.innerHTML = ''; trial_data.card_width_deg = 2*(Math.atan((trial_data["card_width_mm"]/2)/trial_data["view_dist_mm"])) * 180/Math.PI trial_data.px2deg = trial_data["card_width_px"] / trial_data.card_width_deg // size of card in pixels divided by size of card in degrees of visual angle trial_data.rt = performance.now() - start_time; trial_data.scr_width_deg = window.innerWidth/trial_data.px2deg trial_data.scr_height_deg = window.innerHeight/trial_data.px2deg jsPsych.finishTrial(trial_data); }) /* jsPsych.pluginAPI.getKeyboardResponse({ callback_function: after_response, // we need to create after_response valid_responses: [trial.key], // valid_responses expects an array rt_method: 'performance', // This is only relevant for RT in audio stimuli persist: false, // true if you want to listen to more than one key allow_held_key: true // false for a new key pressing in order to get a new response }); */ } function after_response(response_info){ // rt.push(response_info.rt); // response time of the key end_trial(); } function end_trial(){ jsPsych.finishTrial(trial_data); // ends trial and save the data // display_element.innerHTML = ' '; // clear the display jsPsych.pluginAPI.cancelAllKeyboardResponses(); } (function ( distanceSetup, $ ) { // jQuery short-hand for $(document).ready(function() { ... }); distanceSetup.round = function(value, decimals) { return Number(Math.round(value+'e'+decimals)+'e-'+decimals); }; distanceSetup.px2mm = function(cardImageWidth) { const cardWidth = 85.6; //card dimension: 85.60 × 53.98 mm (3.370 × 2.125 in) var px2mm = cardImageWidth/cardWidth; trial_data["px2mm"] = distanceSetup.round(px2mm, 2); return px2mm; }; }( window.distanceSetup = window.distanceSetup || {}, jQuery)) function getCardWidth() { var card_width_px = $('#card').width(); trial_data["card_width_px"] = distanceSetup.round(card_width_px,2); return card_width_px } function configureBlindSpot() { drawBall(); $('#page-size').remove(); $('#blind-spot').css({'visibility':'visible'}); // $(document).on('keydown', recordPosition); $(document).on('keydown', recordPosition); } $( function() { $( "#slider" ).slider({value:"50"}); } ); $(document).ready(function() { $( "#slider" ).on("slide", function (event, ui) { var cardWidth = ui.value + "%"; $("#card").css({"width":cardWidth}); }); $('#slider').on('slidechange', function(event, ui){ config_data["slider_clck"] = true; }); }); //============================= //Ball Animation function drawBall(pos=180){ // pos: define where the fixation square should be. var mySVG = SVG("svgDiv"); const cardWidthPx = getCardWidth() const rectX = distanceSetup.px2mm(cardWidthPx)*pos; const ballX = rectX*0.6 // define where the ball is var ball = mySVG.circle(30).move(ballX, 50).fill("#f00"); window.ball = ball; var square = mySVG.rect(30, 30).move(Math.min(rectX - 50, 950), 50); //square position config_data["square_pos"] = distanceSetup.round(square.cx(),2); config_data['rectX'] = rectX config_data['ballX'] = ballX }; function animateBall(){ ball.animate(7000).during( function(pos){ moveX = - pos*config_data['ballX']; window.moveX = moveX; moveY = 0; ball.attr({transform:"translate("+moveX+","+moveY+")"}); } ).loop(true, false). after(function(){ animateBall(); }); //disable the button after clicked once. $("#start_ball").attr("disabled", true); $('#start_ball').css("display", "none"); }; function recordPosition(event, angle=13.5) { // angle: define horizontal blind spot entry point position in degrees. if (event.keyCode == '32') { //Press "Space" config_data["ball_pos"].push(distanceSetup.round((ball.cx() + moveX),2)); var sum = config_data["ball_pos"].reduce((a, b) => a + b, 0); var ballPosLen = config_data["ball_pos"].length; config_data["avg_ball_pos"] = distanceSetup.round(sum/ballPosLen, 2); var ball_sqr_distance = (config_data["square_pos"]-config_data["avg_ball_pos"])/trial_data["px2mm"]; var viewDistance = ball_sqr_distance/Math.radians(angle) trial_data["view_dist_mm"] = distanceSetup.round(viewDistance, 2); //counter and stop var counter = Number($('#click').text()); counter = counter - 1; $('#click').text(Math.max(counter, 0)); if (counter <= 0) { ball.stop(); // Disable space key $('html').bind('keydown', function(e) { if (e.keyCode == 32) {return false;} }); // Display data $('#info').css("visibility", "visible"); $('#info-h').append(trial_data["view_dist_mm"]/10) $('#proceed').css("display", "inline"); return trial_data.viewing_distance_cm; } ball.stop(); animateBall(); } } //helper function for radians // Converts from degrees to radians. Math.radians = function(degrees) { return degrees * Math.PI / 180; }; return plugin; })();