d3.js 使用 exit() 和 enter() 进行子转换

Posted

技术标签:

【中文标题】d3.js 使用 exit() 和 enter() 进行子转换【英文标题】:d3.js Subtransition with exit() and enter() 【发布时间】:2014-12-12 19:44:47 【问题描述】:

问题简短: 如何在this.selection.exit() 的子转换中访问整个this.selection

我正在尝试制作 d3.js 过渡序列。我知道如何使用transition.transition() 函数来创建序列,但这是我的问题。

顺序应该是:[删除.exit()节点]→[移动节点]→[添加.enter()节点]

代码是:

        this.selection.exit().remove();
        this.selection
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight);
        this.selection.enter().append("div")
            .attr("class", "node")
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight);

如果我在上面的每个命令中添加transition(),所有转换将同时开始。 .delay() 似乎不能同时处理多个转换。

所以我想使用带有.transition() 的子转换,但是如果我将第二个命令应用于第一个命令,我只有.exit() 选择。

编辑 1:

举例说明它是如何工作的:

        this.selection.exit().transition()
        .duration(1000).style("opacity", 0).remove();

        this.selection.transition().delay(1010)
            .duration(1000)
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight)

        this.selection.enter().append("div")
            .attr("class", "node")
            .style("opacity", 0)
            .style("left", this.styleLeft)
            .style("top", this.styleTop)
            .style("width", this.styleWidth)
            .style("height", this.styleHeight)
            .transition()
            .delay(2020)
            .duration(1000)
            .style("opacity", 1);

这里的错误:最后一个转换没有开始,因此所有新节点都是不透明的。但如果我禁用第二个转换,它会起作用。

编辑 2:

http://jsfiddle.net/dq6d117g/6/

如果在转换过程中再次调用该函数,则会出现问题。

另外,延迟应该和动画一样长。如果没有动画,延迟应该是 0。这就是我想使用结束事件的原因。

【问题讨论】:

使用.delay() 应该在这里工作——你能举个例子说明它在哪里不行吗? 谢谢,但是你能不能把它作为一个可重复的例子?我想运行它看看会发生什么。 好的,如果在转换过程中再次调用该函数会出现问题 是的,安排新的过渡会取消所有正在运行的过渡。 【参考方案1】:

您可以按照 Mike Bostock 的 answer here 使用 d3.transition().each() 在预先存在的选择上链接转换,但是,在我的测试中它没有跳过不需要的转换,所以我添加了条件来跳过空选择的转换:

http://jsfiddle.net/dq6d117g/8/

var transition=d3.transition().duration(2000);

if (!selection.exit().empty()) transition=transition.each(function()
    selection.exit()
        .transition()
        .style("opacity", 0)
        .remove();
).transition();

if (!selection.empty()) transition=transition.each(function()
    selection.transition()
    .style("height", function (d) 
        return (d.value * 10) + "px";
    );
).transition();

transition.each(function()
    selection.enter()
        .append("div")
        .attr("class", "bar")
        .attr("id", function (d) 
            return d;
        )
        .style("opacity", 0)
        .style("height", function (d) 
            return (d.value * 9) + "px";
        )
        .text(function (d) 
            return d.id
        )
        .transition()
        .style("opacity", 1)
        .style("height", function (d) 
            return (d * 10) + "px";
        );
);

【讨论】:

以上是关于d3.js 使用 exit() 和 enter() 进行子转换的主要内容,如果未能解决你的问题,请参考以下文章

理解d3.js中的UpdateEnterExit

D3.js使用过程中的常见问题(D3版本D3V4)

d3.js(v5.7)的node与数据匹配(自动匹配扩展函数)

D3.js 与 React.js

D3.js 加标签

D3.js 绘制散点图