【问题标题】:Add text to SVG path dynamically动态添加文本到 SVG 路径
【发布时间】:2021-04-27 21:37:26
【问题描述】:

我有一个从 Adob​​e Illustrator 导出的 SVG,其中包含多个类似这样的路径,它会生成一个我打算用作文本框的小多边形

<svg viewbox="387 390 74 20">
    <g>
        <path class="st37" d="M452,408h-56c-4.42,0-8-3.58-8-8l0,0c0-4.42,3.58-8,8-8h56c4.42,0,8,3.58,8,8l0,0     C460,404.42,456.42,408,452,408z" />
    </g>
</svg>

我想为它动态添加文本。我在这里看到了许多类似的问题,但其中大多数涉及根据 path 元素的 x 和 y 属性为 text 元素指定 x 和 y 属性。但是,我的 path 没有这样的属性。

我尝试使用带有 xlink:href 的 textPath 元素指向我的路径。我被附加到 path,但文本包裹了我的 path 元素,而不是在其中。

那么,有没有办法做到这一点?我在这里接受不同的解决方案。我的梦想是使用 javascript 获取 path 元素并从那里添加文本。但我也可以编辑基本 SVG 文件以添加 text 或任何其他相关元素和属性以使其工作,只要我以后可以从 javascript 动态更改文本。由于这个 SVG 是由 Illustrator 制作的,我还可以在那里尝试不同的导出选项,以获得适合我的目标的输出。

【问题讨论】:

  • 获取路径的边界框,然后使用它来确定放置文本的位置。
  • 您的 sn-p 不起作用
  • @MichaelRovinsky 感谢您的指点,我编辑了问题以解决它

标签: javascript svg text


【解决方案1】:

这里有一些示例代码,它采用标签路径并在其后添加一个 &lt;text&gt; 元素以及您选择的任何文本。

let label1 = document.querySelector("#label1");

addLabelText(label1, "Something");



function addLabelText(bgPath, labelText)
{
   let bbox = bgPath.getBBox();
   let x = bbox.x + bbox.width / 2;
   let y = bbox.y + bbox.height / 2;
   
   // Create a <text> element
   let textElem = document.createElementNS(bgPath.namespaceURI, "text");
   textElem.setAttribute("x", x);
   textElem.setAttribute("y", y);
   // Centre text horizontally at x,y
   textElem.setAttribute("text-anchor", "middle");
   // Give it a class that will determine the text size, colour, etc
   textElem.classList.add("label-text");
   // Set the text
   textElem.textContent = labelText;
   // Add this text element directly after the label background path
   bgPath.after(textElem);
}
.st37 {
  fill: linen;
}

.label-text {
  font-size: 10px;
  fill: rebeccapurple;
  transform: translate(0, 3px); /* adjust vertical position to centre text */
}
<svg viewbox="387 390 74 20">
  <g>
    <path id="label1" class="st37" d="M452,408h-56c-4.42,0-8-3.58-8-8l0,0c0-4.42,3.58-8,8-8h56c4.42,0,8,3.58,8,8l0,0     C460,404.42,456.42,408,452,408z" />
  </g>
</svg>

【讨论】:

    【解决方案2】:

    因为您可以编辑基本 SVG 对齐

    • 创建一个合适的 SVG 来使用

      • 您的 path 是一个背景标签,以较大的偏移量 x=452 y=408 开始(红色圆圈)
      • 我会重新创建它,
        从绿色圆圈开始,(编辑:https://yqnn.github.io/svg-path-editor/)
        在viewBox="0 0 80 20"
      • 获取 backgroundlabel 和(蓝色)textPath 行的单一坐标
    • 之后使用 JavaScript 动态添加文本。

      • 无需文本 x,y 计算,pathLength 和 startoffset 即可完成工作

      • 或者如果你喜欢,你可以从getBBox()动态创建蓝线
        这也适用于您当前的路径;只是需要更多的计算

    • 一切都与坐标有关,
      并定位蓝线(然后使用 stroke="transparent" ):

    游乐场:

    <svg viewbox="387 390 74 20">
      <path fill="lightgreen" d="M452,408h-56c-4.42,0-8-3.58-8-8l0,0c0-4.42,3.58-8,8-8h56c4.42,0,8,3.58,8,8l0,0C460,404.42,456.42,408,452,408z" />
     
      <circle cx="452" cy="408" r="2" fill="red"/>
      <circle cx="388" cy="400" r="2" fill="green"/>
      
      <path id="P" pathLength="100" d="M388 400h72" stroke="blue"/>
      <text>
        <textPath href="#P" startoffset="50" text-anchor="middle" dominant-baseline="middle"
                  fill="green" font-size="14px">My Text</textPath>
      </text>
    </svg>

    【讨论】:

      【解决方案3】:

      感谢您的回答!我最终使用Paul LeBeau's function 的调整版本来考虑the structure suggested by Danny '365CSI' Engelman,因此我不必使用翻译来垂直居中文本。

      let label = document.querySelector("#mylabel");
      
      addLabelTextPath(label, "Something");
      
      function addLabelTextPath(bgPath, labelText) {
      
        let bbox = bgPath.getBBox();
        let x = bbox.x + bbox.width / 2;
        let y = bbox.y + bbox.height / 2;
      
        // Create the path line
        let pathElem = document.createElementNS(bgPath.namespaceURI, "path");
        pathElem.setAttribute("pathLength", 100);
        pathElem.setAttribute("d", `M${bbox.x} ${y}h${bbox.width}`);
        pathElem.id = `baseline-${bgPath.id}`;
      
        // Create a <text> element
        let textElem = document.createElementNS(bgPath.namespaceURI, "text");
      
        // Create a <textPath> element
        let textPath = document.createElementNS(bgPath.namespaceURI, "textPath");
        textPath.setAttribute("href", `#${pathElem.id}`);
        //Center text
        textPath.setAttribute("dominant-baseline", "Middle");
        textPath.setAttribute("startOffset", 50);
        textPath.setAttribute("text-anchor", "middle");
        // Give it a class that will determine the text size, colour, etc
        textPath.classList.add("label-text");
        // Set the text
        textPath.textContent = labelText;
      
        // Add the elements directly after the label background path
        bgPath.after(pathElem);
        pathElem.after(textElem);
        textElem.appendChild(textPath);
      }
      .st37 {
        fill: lightblue;
      }
      
      .label-text {
        font-size: 10px;
        fill: darkblue;
      }
      <svg viewbox="387 390 74 20">
          <g>
              <path id="mylabel" class="st37" d="M452,408h-56c-4.42,0-8-3.58-8-8l0,0c0-4.42,3.58-8,8-8h56c4.42,0,8,3.58,8,8l0,0     C460,404.42,456.42,408,452,408z" />
          </g>
      </svg>

      【讨论】:

      • 您无需使用&lt;textPath&gt; 元素即可使用dominant-baseline。另请注意,并非所有字体都支持dominant-baseline。
      猜你喜欢
      • 2019-06-08
      • 1970-01-01
      • 1970-01-01
      • 2014-04-18
      • 2019-03-19
      • 1970-01-01
      • 2022-01-03
      相关资源
      最近更新 更多