D3应用文本换行wrap函数后内容被重置为初始状态的问题咨询
问题原因
- 核心原因是
text()赋值和wrap()调用被放在了transition()链式调用之后。D3过渡队列的操作是异步执行的,transition.text()会在动画执行阶段(也就是你提到的timerFlush触发时)直接覆盖文本元素的内容,把wrap()函数提前生成的多个tspan节点替换为纯文本字符串,导致换行效果消失。 - 其次你的enter-update-exit执行顺序错误,先声明了enter和update集合再执行exit移除,会导致update集合包含待删除的旧节点,逻辑不符合D3标准更新流程。
- 额外的问题是你在enter和update的过渡链中重复执行
text()赋值和wrap()调用,出现操作冲突。
解决思路
- 调整调用顺序:所有文本设置、
wrap()调用都放在transition()之前执行,transition()仅用来处理需要动画的属性(opacity、x、y坐标等),不要在过渡链中操作文本内容。 - 修正D3数据绑定流程,严格按照「选择元素→绑定数据→处理exit→处理update→处理enter→合并update+enter做公共操作」的顺序执行。
- 仅在文本内容、换行宽度发生变化时调用
wrap()即可,不需要每次过渡都重复调用。
修正后代码示例
function wrap(text, width) { text.each(function () { var text = d3.select(this), words = text.text().split(/\s+/).reverse(), word, line = [], lineNumber = 0, lineHeight = 1.1, // ems x = text.attr("x"), y = text.attr("y"), dy = 0, //parseFloat(text.attr("dy")), tspan = text.text(null) .append("tspan") .attr("x", x) .attr("y", y) .attr("dy", dy + "em"); while (word = words.pop()) { line.push(word); tspan.text(line.join(" ")); if (tspan.node().getComputedTextLength() > width) { line.pop(); tspan.text(line.join(" ")); line = [word]; tspan = text.append("tspan") .attr("x", x) .attr("y", y) .attr("dy", ++lineNumber * lineHeight + dy + "em") .text(word); } } }); } const nodes = [1, 2, 3] // 标准enter-update-exit流程 const nodeTexts = vis.g.selectAll('text.node').data(nodes) // 先处理删除 nodeTexts.exit().remove() // 处理更新:先设置文本、调用换行,再做过渡动画 nodeTexts .text('This is a long text') .call(wrap, 30) .transition(transitionDuration) .attr('x', (d, i) => i*30) .attr('y', (d, i) => i*30) // 处理新增节点 const nodeEnter = nodeTexts.enter() .append('text') .attr('class', 'node') .attr('text-anchor', 'middle') .attr('dominant-baseline', 'middle') .attr('font-size', 12) .style('cursor', 'pointer') .attr('opacity', '0') .attr('x', (d, i) => i*30) .attr('y', (d, i) => i*30) // 先设置文本调用换行,再开过渡 .text('This is a long text') .call(wrap, 30) .transition() .attr('opacity', '1') .attr('x', (d, i) => i*30) .attr('y', (d, i) => i*30)
内容的提问来源于stack exchange,提问作者altern
相关产品推荐
相关产品推荐

