Centering text lines top and bottom in a canvas

I can vertically center 1 or 2 lines of text in a canvas pretty accurately, but when it gets to 3 or 4 (or 5?) I can’t seem to get the right recipe to vertically center it.
Here is what I’m using. The 3rd line is in the ballpark but not quite right. 4 tends to run off the top of the canvas.

if ubound(numLines) = 0 then // there is only 1 line stringHeight = (g.height + g.TextAscent)/2 elseif ubound(numLines) = 1 then // there is 2 lines stringHeight = (g.height + g.TextAscent)/2 - g.TextAscent elseif ubound(numLines) = 2 then // there is 3 lines stringHeight = (g.height + g.TextAscent)/2 - 1.5 * g.TextAscent end if

TextAscent isn’t the correct property, it measures from the baseline to the top of the tallest character. StringHeight measures the whole height of the string. Also consider that each line might be a different height.

Perhaps this might be closer? (I haven’t tested it, post-editor code)

dim dHeight as Double

for i as Integer = 0 to numLines.Ubound
  dim sThis as String = numLines(i)
  dHeight = dHeight + g.StringHeight(sThis, g.Width)

next

// dHeight is now the height of all the lines.

You could join and then measure the whole string to find the height and then draw based on the top+textascent…

[code]Dim lines() As String=Array(“line1”,“LINE2”,"----",“line3”)

Dim joined As String=Join(lines,Chr(13))

Dim firstlineY As Double=g.Height/2-g.StringHeight(joined,g.Width)/2+g.TextAscent

g.DrawString(joined,g.Width/2-g.StringWidth(joined)/2,firstlineY)

[/code]

and if you also wanted to center each line horizontally…

For i As Integer=0 To lines.Ubound g.DrawString(lines(i) , g.Width/2-g.StringWidth(lines(i))/2 , firstlineY+g.TextHeight*i) next

Tim,

forgot to note that “numLines” is a string array populated by splitting “myText” by a marker | where the lines are to break.
so I use numLines = numLines = split(myText,"|") just to figure out how many lines there are. So I really need to join the lines first. they’re already joined in myText.
Would it be dHeight = dHeight + g.StringHeight(myText, g.width) and that would get me the proper line height? Once I do get the proper line height, how do I properly calculate by the number of lines in myText? Is it just a straight dHeight * numLines ?

Jim,

That code might come in handy when I eventually allow each line it to be centered as well. Thanks!
Was also wondering if it were possible to auto-wrap text when painting into a canvas.

If all the text is the same font and font size then

dHeight=g.TextHeight * numLines

and if the is the case then to center should be something like this (off the top of my head)

dHeight=g.TextHeight * (eachLine.ubound+1) // assume you split the text
yTop = yCenter - (dHeight/2) + g.textAscent // where YCenter is the point you want to center the text on Vertically
for i=0 to eachLine.ubound // assume you split the text
g.drawstring eachLine(i),x,yTop
yTop=yTop+g.textHeight
next i

thanks. I’ll play around with that. getting centered vertically will be the key.

I’m going to break out your questions one at a time just so it’s easier to answer.

The original calculation I offered adds the individual line heights (they can be different depending on the characters in the line!) so that at the end of the for loop dHeight is the total correct height for the block of myText.

The example I wrote calculates the whole block of text height. I had written my example assuming numLines was your array of strings to write. If you want each individual line, draw the string after the dHeight is calculated for that line within the loop.

No, you can’t assume that each line height is the same. A line’s height is affected by the characters in the line. Letters like y and j extend below the baseline which is why you can’t use TextAscent for this calculation. Letters like h and i are taller than n, m, c, v. I’m not a languages expert, but I wouldn’t trust that a line would always have letters that are tall.
( @Michel Bujardet is probably dying inside reading my butchering of this).

I would recommend calculating and drawing each line individually. This will make it easier for you to implement horizontal alignment later down the road. Insert a DrawString underneath the dHeight calculation in my example loop to get started down that path :slight_smile:

if the TextFont is the same the Height is the same… TextHeight is from top to bottom (below baseline), TextAscent is from top to baseline… but the metrics of HEIGHT are constant which is why there is a TextHeight property. Width however is a totally different story depending on the font

Ah, I stand corrected! Thanks for the update :slight_smile: