function labels(svg) {
let label = svg.append("g")
.style("font", "bold 12px var(--sans-serif)")
.style("font-variant-numeric", "tabular-nums")
.attr("text-anchor", "end")
.selectAll("text");
return ([date, data], transition) => label = label
.data(data.slice(0, n), d => d.name)
.join(
enter => enter.append("text")
.attr("transform", d => `translate(${x((prev.get(d) || d).value)},${y((prev.get(d) || d).rank)})`)
.attr("y", y.bandwidth() / 2)
.attr("x", -6)
.attr("dy", "-0.25em")
.text(d => d.name)
.call(text => text.append("tspan")
.attr("fill-opacity", 0.7) // 设置透明度
.attr("font-weight", "normal") // 设置字重
// 对文字进行偏移微调
.attr("x", -6)
.attr("dy", "1.15em") // 设置纵向偏移,避免公司的价值(数字)与公司的名字重叠
),
// 设置 updating 选择集
// 不进行处理,直接返回该选择集
update => update,
// 设置 exting 选择集
// 将该选择集中的元素移除,并使用过渡管理器 transition 的配置,为该过程该过程创建一个过渡
exit => exit.transition(transition).remove()
// 过渡最终状态的文字定位通过 CSS 的 transform 属性来设置
// 最终状态使用下一个时间点的数据 next.get(d) 来设置(而当前时间点的数据 d 则作为回退的备选项)
// 所以移除(柱子元素)的标注信息会有一个(从底部)缓出
.attr("transform", d => `translate(${x((next.get(d) || d).value)},${y((next.get(d) || d).rank)})`)
// 在过渡的过程中,还同时为公司价值的数字设置 tween 动画(类似秒表计数的动效)
// 使用 transition.tween(name[, value]) 方法设置补间动画
// 第一个参数是需要设置的元素属性
// 第二个参数是一个返回插值器的函数(选择集的每个元素依次调用它,传入的参数 d 是元素所绑定的数据)
// 更详细的说明可以查看官方文档 https://github.com/d3/d3-transition/#transition_tween
// 其中 textTween() 返回一个插值器,可以基于当前时间点的公司价值 d.value 和下一个时间点的公司价值 next.get(d),在过渡期间计数出一系列的插值(如果下一个时间点的公司价值未定义,则以当前时间点的数据 d 则作为回退的备选项)
.call(g => g.select("tspan").tween("text", d => textTween(d.value, (next.get(d) || d).value)))
)
// 最后用当前时间点的数据来更新标注信息的定位
// 并使用过渡管理器 transition 的配置,为该过程该过程创建一个过渡
.call(bar => bar.transition(transition)
// 前面没有根据新数据更新 updating 选择集的元素的定位
// 而且前面将 entering 选择集的元素采用上一个时间点数据 prev.get(d) 进行定位
.attr("transform", d => `translate(${x(d.value)},${y(d.rank)})`) // 在这里更新选择集(合并了 updating 和 entering 选择集)元素的定位 👈
// 另外在过渡的过程中,也对 updating 和 entering 选择集中的元素中表示公司价值的数字设置 tween 动画
// 从上一个时间点的公司价值 prev.get(d) 变动到当前时间点的公司价值 d.value
.call(g => g.select("tspan").tween("text", d => textTween((prev.get(d) || d).value, d.value))));
}