在没有删除线的情况下使用SVG中的路径内联文本

时间:2016-08-25 14:52:15

标签: svg jointjs

我正在尝试让文字显示在线条内部,以便与线路相连接,如下图所示。

target

使用该行作为图像的textPath不起作用,因为当我将文本内联时,该行继续通过文本。 Strikethrough sample

我有一个适用于直路径的解决方案。我测量文本长度和完整路径长度,然后将其分成3个单独的路径。我在第1和第3条路径上绘制了一个笔划,中间路径用于textPath。

我无法将此工作用于除直线路径以外的任何其他工作,因为我无法测量文本或计算出每个部分的长度。

我正在使用JointJS,但纯粹的伪代码/ SVG答案也同样有帮助。

3 个答案:

答案 0 :(得分:1)

解决此问题的一种方法是创建一个文本块,其长度与文本相同,只是Unicode块字符的填充等于您的背景颜色,并在绘制之前绘制实际文本路径。 (您需要将扩张滤镜添加到纸上,以消除由弧/曲线引起的伪影 - 您可能需要根据需要调整半径。)



<svg width="12cm" height="3.6cm" viewBox="0 0 1000 300" version="1.1"
 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
<path id="MyPath"
      d="M 100 200 
         C 200 100 300   0 400 100
         C 500 200 600 300 700 200
         C 800 100 900 100 900 100" />

<filter id="dilatethis">
  <feMorphology operator="dilate" radius="4"/>
</filter>
  </defs>

  <use xlink:href="#MyPath" fill="none" stroke="red" stroke-width="5" y="-15" />

  <text font-family="monospace" font-size="42.5" fill="white" filter="url(#dilatethis)" >
<textPath xlink:href="#MyPath" startOffset="155" >
  &#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;&#9608;
</textPath>
  </text>


  <text font-family="Verdana" font-size="42.5" fill="blue">
<textPath xlink:href="#MyPath" startOffset="155" >
  Just imagine that this  
</textPath>
  </text>

</svg>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

最简单的解决方案就是在行的顶部和文本下方放置一个白色(或任何背景颜色)矩形。

<svg width="400px" height="100px">
  <line x1="50" y1="50" x2="350" y2="50" stroke="blue" stroke-width="2"/>
  <rect x="125" y="40" width="150" height="20" fill="white"/>
  <text x="200" y="54" text-anchor="middle" fill="blue">Text inline with arrow</text>
</svg>

或者,不是矩形,而是放置文本的副本,但将其设为白色并给它一个粗的笔划。这种方法的优点是你不必为尝试找出矩形的正确尺寸而烦恼。

<svg width="400px" height="100px">
  <line x1="50" y1="50" x2="350" y2="50" stroke="blue" stroke-width="2"/>
  <text x="200" y="54" text-anchor="middle" fill="white" stroke="white" stroke-width="5">Text inline with arrow</text>
  <text x="200" y="54" text-anchor="middle" fill="blue">Text inline with arrow</text>
</svg>

这种方法的一个方面是,如果字母中的间隙或单词之间的间隙足够大,则显示该行。您可能会或可能不会找到理想的。

这只是两种可能的方法。我可以想到更多,但他们更多参与。

答案 2 :(得分:0)

使用Michael Mullany和Paul LeBeau的答案,我已经在JointJS中实现了这一点,所以我发布了所需的更改。

定义一个扩展joint.dia.Link的新形状模型,例如:joint.shapes.gary.InlineLabelLink

使用两个新文本字段扩展形状模型中的标记。一个用于标签(inlineText),一个用于位于标签后面的掩码(inlineTextMask)。

添加一些属性以确保文本在需要的位置。

添加一个名为&#34; caption&#34;的新属性它将保存内联标签文本。

例如:

joint.shapes.gary.InlineLabelLink = joint.dia.Link.extend({

    defaults: joint.util.deepSupplement({
    markup: [
        '<path class="connection" stroke="black" d="M 0 0 0 0"/>',
        '<path class="marker-source" fill="black" stroke="black" d="M 0 0 0 0"/>',
        '<path class="marker-target" fill="black" stroke="black" d="M 0 0 0 0"/>',
        '<path class="connection-wrap" d="M 0 0 0 0"/>',
        '<text class="inlineTextMask" />',
        '<text class="inlineText" />',
        '<g class="labels"/>',
        '<g class="marker-vertices"/>',
        '<g class="marker-arrowheads"/>',
        '<g class="link-tools"/>'
    ].join(''),
    attrs: {
        '.inlineText': {
            'dominant-baseline': 'central',
            'text-anchor': 'middle',
            'pointer-events': 'none',
            'font-size': 10
        },
        '.inlineTextMask': {
            'dominant-baseline': 'central',
            'text-anchor': 'middle',
            'pointer-events': 'none',
            'fill':'#ffffff',
            'stroke':'#ffffff',
            'stroke-linejoin':'smooth',
            'stroke-linecap':'round',
            'stroke-width': 8,
            'font-size': 10
        }
    },
    caption: 'TBD'
}, joint.dia.Link.prototype.defaults)});

然后创建一个从joint.dia.LinkView

延伸的新View类

在该课程中,我们覆盖update函数,以便它可以在正确的位置绘制内联标签。

joint.shapes.gary.InlineLabelLinkView =  joint.dia.LinkView.extend({

    update: function() {
        joint.dia.LinkView.prototype.update.apply(this, arguments);

        var inlinePath = this._V.connection.node.getAttribute('d');


        this._V.inlineText.text(this.model.get('caption'),
            {textPath: { d: inlinePath, startOffset:"50%" } });

        this._V.inlineTextMask.text(this.model.get('caption').replace(' ','\u9608'),
            {textPath: { d: inlinePath, startOffset:"50%" } });

        return this;
    }
});

更新的View类从链接获取路径,然后将此路径应用于文本掩码和文本属性。它使用Vectorizer的文本方法创建适当的defs,textPath和tspan条目。

这确实存在这样的问题:有时文本可能会颠倒,具体取决于链接的方向。这可以通过反转路径的方向来解决。

我已经为此使用了定制功能(未显示),但有像https://github.com/SmartArtsStudio/smart-svg-pathhttps://www.npmjs.com/package/svg-path-reverse这样的库

    if (this.sourcePoint.x > this.targetPoint.x) {
        inlinePath = reversePath(inlinePath);
    }