xxxxxxxxxx
284
/*
IMPORTANNOTS PARADIGM
INPUT: IMAGE
OUTPUT: ANNOTATED AREAS
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.
> 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_importannots";
// write the filenames of your images as strings
const filenames = [
"ajaxmadrid.jpg",
"vatican.jpg"
];
// here you can write instructions for the user. Change to '' to remove.
const instruction = ["Mark the objects that stand out most to you."];
// Here you can set the distance between lasso points in pixels.
const distanceBetweenLassoPoints = 5;
// here you can set the colors of the annotations in RGBA
const strokecolor = "rgba(71, 84, 248, 1.0)";
const fillcolor = "rgba(124, 242, 207, 0.44)";
const strokeselectcolor = "rgba(255, 0, 80, 1.0)";
const fillselectcolor = "rgba(255, 0, 225, 0.44)";
// set this to false to show images in the order of filenames
const randomOrder = true;
// ************* END OF PARAMETERS *************
let annotation;
let currentPoint;
let sub;
let presentationOrder = [],
images = [];
let drawing = false,
done = false,
saved = false;
// Used to store image data
let inputImage, imw, imh;
let trial = 0,
imgtrial = 0;
function preload() {
for (i = 0; i < filenames.length; i++) {
images.push(loadImage("images/" + filenames[i]));
presentationOrder.push(i);
}
if (randomOrder) {
shuffle(presentationOrder, true);
}
}
function setup() {
// determine which image has the biggest width/height
let max_width = 0,
max_height = 0;
for (i = 0; i < images.length; i++) {
if (images[i].width > max_width) {
max_width = images[i].width;
}
if (images[i].height > max_height) {
max_height = images[i].height;
}
}
//use the image size for the canvas, so mind that your images are the right size!
cnv = createCanvas(max_width, max_height);
cnv.mousePressed(pressOnCanvas);
cnv.parent("sketch");
document
.getElementById("sketch")
.setAttribute("style", "height:" + cnv.height + "px");
res = select("#setuptext");
if (instruction[presentationOrder[imgtrial]]) {
res.html(instruction[presentationOrder[imgtrial]]);
} else {
res.html(instruction[0]);
}
sub = createButton("Submit").mousePressed(submit);
data = new p5.Table();
data.columns = ["image", "annot", "x", "y"];
// store image dimensions in the header to be used by the visualizer
for (i = 0; i < filenames.length; i++) {
data.columns.push(filenames[i], images[i].width, images[i].height);
}
}
function draw() {
// Clear background
background(0);
// Draw the image
image(images[presentationOrder[imgtrial]], 0, 0);
for (i = 0; i <= trial; i++) {
// set annotation border color
stroke(strokecolor);
// set annotation fill color
fill(fillcolor);
if (i == trial) {
// set annotation border color
stroke(strokeselectcolor);
// set annotation fill color
fill(fillselectcolor);
}
// Start the shape area
beginShape();
// for all the points draw a point on the canvas
for (j = 1; j < data.rows.length; j++) {
if (
data.getString(j, "image") == filenames[presentationOrder[imgtrial]] &&
data.getNum(j, "annot") == i
) {
vertex(data.getNum(j, "x"), data.getNum(j, "y"));
}
}
// Add the current point
if (j == trial && currentPoint) {
vertex(currentPoint.x, currentPoint.y);
}
// Close the shape
endShape(CLOSE);
}
if (done) {
background(255);
noStroke();
fill(0);
textSize(16);
text("Experiment over!", 30, 60);
if (!saved) {
text("Sending data...", 30, 90);
} else {
text("Data sent!", 30, 90);
}
}
}
function pressOnCanvas() {
if (!done) {
createPoint();
drawing = true;
}
}
function mouseDragged() {
if (drawing) {
// Check the previous point
const previousPoint = createVector(
data.getNum(data.rows.length - 1, "x"),
data.getNum(data.rows.length - 1, "y")
);
// If we moved the the cursor at least X amount of pixels then add a new point
currentPoint = createVector(mouseX, mouseY);
if (previousPoint.dist(currentPoint) >= distanceBetweenLassoPoints) {
createPoint();
currentPoint = null;
}
}
}
function mouseReleased() {
if (drawing) {
trial++;
drawing = false;
}
}
function createPoint() {
//STORE DATA!!
let newRow = data.addRow();
newRow.setString("image", filenames[presentationOrder[imgtrial]]);
newRow.setNum("annot", trial);
newRow.setNum("x", mouseX);
newRow.setNum("y", mouseY);
}
function submit() {
if (imgtrial + 1 == filenames.length) {
done = true;
res.html("");
sub.remove();
// 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);
} else {
imgtrial++;
trial = 0;
if (instruction[presentationOrder[imgtrial]]) {
res.html(instruction[presentationOrder[imgtrial]]);
} else {
res.html(instruction[0]);
}
}
}
/**
* 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);
}
}