psychopy.org | Reference | Downloads | Github

Run a Javascript on Psychopy

Hi there…I found this JS in Pavlovia and I was wondering if it possible to run it on psychopy, I’ve tried to copy and paste the code on the code section of the builder but I know very little about coding so I probably made some mistakes. Does any of you know if it’s something possible to do?

This is the code I’m tring to run on psychopy:

/**
 * Created by Qisheng Li in 11/2019.
 */

//Store all the configuration data in variable 'data'
var data = {"dataType":"configurationData"};
data["ballPosition"] = [];
data["fullScreenClicked"] = false;
data["sliderClicked"] = false;

(function ( distanceSetup, $ ) {

    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;
        data["px2mm"] = distanceSetup.round(px2mm, 2);
        return px2mm; 
    };

}( window.distanceSetup = window.distanceSetup || {}, jQuery));


function getCardWidth() {
    var cardWidthPx = $('#card').width();
    data["cardWidthPx"] = distanceSetup.round(cardWidthPx,2);
    return cardWidthPx
}


function configureBlindSpot() {

    drawBall();
    $('#page-size').remove();
    $('#blind-spot').css({'visibility':'visible'});
    $(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){
        data["sliderClicked"] = 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
    data["squarePosition"] = distanceSetup.round(square.cx(),2);
    data['rectX'] = rectX
    data['ballX'] = ballX
};


function animateBall(){
    ball.animate(7000).during(
        function(pos){
            moveX = - pos*data['ballX'];
            window.moveX = moveX;
            moveY = 0;
            ball.attr({transform:"translate("+moveX+","+moveY+")"});

        }
    ).loop(true, false).
    after(function(){
        animateBall();
    });

    //disbale the button after clicked once.
    $("#start").attr("disabled", true);
};

function recordPosition(event, angle=13.5) {
    // angle: define horizontal blind spot entry point position in degrees.
    if (event.keyCode == '32') { //Press "Space"

        data["ballPosition"].push(distanceSetup.round((ball.cx() + moveX),2));
        var sum = data["ballPosition"].reduce((a, b) => a + b, 0);
        var ballPosLen = data["ballPosition"].length;
        data["avgBallPos"] = distanceSetup.round(sum/ballPosLen, 2);
        var ball_sqr_distance = (data["squarePosition"]-data["avgBallPos"])/data["px2mm"];
        var viewDistance = ball_sqr_distance/Math.radians(angle)
        console.log(Math.radians(angle))
        data["viewDistance_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;}
            });   

            // You can then DO SOMETHING HERE TO PROCEED TO YOUR NEXT STEPS OF THE EXPERIMENT. For example, add a button to go to the next page.        
            return;
        }

        ball.stop();
        animateBall();
    }
}

//===================
//Helper Functions
function fullScreen(){
    doc = document.documentElement;
    if(doc.requestFullScreen) {
        doc.requestFullScreen();
    } else if(doc.mozRequestFullScreen) {
        doc.mozRequestFullScreen();
    } else if(doc.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT)) {
        doc.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
    }
};

function registerClick(){
    data["fullScreenClicked"] = true;
}

// Converts from degrees to radians.
Math.radians = function(degrees) {
  return degrees * Math.PI / 180;
};


Do you intend to run this code locally?

Psychopy runs python code only. You’ll need to translate this to python if you want it to work on psychopy. Or alternatively, you can paste it as a JS code component in your psychopy builder and run it on pavlovia.

1 Like

Thank you for answering, I really appreciate your help!
I intend to run it online, but if I try to copy and paste the code as JS coponent it doesn’t work on pavlovia. Is it possible that I pasted it in the wrong section? The code component in the builder has different section (I need this at the beginning of the experiment so I pasted the whole code in “begin the experiment”)?

So, the code snippet you shared above is only a bunch of function definitions. If you are familiar with programming of any kind, you’ll recall that function definitions are not run until they are called. For example, you may have a dog in your backyard, the dog will stay in her shed until you call her, right? You won’t really have any use of the dog until you call her and start playing with her.

So you need to call these functions or in other words you’ll need to use them. These are only definitions and won’t be executed until you call them.

So, if there is an example of how this code is run, you should take a look at how it has been used before and call the functions in its intended order and structure. This would be either under the “begin routine” tab or “each frame” tab or even both.

Depends on how this code was intended to be used by the author.

2 Likes

Ok perfect, I’m not very familiar with coding but I’ll try some cobination hoping that some of them will work :sweat_smile: Thanks again for your help! :slightly_smiling_face:

Hi @Giorgio_Li_Pira ,

The code is from this repository: GitHub - QishengLi/virtual_chinrest: JavaScript plug-in, data, and analysis code for Scientific Reports submission: Controlling for Participants’ Viewing Distance in Large-Scale, Psychophysical Online Experiments Using a Virtual Chinrest

It’s writed in javascript and using jquery ( a general purpose liibrary, not related with psych experiments).

I hope this help you if you want to implement it.

Best,

Gustavo.