xxxxxxxxxx
285
/*
ATTRIBUTE RATING
INPUT: IMAGES, ATTRIBUTES
OUTPUT: ATTRIBUTE 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 image(s) to the images folder.
3. Write the names of the images in filenames.
4. Write the attributes you would like participants to score.
5. Adjust the labels accordingly.
> 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_attribute_rating";
// write the filenames of your images as strings
const filenames = [
"1.jpg",
"2.jpg",
"3.jpg"
];
// Here you can change the prompts the user gets.
const attributes = [
"attractiveness",
"uniqueness",
"luxuriousness"
];
const leftLabel = [
"not so attractive",
"not so unique",
"not so luxurious"
];
const rightLabel = [
"very attractive",
"very unique",
"very luxurious"
];
// set this to false to show images in the order of filenames
const randomOrder = true;
// ************* END OF PARAMETERS *************
var presentationOrder = [];
var hoverS, hoverBool;
var ratings = [];
var imgX = 100;
var imgY = 30;
var aspectRatio = 1.5;
var imgHeight = 400;
var imgWidth = aspectRatio * imgHeight;
var lineY = imgY + imgHeight + 100;
var marginY = 80;
var images = [];
var sliderX1 = 150;
var sliderX2 = 650;
var sliderBallRadius = 18;
var tickHeight = -8;
var nTicks = 6;
var ratingValue;
var labelYOffset = 35;
var trialNumber = 0;
let saved = false;
function preload() {
for (var i = 0; i < filenames.length; i++) {
images[i] = loadImage("img/" + filenames[i]);
presentationOrder[i] = i;
}
if (randomOrder) {
presentationOrder = shuffle(presentationOrder);
}
}
function setup() {
createCanvas(800, 700 + marginY * (attributes.length - 1));
data = new p5.Table();
data.addColumn("image");
for (i = 0; i < attributes.length; i++) {
data.addColumn(attributes[i]);
ratings.push(-1);
}
}
function draw() {
background(220);
if (trialNumber < filenames.length) {
let shown = images[presentationOrder[trialNumber]];
if(shown.width/shown.height > aspectRatio){
image(shown, imgX, imgY, imgWidth, shown.height * (imgWidth/shown.width));
} else{
image(shown, imgX, imgY, shown.width * (imgHeight/shown.height), imgHeight);
}
fill(0, 102, 153);
noStroke();
textSize(22);
text(
"Please rate the object in the image on the following attributes:",
100,
480
);
hoverBool = false;
for (i = 0; i < attributes.length; i++) {
drawSlider(i);
}
} 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 drawSlider(i) {
strokeWeight(4);
stroke(80);
line(sliderX1, lineY + i * marginY, sliderX2, lineY + i * marginY);
//draw ticks
for (var j = 0; j < nTicks; j++) {
var xtemp = map(j, 0, nTicks - 1, sliderX1, sliderX2);
line(xtemp, lineY + i * marginY, xtemp, lineY - tickHeight + i * marginY);
}
//draw slider ball
fill(158, 194, 208);
stroke(50);
strokeWeight(4);
if (
mouseY > lineY + i * marginY - marginY / 2 &&
mouseY < lineY + i * marginY + marginY / 2 &&
ratings[i] < 0
) {
ellipse(sliderX(mouseX), lineY + i * marginY, sliderBallRadius);
hover = i;
hoverBool = true;
}
if (ratings[i] != -1) {
fill(128, 128, 128);
ellipse(
map(ratings[i], 0, 100, sliderX1, sliderX2),
lineY + i * marginY,
sliderBallRadius
);
}
fill(0);
noStroke();
textSize(18);
text(leftLabel[i], sliderX1, lineY + labelYOffset + i * marginY);
textAlign(RIGHT);
text(rightLabel[i], sliderX2, lineY + labelYOffset + i * marginY);
textAlign(LEFT);
}
function mouseClicked() {
if (trialNumber < filenames.length && hoverBool) {
ratings[hover] = round(100 * ratingX(mouseX));
// save the data
if (checkSliders()) {
let newRow = data.addRow();
newRow.setString("image", filenames[presentationOrder[trialNumber]]);
for (i = 0; i < attributes.length; i++) {
newRow.setNum(attributes[i], ratings[i]);
ratings[i] = -1;
}
trialNumber++;
if (trialNumber == filenames.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 checkSliders() {
for (i = 0; i < attributes.length; i++) {
if (ratings[i] < 0) {
return false;
}
}
return 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);
}
}