Finding the x,y location of a word when text wrapped

thank you! :smiling_face_with_three_hearts:

new version, minor changes

// Text box (to replace text() with 5 parameters) with wrapping, so that each word can be separately detected when mouse is over. 
// Click mouse on a word to get the word via println or hover mouse on a word for the small status bar.

// Sketch can be strongly improved 

// https://discourse.processing.org/t/finding-the-x-y-location-of-a-word-when-text-wrapped/38243

final String  txt_copy = "Nullam feugiat mauris vitae sapien tincidunt iaculis. Nam malesuada varius porta. Integer sed dolor tempor, tristique nibh quis, vehicula est.";

PFont myFont;

// core idea: the class
TextBox textBox;  

// -------------------------------------------------------------------

void setup() {
  size(400, 400);
  background(0);

  myFont = createFont("Georgia", 20);
  textFont(myFont);
  textSize(20);

  // core idea: fill the class
  textBox = new TextBox(txt_copy, 29, 47, 
    350, 300);
}//func 

void draw() {
  background(0);

  // core idea: USE the class
  textBox.show();
  showMouseOver();
}//func 

// -------------------------------------------------------------------
// Inputs 

void mousePressed() {
  // core idea: USE the class
  println(textBox.getWordUnderMouse());
}//func 

// -------------------------------------------------------------------
// Tools

void showMouseOver() {
  // hover mouse on a word for status bar. 
  // get word 
  String result = textBox.getWordUnderMouse();   // core idea: USE the class
  // status bar 
  showStatusBar(result);
}//func

void showStatusBar (String text_) {
  // status bar 
  noStroke(); 
  fill(111);
  rect(0, height-27, 
    width, 111);

  fill(255); 
  text(text_, 9, height-6);
}//func 

// =================================================================

class TextBox {

  final float textSpacing = 23; 

  ArrayList<String> listOfLines = new ArrayList();

  float xTextBox, yTextBox, 
    wTextBox, hTextBox; 

  // constr
  TextBox (String str_, 
    float x_, float y_, 
    float w_, float h_) {

    // no output, just prepare the object derived from class TextBox.
    // float h_ not in use. 
    // assuming textWrap(WORD);

    // fill box
    xTextBox = x_;
    yTextBox = y_;
    wTextBox = w_;
    hTextBox = h_;

    defineListOfLines(str_, w_);
  } // constr

  void defineListOfLines(String str_, float w_) {
    // Helper for the constr 

    String[] stringArray = split(str_, " " );   //  String[] s1 = splitTokens ( str_, " ,.!?;:" ); 

    String currentLine=""; 
    int wordCount=0;

    // Loop over array
    for (String currentWord : stringArray) {
      String previousVersion = currentLine; 
      currentLine = currentLine + " " + currentWord; 
      currentLine = currentLine.trim(); 

      float cw = textWidth(currentLine);

      // When too long 
      if (cw > w_-5) {
        listOfLines.add(previousVersion); 
        // reset
        previousVersion=""; 
        currentLine=currentWord;
      }//if

      // When end of Array  
      if (wordCount == stringArray.length-1) {
        listOfLines.add(trim(currentLine));
        break;
      }//if
      //
      wordCount++;
      //
    }//for
  }

  void show() {
    // show Text 

    /*
     //show box
     noFill();
     stroke(255, 0, 0); 
     rect(xTextBox, yTextBox, 
     wTextBox, hTextBox   );
     */

    fill(255); 
    int lineCount=1; // start with 1 to move text one line down, so it's inside the rectangle  
    for (String s1 : listOfLines) {
      //output
      text (s1, 
        xTextBox, yTextBox + lineCount * textSpacing);
      lineCount++;
    }//for
  }//method

  String getWordUnderMouse() {
    // core idea: find word under mouse in ArrayList list

    // find Line from mouseX ---

    String resultingLine="";
    int lineCount=1; // start with 1 to move text one line down  

    for (String currentLine : listOfLines) {
      if (mouseY > yTextBox + (lineCount-1) * textSpacing && 
        mouseY < yTextBox + lineCount * textSpacing) {
        resultingLine=currentLine; //found
        break;
      }//if
      lineCount++;
    }//for

    // find word from mouseY ---

    String[] stringArray = split (resultingLine, " ");
    String resultingWord="";
    String currentLine=""; 

    // loop over words in this line 
    for (String currentWord : stringArray) {

      // previous textWidth
      float lineWidthOld = xTextBox+textWidth(currentLine);

      currentLine+= " " + currentWord; 
      // new textWidth
      float lineWidthNew = xTextBox+textWidth(currentLine);

      if (mouseX > lineWidthOld && 
        mouseX < lineWidthNew) {
        resultingWord=currentWord; //found
        break;
      }//if
    } //for 

    // return result ---
    // removing . and , etc. at the end of the word 
    final String deleteCharacters=" ,.!?;:";
    resultingWord = removeCharsFromString(resultingWord, deleteCharacters);  
    return resultingWord;
  } // method 

  String removeCharsFromString ( String in_, String remove_) {
    // removing . and , etc. at the end of the word 
    for (char currentChar : remove_.toCharArray()) {
      in_=in_.replace(currentChar, ' ');
    }//for 
    in_=trim(in_);
    return in_;
  }//method
  //
}//class
//

4 Likes