将弯曲的 textPath 居中放置在圆弧内

Center the curved textPath inside an arc

给定一条沿着给定弧线的弯曲文本路径,所述文本路径如何在弧线内居中

请看this example

其中我通过反复试验在上手动设置x和dy,这样结果就是我想要的(文本沿圆弧居中)。

但我正在动态生成许多圆弧,需要一种动态居中文本位置的方法(取决于 d)。

我认为这里的子问题是 d.x 和 d.dx 如何与 dx 和 x 相关? y 也一样。

使用 SVG 路径的 getPointAtLength 方法。希望这有帮助。

var path = svg.append("path")
   .attr("id", "path")
   .attr("d", arc(1));

var text = "Hello, curved textPath!"; 
var pt = path.node().getPointAtLength(path.node().getTotalLength()/2-text.length);

svg.append("text")       
    .attr("clip-path", "url(#text-clip)")    
    .attr("x", pt.x) 
    .attr("dy", 28)
    .append("textPath")
    .attr("xlink:href", "#text-path")
    .text("Hello, curved textPath!");

为了子孙后代;)

之所以需要 dy 是因为 TextPathouterRadius 定义的路径的开头开始绘制文本,使其基线与路径匹配.然后它将继续到这条外部路径的末端并环绕到内部路径。我还没有找到或想出一种方法来计算字体的高度并相应地调整 dy。或者,您可以创建一个新的圆弧来引导文本并将半径调整到合适的值。

要使文本自动居中于上弧,您需要设置两个属性。第一个是startOffset,用来偏移起点;它应该设置为 25%,因为线的全长包括内半径和外半径。这可能会稍微偏离,因为外弧比内弧长。或者,您可以创建第二条内半径和外半径相同的路径,并将该路径用于文本。然后你需要使用 text-anchor 并将其设置为 middle.

如果要防止文本从外弧绕到内弧,可以先从路径中移除内弧,然后将文本偏移 50% 而不是 25%。

function removeInnerArc(path) {
  return path.replace(/(M.*A.*)(A.*Z)/, function(_, m1) {
    return m1 || path;
  });
}

var arc = d3.svg.arc()
  .innerRadius(180)
  .outerRadius(220)
  .startAngle(-Math.PI / 4)
  .endAngle(function(t) {
    return t * 2 * Math.PI / 3;
  });

// Generate a new arc to guide the text
// The radius determines the baseline for the text
var textArc = d3.svg.arc()
  .innerRadius(190)
  .outerRadius(190)
  .startAngle(-Math.PI / 4)
  .endAngle(function(t) {
    return t * 2 * Math.PI / 3;
  });

var svg = d3.select("body").append("svg")
  .attr("width", 960)
  .attr("height", 500)
  .append("g")
  .attr("transform", "translate(250,250)");

svg.append("defs").append("path")
  .attr("id", "text-path")
  .attr("d", removeInnerArc(textArc(1)));

svg.append("path")
  .attr("id", "path")
  .attr("d", arc(1));

svg.append("clipPath")
  .attr("id", "text-clip")
  .append("use")
  .attr("xlink:href", "#path");

svg.append("text")
  .attr("clip-path", "url(#text-clip)")
  .append("textPath")
  .attr("xlink:href", "#text-path")
  .text("Hello, curved textPath!")
  // You need the following two lines to position the text correctly
  .attr("text-anchor", "middle")
  .attr("startOffset", "50%");
path {
  fill: #3182bd;
}

text {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 24px;
}
<html>

<head>
  <link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css?family=Open+Sans:400,600">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

  <script src="http://d3js.org/d3.v3.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>

<body>
</body>

</html>