processing / p5.js

p5.js is a client-side JS platform that empowers artists, designers, students, and anyone to learn to code and express themselves creatively on the web. It is based on the core principles of Processing. http://twitter.com/p5xjs —
http://p5js.org/
GNU Lesser General Public License v2.1
21.59k stars 3.31k forks source link

textBounds on multiline text breaks if global textLeading does not match the provided font size #7147

Open davepagurek opened 2 months ago

davepagurek commented 2 months ago

Most appropriate sub-area of p5.js?

p5.js version

1.9.4

Web browser and version

Firefox, Chrome

Operating system

MacOS

Steps to reproduce this

Steps:

  1. Load a font
  2. Measure the textBounds() of multiline text, passing in a larger font size than the default (e.g. 50)
  3. The resulting box does not cover the text

Snippet:

In this example, I'm setting the font size on a graphic, so the main canvas still has the default text size:

let message
let fnt
let g

function tightBound() {
  const bbox = fnt.textBounds(message.value(), 0, 0,g.textSize());
  g.noFill()
  g.rectMode(CENTER)

  g.rect(0,0,bbox.w,bbox.h)
  console.log(message.value())
}

function preload() {
fnt = loadFont("https://fonts.gstatic.com/s/opensans/v40/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsg-1y4nY1M2xLER.ttf")
}

function setup() {

  createCanvas(windowWidth,windowHeight);
  g = createGraphics(width, height)
message = createElement('textarea');
  message.value('test\nanother')
  message.position(20, 20);
  message.size(300, 200);
  g.textAlign(CENTER,CENTER)
}

function draw() {
  g.background(220);
  g.push()
  g.translate(width/2,height/2)
      g.textFont(fnt);
  g.textSize(50)
  g.text(message.value(),0,0)
  tightBound()
  g.pop()
  image(g, 0, 0)
}

Result: image

Expected: image

Cause

In the implementation of textBounds, it gets the text leading from the main instance's renderer: https://github.com/processing/p5.js/blob/6781c1d1db83cb8beefbca74a9473e546b4f1e1f/src/typography/p5.Font.js#L209

I'm not sure the best way to fix this; if you're drawing text onto a different renderer like a graphic, there's not a deterministic way to figure out which renderer to use ahead of time. The best option might be to let you pass that value in, which might require a change to the arguments to this function to not have an overwhelmingly long parameter list.

dhowe commented 2 months ago

Thanks @davepagurek -- this is a known-issue discussed in https://github.com/processing/p5.js/pull/6967 The fix, which will hopefully be included in v2.0, is to accept textLeading (and all other relevant params) as part of options