Help with adding autocomplete to a sketch

Hi all-

Im hoping someone might be able to help point me in the right direction. Im creating a sketch that acts as an interactive inventory map for the shop that i work in. For example, when a person types in a search term such as “hammers” and either clicks the submit button or presses the enter key on the keyboard, a simple animation plays on the location (a picture of the shop floor layout) of the item in the shop. So far the sketch works really pretty well (i think), however, I want to add suggestions for key search words after the first few letters are typed. So, lets say a user types in the letters “h”, and “a”, a list of all items that begin with those letters would be listed to make it a little easier for people. My sketch uses google sheets for its data and each “location” (i.e. cabinet #1 or table#4, etc.) is arranged in the google sheet in columns. (Not sure if this tidbit of info is relevant or not to anyone trying to help)

I did find one sketch from a google search, unfortunately Im just not skilled enough to take the example i found and use it in my sketch.

Heres my sketch

let dia = 0;
let growAmount = 0.5;
let grow = true;

let input, button, greeting, img, data;

let url =
  "https://docs.google.com/spreadsheets/d/e/2PACX-1vRmua9Ue9Uv2olN_0kOvTbAPPBkJ3ckciRbDUs_jUr9eMv43sgdFrzmcluQGd4MQrsiYemarPqLsjVj/pub?gid=0&single=true&output=csv";

///////////////////////////////////////////////////////////////////////////

function preload() {
  data = loadTable(url, "csv", "header");
}

///////////////////////////////////////////////////////////////////////////

function setup() {
  // create canvas
  createCanvas(1794, 600);

  img = loadImage("LMP Map2.png");
  name = null;

  input = createInput();
  input.position(20, 600);

  button = createButton("submit");
  button.position(input.x + input.width, 600);
  button.mousePressed(greet);

  greeting = createElement("h2", "Search (Press Esc to clear)");
  greeting.position(20, 550);

  // textAlign(LEFT);
  // textSize(50);
}

///////////////////////////////////////////////////////////////////////////

function draw() {
  background(255);
  image(img, 0, 0);

  if (keyIsPressed) {
    if (keyCode == ENTER || keyCode == RETURN) {
      greet();
    } else if (keyCode == 51) {
      input.value("screwdrivers"); // test
    } else if (keyCode == 27) {
      input.value(null);
      name = null;
    }
  }

  c1 = data.getColumn("1");
  c2 = data.getColumn("2");
  c3 = data.getColumn("3");
  c4 = data.getColumn("4");
  c5 = data.getColumn("5");
  c6 = data.getColumn("6");

  if (c1.includes(name)) {
    anim1();
  }

  if (c2.includes(name)) {
    anim2();
  }
  //     if (c3.includes(name)) {
  //     anim3();
  //   }

  //     if (c4.includes(name)) {
  //     anim4();
  //   }

  //     if (c5.includes(name)) {
  //     anim5();
  //   }

  //     if (c6.includes(name)) {
  //     anim6();
  //   }
}

///////////////////////////////////////////////////////////////////////////

function greet() {
  

  //Changes input.value to uppercase in console, NEED TO MAKE NOT CASE SENSITIVE
  name = input.value().toUpperCase();
  string =
    name.charAt(0).toUpperCase() + name.substr(1, name.length).toUpperCase();
  print(string);

}

///////////////////////////////////////////////////////////////////////////

// function smallReset() { //THIS MAY NOT NE NECESSARY, SUPPOSED TO BE FOR RESETTING ANIMATION
//   //resets animation
//   var dia = 0;
//   var growAmount = 0;
//   var grow = 0;
// }

///////////////////////////////////////////////////////////////////////////

function anim1() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(200, 200, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}

function anim2() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(400, 400, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}

`
Any help is greatly appreciated! Many, many thanks in advance!

1 Like

Hi @zara2355,

Look here for an example…
The steps are

  • Add event listener for input on your textbook.
  • Search for data on input
  • Display suggestions if matches found

Cheers
— mnse

EDIT: I’ve modified the code from example formerly linked as it was imo not sufficient and rewrited it based on the original to add a datalist so user can select on filter.
EDIT: Sorry was still fiddling now it is ok :slight_smile:

Sorry for the delay here, and thank you for the response.

I think what im having a hard time with is the example you give sort of ignores the google sheet and instead uses a JSON file. Is it possible to create the autocomplete without using an event listener? That is, i see the event listener looks in the html part for an input field, but the input field I created is all made within the P5 part.

Sorry for the noob questions, but well, am a noob

1 Like
//  ["ENDMILL", "HAMMER", "SCREWS", "CLAMPS", "SCREWDRIVERS"]

let dia = 0;
let growAmount = 0.5;
let grow = true;

let input1, button, greeting, img, data;

let resultContinuousSearch = "";

let url =
  "https://docs.google.com/spreadsheets/d/e/2PACX-1vRmua9Ue9Uv2olN_0kOvTbAPPBkJ3ckciRbDUs_jUr9eMv43sgdFrzmcluQGd4MQrsiYemarPqLsjVj/pub?gid=0&single=true&output=csv";

///////////////////////////////////////////////////////////////////////////

function preload() {
  data = loadTable(url, "csv", "header");
}

///////////////////////////////////////////////////////////////////////////

function setup() {
  // create canvas
  createCanvas(1794, 300);

  // img = loadImage("LMP Map2.png");
  name = null;

  input1 = createInput();
  input1.position(20, 600);
  input1.input(myInputEvent);

  button = createButton("submit");
  button.position(input1.x + input1.width, 600);
  button.mousePressed(greet);

  greeting = createElement("h2", "Search (Press Esc to clear)");
  greeting.position(20, 550);

  rcs = createElement("rcs");
  rcs.position(20, 450);

  // textAlign(LEFT);
  // textSize(50);
}

///////////////////////////////////////////////////////////////////////////

function draw() {
  background(255);
  // image(img, 0, 0);

  // console.log(input1.getText());

  if (keyIsPressed) {
    if (keyCode == ENTER || keyCode == RETURN) {
      greet();
    } else if (keyCode == 51) {
      input1.value("screwdrivers"); // test
    } else if (keyCode == 27) {
      input1.value(null);
      name = null;
    }
  }

  c1 = data.getColumn("1");
  c2 = data.getColumn("2");
  c3 = data.getColumn("3");
  c4 = data.getColumn("4");
  c5 = data.getColumn("5");
  c6 = data.getColumn("6");

  if (c1.includes(name)) {
    anim1();
  }

  if (c2.includes(name)) {
    anim2();
  }
  //     if (c3.includes(name)) {
  //     anim3();
  //   }

  //     if (c4.includes(name)) {
  //     anim4();
  //   }

  //     if (c5.includes(name)) {
  //     anim5();
  //   }

  //     if (c6.includes(name)) {
  //     anim6();
  //   }
}

///////////////////////////////////////////////////////////////////////////

function myInputEvent() {
  if (this.value().length >= 1) {
    resultContinuousSearch = "";
    c1 = data.getColumn("1");

    for (let i = 0; i < c1.length; i++) {
      if (contains(c1[i], this.value())) {
        // console.log(c1[i]);
        resultContinuousSearch += c1[i] + "\n";
      } //if
    }
    //
    rcs.html(resultContinuousSearch);
  } //if
} //func

function contains(s1, s2) {
  for (let i = 0; i < s2.length; i++) {
    if (s1[i].toUpperCase() != s2[i].toUpperCase()) return false;
  } //for
  return true;
} //func

function greet() {
  //Changes input1.value to uppercase in console, NEED TO MAKE NOT CASE SENSITIVE
  name = input1.value().toUpperCase();
  string =
    name.charAt(0).toUpperCase() + name.substr(1, name.length).toUpperCase();
  print(string);
}

///////////////////////////////////////////////////////////////////////////

// function smallReset() { //THIS MAY NOT NE NECESSARY, SUPPOSED TO BE FOR RESETTING ANIMATION
//   //resets animation
//   var dia = 0;
//   var growAmount = 0;
//   var grow = 0;
// }

///////////////////////////////////////////////////////////////////////////

function anim1() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(200, 200, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}

function anim2() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(400, 400, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}
//

new version without an event function - we just control the input throughout

  • see resultContinuousSearch and rcs
//  ["ENDMILL", "HAMMER", "SCREWS", "CLAMPS", "SCREWDRIVERS"]

let dia = 0;
let growAmount = 0.5;
let grow = true;

let input1, button, greeting, img, data;

let resultContinuousSearch = "";

let url =
  "https://docs.google.com/spreadsheets/d/e/2PACX-1vRmua9Ue9Uv2olN_0kOvTbAPPBkJ3ckciRbDUs_jUr9eMv43sgdFrzmcluQGd4MQrsiYemarPqLsjVj/pub?gid=0&single=true&output=csv";

///////////////////////////////////////////////////////////////////////////

function preload() {
  data = loadTable(url, "csv", "header");
}

///////////////////////////////////////////////////////////////////////////

function setup() {
  // create canvas
  createCanvas(1794, 300);

  // img = loadImage("LMP Map2.png");
  name = null;

  input1 = createInput();
  input1.position(20, 600);

  button = createButton("submit");
  button.position(input1.x + input1.width, 600);
  button.mousePressed(greet);

  greeting = createElement("h2", "Search (Press Esc to clear)");
  greeting.position(20, 550);

  rcs = createElement("rcs");
  rcs.position(20, 450);

  // textAlign(LEFT);
  // textSize(50);
}

///////////////////////////////////////////////////////////////////////////

function draw() {
  background(255);
  // image(img, 0, 0);

  if (keyIsPressed) {
    if (keyCode == ENTER || keyCode == RETURN) {
      greet();
    } else if (keyCode == 51) {
      input1.value("screwdrivers"); // test
    } else if (keyCode == 27) {
      input1.value(null);
      name = null;
    }
  }

  c1 = data.getColumn("1");
  c2 = data.getColumn("2");
  c3 = data.getColumn("3");
  c4 = data.getColumn("4");
  c5 = data.getColumn("5");
  c6 = data.getColumn("6");

  if (c1.includes(name)) {
    anim1();
  }

  if (c2.includes(name)) {
    anim2();
  }
  //     if (c3.includes(name)) {
  //     anim3();
  //   }

  //     if (c4.includes(name)) {
  //     anim4();
  //   }

  //     if (c5.includes(name)) {
  //     anim5();
  //   }

  //     if (c6.includes(name)) {
  //     anim6();
  //   }

  checkInput();
}

function checkInput() {
  // NOT an event

  resultContinuousSearch = "";

  if (input1.value().length >= 1) {
    c1 = data.getColumn("1");

    for (let i = 0; i < c1.length; i++) {
      if (contains(c1[i], input1.value())) {
        // console.log(c1[i]);
        resultContinuousSearch += c1[i] + "\n";
      } //if
    }
    //
  } //if
  rcs.html(resultContinuousSearch);
}

///////////////////////////////////////////////////////////////////////////

function contains(s1, s2) {
  for (let i = 0; i < min(s1.length, s2.length); i++) {
    if (s1[i].toUpperCase() != s2[i].toUpperCase()) return false;
  } //for
  return true;
} //func

function greet() {
  //Changes input1.value to uppercase in console, NEED TO MAKE NOT CASE SENSITIVE
  name = input1.value().toUpperCase();
  string =
    name.charAt(0).toUpperCase() + name.substr(1, name.length).toUpperCase();
  print(string);
}

///////////////////////////////////////////////////////////////////////////

// function smallReset() { //THIS MAY NOT NE NECESSARY, SUPPOSED TO BE FOR RESETTING ANIMATION
//   //resets animation
//   var dia = 0;
//   var growAmount = 0;
//   var grow = 0;
// }

///////////////////////////////////////////////////////////////////////////

function anim1() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(200, 200, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}

function anim2() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(400, 400, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}
//

Chrisir

Wow! Thank you! I’ve been struggling to try to combine the two methods and I think this really simplifies it a lot. That said, ive learned a ton, both on the html/css side as well a p5.js.

i will look deeply into your example and try to figure out WHY everything does what it does so that I can really understand.

Again, thank you!

2 Likes

One more question, specifically with line # 107 in the sketch example, is there a way that the resultContinuousSearch += c1[i] + "\n"; is able to separate the results not in a continuous line of text, but rather in a column as if you were to hit “enter” after each result?

1 Like

Ok, so i think i’ve figured it out by using split. I then increased the canvas size a bit (from 600 to 800 on the Y axis) to allow for a handful of suggestions to search for. If anyone has input to make this more efficient, please let me know! I think ive got some minor changes (i.e. i have an idea to make the data formatting better), but i think this might be close to a workable sketch. Thank you all so much!

//  ["ENDMILL", "HAMMER", "SCREWS", "CLAMPS", "EXT", "SCREWDRIVERS", "HELL"]



let dia = 0;
let growAmount = 0.5;
let grow = true;

let input1, button, greeting, img, data;

let resultContinuousSearch = "";

let url =
  "https://docs.google.com/spreadsheets/d/e/2PACX-1vRmua9Ue9Uv2olN_0kOvTbAPPBkJ3ckciRbDUs_jUr9eMv43sgdFrzmcluQGd4MQrsiYemarPqLsjVj/pub?gid=0&single=true&output=csv";


///////////////////////////////////////////////////////////////////////////

function preload() {
  data = loadTable(url, "csv", "header");
}

///////////////////////////////////////////////////////////////////////////

function setup() {
  
    

  
  // create canvas
  createCanvas(1794, 1000);

  img = loadImage("LMP Map2.png");
  name = null;

  input1 = createInput();
  input1.position(20, 600);

  button = createButton("submit");
  button.position(input1.x + input1.width, 600);
  button.mousePressed(greet);

  greeting = createElement("h2", "Search (Press Esc to clear)");
  greeting.position(20, 550);

  rcs = createElement("rcs");
  rcs.position(20, 620);

  // textAlign(LEFT);
  // textSize(50);
}

///////////////////////////////////////////////////////////////////////////

function draw() {
  

  
  
  background(255);
  image(img, 0, 0);

  if (keyIsPressed) {
    if (keyCode == ENTER || keyCode == RETURN) {
      greet();
    } else if (keyCode == 51) {
      input1.value("screwdrivers"); // test
    } else if (keyCode == 27) {
      input1.value(null);
      name = null;
    }
  }

  c1 = data.getColumn("1");
  c2 = data.getColumn("2");
  c3 = data.getColumn("3");
  c4 = data.getColumn("4");
  c5 = data.getColumn("5");
  c6 = data.getColumn("6");

  if (c1.includes(name)) {
    anim1();
  }

  if (c2.includes(name)) {
    anim2();
  }
  //     if (c3.includes(name)) {
  //     anim3();
  //   }

  //     if (c4.includes(name)) {
  //     anim4();
  //   }

  //     if (c5.includes(name)) {
  //     anim5();
  //   }

  //     if (c6.includes(name)) {
  //     anim6();
  //   }

  checkInput();
}

function checkInput() {
  // NOT an event

  resultContinuousSearch = "";

  if (input1.value().length >= 1) {
    c1 = data.getColumn("1");

    for (let i = 0; i < c1.length; i++) {
      if (contains(c1[i], input1.value())) {
        // console.log(c1[i]);
        let A = split(resultContinuousSearch, ',');
        resultContinuousSearch += c1[i] + "\n"   ;
        
let names = resultContinuousSearch;
let splitString = split(names, ',');
        
text(splitString[0], 5, 650);
        textSize(20);
        fill(0, 0, 0);
// text(splitString[1], 5, 670);
// text(splitString[2], 5, 690);

      } //if
    }
    //
  } //if
  // rcs.html(resultContinuousSearch) ;
}

///////////////////////////////////////////////////////////////////////////

function contains(s1, s2) {
  for (let i = 0; i < min(s1.length, s2.length); i++) {
    if (s1[i].toUpperCase() != s2[i].toUpperCase()) return false;
  } //for
  return true;
} //func

function greet() {
  //Changes input1.value to uppercase in console, NEED TO MAKE NOT CASE SENSITIVE
  name = input1.value().toUpperCase();
  string =
    name.charAt(0).toUpperCase() + name.substr(1, name.length).toUpperCase();
  print(string);
}

///////////////////////////////////////////////////////////////////////////

// function smallReset() { //THIS MAY NOT NE NECESSARY, SUPPOSED TO BE FOR RESETTING ANIMATION
//   //resets animation
//   var dia = 0;
//   var growAmount = 0;
//   var grow = 0;
// }

///////////////////////////////////////////////////////////////////////////

function anim1() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(200, 200, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}

function anim2() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(400, 400, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}
//
1 Like

Yeah, next step would be to make the autocomplete suggestions clickable by mouse.

Like a list you chose from.

Or cursor keys.

  • when you have a lot of items you want to increase the required minimum length to 3 or so

  • why do you have c1 and c2? Because of upper case? This seems like two different columns

Chrisir

I completely agree with the idea of the clickable selections or selecting a suggestion using cursor keys. I think that may well be the real polish on it and will try to figure that out.

Not sure you mean by

when you have a lot of items you want to increase the required minimum length to 3 or so

Can you clarify what you mean here?

In the meantime, ive rearranged my data a bit to try to make this both easier on myself (im responsible for this code) and easier on the person(s) keeping the inventory. Im sort of wondering what might be the most efficient way of organizing eith the spreadsheet or writing a clunky sketch. Specifically, if i put the burden on the person updating the inventory spreadsheet, they might have to also update the new columns (“X Coordinate” and “Y Coordinate”) This doesnt seem like it will be a good idea at all and will end badly for me. On the other hand, i could write a bunch of “if” statements where the people keeping inventory only need to enter in what cabinet number it is, and then in my sketch my “if” statements then assign new var for x and x for the location of the animation. THis too is bad, since theres about 60 different cabinets, and therefore 60 “if” statements in the sketch, which seems really super clunky and not efficient at all. To be perfectly honest, not sure which is the less-worse, but i have to think theres a better solution that i just dont know from lack of experience

Heres the new sketch so you can look at both the spreadsheet (and see the new columns) as well as the “if” statements. (lines 142 - 155 in the sketch)

let dia = 0;
let growAmount = 0.5;
let grow = true;

let input1, button, greeting, img, data;

let resultContinuousSearch = "";

let url =
  "https://docs.google.com/spreadsheets/d/e/2PACX-1vRmua9Ue9Uv2olN_0kOvTbAPPBkJ3ckciRbDUs_jUr9eMv43sgdFrzmcluQGd4MQrsiYemarPqLsjVj/pub?gid=0&single=true&output=csv";

///////////////////////////////////////////////////////////////////////////

function preload() {
  data = loadTable(url, "csv", "header");
}

///////////////////////////////////////////////////////////////////////////

function setup() {
  createCanvas(1794, 1000);

  img = loadImage("LMP Map2.png");
  name = null;

  input1 = createInput();
  input1.position(20, 600);

  button = createButton("submit");
  button.position(input1.x + input1.width, 600);
  button.mousePressed(greet);

  greeting = createElement("h2", "Search (Press Esc to clear)");
  greeting.position(20, 550);

  rcs = createElement("rcs");
  rcs.position(20, 620);
}

///////////////////////////////////////////////////////////////////////////

function draw() {
  background(255);
  image(img, 0, 0);

  if (keyIsPressed) {
    if (keyCode == ENTER || keyCode == RETURN) {
      greet();
    } else if (keyCode == 51) {
      input1.value("screwdrivers"); // test
    } else if (keyCode == 27) {
      input1.value(null);
      name = null;
      dia = 0;
    }
  }

  getData();

  checkInput();
}

///////////////////////////////////////////////////////////////////////////

function checkInput() {
  // NOT an event

  resultContinuousSearch = "";

  if (input1.value().length >= 1) {
    c1 = data.getColumn("TOOL");

    for (let i = 0; i < c1.length; i++) {
      if (contains(c1[i], input1.value())) {
        // console.log(c1[i]);
        let A = split(resultContinuousSearch, ",");
        resultContinuousSearch += c1[i] + "\n";

        let names = resultContinuousSearch;
        let splitString = split(names, ",");
        fill(0, 0, 0);
        textSize(20);
        text(splitString[0], 25, 650);
      }
    }
  }
}

///////////////////////////////////////////////////////////////////////////

function contains(s1, s2) {
  for (let i = 0; i < min(s1.length, s2.length); i++) {
    if (s1[i].toUpperCase() != s2[i].toUpperCase()) return false;
  }
  return true;
}

function greet() {
  //Changes input1.value to uppercase in console, NEED TO MAKE NOT CASE SENSITIVE
  name = input1.value().toUpperCase();
  string =
    name.charAt(0).toUpperCase() + name.substr(1, name.length).toUpperCase();
  print(string);
}


///////////////////////////////////////////////////////////////////////////

function anim1() {
  //Creates the animation for location of item
  fill(0, 255, 0);
  ellipse(c, xLoc, dia, dia);

  if (dia > 50) {
    grow = false;
  }
  if (dia < 0) {
    grow = true;
  }

  if (grow == true) {
    dia += growAmount;
  } else {
    dia -= growAmount;
  }
}

///////////////////////////////////////////////////////////////////////////

function getData() {
  for (let i = 0; i < data.getRowCount(); i++) {
    let row = data.getRow(i);
    let c = row.getString("TOOL");
    let l = row.getNum("LOCATION");
    let xLoc = row.getNum("X Coordinate");
    let yLoc = row.getNum("Y Coordinate");

    
    
  
    
//     if (l == 1){
//       var xLoc = 500;
//       var yLoc = 200;
//     }
    
//         if (l == 2){
//       var xLoc = 350;
//       var yLoc = 200;
//     }
    
//         if (l == 3){
//       var xLoc = 200;
//       var yLoc = 500;
//     }
    
 
    
    
    // print(xLoc);
    // noLoop();

    if (name == c) {
      fill(0, 255, 0);
      ellipse(xLoc, yLoc, dia, dia);

      if (dia > 50) {
        grow = false;
      }
      if (dia < 0) {
        grow = true;
      }

      if (grow == true) {
        dia += growAmount;
      } else {
        dia -= growAmount;
      }
    }
  }
}

Thanks a million, once again

1 Like

There is an if clause when we start to compare the input to the list. Long list would be Time consuming.
Hence, you can say just search when length > 3

Remember in one of my previous versions (other thread) I had a shelf name (for example “Cabinet 1”) and the coordinates where there.
You can make also a separate table to give your shelf name and x and y. So the poor soul can work with shelf name mainly and ignore x,y since it’s read from this separate table.

So when you have many items in ONE shelf
this might work.

  • Besides: my contains function is probably a built-in function somewhere but I couldn’t find it.

Chrisir

Hi again, and thanks for the helpful response!

Im wondering, regarding your suggestion to add in the “clickable by mouse/cursor keys” are there any tips or tutorials that might help in this instance? Im asking about this specifically because of the way the new autocomplete is written (that is, entirely in the p5js sketch and not utilizing the html/css side).

Also, im still trying to figure out the best way to approach the data tables issue i spoke about before (requiring the inventory person to update the item location as well as the X and Y coordinates, OR write ~60 “if” statement). I think part of the fun with this project is trying to see if i can figure these solutions from research and trial and error.

As usual, many many thanks to you and everyone here!

this comes to mind: reference | p5.js

or reference | p5.js

these you could fill dynamically with the suggestions.

You can also make a couple of buttons underneath each other.


I hoped to have answered this in my previous post with the separate table.

  • You can of course make a separate Sketch where the poor guy can click with the mouse in the ground floor plan to store x,y for each cabinet/ regal / product. Store the result in the said separate table.