Your code is definitely on the right track. Getting a good approximation without just reusing Processing’s own code (which is also an option!) can be an extremely fiddly problem because it may rely on specifics of how Processing line leading works with defaults / magic values.
Try this:
// Default leading value matches Processing default text behavior for the default Font.
boolean isTextOverflow(String txt, float x, float y, float w, float h, float tsize) {
return isTextOverflow(txt, x, y, w, h, tsize, tsize * 0.525);
}
/**
* Will the text fit in the box at the given text size?
* @param txt text string to fit
* @param x x coordinate of text box
* @param y y coordinate of text box
* @param w width of text box
* @param h height of text box
* @param tsize text size to test for string fit
* @param leading vertical space between lines in px
* @return true if text will overflow
*/
boolean isTextOverflow(String txt, float x, float y, float w, float h, float tsize, float leading) {
String[] words;
float xoffset = x;
float yoffset = y + tsize;
pushStyle();
textSize(tsize);
float spacing = textWidth(" ");
textLeading(leading);
words = split(txt, " ");
// loop through words, move to next line if a word won't fit
for (String word : words) {
if (xoffset + textWidth(word) > x + w) {
xoffset = x;
yoffset = yoffset + tsize + leading;
// stopping printing lines beyond the bottom of the box
if (yoffset > y + h - tsize - leading) {
popStyle();
return true;
}
}
////preview layouts
//fill(220);
//text(word, xoffset, yoffset);
xoffset = xoffset + spacing + textWidth(word);
}
popStyle();
return false;
}
Now, if you want to call it like text(), wrap your while()
loop in another function.
/**
* Display text fit into the box -- if needed, shrink textSize repeatedly until it fits.
* Does not display if text shrinks to textSize(2) without fitting.
* @param txt text string to fit
* @param x x coordinate of text box
* @param y y coordinate of text box
* @param w width of text box
* @param h height of text box
* @param maxTextSize maximum text size to fit
*/
void textFit(String txt, float x, float y, float w, float h, float maxTextSize) {
float tsize = maxTextSize;
while(tsize > 2 && isTextOverflow(txt, x, y, w, h, tsize)) {
tsize--;
}
if(tsize>2) {
println(tsize);
pushStyle();
textSize(tsize);
text(txt, x, y, w, h);
popStyle();
}
}
Now you can just call textFit()! For example, here is a sketch that prints some lorem ipsum text into the full window.
String txt = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. FIN.";
void setup() {
size(600, 600);
stroke(0);
surface.setResizable(true);
}
void draw() {
background(255);
fill(0);
textFit(txt, 0, 0, width, height, 60);
}
The window is resizeable, so drag the corner around and watch the text reflow into the window!