因为业务需要折腾起了图表,该系列用于记录使用该库制作 Tree 图表的一些笔记。本节我们要在 link 连接线上,添加文字说明。
# 添加曲线文字
# textPath
除了笔直地绘制一行文字以外, SVG 也可以根据 <path> 元素的形状来放置文字。 只要在<textPath>元素内部放置文本,并通过其xlink:href属性值引用<path>元素,我们就可以让文字块呈现在<path>元素给定的路径上了。
# 添加 textPath
简单来说,我们想要实现连接线上增加文字说明,需要进行这样的处理:
- 给每个 link 的 svg 元素
<path>添加 id 标识。 - 在 link 的 enter 操作中,添加
<textPath>元素,并设置xlink:href属性值引用对应的<path>。 - 给每个
<textPath>添加对应的文字和颜色。 
# 给 path 添加 id 标识
在 link 的 enter 操作中,给<path>添加 id:
// 添加enter操作,添加类名为link的path元素
var linkEnter = link
  .enter()
  .insert("path", "g")
  .attr("class", "link")
  // 添加id
  .attr("id", d => {
    return "textPath" + d.id;
  });
// ...其他操作
# 添加 textPath 文字
我们在 link 的 enter 操作中,添加 text,同时添加与 path 匹配的 textPath:
link
  .enter()
  .append("text")
  // 给text添加textPath元素
  .append("textPath")
  // 给textPath设置path的引用
  .attr("xlink:href", d => {
    return "#textPath" + d.id;
  })
  // 字体居中
  .style("text-anchor", "middle")
  .attr("startOffset", "50%")
  // 父节点的name
  .style("fill", "red")
  .text(function(d) {
    return d.parent.id;
  })
  .append("tspan")
  .style("fill", "blue")
  .text(" --> ")
  // 子节点的name
  .append("tspan")
  .style("fill", "red")
  .text(function(d) {
    return d.id;
  });
上面我们还处理了这样的事情,添加文字说明:父节点 id --> 子节点 id,同时还设置了颜色。
# path 方向调整
如果按照这样的方式,我们会发现我们的文字反了:

像一个个蝙蝠,倒挂着在那。这是因为 pathText 是有方向的,而我们在添加 path 元素的时候,使用的贝塞尔曲线为子节点到父节点的方向,故我们需要进行调整:
// 添加贝塞尔曲线的path,方向为父节点指向子节点
function diagonalReverse(s = {}, d = {}) {
  path = `M ${d.y} ${d.x}
                  C ${(s.y + d.y) / 2} ${d.x},
                  ${(s.y + d.y) / 2} ${s.x},
                  ${s.y} ${s.x}`;
  return path;
}
然后把之前diagonal改为diagonalReverse,就可以实现想要的效果了。
最终效果如图:

# 结束语
本节介绍了一个新的 svg 元素--textPath,可以通过绘制 path,然后给 text 添加 textPath 来绘制曲线文字。刚开始本骚年还以为是 d3 的能力,看来是小瞧了 svg 了呢,不过现在似乎 svg 使用越来越少了呢。Sign~