With TextLabels, there is currently no property or API to get the actual “TextSize” of a TextLabel when the property TextScaled is enabled.
Why is this an issue?
The TextWrapped property is force enabled with TextScaled, so now instead of just having 1 row of text (A simple TextLabel.TextBounds.Y), you could have multiple rows!!
Okay but does it look good?
The popping out is the viewport updating the TextBounds before I manually update TextSize
This code block provided below is a quick way to get an “approximated” TextSize. From my testing it is nearly perfect, only occasionally being a pixel off.
local Params = Instance.new("GetTextBoundsParams")
function getTextBoundParams(TextLabel, TextSize)
Params.Size = TextSize
Params.Font = TextLabel.FontFace
Params.Width = math.huge
Params.Text = TextLabel.Text
Params.RichText = TextLabel.RichText
return Params
end
function GetTextSize(TextLabel)
if TextLabel.TextScaled then
local smallSample, bigSample = 1, 100
local lower = TextService:GetTextBoundsAsync(getTextBoundParams(smallSample))
local upper = TextService:GetTextBoundsAsync(getTextBoundParams(bigSample))
local verticalBound = math.floor(TextLabel.TextBounds.Y)
local volume = math.floor(TextLabel.TextBounds.X) * verticalBound
local lowerVolume = (lower.X * lower.Y) / volume -- Scalar to compare TextSize 1 TextBounds vs the actual TextBounds of the TextLabel
local upperVolume = (upper.X * upper.Y) / volume -- Same as lowerVolme but TextSize 100
local s1 = math.sqrt(lowerVolume)
local s2 = math.sqrt(upperVolume)
-- Linearly interpolate the volumes by the slope to find the "perfect" volume along the slope.
local textSizeApproximation = smallSample + (1 - s1) * (bigSample - smallSample) / (s2 - s1)
local rows = math.round(verticalBound / textSizeApproximation)
return math.floor(verticalBound / rows)
end
return TextLabel.TextSize
end
Let me know if this has helped you at all and feel free to pitch in!
Hi, MasterDevelopments here, so I wanted to make an honest answer., I feel like this is very useful in MY opinion. The code is great, nothing there I don’t like or think needs major changing, but some suggestions.
Make it a Module. A script is fine, but a module is reusable
I find this useful, but please, and by please, I mean please recycle your params. its unoptimized
Don’t use self unless it’s an OOP or metatable, either then that, please do noit’sits annoying.
Oh, my bad on number 2, In the video you kept creating params when you were changing your viewport size, but silly me, anyways, I refactored your code, here you are:
local TextService = game:GetService("TextService")
local TextSizeEstimator = {}
TextSizeEstimator.__index = TextSizeEstimator
function TextSizeEstimator.new(label)
assert(label:IsA("TextLabel"), "TextSizeEstimator expects a TextLabel")
local self = setmetatable({}, TextSizeEstimator)
self.Label = label
self.Params = Instance.new("GetTextBoundsParams")
self.Params.Font = label.FontFace
self.Params.Width = math.huge
self.Params.Text = label.Text
self.Params.RichText = label.RichText
return self
end
function TextSizeEstimator:GetBounds(size)
self.Params.Size = size
return TextService:GetTextBoundsAsync(self.Params)
end
function TextSizeEstimator:Estimate()
if not self.Label.TextScaled then
return self.Label.TextSize
end
if not self.Label.Text or self.Label.Text == "" then
return 0
end
local smallSize, largeSize = 1, 100
local boundsSmall = self:GetBounds(smallSize)
local boundsLarge = self:GetBounds(largeSize)
local actualBounds = self.Label.TextBounds
local volume = actualBounds.X * actualBounds.Y
local volumeSmall = boundsSmall.X * boundsSmall.Y
local volumeLarge = boundsLarge.X * boundsLarge.Y
local scaleSmall = math.sqrt(volumeSmall / volume)
local scaleLarge = math.sqrt(volumeLarge / volume)
local estimatedSize = smallSize + (1 - scaleSmall) * (largeSize - smallSize) / (scaleLarge - scaleSmall)
local rows = math.max(1, math.round(actualBounds.Y / estimatedSize))
return math.floor(actualBounds.Y / rows)
end
return TextSizeEstimator