Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to vertically center text? #1015

Closed
mgroth0 opened this issue May 28, 2021 · 7 comments
Closed

How to vertically center text? #1015

mgroth0 opened this issue May 28, 2021 · 7 comments

Comments

@mgroth0
Copy link

mgroth0 commented May 28, 2021

First of all to the creators/contributors, thanks so much for a great library.

I have create a GenericStyledArea that incorporates both text (using the default TextExt) and custom nodes. For example, one custom node renders some math:

Screen Shot 2021-05-28 at 4 49 55 AM

Problem is they are not vertically aligned.

The rendered math is a Canvas. If it were translated up or down, this introduces possible clipping. So I think the TextExt needs to be vertically centered, possible with an additional offset as well.

However, using the translateYProperty for the TextExt would also possibly cause clipping, unless it were bound to the height of the ParagraphBox. Even if it were bound to the height of the ParagraphBox, it would also need to consider how many line-wraps there are. This is way more complicated than setting the alignmentProperty of an HBox, for example.

Also, the vertical alighment method needs to be segment by segment, and generalize to multi-line cases.

I couldn't find any vertical alignment property and a search for "vertical alignment" here comes up empty, so maybe not thinking about this correctly or maybe I'm searching the wrong terms.

Any ideas?

Here's a more extreme case:
Screen Shot 2021-05-28 at 5 09 36 AM

@Jugen
Copy link
Collaborator

Jugen commented May 28, 2021

First of all: VERY NICE !!!
Unfortunately I don't have an answer off the top of my head, but here is what I suggest.

Since RichTextFX basically just uses a JavaFX TextFlow control for the layout of nodes (in your case Text & Canvas) try experimenting with a plain TextFlow to get the alignment you want (in various scenarios if need be). Once to you get that right, then you should be able to apply the same technique to RichTextFX.

If you get what you want with TextFlow but can't seem to get the same results with RichTextFX then post your TextFlow findings here and I'll try and help if I can.

@Jugen
Copy link
Collaborator

Jugen commented May 28, 2021

Also try looking here in the Wiki, maybe this helps ....

@mgroth0
Copy link
Author

mgroth0 commented Jun 5, 2021

Thanks @Jugen!

Looking into this, I found this JDK bug report. According to that, the best way to solve this issue seems to be by overriding TextFlow::getBaselineOffset.

From looking around the code I've learned that RichTextFX subclasses TextFlow as TextFlowExt and ParagraphText. The ParagraphText constructed as a ParagraphBox is constructed. And the ParagraphBox is constructed inside the private method GenericStyledArea::createCell.

Therefore, subclassing ParagraphText seems like it would involve adapting a huge amount of internal richtextfx code. I think I might be up for it, but it would be awesome if someone with more experience could help me with a few step by step instructions on how best to do this.

@Jugen
Copy link
Collaborator

Jugen commented Jun 6, 2021

Hi @mgroth0, ummm .... I think you misread the solution the JDK bug report offers ?

It's not the TextFlow's baseline offset that gets overridden it's your Canvas getBaselineOffset that you need to override.

Apparently something like the following (according to Christian) will roughly center the canvas on the line:

public double getBaselineOffset()
{
    return getHeight() * 0.75;
}

Note that according to Felipe:

To center it at the middle of the line I think the math is: imageHeight/2 + textBaseline - textHeight/2 (where textBaseline and textHeight can be extract from a text node).

@mgroth0
Copy link
Author

mgroth0 commented Jun 6, 2021

Excellent @Jugen, you are completely right!

This was from the height * 0.75 approach.

Screen Shot 2021-06-06 at 12 37 12 PM

I understand if I need even more precision (for example to try to line up "sum of squares" with the equals sign on the second example) I can try Felipe's approach. However, I'm not sure of the best way to get textBaseline and textHeight. Especially since my textflow has multiple types of segments with different heights, and some are text and some are custom nodes.

@Jugen
Copy link
Collaborator

Jugen commented Jun 6, 2021

Hey, that's great :-)

Okay, so I have two suggestions on how to go about this:

  1. The parent of Canvas is TextFlow so just grab the first Text item from its children:
public double getBaselineOffset()
{
    // Hopefully the canvas is a child of TextFlow at this point ?
    // Change, if you may want to find a more specific Text node ....
    Optional<Text> text = getParent().getChildrenUnmodifiable().stream()
            .filter( n -> n instanceof Text )
            .map( n -> (Text) n )
            .findFirst();

    if ( text.isPresent() )
    {
        double txtBase = text.get().getBaselineOffset();
        double txtHeight = text.get().getLayoutBounds().getHeight();
        // This is my own untested calculation and probably isn't right ?
        return txtBase + (txtHeight - txtBase)/2 - getHeight() / 2;
    }

    return getHeight() * 0.75;
}
  1. If the Canvas doesn't have a parent when getBaselineOffset() is invoked then I think you'll need to create a local dummy Text object with the same font characteristics as what is being displayed and use that.

@Jugen
Copy link
Collaborator

Jugen commented Jul 21, 2021

@mgroth0 hope you came right with this .... please reopen if not.

@Jugen Jugen closed this as completed Jul 21, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants