SVG 文本路径,确定文本何时超出路径

Posted

技术标签:

【中文标题】SVG 文本路径,确定文本何时超出路径【英文标题】:SVG textpath, determine when text goes beyond the path 【发布时间】:2011-10-11 15:27:26 【问题描述】:

我有下面的代码来沿路径显示文本。我打算在其中输入我想要的内容并沿路径显示它。还没有弄清楚如何做到这一点,任何建议都会受到欢迎。

但是我的问题是,我如何才能准确地找出文本超出路径末尾并且不再显示的位置。这个想法是当我让它动态工作时,如果用户输入的句子比路径可以处理的长,它会告诉你文本将从某个点被切断。在这种情况下,用户只看到单词“The quick brown fox jum”,前面我希望错误消息说“ps over the lazy dog”无法显示或至少至少要说“The sentence is太长了,没有完整显示”

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 
<svg viewBox = "0 0 500 300" version = "1.1">
    <defs>
      <path id = "s3" d = "M 10,90 Q 100,15 200,70 "/>
    </defs>
    <g>
        <text font-size = "20">
            <textPath xlink:href = "#s3">
                The quick brown fox jumps over the lazy dog                
            </textPath>
        </text>
        <use x = "0" y = "0" xlink:href = "#s3" stroke = "black" fill = "none"/>
    </g>
</svg>

【问题讨论】:

【参考方案1】:

您可以查询应该在路径上的字符串的计算长度,以及路径的长度。然后比较两者,如果字符串长度比路径长度长,那么文本会从路径中掉出来。

你也可以使用路径长度的知识来压缩字符串以适应,像这样:

<svg viewBox="0 0 500 300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <path id="s3" d="M 10,90 Q 100,15 200,70 "/>
    </defs>
    <g>
        <text font-size="20">
            <textPath xlink:href="#s3" textLength="204" lengthAdjust="spacingAndGlyphs">
                The quick brown fox jumps over the lazy dog                
            </textPath>
        </text>
        <use x="0" y="0" xlink:href="#s3" stroke="black" fill="none"/>
    </g>
</svg>

这是一个通过减小字体大小来控制字符串长度的示例:

<svg viewBox="0 0 500 300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
      <path id="s3" d="M 10,90 Q 100,15 200,70 "/>
    </defs>
    <g>
        <text font-size="20" font-family="Arial,Helvetica,sans-serif">
            <textPath id="tp" xlink:href="#s3" lengthAdjust="spacingAndGlyphs">
                The quick brown fox jumps over the lazy dog
            </textPath>
        </text>
        <use x="0" y="0" xlink:href="#s3" stroke="black" fill="none"/>
    </g>
    <script><![CDATA[
        var textpath = document.getElementById("tp");
        var path = document.getElementById("s3");
        var fontsize = 20;
        while (textpath.getComputedTextLength() > path.getTotalLength())
        
            fontsize -= 0.01;
            textpath.setAttribute("font-size", fontsize);
        
    ]]></script>
</svg>

【讨论】:

+1,这不是完全正确,因为最后一个字符只有在一半以上从路径上掉下来时才会消失。所以getComputedTextLength() 可以比getTotalLength() 稍微大一点,然后才真正消失。当你开始弄乱text-anchorstartOffset,或者开始在路径上移动tspans 时,情况会变得更加复杂。 @mercator:你是对的,但是可以单独测量每个字符并更精确。 startOffset 只是设置路径上的对齐点(沿路径的百分比),而 text-anchor 设置如何围绕对齐点对齐。它有点复杂,但我认为仍然可以在脚本中计算。 大家好!一个问题......如果我想要像文本这样的东西通过路径溢出怎么办?对不起,如果这是一个愚蠢的问题,但我对 SVG 知之甚少,并且溢出属性使用路径并不那么明显......:S @beto:这应该是一个新问题。 我不得不克隆没有路径的文本元素并使用它来获取所有字符的真实实际宽度。文本路径上的文本宽度不包括不可见字符。【参考方案2】:

我必须像这样调整它才能按预期工作:

        var textpath = document.getElementById("tp");
        var path = document.getElementById("s3");
        var fontsize = 20;
        while ( (textpath.getComputedTextLength()*1.50) > path.getTotalLength())
        
            fontsize -= 0.01;
            textpath.setAttribute("font-size", fontsize);
        

【讨论】:

【参考方案3】:

有一个技巧可以检测 Chrome 上的文本溢出:在您的 textPath 元素上调用 getStartPositionOfChar 以获取第一个和最后一个字符索引(如果有的话),如果发生溢出,该函数只会返回一个坐标为原点x: 0, y: 0的对象。

然后,您可以按照其他答案的建议进行线性/二进制搜索。它比getComputedTextLength 更准确,但是它在 Firefox 上不起作用;由于某种原因,浏览器会尝试推断位置并返回垃圾值。

【讨论】:

【参考方案4】:

设置&lt;path id="#P" pathLength="100" ...&gt;

https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength

设置&lt;textPath href="#P" startoffset="100" text-anchor="end"&gt;

https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor

pathLength 在其他元素上适用于 FireFox,而不适用于 Chromium(2021 年 3 月)

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 40">
  <rect   fill="beige"></rect>
  <path id="P" pathLength="100" d="M20 20h160" stroke="blue"></path>
  <text>
    <textPath href="#P" 
              startoffset="0" 
              text-anchor="start">start</textPath>
  </text>
  <text>
    <textPath href="#P"
              startoffset="50" 
              dominant-baseline="hanging"
              text-anchor="middle">middle</textPath>
  </text>
  <text>
    <textPath href="#P" 
              startoffset="100" 
              text-anchor="end">end</textPath>
  </text>
</svg>

【讨论】:

以上是关于SVG 文本路径,确定文本何时超出路径的主要内容,如果未能解决你的问题,请参考以下文章

SVG在路径内弯曲文本

仅在将鼠标悬停在圆圈上时才沿文本路径为 SVG 文本设置动画

Inkscape

如何确定 SVG 路径偏移

opentype.js 和 maker.js 为文本呈现不正确的路径

以编程方式确定 SVG 路径生成的形状