d3实现字符跳动效果

本文的示例之前出现在 d3 官方 demo 中,这里对它重新实现一遍,你可以点击这里查看最终效果

主要实现效果

  1. 进入时,字符为绿色,从上方 50 像素的位置,由透明变为不透明偏移进入。
  2. 进入后,插入到正确位置,原来字符需要移动的,就偏移到正确位置,更新的字符颜色变为#ccc
  3. 下一次更新时,不存在的节点直接删除,删除时字符变为红色,并向下偏移 50 像素变为透明移除。

实现

首先需要创建一组字符,并将字符显示到页面中。

const text = svg.selectAll('text').data(data, (d) => d);

text
  .enter()
  .append('text')
  .attr('y', 50)
  .style('font-size', 18)
  .attr('fill', '#ccc')
  .attr('x', (d, i) => i * 32)
  .text((d) => d);

此时页面中将会存在一组静态的字符。

接下来,就要让字符动起来,使用interval定时重复执行渲染。

这里每次都将字符的顺序打乱进行渲染。

d3.interval(() => {
  update(
    d3
      .shuffle(words)
      .slice(0, Math.floor(Math.random() * 26))
      .sort(),
  );
}, 2000);

你会发现,字符并没有任何变化,这是因为还没有写更新相关的代码。

// 加上更新代码
text.attr('x', (d, i) => i * 32);

又出问题了,好多字符都重叠在一起。这是因为在每一次更新时还保留了上一次的内容,所以导致了字符覆盖。因此,在每一次插入之前,我们需要将不存在的字符节点删除。

text.exit().remove();

这下页面正常了。不知道你是否发现,上述代码的处理进入时和更新时其实有一部分逻辑是一样的,为了减少这部分一样的逻辑,d3 提供了一个merge方法。

text
  .enter()
  .append('text')
  .attr('y', 50)
  .style('font-size', 18)
  .attr('fill', '#ccc')
  .text((d) => d)
  .merge(text)
  // 之前enter部分的逻辑可以挪动到merge之后,表示处理enter和update
  .attr('x', (d, i) => i * 32);

虽然实现的字符变化的效果,但是变化的过程十分生硬,我们可以通过 transition 给它加上动画。

使用 transition,可以控制位置、颜色等等样式进行动画过渡。

text.attr('x', 10).style('fill', '#f00').transition().duration(500).attr('x', 20).attr('fill', '#0f0');

上面这段代码可以简单地实现在 500 毫秒中,坐标从 10 过渡到 20,颜色从红色过渡为绿色。

那么,对于字符的动画处理也是如此。

const t = d3.transition().duration(750);
text
  .enter()
  .append('text')
  .style('fill-opacity', 1e-6)
  .attr('dy', -50)
  // 设置过渡
  .transition(t)
  .attr('dy', 0)
  .style('fill-opacity', 1);

最终实现的效果可以参见字符跳动效果

如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注