12-09-2017 19:59
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
12-09-2017 19:59
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I'm trying to set up a view so that there is a set of large numbers followed by a set of small numbers. Think something like:
123.45
The problem is, if I use two <text> elements (one with a large size, one with a small size) and use absolute positioning, I can end up with the following scenarios, neither of which are desirable:
12 .34 (too much space between numbers)
12.34 (too much white space on the left)
Or worse, if the large text were to have four digits (e.g. 1234.56), they would begin to overlap the small ones. Therefore, I would like the right <text> block to be attached to the right side of the left <text> block.
I know that what I'm looking for can be achieved, as it has been accomplished by the built-in timer app. The small text on the right is attached to the right so that the entire timer is centered, rather than being centered on the decimal point. (Pictured below.)
I have investigated using the .width attribute of the left text box to position the one on the right; however, it is always 0 unless I set it manually.
How can I achieve this?
Answered! Go to the Best Answer.
Accepted Solutions
12-10-2017 13:13
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
12-10-2017 13:13
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Okay, I found a solution. It's somewhat hacky, but it works to perfectly align the two fields.
Essentially, what it does is set the initial large-text width to 1 and ensure that overflowing text is clipped. Then, when the large-text is updated, we decrease the width of the large-text box to make it as small as possible. Then, we increase the width of the large-text box until it's no longer overflowing. At this point, we can use the x and width properties to set the small text's x property.
First, the CSS setup:
#large-text { text-overflow: clip; width: 1; }
Then, the text code, that has to run every time the contents of #large-text change:
let $largeText = document.getElementById("large-text");
let $smallText = document.getElementById("small-text");
// Reduce the width of the text field until text overflows while (!$largeText.textOverflowing) { $largeText.width--; } // Increase the width of the text field until text is no longer overflowing while ($largeText.textOverflowing) { $largeText.width++; }
$smallText.x = $largeText.x + $largeText.width;
I don't know if this has any measurable effect on battery life, but it seems to have no major performance impact, at least.
12-10-2017 03:24
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

12-10-2017 03:24
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Use text-anchor="end" for the big one and text-anchor="start" for the small ones.

12-10-2017 09:49
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
12-10-2017 09:49
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Thanks for the reply!
Unfortunately, that won't work. This results in the second "undesirable" scenario I outlined in my original post. If you imagine the watch face outlined by the | below...
| 1.23 |
|12.34 |
1|23.45 |
The large text with text-anchor:end overflows to the left while there's still lots of screen real estate left. The way it should work is like this:
|1.23 |
|12.34 |
|123.45 |
Which means that the left boundary of the small text needs to move to the right as the large text contains more characters.

12-10-2017 11:53
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


12-10-2017 11:53
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Here's an ugly suggestion: use a fixed-width font and pad the first field with spaces before the number.
Alternatively, use a fixed-width font and work out the width of each character, then vary the element's width attribute depending on the number of characters to be displayed.
Yuck?
Gondwana Software
12-10-2017 12:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
12-10-2017 12:01
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Hmm... kind of hacky, but not a terrible idea. In fact, I'm wondering if that's how the built-in Timer app I showed in my original post worked. The 1s seem to have the same width as the 8, so maybe they used a calculation related to that.
Definitely open to other suggestions but I will use that idea for now. Thanks!

12-10-2017 12:12
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

12-10-2017 12:12
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I feel like there must be some more elegant solution.
Have you looked into:
- display-align: (before, center, after)
Or a G container with one element scaled?

12-10-2017 12:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
12-10-2017 12:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
It looks like display-align is only for vertical alignment in a <textarea>.
I think the g-container might have more possibilities. I'm still looking into it, but it seems like you can only scale individual elements, which would still mean that the small-text element would need to be positioned based on the large-text element (even if it were scaled using a g-container). I don't see any way to scale down only part of a single text element (i.e. the small-text portion).

12-10-2017 13:13
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
12-10-2017 13:13
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
Okay, I found a solution. It's somewhat hacky, but it works to perfectly align the two fields.
Essentially, what it does is set the initial large-text width to 1 and ensure that overflowing text is clipped. Then, when the large-text is updated, we decrease the width of the large-text box to make it as small as possible. Then, we increase the width of the large-text box until it's no longer overflowing. At this point, we can use the x and width properties to set the small text's x property.
First, the CSS setup:
#large-text { text-overflow: clip; width: 1; }
Then, the text code, that has to run every time the contents of #large-text change:
let $largeText = document.getElementById("large-text");
let $smallText = document.getElementById("small-text");
// Reduce the width of the text field until text overflows while (!$largeText.textOverflowing) { $largeText.width--; } // Increase the width of the text field until text is no longer overflowing while ($largeText.textOverflowing) { $largeText.width++; }
$smallText.x = $largeText.x + $largeText.width;
I don't know if this has any measurable effect on battery life, but it seems to have no major performance impact, at least.
12-10-2017 22:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


12-10-2017 22:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Very cunning; definitely thinking outside the (text) box.
Gondwana Software

01-15-2018 14:19 - edited 01-15-2018 14:21
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-15-2018 14:19 - edited 01-15-2018 14:21
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Isn't the following a less 'hacky' way to solve the problem?
styles.css
.textright { font-family: Seville-Regular; font-size: 80; fill: yellow; text-anchor: end } .textleft { font-family: Seville-Regular; font-size: 35; fill: white; text-anchor: start }
index.gui
<svg> <text class="textright" x="85%-2" y="50%" >9999.99</text> <text class="textleft" x="85%+2" y="50%" >mi</text> </svg>
That's not to say the overflow method of deducing width doesn't have a place in the programming arsenal in the absence of the SDK providing width. For height that is a different matter of course.

01-15-2018 14:57
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-15-2018 14:57
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@SunsetRunner That only works if one of your text fields (in your example, textleft) is fixed-width. Otherwise, there will be whitespace left over when the text becomes narrower, or will overflow if it becomes wider. In my case, both fields are variable width, so this wouldn't work.
I can see its application to your specific example, though (using a fixed "unit" field), so hopefully it helps someone who has that use case.
Honestly, I am still looking for a more performant way of doing this, but haven't come across one yet. I've been meaning to look into Bounded and DOMRect but haven't yet.

01-15-2018 15:06 - edited 01-15-2018 15:08
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-15-2018 15:06 - edited 01-15-2018 15:08
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@SunsetRunner:
There are two text-anchors: end and start
The end anchor effectively makes a right aligned field. The start anchor is for left aligned.
Your large text would be anchored end, small text anchored start. I have it working.
working with the following gui
<svg> <text class="textright" x="85%-2" y="75" >99.99</text> <text class="textleft" x="85%+2" y="75" >mi</text> <text class="textright" x="85%-2" y="155" >999.99</text> <text class="textleft" x="85%+2" y="155" >km</text> <text class="textright" x="85%-2" y="235" >1999.99</text> <text class="textleft" x="85%+2" y="235" >m</text> </svg>

01-15-2018 15:25
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-15-2018 15:25
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@SunsetRunner Actually, that image illustrates exactly why it doesn't work if the second field is dynamic.
Imagine the right-hand field is a number, like in my initial example. Something like .1 would be be like "m", with some whitespace to the right. .11 would be more like "mi", with less white space. .111 would be more like "km", hugging close to the right. Once you transition into .1111 or .11111, it's going to flow off the screen.

01-15-2018 23:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

SunsetRunner
01-15-2018 23:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
@SunsetRunner Reread one of your earlier posts .... my misunderstanding. You are centering the two combined fields. Of course you are right.

01-16-2018 00:45
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post


01-16-2018 00:45
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I may need to do something similar. My case could be more demanding because it's for image captions, which could vary from 0 to say 1,000 px.
Using @SunsetRunner's cunning solution verbatim could require 1,000 iterations, so I'll modify it by using a binary search. This should cut down the maximum number of iterations to 10. It's still kludgy but should perform better.
Gondwana Software

01-16-2018 06:24
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-16-2018 06:24
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
@SunsetRunner wrote:
I have investigated using the .width attribute of the left text box to position the one on the right; however, it is always 0 unless I set it manually.
What about using the bounding box to get the width? I've got text I'm trying to center between two other pieces of text. Based on the bounding box, I calculate a center point, and use that. Could do something similar:
txtSteps.getBBox().width
01-17-2018 02:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

01-17-2018 02:55
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Thanks @bhwolf , this is the exact solution I was looking for to centre align image + text in the same line (same Y cords).

07-08-2018 07:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

07-08-2018 07:29
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
I don't suppose there is an example of this somewhere. i looked through github and didn't see it used...but there are a bunch in there and I may have missed it.
Thanks

08-25-2019 11:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

08-25-2019 11:31
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
- Who Voted for this post?
@SunsetRunner How about this solution
const ltbox = largeText.getBBox();
smallText.x =ltbox.width+3;
3 = the space you want between the text.
10-27-2021 13:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post

10-27-2021 13:56
- Mark as New
- Bookmark
- Subscribe
- Permalink
- Report this post
Thank you Patricio!

