如何在字母而不是数字上应用补间函数?

How to apply a tween function on letters instead of numbers?

对于我在 d3.js 中应用于文本对象的过渡,我想像 this example 中那样对文本进行补间。但是,我的问题是,如果文本由字母而不是数字组成,这将不起作用,直到现在我只找到仅使用数字的示例。

所以我的问题是:是否可以在带有字母的文本对象上创建这样的补间过渡?

这是我目前应用它的方式(使用 interpolateString() function):

var mytext = svg.append("text")
    .style("fill", 'black')
    .attr("x", 0)
    .attr("y", 0)
    .style("font-size", "14")
    .text("My old text")

mytext
    .transition()
          .delay(1500)
          .duration(1000)
          .tween("text", function(d) { 
              var self = d3.select(this)
                var i = d3.interpolateString(self.text().replace(/,/g, ""), "My new text");
                    return function(t) {self.text(i(t))};
              });


您对 interpolateString 的作用有误解。如果您查看 API,您会发现它...

Returns an interpolator between the two strings a and b. The string interpolator finds numbers embedded in a and b, where each number is of the form understood by JavaScript (emphasis mine)

因此,它不会插入仅由字母组成的字符串。

话虽这么说,但它引出了一个问题:你想如何插入字母?例如,您可以根据它们在罗马字母表中的位置对它们进行插值。如果是这样,这是一种方法:

用字母创建一个数组...

const alphabet = " abcdefghijklmnopqrstuvwxyz".split("");

... 并且,在 tween 函数中,插入字母表中每个字母的索引,从旧文本到新文本:

.tween("text", function() {
    return function(t) {
      d3.select(this).text(oldText.map(function(d,i){
        return alphabet[~~(d3.interpolate(alphabet.indexOf(d), alphabet.indexOf(newText[i]))(t))]
      }).join(""))
    };
});

这是一种非常基本的方法,只有当两个字符串的长度完全相同时才有效。另外,请注意我在 alphabet 数组中放置了一个 space,否则我们将在字符串中的 space 中得到 undefined

这是一个演示:

const svg = d3.select("svg")
const oldText = "this is my old text".split("");
const newText = "here is my new text".split("");
const alphabet = " abcdefghijklmnopqrstuvwxyz".split("");
const text = svg.append("text")
  .attr("y", 50)
  .attr("x", 20)
  .attr("font-size", 30)
  .text(oldText.join(""));
text.transition()
  .delay(500)
  .duration(2000)
  .ease(d3.easeLinear)
  .tween("text", function() {
    return function(t) {
      d3.select(this).text(oldText.map(function(d, i) {
        return alphabet[~~(d3.interpolate(alphabet.indexOf(d), alphabet.indexOf(newText[i]))(t))]
      }).join(""))
    };
  });
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>