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

Create directional arrows on an SVG path using D3

我有一个 svg 路径,代表制造业中真实的穿梭轨道。每个班车在轨道上以特定方向移动,我希望 svg 路径显示方向以供快速参考。最初,我尝试使用标记在路径上的特定间隔处创建箭头,但这只允许我标记路径的中间和末端。我在

上找到了这个问题的解决方案

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

无论如何,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.

@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%。我在 svg 路径上附加了一个 text 元素,然后是一个 textPath 元素,并赋予它一系列属性。这些属性中最重要的是 id(每个箭头需要不同的 id),dominant-baseline:center(告诉文本保持在路径的中心),href(svg 路径其中将附加这些箭头),startOffset(每个箭头的特定长度定义为路径总距离的百分比),最后是 .html 文本 属性 定义文本标记 (➤)。我然后return路径的修改值。

感谢 Whosebug 社区的每一个人。我查看了很多答案来弄清楚所有这些,遗憾的是,我不能 link 每个人都在这里。