xxxxxxxxxx
261
/*
SIMILARITY
INPUT: IMAGES
OUTPUT: SIMILARITY RATINGS
HOW TO USE:
1. In SAVE_DATA_SHEET_NAME, write the name of the sheet you want to save the data to, preferrably as: "studentID_visualsearch"
2. Upload your images to the images folder.
3. Write the names of the images in filenames.
> Click File>Share and send the "Fullscreen" link to your participants
*/
// !! 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 = "example_similarity";
// write the filenames of your images as strings
const filenames = [
"1.jpg",
"2.jpg",
"3.jpg",
"4.jpg"
];
// Here you can change the prompts the user gets.
const instruction = "Please rate the similarity of the 2 objects shown above";
const leftLabel = "not so similar";
const rightLabel = "very similar";
// set this to false to show images in the order of filenames
const randomOrder = true;
// ************* END OF PARAMETERS *************
var imgX1 = 340;
var imgX2 = 860;
var imgY = 270;
var imgSize = 480;
var lineY = imgY + imgSize/2 + 160;
var images = [];
var sliderX1 = 150;
var sliderX2 = 1050;
var sliderBallRadius = 18;
var ratingValue;
var labelYOffset = 35;
var trialNumber = 1;
var imgMatrix = makeCombinations(filenames.length);
let saved = false;
function preload() {
for (var i = 0; i < filenames.length; i++) {
images[i] = loadImage("images/" + filenames[i]);
}
}
function setup() {
if (randomOrder) {
shuffleMatrix(imgMatrix);
}
createCanvas(1200, 800);
print(imgMatrix);
data = new p5.Table();
data.addColumn("Image 1");
data.addColumn("Image 2");
data.addColumn("Similarity Ratings");
imageMode(CENTER);
}
function draw() {
background(220);
if (trialNumber <= imgMatrix.length) {
let shown = imgMatrix[trialNumber - 1];
for(i=0;i<2;i++){
if(images[shown[i]].width > images[shown[i]].height){
image(images[shown[i]], imgX1 + i * 520, imgY, imgSize, images[shown[i]].height * (imgSize/images[shown[i]].width));
} else{
image(images[shown[i]], imgX1 + i * 520, imgY, images[shown[i]].width * (imgSize/images[shown[i]].height), imgSize);
}
}
image(images[imgMatrix[trialNumber - 1][1]], imgX2, imgY, imgSize, imgSize);
fill(0, 102, 153);
noStroke();
textSize(22);
textAlign(LEFT);
text(instruction, 100, 560);
fill(80);
textSize(18);
text(
"Move mouse horizontally to adjust slider, click to respond and proceed to next trial.",
100,
590
);
strokeWeight(4);
stroke(80);
line(sliderX1, lineY, sliderX2, lineY);
drawSliderTicks();
fill(158, 194, 208);
stroke(50);
strokeWeight(4);
ellipse(sliderX(mouseX), lineY, sliderBallRadius);
fill(0);
noStroke();
textSize(18);
text(leftLabel, sliderX1, lineY + labelYOffset);
textAlign(RIGHT);
text(rightLabel, sliderX2, lineY + labelYOffset);
} else {
//final page, data download instruction
fill(0, 102, 153);
noStroke();
textSize(28);
textAlign(CENTER);
text("Experiment over!", 400, 300);
fill(100);
textSize(20);
if (!saved) {
text("Sending data...", 400, 350);
} else {
text("The data has been sent.", 400, 350);
}
}
}
function mouseClicked() {
if (trialNumber <= imgMatrix.length) {
ratingValue = round(100 * ratingX(mouseX));
// save the data
let newRow = data.addRow();
newRow.setString("Image 1", filenames[imgMatrix[trialNumber - 1][0]]);
newRow.setString("Image 2", filenames[imgMatrix[trialNumber - 1][1]]);
newRow.setNum("Similarity Ratings", ratingValue);
trialNumber++;
if (trialNumber > imgMatrix.length) {
// 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);
}
}
}
function sliderX(mx) {
var mq = max([mx, sliderX1]);
return min([mq, sliderX2]);
}
function ratingX(mx) {
var mq = max([mx, sliderX1]);
mq = min([mq, sliderX2]);
return map(mq, sliderX1, sliderX2, 0, 1);
}
function drawSliderTicks() {
var tickHeight = -8;
var nTicks = 6;
for (var i = 0; i < nTicks; i++) {
var xtemp = map(i, 0, nTicks - 1, sliderX1, sliderX2);
line(xtemp, lineY, xtemp, lineY - tickHeight);
}
}
function makeCombinations(n) {
//create a 2 by n matrix
holder = [];
for (var i = 0; i < n; i++) {
for (var j = i; j < n; j++) {
if(i!=j){
holder.push([i, j]);
}
}
}
return holder;
}
function shuffleMatrix(matrix) {
shuffle(matrix, true);
for (var i = 0; i < matrix.length; i++) {
shuffle(matrix[i], true);
}
}
/**
* 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);
if (result == "SAVED!") {
saved = true;
}
} catch (e) {
// There was an error while saving if we get here!
console.error(e);
}
}