radlan
radlan

Reputation: 2563

getting text width in SVG prior to rendering

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

Answers (3)

DarthVanger
DarthVanger

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

Madis Kalme
Madis Kalme

Reputation: 1

I know this is old, but a few ideas:

  1. If you can choose a mono-spaced font, you know your width by a simple constant multiplication with glyph count

  2. 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

  1. Predetermine glyph widths with 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

matanox
matanox

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

Related Questions