Reputation: 2563
I want to put a rectangle around a text in SVG.
The height of the text is known to me (the font-size
attribute of the text
element). But the width is dependent on the actual content. Using getBBox()
or getComputedTextLength()
should work. But this only works after rendering.
Is there a way to specify that in an other way? For example defining the x
and width
attributes relative to other values? I didn't find anything like that in the SVG Spec.
Upvotes: 10
Views: 4651
Reputation: 1183
It is possible using canvas
with measureText()
:
// Get text width before rendering
const getTextWidth = (text, font) => {
const element = document.createElement('canvas');
const context = element.getContext('2d');
context.font = font;
return context.measureText(text).width;
}
// Demo
const font = '16px serif';
const text = 'My svg text';
const textWidth = getTextWidth(text, font);
document.body.innerHTML = `
<svg>
<text x="0" y="20" font="${font}">${text}</text>
<rect x="0" y="30" width="${textWidth}" height="4" fill="red" />
</svg>
`;
Adapted from https://stackoverflow.com/a/31305410/1657101
Upvotes: 2
Reputation: 1
I know this is old, but a few ideas:
If you can choose a mono-spaced font, you know your width by a simple constant multiplication with glyph count
If you are bound to proportional fonts, you can find an average glyph size, do the math as with mono-space, and leave enough padding. Alternatively you can fill the padding with text
element textLength
attribute. If the constant is chosen carefully, the results are not very displeasing.
EDIT: As matanster found it to be hacky
getComputedTextLength()
and build a lookup table. Downside is that it does not account for kerning, but if your cache size is not a problem, you can append glyph-pair widths to this lookup.Going beyond that is to find some way to do server side rendering: Is there a way to perform server side rendering of SVG graphics using React?
Upvotes: 0
Reputation: 13736
Figuring where text ends presumably requires roughly the same underlying code path as the rendering itself implements - going through the width of each character based on the font and style, etc... As I am not aware the SVG standards define a method for directly getting this information without doing the actual full rendering, till such methods emerge or are reported here by others, the approach should be to render invisibly before doing the actual rendering.
You can do that in a hidden layer (z-index, opacity and stuff) or outside the visible viewport, whichever works best in experimentation. You just need to get the browser do the rendering to find out, so you render invisibly for that sake, then use getComputedTextLength()
Upvotes: 4