xxxxxxxxxx
238
/*
todo:
- stylistic congruency
- label "car"
Instructions:
1. Upload images
2. Write image filenames
2. Set the attributes you would like to rate them on
3. Adjust the labels accordingly
*/
// !! 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 = "attribute_rating_test";
const filenames = ['1.jpg', '2.jpg', '3.jpg'];
const attributes = ['attractiveness', 'uniqueness', 'luxuriousness'];
const leftLabel = ['not so attractive', 'not so unique', 'not so luxurious'];
const rightLabel = ['very attractive', 'very unique', 'very luxurious'];
const randomOrder = true;
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;
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) {
image(images[presentationOrder[trialNumber]], imgX, imgY, imgWidth, imgHeight);
fill(0, 102, 153);
noStroke();
textSize(22);
text('Please rate the vehicle 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('The End', 400, 300);
fill(100);
textSize(20);
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)
} catch (e) {
// There was an error while saving if we get here!
console.error(e)
}
}