xxxxxxxxxx
326
/*
question:
do we want them to look for multiple differences per image?
i think not.
instructions:
0. Photoshop your image(s) to create small differences.
1. Upload all your (edited and unedited) images to the images folder.
2. Write the filenames for the unedited images in "prenames" and for the edited ones in "postnames"
3. Change setupmode to true.
4. Run the sketch, marking the areas where you made a change.
5. Copy the coordinates into the code.
6. Change setupmode back to false
*/
// !! Change this to you own project's name in order to save your experiments data.
// The data can be found on the google drive
const SAVE_DATA_SHEET_NAME = "change_blindness_test";
const setupmode = false;
const prenames = ['0_pre.png', '1_pre.png', '2_pre.png', '3_pre.png', '4_pre.png', '5_pre.png'];
const postnames = ['0_post.png', '1_post.png', '2_post.png', '3_post.png', '4_post.png', '5_post.png'];
const targetCoords = [[196,70,48,44], [278,372,93,86], [192,179,41,34], [400,57,74,53], [294,407,61,59], [178,318,67,27]]
const randomOrder = true;
//setup mode variables
let selecting = false;
let selectionCount = 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 variables
var experiment = false;
var stimuli = [];
let presentationOrder = [];
var trial = 0
let randomtrial;
var max_height = 0;
var max_width = 0;
var image_offset = 50;
var stimulus;
let startTime;
function preload() {
// create a table to store results
data = new p5.Table();
data.columns = ['target','reaction time (ms)','hit/distance','x','y']
for (let i = 0; i < prenames.length; i++) {
stimuli.push([
loadImage('images/' + prenames[i]),
loadImage('images/' + postnames[i])
]);
presentationOrder[i] = i;
}
if(randomOrder){presentationOrder=shuffle(presentationOrder);}
}
function setup() {
// determine which image has the biggest width/height
for (let i = 0; i < stimuli.length; i++) {
pair = stimuli[i];
if (max(pair[0].width, pair[1].width) > max_width) {
max_width = max(pair[0].width, pair[1].width)
}
if (max(pair[0].height, pair[1].height) > max_height) {
max_height = max(pair[0].height, pair[1].height)
}
}
// create canvas equal to the largest image, plus a little extra space for text
cnv = createCanvas(max_width, max_height + image_offset);
if(setupmode){
res = select('#setuptext');
res.html(setupText);
cnv.mousePressed(startSelect);
cnv.mouseReleased(endSelect);
cnv.parent("sketch");
document.getElementById('sketch').setAttribute("style","height:" + cnv.height + "px");
}
else{
cnv.mouseClicked(clickOnCanvas);
background(128);
textSize(16);
text('Try to spot the difference',30,40);
text('Click to start the task',30,60);
frameRate(10);
}
}
function draw() {
//this code is to draw the rectangles
if(setupmode){
background(128);
// Show the difference between the two images
image(stimuli[selectionCount][0],0, 50);
blendMode(DIFFERENCE);
image(stimuli[selectionCount][1],0, 50);
filter(THRESHOLD,0.1);
blendMode(NORMAL);
strokeWeight(1);
if(selecting){
let xs,ys,ws,hs;
rectfill = color(0, 200, 200);
rectfill.setAlpha(100);
fill(rectfill);
stroke(0,255,255);
if(mouseX>targetSelection[selectionCount][0]){
xs = targetSelection[selectionCount][0];
ws = mouseX - xs;
}else{
xs = mouseX;
ws = targetSelection[selectionCount][0] - xs;
}
if(mouseY>targetSelection[selectionCount][1]){
ys = targetSelection[selectionCount][1];
hs = mouseY - ys;
}else{
ys = mouseY;
hs = targetSelection[selectionCount][1] - ys;
}
rect(xs,ys,ws,hs);
}
}
if (experiment) {
text("Click where you see the change. Trial: " + trial+1, 20, 20)
randomtrial=presentationOrder[trial];
stimulus = stimuli[randomtrial];
if (frameCount < 5) { // we show the first image at frame 1,2,3,4
image(stimulus[0], 0, 50);
} else if (frameCount > 5 & frameCount < 10) { // second image @ 6,7,8,9
image(stimulus[1], 0, 50);
} else { // we show the background at frame 5 and 10
background(128);
}
if (frameCount == 10) {
frameCount = 0;
}
}
}
function clickOnCanvas() {
if (experiment) {
// check accuracy
let randomtrial=presentationOrder[trial]; //i really dont like this
let d;
if(mouseX>=targetCoords[randomtrial][0] && mouseX<=targetCoords[randomtrial][0] + targetCoords[randomtrial][2] && mouseY>=targetCoords[randomtrial][1] && mouseY<=targetCoords[randomtrial][1] + targetCoords[randomtrial][3]){
d = 0;
} else{
var dx = Math.max(targetCoords[randomtrial][0] - mouseX, 0, mouseX - (targetCoords[randomtrial][0] + targetCoords[randomtrial][2]));
var dy = Math.max(targetCoords[randomtrial][1] - mouseY, 0, mouseY - (targetCoords[randomtrial][1] + targetCoords[randomtrial][3]));
d = sqrt(dx*dx + dy*dy)
}
//write result to table
let newRow = data.addRow();
newRow.setNum('target', presentationOrder[trial]);
newRow.setNum('reaction time (ms)', millis()-startTime);
newRow.setNum('hit/distance', int(d));
newRow.setNum('x', int(mouseX));
newRow.setNum('y', int(mouseY));
nextTrial();
}
else { // first time, after that ignore
frameCount = 0;
experiment = true
console.log("experiment start")
background(128);
startTime=millis();
}
}
//called when mouse is pressed in setup mode
function startSelect(){
targetSelection.push([mouseX,mouseY]);
selecting = true;
}
//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[selectionCount][0]){
xs = targetSelection[selectionCount][0];
ws = mouseX - xs;
}else{
xs = mouseX;
ws = targetSelection[selectionCount][0] - xs;
}
if(mouseY>targetSelection[selectionCount][1]){
ys = targetSelection[selectionCount][1];
hs = mouseY - ys;
}else{
ys = mouseY;
hs = targetSelection[selectionCount][1] - ys;
}
targetSelection[selectionCount] = [int(xs), int(ys), int(ws), int(hs)];
for(i=0;i<targetSelection.length;i++){
if(i==0){
targetsText = '[[' + targetSelection[i] + ']';
}
else{
targetsText += ', [' + targetSelection[i] + ']';
}
}
targetsText += "]";
res.html(setupText + targetsText);
selecting = false;
selectionCount++;
print(targetSelection);
}
function nextTrial() {
// start the next trial
trial++;
frameCount = 0;
background(128);
if (trial == stimuli.length) {
experiment = false // experiment has ended
console.log("experiment end");
text("That's the end of the experiment!", 20, 20)
// Translate the p5 Table to a two dimensional array and send it to Google sheets
dataExport = data.getArray();
dataExport.unshift(data.columns);
saveToSheet(SAVE_DATA_SHEET_NAME, dataExport);
}
}
/**
* This function saves the data to a google sheet of the given name.
* Make sure that the name is unique for you project!
* If your name is not unique then you will share a google sheet with someone else.
*
*
* @param {string} sheetName - The name of you sheet. Make sure it is unique to your project.
* @param {Array<Array>} data - A two dimensional array representing the data.
* Data example:
* data = [
* (row1:) [col1, col2, col3],
* (row2:) [col1, col2, col3]
* ]
* @param {string} [tabName] - (OPTIONAL) The name of the tab/worksheet that this instance of data will be in.
* If you leave this empty it will fall back to using the current time of data submission as tab name
* IMPORTANT! if you are using custom tab names make sure that every name is unique.
* If a name already exists saving wil result in an error.
*/
async function saveToSheet(sheetName, data, tabName) {
// Safety check
if (!sheetName) {
return console.error("The name for the sheet was not valid!")
}
if (!data || data.length === 0) {
return console.error("Cannot save empty data!")
}
// Building save request
const requestBody = {
sheetName,
data
}
// Add tabName if it exists
if (tabName && typeof tabName === "string") {
requestBody.tabName = tabName
}
try {
// Send the save request
const response = await fetch("https://node.bykrijgsman.com/save-data", {
method: "POST",
mode: "cors",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
})
const result = await response.text()
console.log(result)
} catch (e) {
// There was an error while saving if we get here!
console.error(e)
}
}