xxxxxxxxxx
292
/*
TODO:
experiment mode:
- fix canvas size
- fix image ordering system? it works but it's a mess and probably really hard for students to understand/make changes to
*/
/*
Visual search task using a 'target' from a 'scene'. The target is first shown in a random location (randomX, randomY), and after a mouse click the scene is shown and the target can be selected with the cross (can also be changed not a circle/ellipse if needed).
To use this code:
1. upload image(s)
2. write filenames in code
3. run in setup mode
4. copy all the numbers they get into array
5. take out of setup mode
*/
// change this to false to execute the experiment
const setupMode = false;
const filenames = ['vatican.jpeg', 'ajaxmadrid.jpg'];
// change this to the copied coordinates
const targetCoords = [[[181,173,34,47], [392,5,68,41], [502,246,33,57]], [[260,4,95,56], [72,176,45,112], [404,153,48,26]]]
// set this to false to show sections in the selected order
const randomOrder = true;
const imgRandomOrder = true;
// real code
//setup mode vars
let selectionCount = 0;
let imgSelectionCount = 0;
let targetSelection = [];
let res;
let setupText = 'Press enter to go to the next image. <br>Copy the following into the code: <br>';
let targetsText = "[]";
//experiment vars
let images = [];
let clicks=0;
var randomX,randomY;
var reactionTime = 0;
var startTime = 0;
var targets =[];
let presentationOrder = [], imgPresentationOrder = [];
let trial = 0, imgtrial = 0;
function preload(){
for(i=0;i<filenames.length;i++){
images[i] = loadImage('images/' + filenames[i]);
imgPresentationOrder.push(i);
// for setup mode
targetSelection.push([]);
}
}
function setup() {
//use the image size for the canvas, SO MIND THAT YOU USE A SMALL ENOUGH IMAGE!
cnv = createCanvas(images[0].width, images[0].height);
if(setupMode){
res = select('#setuptext');
res.html(setupText);
cnv.mousePressed(startSelect);
cnv.mouseReleased(endSelect);
cnv.parent("sketch");
document.getElementById('sketch').setAttribute("style","height:" + images[0].height + "px");
}
else{
cnv.mouseClicked(clickOnCanvas);
//first random location for the target
randomX=random(100,width-100);
randomY=random(100,height-100);
for(j=0;j<targetCoords.length;j++){
image(images[j],0,0);
presentationOrder.push([]);
targets.push([]);
for(i=0;i<targetCoords[j].length;i++){
targets[j].push(get(targetCoords[j][i][0], targetCoords[j][i][1], targetCoords[j][i][2], targetCoords[j][i][3]));
presentationOrder[j][i] = i;
}
}
print(targets);
if(randomOrder){
for(i=0;i<presentationOrder.length;i++){
shuffle(presentationOrder[i], true);
}
}
if(imgRandomOrder){shuffle(imgPresentationOrder, true);}
data = new p5.Table();
data.columns = ['image', 'target','reaction time (ms)','hit/distance','x','y'];
}
}
function draw() {
//this code is to draw the rectangles
if(setupMode){
background(0);
image(images[imgSelectionCount],0,0);
strokeWeight(1);
textSize(16);
for(i=0;i<targetSelection[imgSelectionCount].length;i++){
let xs,ys,ws,hs;
if(i == selectionCount){
rectfill = color(0, 200, 200);
rectfill.setAlpha(100);
fill(rectfill);
stroke(0,255,255);
if(mouseX>targetSelection[imgSelectionCount][i][0]){
xs = targetSelection[imgSelectionCount][i][0];
ws = mouseX - xs;
}else{
xs = mouseX;
ws = targetSelection[imgSelectionCount][i][0] - xs;
}
if(mouseY>targetSelection[imgSelectionCount][i][1]){
ys = targetSelection[imgSelectionCount][i][1];
hs = mouseY - ys;
}else{
ys = mouseY;
hs = targetSelection[imgSelectionCount][i][1] - ys;
}
}
else{
rectfill = color(255, 0, 255);
rectfill.setAlpha(100);
fill(rectfill);
stroke(255,0,255);
xs = targetSelection[imgSelectionCount][i][0];
ys = targetSelection[imgSelectionCount][i][1];
ws = targetSelection[imgSelectionCount][i][2];
hs = targetSelection[imgSelectionCount][i][3];
text(i+1,xs,ys);
}
rect(xs,ys,ws,hs);
}
}
//this is the regular experiment
else{
background(220);
//search scene & arrow are shown anyway but...
image(images[imgPresentationOrder[imgtrial]],0,0);
//... with no mouseclicks, a white background occludes the scene and target is shown...
if(clicks==0){
showTarget(trial);
}
}
}
//called when mouse is pressed in setup mode
function startSelect(){
targetSelection[imgSelectionCount].push([mouseX,mouseY]);
}
//called when mouse is released in setup mode
function endSelect(){
//sort numbers so they're in "x,y,w,h" format
let xs, ys, ws, hs;
if(mouseX>targetSelection[imgSelectionCount][selectionCount][0]){
xs = targetSelection[imgSelectionCount][selectionCount][0];
ws = mouseX - xs;
}else{
xs = mouseX;
ws = targetSelection[imgSelectionCount][selectionCount][0] - xs;
}
if(mouseY>targetSelection[imgSelectionCount][selectionCount][1]){
ys = targetSelection[imgSelectionCount][selectionCount][1];
hs = mouseY - ys;
}else{
ys = mouseY;
hs = targetSelection[imgSelectionCount][selectionCount][1] - ys;
}
targetSelection[imgSelectionCount][selectionCount] = [int(xs), int(ys), int(ws), int(hs)];
//translates targetSelection to a string (targetsText)
targetsText = '[';
for(i=0;i<targetSelection.length;i++){
for(j=0;j<targetSelection[i].length;j++){
if(j==0){
targetsText += '[[' + targetSelection[i][j] + ']';
}
else{
targetsText += ', [' + targetSelection[i][j] + ']';
}
}
if(i<targetSelection.length - 1){
targetsText += '], ';
} else{
targetsText += ']]';
}
}
res.html(setupText + targetsText);
selectionCount++;
}
// Here we keep track of reaction time and how many times has been clicked:
function clickOnCanvas() {
print('clicks: ' + clicks + ', trial: ' + trial + ', imgtrial: ' + imgtrial);
if(clicks==0){
startTime=millis();
clicks++;
randomX=random(100,width-100);
randomY=random(100,height-100);
}
else if(clicks==1){
// check accuracy
let imgnum = imgPresentationOrder[imgtrial];
let target = targetCoords[imgnum][presentationOrder[imgnum][trial]];
let d;
if(mouseX>=target[0] && mouseX<=target[0] + target[2] && mouseY>=target[1] && mouseY<=target[1] + target[3]){
d = 0;
} else{
var dx = Math.max(target[0] - mouseX, 0, mouseX - (target[0] + target[2]));
var dy = Math.max(target[1] - mouseY, 0, mouseY - (target[1] + target[3]));
d = sqrt(dx*dx + dy*dy)
}
// write results to the table
let newRow = data.addRow();
newRow.setString('image', filenames[imgnum]);
newRow.setNum('target', presentationOrder[imgnum][trial]);
newRow.setNum('reaction time (ms)', millis()-startTime);
newRow.setNum('hit/distance', int(d));
newRow.setNum('x', int(mouseX));
newRow.setNum('y', int(mouseY));
if(trial + 1 == targetCoords[imgnum].length){
if(imgtrial + 1 == targetCoords.length){
// OUTPUT HERE
saveTable(data, 'new.csv');
clicks = 2;
} else{
imgtrial++;
trial = 0;
clicks = 0;
}
}else{
trial++;
clicks = 0;
}
}
}
function keyPressed(){
if(keyCode==ENTER && imgSelectionCount < filenames.length-1){
imgSelectionCount++;
selectionCount = 0;
}
}
function showTarget(i){
background(255);
noStroke();
textSize(16);
text('Try to find the target a.s.a.p.',30,40);
text('Click to start the task',30,60);
image(targets[imgPresentationOrder[imgtrial]][presentationOrder[imgPresentationOrder[imgtrial]][trial]],randomX,randomY);
}