使用 D3 在 SVG 路径上创建方向箭头

Posted

技术标签:

【中文标题】使用 D3 在 SVG 路径上创建方向箭头【英文标题】:Create directional arrows on an SVG path using D3 【发布时间】:2022-01-15 15:07:39 【问题描述】:

我有一个 svg 路径,它代表了现实生活中的制造穿梭轨道。每个穿梭机在轨道上向特定方向移动,我希望 svg 路径显示方向以供快速参考。最初,我尝试使用标记在路径上以特定间隔创建箭头,但这仅允许我标记路径的中间和末端。我在 another question that I asked on ***.

上找到了解决此问题的方法

这个问题得到了充分的回答,但我的真正目标是创建一系列箭头来标记沿整个长度的路径,而不仅仅是在端点处标记。想要沿着整个路径的箭头的原因是我打算使用箭头作为穿梭方向的指示器,同时也作为路径长度的指示器。有时 svg 形式的路径与现实世界路径的长度不匹配,这可能会导致现场出现问题。如果我使用的是 svg 折线,这将很容易,因为有一种很好的方法可以在折线上创建一系列点,因为它是由一系列小线组成的。 There's great post outlining how to add arrows to a polyline on ***.

无论如何,I found a creative method for adding text arrows to an SVG path(谢谢@Holger Will),然后在 D3 中实现了这个方法,并想要一个地方分享它,所以我发布这个问题作为记录我的解决方案的一种方式(解决方案发布为一个答案)。

You can see a working version of my solution on this stackblitz.

【问题讨论】:

【参考方案1】:

@Holger Will recommended a creative solution for adding arrows to an svg path。基本上,如果您使用 svg textPath 和 startOffset 属性,您可以使用 webfonts 添加文本箭头。这是一个巧妙的解决方案!

就我而言,我需要在 D3 中实现它,这就是我的做法:

import  svgPathProperties  from 'svg-path-properties';
import  Selection  from 'd3';
/**
 * Path Arrow Points
 * ---
 * Create a series of arrows that follow a specified path
 * to indicate the direction of movement on the track segment.
 * @param mainPath 'd' path value for calculating the length of the svg
 * @param numberOfPoints total number of points per length of path: used to calculate distance between points
 * @param lengthOfPath used with numberOfPoints to calculate distance between points
 * @param d3GroupSelection path group that contains a path onto which we can append arrows
 * @param d3PathID path ID from track segment that will have arrows appended onto it
 */
export const PathArrowPoints = (
  mainPath: string,
  numberOfPoints: number,
  lengthOfPath: number,
  d3GroupSelection: Selection<any, any, any, any>,
  d3PathID: string
): Selection<any, any, any, any> => 
  /**
   *
   */
// I want lines on 100% of the distance of the path
  const totalPercent = 100;
  const workingPath = new svgPathProperties(mainPath);
// Defines the length of the svg path
  const svgPathLength = workingPath.getTotalLength();
// Finds the distance between two points on the path
  const distanceBetweenPoints = Math.floor(lengthOfPath / numberOfPoints);
  const totalPoints = Math.floor(svgPathLength / distanceBetweenPoints);
// How many points do I want per length of path.
  const pointInterval = totalPercent / totalPoints;
  const updatedSelection: Selection<any, any, any, any> = d3GroupSelection;
  /**
   *
   */
  for (let point = pointInterval; point < totalPercent; point += pointInterval) 
    updatedSelection
      .append('text')
      .append('textPath')
      .attr('id', `$point`)
      .attr('fill', 'green')
      .attr('dominant-baseline', 'central')
      .attr('font-size', '10px')
      .attr('href', `#$d3PathID`)
      .attr('startOffset', `$point%`)
      .html('➤');
  
  /**
   *
   */
  return updatedSelection;
;

我使用来自 npm 的svgPathProperties library 来访问 svg 路径数据,并计算路径的距离、路径上我想要的点数以及我想要设置这些点的频率。 我传入了一系列参数来定义点数等,但最重要的是,我传入了我想在其上附加箭头的 d3 路径的一部分。 接下来,我创建了一个 for 循环,它将为每个箭头点运行一次,直到我们达到路径距离的 100%。我将text 元素和textPath 元素附加到svg 路径上,并为其赋予一系列属性。其中最重要的属性是 id(每个箭头需要不同的 id)、dominant-baseline:center(告诉文本保持在路径的中心)、href(这些箭头将被附加到的 svg 路径)、startOffset(每个箭头的特定长度定义为路径总距离的百分比),最后是定义文本标记 (➤) 的 .html 文本属性。然后我返回路径的修改值。

感谢 *** 社区的每一个人。我查看了很多答案来弄清楚这一切,遗憾的是,我无法在这里链接所有人。

【讨论】:

以上是关于使用 D3 在 SVG 路径上创建方向箭头的主要内容,如果未能解决你的问题,请参考以下文章

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

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

如何用svg在网页中画一条带箭头的连接线

SVG路径上的D3.js通配符选择[关闭]

将空值传递给 SVG 路径(使用 d3.js)以抑制丢失数据

如何在 d3.js 中拖动路径