Last active
April 25, 2025 03:17
-
-
Save TarVK/9b81f9540754b676945ff23d1178501f to your computer and use it in GitHub Desktop.
Obtain the font size for text to fit a given width or height, using binary search
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** A type for font info */ | |
type IFontStyle = { | |
family: string; | |
style?: "normal" | "italic" | "oblique"; | |
weight?: | |
| "normal" | |
| "bold" | |
| "bolder" | |
| "lighter" | |
| "100" | |
| "200" | |
| "300" | |
| "400" | |
| "500" | |
| "600" | |
| "700" | |
| "800" | |
| "900"; | |
}; | |
type IFont = IFontStyle & { | |
size?: number; | |
}; | |
/** | |
* Retrieves the font object from an element | |
* @param element The element to retrieve the font fro;m | |
* @returns The font object | |
*/ | |
const getFontFromElement = (element: HTMLElement): IFont => { | |
const style = window.getComputedStyle(element); | |
return { | |
family: style.fontFamily, | |
size: parseFloat(style.fontSize), | |
style: style.fontStyle as any, | |
weight: style.fontWeight as any | |
}; | |
}; | |
/** | |
* Retrieves the font as a string to be set on a canvas | |
* @param font The font object | |
* @returns The font string | |
*/ | |
const getFontString = (font: IFont): string => { | |
return `${font.style || ""} ${font.weight || ""} ${font.size}px ${ | |
font.family | |
}`; | |
}; | |
/** | |
* Retrieves the font size given the max width and or height, text and font style | |
* @returns The font size | |
*/ | |
const getFontSize = ({ | |
width = Infinity, | |
height = Infinity, | |
text, | |
font | |
}: { | |
width?: number; | |
height?: number; | |
text: string; | |
font: IFontStyle; | |
}): number => { | |
let step = 256; | |
let size = step; | |
const canvas = document.createElement("canvas"); | |
const ctx = canvas.getContext("2d"); | |
ctx.font = getFontString(font); | |
while (step > 1) { | |
step /= 2; | |
ctx.font = getFontString({...font, size}); | |
const measurement = ctx.measureText(text); | |
const msrHeight = | |
measurement.actualBoundingBoxAscent + measurement.actualBoundingBoxDescent; | |
size += | |
(measurement.width < width && msrHeight < height ? (step == 1 ? 0 : 1) : -1) * | |
step; //(step==1?0:1) ensures that the last step doesn't enlarge which could have caused text to not fit anymore | |
} | |
return size; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
And a hook for usage to fit a component's width in react