0

First of all I looked at all possible related answers here but none of them seem to bring the answer I need so here I am. Given a svg text path:

<svg viewBox="0 0 900 900"
     xmlns="http://www.w3.org/2000/svg" 
     xmlns:xlink="http://www.w3.org/1999/xlink"
     id="mysvg"
     >
  <defs>
      <path id="myPath" d="M70 110 C 70 140, 110 140, 110 110" stroke="black" fill="transparent"/>
  </defs>

  <use xlink:href="#myPath" fill="none" stroke="red"  />

  <text id="names" font-family="Verdana" font-size="10" text-anchor="middle" >
    <textPath xlink:href="#myPath" startOffset="50%">
      My text is going to exceed at some point…
    </textPath>
  </text>
</svg>

At this point the text exceeds the textpath

Text exceeding path

I can't find a way to check for possible overflow through jquery. This command won't actually return undefined:

alert($("text#names").attr("textLength") );

I am trying to check for overflows in order to fit the text to the maximum length or so.

Loic
  • 2,173
  • 10
  • 13

2 Answers2

0

I had the same problem when adjusting font size so that the given text will be drawn with the largest possible font size without overflow. Its quite simple using plain JS.

1) Determine the np. of characters in the text element with a minimum font size:

textElement.css('font-size', 1);                                                        
var allCharCount = textElement[0].getNumberOfChars();                                   

2) Then set font size to any value and determine the length again

var hasOverflow = allCharCount != textElement[0].getNumberOfChars();                

getNumberOfChars() will only return the no. of chars drawn. If there is an overflow this number will be smaller then from the original whole string.

RED SOFT ADAIR
  • 12,032
  • 10
  • 54
  • 92
  • Thanks for your input. Will try it asap and let you know ;) – Loic Sep 17 '17 at 11:41
  • @6infinity8: I did not find any other solution. Do you know any? – RED SOFT ADAIR Jul 13 '19 at 15:16
  • @REDSOFTADAIR For simple curves (arcs and lines) it turns out you can easily increase the length of the path, say double it, and then detect overflow by comparing the values of `path.getTotalLength() / 2` & `text.getComputedTextLength()`. That was sufficient for me, otherwise you can also check my last answer that works on Chrome only: https://stackoverflow.com/a/57043365/4413709 – 6infinity8 Jul 15 '19 at 20:55
0

It looks like text.getNumberOfChars() has changed since the other answer was written, and now returns the total number of characters in the string, regardless of if they're rendered or not.

My approach to this problem is to:

  • Change the <textPath> element to draw on a much longer path, then calculate the text length using text.getComputedLength()
  • Change the <textPath> back to the original path and calculate length again
  • If the length on the original path is shorter than the length on the longer path, you know there's an overflow.

const textPath = document.querySelector('textPath');

const checkClipped = () => {
  textPath.setAttribute('xlink:href', '#fullWidthPath');
  const fullLength = textPath.getComputedTextLength();
  textPath.setAttribute('xlink:href', '#myPath');
  const curvedLength = textPath.getComputedTextLength();
  return fullLength > curvedLength;
}

const findLongestString = () => {
  const text = textPath.innerHTML;
  if (checkClipped()) {
    const newText = text.substring(0, text.length - 1);
    textPath.innerHTML = newText;
    return findLongestString(newText);
  } else {
    return text;
  }
}

console.log(findLongestString())
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mysvg">
  <defs>
      <path id="myPath" d="M70 110 C 70 140, 110 140, 110 110" stroke="black" fill="transparent"/>
      <path id="fullWidthPath" d="M 0 0 L 0 10000" />
  </defs>

  <use xlink:href="#myPath" fill="none" stroke="red"  />

  <text id="names" font-family="Verdana" font-size="10" text-anchor="middle" >
    <textPath xlink:href="#myPath" startOffset="50%">
      My text is going to exceed at some point…
    </textPath>
  </text>
</svg>
gingerchris
  • 216
  • 1
  • 2
  • 8