SVG 标记方向箭头出现在 DOM 中,但标记本身不可见

Posted

技术标签:

【中文标题】SVG 标记方向箭头出现在 DOM 中,但标记本身不可见【英文标题】:SVG marker direction arrows appear in DOM, but the marker itself isn't visible 【发布时间】:2022-01-06 19:39:37 【问题描述】:

我正在尝试在使用 d3 呈现的 svg 路径上创建方向箭头。我使用路径字符串和svg-path-properties npm 包获取起点。然后,我将这些点推送到一个数组中,并在另一个函数中,使用 d3 逻辑将这些点映射到原始 svg 路径上,以在每个点处创建三角形。

  public mapArrowPoints(): void 
    this.arrowPoints.forEach((point: ArrowPointObject) => 
      const path = d3.path();
      path.moveTo(parseInt(point.x, 10), parseInt(point.y, 10));
      path.lineTo(parseInt(point.x, 10) + 8, parseInt(point.y, 10) + 2);
      path.lineTo(parseInt(point.x, 10) + 0, parseInt(point.y, 10) + 8);
      path.closePath();

      const svg = d3.select('svg#topLevel');
      const defs = svg.insert('defs', '#curve');
      const marker = defs.append('marker');

      marker
        .attr('id', 'triangle')
        .attr('viewBox', '0 -5 10 10')
        .attr('markerWidth', 4)
        .attr('markerHeight', 4)
        .attr('orient', 'auto')
        .append('path')
        .attr('d', path.toString())
        .attr('fill', 'red')
        .attr('stroke', 'black')
        .attr('stroke-width', '3px');

      svg
        .select('#curve')
        .attr('marker-start', 'url(#triangle)')
        .attr('marker-mid', 'url(#triangle)')
        .attr('marker-end', 'url(#triangle)');
    );
  

现在,当我检查浏览器时,我可以看到我的主路径,但看不到三角形。我可以检查 DOM,并查看应该附加到的 svgdefsmarkerpath。我还可以选择标记路径本身,并查看它应该在哪里渲染(蓝色框显示三角形应该在哪里)。我不太明白为什么三角形没有显示出来。任何帮助都感激不尽。我创建了一个stackblitz example 用于试验解决方案。

【问题讨论】:

你有 108 个箭头点,所以你创建了 108 个 defs 元素,每个元素都有一个 id="triangle" 的元素。所有 id 值都必须是唯一的,而你的不是。 这是有道理的。我是 svg 的新手,所以还有很多东西要学。谢谢@RobertLongson! 【参考方案1】:

除了您有许多具有相同 id 的标记元素之外,您的标记还有一个 viewBox 可以使三角形落在标记框之外。具有 3 个单位笔划的路径的正确视图框将大于它的边界框,因此我将使用“视图框 =”18 5 14 14“”。您可能需要选择不同的 viewBox。

在这里您可以看到要用作标记的路径:

svgborder: solid
<svg viewBox="18 5 14 14"  >
      <path  d="M20,7L28,9L20,15Z" fill="red" stroke="black" stroke-></path>
    </svg>

一旦你有了这个 wiewBox 作为标记,你就会看到标记,但它落在路径之外。这是因为标记具有 refX 和 refY 属性,这些属性引用标记将自身附加到路径的点。默认情况下,此点为 0,0。我将使用 refX="18.5" refY="9"。我选择 9 因为三角形的尖端有 y=9 (d="M20,7L28,9L20,15Z")

在下一个示例中,我用金色圆圈标记了这一点。您可能需要选择不同的。

svgborder: solid
<svg viewBox="18 5 14 14"  >
      <path  d="M20,7L28,9L20,15Z" fill="red" stroke="black" stroke-></path>
      
      <circle cx="18.5" cy="9" r=".5" fill="gold"/>
    </svg>

这就是带有标记的路径的样子:

<svg viewBox="0 0 700 800" >
  <defs>
    <marker id="triangle" viewBox="18 5 14 14" markerWidth="8" markerHeight="8" orient="auto" refX="18.5" refY="9">
      <path  d="M20,7L28,9L20,15Z" fill="red" stroke="black" stroke-></path>
    </marker>
  </defs>
 

  <path fill="none"  stroke="black"  id="curve" d="M 0.05965662,9.8756182 C 665.77394,-70.124378 654.96347,387.98451 654.96347,387.98451 L 45.773941,621.3042 650.91307,783.4508" marker-start="url(#triangle)" marker-mid="url(#triangle)" marker-end="url(#triangle)"></path>
</svg>

【讨论】:

以上是关于SVG 标记方向箭头出现在 DOM 中,但标记本身不可见的主要内容,如果未能解决你的问题,请参考以下文章

获取箭头指向D3中节点的外边缘

带有USE标记的SVG无法呈现

如何使标记完美重叠,使其不会在同一端出现两次?

html中这种箭头怎么实现?

使用 d3 javascript 库时在路径上的特定点放置箭头(标记)

在 D3 强制布局链接标记上缩放箭头