Search code examples
javascripttypescriptfabricjs

FabricJS fixed size TextBox with dynamic fontsIze (shrink text to fit size)


How can I fix the size of a TextBox and dynamically decrease the fontSize if the text gets to large for the TextBox? Yes a similar question exists here but it only works for one line of text.

I want to achieve exactly that: (example from the imgflip meme editor)
enter image description here

I have tried following approach:

let text = new fabric.Textbox(box.text, {
    top: box.top,
    left: box.left,
    width: box.width,
});
if (text.width > box.width) {
    text.fontSize *= box.width / (text.width + 1);
    text.width = box.width;
}
if (text.height > box.height) {
    text.fontSize *= box.height / (text.height + 1);
    text.height = box.height;
}
canvas.add(text);

This way the fontSize decreases by the ratio of which the width or height of the textbox changed. But this causes the text to get extremely small sometimes because the text won't get wrapped as nicely as it could. The fontSize and the wrapping need to find an optimum somehow. Any ideas? Thanks!


Solution

  • I actually found a solution. Just in case someone has the same problem.

    Adjusting the font size for the width works well with my original code:

    if (text.width > box.width) {
        text.fontSize *= box.width / (text.width + 1);
        text.width = box.width;
    }
    

    This will only adjust the font size for really long words because the Textbox automatically wraps the text. But this wrapping causes the height to shrink too much with my original code. In order to take the wrapping into consideration I ended up gradually decreasing the font size and recalculating the text wrapping by calling canvas.renderAll() every time:

    while (text.height > box.height && text.fontSize > 12) {
        text.fontSize--;
        canvas.renderAll();
    }
    

    This might be inefficient but it served my use case.