How to properly vertically align text?

Hello,

I've been working on an analogue watch which has a combination of ticks and only the digits 12,3, 6 and 9 which are all at the edges of the clock screen.

I am aware of the fact that text is drawn from the top left of the position you specify and that you have to adjust by half the font height; so why is it that the 3 and 9 work perfectly (for all fonts):-

// lHeight is the font height of the largeFont divided by 2
dc.drawText(screenWidth-3, (screenHeight/2)-lHeight, largeFont, "3", Graphics.TEXT_JUSTIFY_RIGHT);
dc.drawText(3, (screenHeight/2)-lHeight, largeFont, "9", Graphics.TEXT_JUSTIFY_LEFT); 

But the 6 and 12 does not, and vary inconsistently across devices.  Sometimes they are too high, or too low, or a combination of both...

dc.drawText((screenWidth/2), (0-lHeight*0.5), largeFont, "12", Graphics.TEXT_JUSTIFY_CENTER);
dc.drawText(screenWidth/2, (screenHeight-lHeight*2), largeFont, "6", Graphics.TEXT_JUSTIFY_CENTER);

Is there something else, like a trick that I'm missing?  Please advise and thanks in advance.

Regards

  • If you are using number fonts, on some devices there is white space above and below them.  Is that what you're seeing?.  Maybe screen shots point out what you see.

    Also to align a font in the middle, you can use Gfx.TEXT_JUSTIFY_VCENTER (Gfx.TEXT_JUSTIFY_CENTER|Gfx.TEXT_JUSTIFY_VCENTER)

  • Here's a survey for you:

    $ egrep -iR --include=*.mc 'drawText.*"\s*(3|6|9|12)\s*"'|sed 's/.*dc.draw/dc.draw/'|sort -u
    dc.drawText(0, height_screen/2, Gfx.FONT_MEDIUM, " 9",Gfx.TEXT_JUSTIFY_LEFT + Gfx.TEXT_JUSTIFY_VCENTER);
    dc.drawText(16, (height / 2) - 17, Gfx.FONT_SYSTEM_LARGE   , "9", Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(16, (height / 2) - 18, font1, "9", Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(16, (height / 2) - 20, font1, "9", Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(16, (height / 2) - 22, font1, "9", Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(16, (height / 2) - 22, Gfx.FONT_SYSTEM_LARGE   , "9", Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(16, (height / 2) - 26, font1, "9", Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(1,j,iconFont,"3",Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(inboard+4,width/2-fontheight/2 -2,Gfx.FONT_NUMBER_MILD,"3",Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText(inboard+5,width/2-fontheight/2 -2,Gfx.FONT_NUMBER_MILD,"9",Gfx.TEXT_JUSTIFY_LEFT);
    dc.drawText((width * 0.1), (height * 0.42), Graphics.FONT_MEDIUM, "9", Graphics.TEXT_JUSTIFY_CENTER);
    dc.drawText((width * 0.9), (height * 0.42), Graphics.FONT_MEDIUM, "3", Graphics.TEXT_JUSTIFY_CENTER);
    dc.drawText(width - 16, (height / 2) - 17, Gfx.FONT_SYSTEM_LARGE  , "3", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText(width - 16, (height / 2) - 18, font1, "3", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText(width - 16, (height / 2) - 20, font1, "3", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText(width - 16, (height / 2) - 22, font1, "3", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText(width - 16, (height / 2) - 22, Gfx.FONT_SYSTEM_LARGE  , "3", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText(width - 16, (height / 2) - 26, font1, "3", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText((width / 2), 0, font1, "12", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText((width / 2), 10, Gfx.FONT_SYSTEM_LARGE   , "12", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText((width / 2), -12, font1, "12", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText((width / 2), 15, font1, "12", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText((width / 2), -3, Gfx.FONT_SYSTEM_LARGE   , "12", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText((width / 2), 5, font1, "12", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText((width / 2), (height * 0.05), Graphics.FONT_LARGE, "12", Graphics.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 30, Gfx.FONT_SYSTEM_LARGE   , "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 33, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 35, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 39, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 41, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 45, Gfx.FONT_SYSTEM_LARGE   , "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 48, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 50, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 52, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width / 2, height - 54, font1, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText((width/2),inboard ,Gfx.FONT_NUMBER_MILD,"12",Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width/2,width-fontheight-2-inboard,Gfx.FONT_NUMBER_MILD,"6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width-inboard-6,width/2-fontheight/2-2,Gfx.FONT_NUMBER_MILD,"3", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText(width-inboard-6,width/2-fontheight/2-2,Gfx.FONT_NUMBER_MILD,"9", Gfx.TEXT_JUSTIFY_RIGHT);
    dc.drawText((width_screen/2), 0, Gfx.FONT_MEDIUM, "12",Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width_screen/2, height_screen-30, Gfx.FONT_MEDIUM, "12", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width_screen/2, height_screen-30, Gfx.FONT_MEDIUM, "6", Gfx.TEXT_JUSTIFY_CENTER);
    dc.drawText(width_screen, height_screen/2, Gfx.FONT_MEDIUM, "3 ", Gfx.TEXT_JUSTIFY_RIGHT + Gfx.TEXT_JUSTIFY_VCENTER);
    dc.drawText(width_screen, height_screen/2, Gfx.FONT_MEDIUM, "6 ", Gfx.TEXT_JUSTIFY_RIGHT + Gfx.TEXT_JUSTIFY_VCENTER);

  • The TEXT_JUSTIFY_VCENTER I didn't know about before, so thanks - it helped.  By adding a separate background colour for the fonts, I was able to tell which ones have the space above and below the fonts - but I understand that fontHeight does not include the spaces anyway, so I will still need to do some adjustments.  Surprisingly the results below were for just one font - FONT_SYSTEM_NUMBER_MILD:

    Ref Family Font Height/2 Font Space?
    2402404040 D2Tm Charlie 13 n
    2402404033 Approach® S60 19 y
    2151804040 Forerunner® 735xt 16 y
    2182183030 Captain Marvel 20 y
    2602603535 First Avenger 24 y
    2182183636 fēnix® 5S 12 n
    2602604040 fēnix® 6 30 y
    1482054033 vívoactive® HR 14 y
    2802804040 fēnix® 6X Pro / 6X Sapphire / 6X Pro Solar 32 y
    3903906060 VenuTm 36 y

    My plan is to isolate those families with the spaces and those without and treat them accordingly - but I would then have to estimate a font height of around 26 or less to separate them.  Not the most accurate but I don't know what else to do.

  • dc.getFontHight() does include the white space above and below, This is most obvious with some number fonts.

    Try this:

    var font=Gfx.FONT_NUMBER_MILD;

    var fh=dc.getFontHeight(font);

    var y=(whatever)

    dc.drawText(100,y,font,"12",Gfx.TEXT_JUSTIFY_CENTER);

    y+=fh;

    dc.drawText(100,y,font,"34",Gfx.TEXT_JUSTIFY_CENTER);

  • Thanks.  I assumed y should be where I wanted the text (so 12 would be 0 and 6 would be screenHeight) but I couldn't get it to work that way.  Is "y+=fh" correct or am i missing something?

    But I did approach it using the font space and font height (with another setting for fenix 6 and fenix 6 pro) and got it to work though.

    I wanted to add the code of how I did it, but for some reason I'm not allowed to add it - maybe it was too much?

  • largeFont = Graphics.FONT_SYSTEM_NUMBER_MILD;

    lHeight = dc.getFontHeight(largeFont)/2;

    if (screenWidth == screenHeight && (screenWidth == 218 || screenWidth == 240) &&
    dc.getFontHeight(largeFont) <= 26) {
    fontSpace = false;
    } else {
    fontSpace = true;
    }

    partNumber = System.getDeviceSettings().partNumber;
    if (partNumber == "006-B3289-00") {
    deviceName = "fenix6";
    } else if (partNumber == "006-B3290-00") {
    deviceName = "fenix6pro";
    } else {
    deviceName = "other";
    }

    if (deviceName == "fenix6" || deviceName == "fenix6pro") {
    dc.drawText((screenWidth/2), (0+lHeight*0.5), largeFont, "12", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    dc.drawText(screenWidth/2, (screenHeight-lHeight*0.5), largeFont, "6", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    } else if (fontSpace == false) {
    dc.drawText((screenWidth/2), (0+lHeight), largeFont, "12", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    dc.drawText(screenWidth/2, (screenHeight-lHeight), largeFont, "6", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    } else {
    dc.drawText((screenWidth/2), (0+lHeight*0.65), largeFont, "12", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    dc.drawText(screenWidth/2, (screenHeight-lHeight*0.65), largeFont, "6", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    }

  • y is the row, so start it with say y=30;

    y+=fh added the font height to that (it's short for y=y+fh;)

    So the second line is spaced "fh" from the first.

    Here's a screen from one of my test apps.  It's displaying the two largest number fonts.  The 1st line is the "y" for the drawText, and the second line is that plus the font height (which you see in a small number to the right - 94.  You can plainly see the font height includes the white space above and below.

    Here's the exact same thing on a fenix5 - notice no white space.

  • Thanks for the further clarification.  Forgive me, but I'm still not getting it to work.  I have a few questions:-

    1.  The text is drawn starting from the top left of the "y" specified, so from the images above it appears that the code is instructing the text to be drawn below the 30 line regardless of the font height/spaces; but as in most cases we the devs know where we want it to fit in the first place (in the middle of the line) wouldn't it be best to start with where we want it fitted and move from there?  As we won't always be able to tell where the top line should be.

    2.  Does your example preclude knowing which devices have the font spaces before writing code to place them?

    Edited to add: I want the 12 to be drawn from below the 0 line and the 6 from on top of the screenHeight line.

  • The text can be drawn starting at the top left at y, but doesn't have to be,  Gfx.TEXT_JUSTIFY_VCENTER says y is the vertical center of the font.

    In the images I posted, "y" is the line drawn under Num1 (no VCENTER here).  The line near the middle of the screen is that y+ the height of that font (what you see here are FONT_NUMBER_THAI_HOT (the top one), and FONT_NUMBER_HOT.

    It's easy to see that the white space above and below the digits is included in the font height on the 945, and there is no white space on the 945

    You may have to play with these numbers, but lets say

    font=Gfx.FONT_NUMBER_MILD;

    width=screen width

    height=screen height

    fontHeight= the height of "font"

    off=offset from top or bottom of screen for the numbers

    dc.drawText(width/2,off,font,"1",Gfx.TEXT_JUSTIFY_CENTER);

    dc.drawText(width/2,off+fontHeight,font,"2",Gfx.TEXT_JUSTIFY_CENTER);

    dc.drawText,width/2,height-off-fontHeight,font,"6",Gfx.TEXT_JUSTIFY_CENTER);

    so you'll get

         1

         2

         6

    for 3 and 9, I'd use TEXT_JUSTIFY_VCENTER like this

    dc.drawText(off,height/2,font,"9",Gfx.TEXT_JUSTIFY_VCENTER|Gfx.TEXTJUSTIFY_LEFT);

    dc.drawText(width-off,height/2,font,"3",Gfx.TEXT_JUSTIFY_VCENTER|Gfx.TEXTJUSTIFY_RIGHT)

    ;

    Now, based on the device, the spacing between the 1 and 2 may off.  Few things you can do -

    1) Adjust fontHeight to make things display better, but this would be device specific

    2) Instead of a FONT_NUMBER, use a non-number (say FONT_SMALL) where the white space issue between devices isn't that great.

    3) Use custom fonts

  • Apologies for the late response.

    I've only just had a chance to look at your very detailed explanation - thanks so much.  I agree with what you're basically saying that there is no exact science regarding getting the position right, and you have to "play with the numbers" to get things right.

    I would love to use a non-number font, but in this particular project the numbers need to be big and the LARGE is too small, so I will settle with this for the time being:- (largeFont is Graphics.FONT_SYSTEM_NUMBER_MILD)

    if (deviceName == "fenix6" || deviceName == "fenix6pro") {
        	dc.drawText((screenWidth/2), 0, largeFont, "12", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    	    dc.drawText(screenWidth/2, screenHeight, largeFont, "6", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);	
        } else if (fontSpace == false) {
        	dc.drawText((screenWidth/2), (0+lHeight), largeFont, "12", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
        	dc.drawText(screenWidth/2, (screenHeight-lHeight), largeFont, "6", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
        } else {
        	dc.drawText((screenWidth/2), (0+lHeight*0.65), largeFont, "12", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);
    	    dc.drawText(screenWidth/2, (screenHeight-lHeight*0.65), largeFont, "6", Graphics.TEXT_JUSTIFY_CENTER|Graphics.TEXT_JUSTIFY_VCENTER);   
        }    

    I've never had such issues with the 3 and 9, as they have always worked perfectly.