5

Is there a nice and easy way to to have the functionality of lengthAdjust (together with textLength) for shrinking text if necessary (if too wide) but never attempting to stretch it?

Two possible solutions for a SVG generated through JS come to my mind:

  • Count characters (or rather grapheme clusters) and based on that (together with some heuristics unless a fixed-width size font is used) determine whether to set textLength or not.
  • First do it without textLength set and then determine using getBBox() whether the text needs some shrinking in which case textLength will be set.

Both solutions are IMHO quite ugly (and possibly buggy from my recollections of past encounters with getBBox()). Is there maybe some nicer solution I missed?

phk
  • 2,002
  • 1
  • 29
  • 54

1 Answers1

1

Have a look at this: https://stackoverflow.com/a/39886640/1925631 Essentially, make a path which spans the exact coordinates where you want to spread your text on a path. Measure this path. Then, measure how many pixels your text requires, with a font-size of 1px (and other desired font-features). Now adjust the font-size to fill your desired percentage of the available path advance width. Adjust start-offset and text-anchor. Now finally calculate your author specified textLength and choose a lengthAdjust value to get exact alignment on low precision / non-conformant renderers.

Finally, if you need to support viewers without text on a path rendering support, you can use a conformant viewer with javascript support to create a backwards compatible/fallback version. Render the content and use the SVG DOM api to fetch the x, y and rotate values for each character/glyph, now create a new SVG DOM representation with those attributes specified. You might need javascript to calculate absolute width and height for the root svg element as well, and a correctly specified viewBox, and cascade/resolve/convert all css selectors/rules/properties to inline attributes. But this way you can get cross-platform, cross-browser/viewer rendering of text, with a single compilation step per immutable source file version.

I've also made a gist to ease the last step, of resolving the css and removing all classNames, while preserving the rendered end-result: https://gist.github.com/msand/4b37d3ce04246f83cb28fdbfe4716ecc

This is for the purpose of a single universal svg + javascript codebase, and web+ios+android software development (based on react + react-native + react-native-svg)

msand
  • 468
  • 4
  • 8
  • 1
    Some issues with getComputedTextLength in various browsers, and the importance of choosing an appropriate conformant viewer, to calculate per character / glyph position values based on the common subset of available svg / font features in the required viewers: https://bl.ocks.org/MSCAU/58bba77cdcae42fc2f44 – msand Aug 23 '17 at 16:28
  • A collection of relevant runnable tests/animations/visualisations: https://codepen.io/jovdb/full/egXVxo – msand Aug 23 '17 at 16:33
  • Complexities of calculating font metrics related aspects such as font-size/line-height/text-bounds: http://christopheraue.net/2014/03/05/vertical-align/ and another beautiful one about how the all the properties and font data/metrics interact, and how vertical-alignment affects the line-height, content-area, virtual-area, line-box and thus the various bounds metrics and lengths: https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align – msand Aug 23 '17 at 16:43
  • One might have to keep in mind that `getComputedTextLength` is independent of the stroke (and therefore any `stroke-width` value). – phk Dec 07 '17 at 17:27