D3.js 更新嵌套数据

D3.js 更新嵌套数据,d3.js,D3.js,我试图找出如何在嵌套深度大于2级的D3应用程序中更新嵌套数据。让我们从我的代码开始 这是页面准备就绪时的jQuery处理程序 $(function () { var data = createDataSet(); updateD3(data); setTimeout(function () { var dataAgain = createDataSet(); updateD3(dataAgain); }, 5000); });

我试图找出如何在嵌套深度大于2级的D3应用程序中更新嵌套数据。让我们从我的代码开始

这是页面准备就绪时的jQuery处理程序

$(function () {
    var data = createDataSet();
    updateD3(data);

    setTimeout(function () {
        var dataAgain = createDataSet();
        updateD3(dataAgain);
    }, 5000);
});
这里是更新函数

function updateD3(data) {
    var level1 = d3
        .select('body')
        .selectAll('div.level-1')
        .data(data);

    // UPDATE existing data.
    level1
        .text(function (d) { return d.nameLevelOne + '-'; })
        .selectAll('div.level-2')
        .data(function (d) { return d.valuesLevelOne; })
        .text(function (d) { return d.nameLevelTwo + '-'; })
        .selectAll('div.level-3')
        .data(function (d) { return d.valuesLevelTwo; })
        .text(function (d) { return d.nameLevelThree + ' ' + d.count + '-'; });

    // CREATE new data.
    level1
    .enter()
        .append('div')
        .attr('class', 'level-1')
        .text(function (d) { return d.nameLevelOne; })
        .selectAll('div')
        .data(function (d) { return d.valuesLevelOne; })
    .enter()
        .append('div')
        .attr('class', 'level-2')
        .text(function (d) { return d.nameLevelTwo; })
        .selectAll('div')
        .data(function (d) { return d.valuesLevelTwo; })
    .enter()
        .append('div')
        .attr('class', 'level-3')
        .text(function (d) { return d.nameLevelThree + ' ' + d.count; });

    // REMOVE deleted data.
    level1
    .exit()
        .selectAll('div')
        .transition()
        .style('opacity', 0)
        .remove();
}
这里是数据创建函数,它还记录了数据的结构

function createDataSet() {
        return [
        {
            nameLevelOne: 'A',
            valuesLevelOne: [{
                nameLevelTwo: 'AA',
                valuesLevelTwo: [
                    {
                        nameLevelThree: 'AAA',
                        count: Math.random() * 100
                    }
                ]
            }]
        },
        {
            nameLevelOne: 'B',
            valuesLevelOne: [{
                nameLevelTwo: 'BB',
                valuesLevelTwo: [
                    {
                        nameLevelThree: 'BBB',
                        count: Math.random() * 100
                    }
                ]
            }]
        }
    ];
}
当我在浏览器中运行此代码时,第一个
updateD3()
调用非常完美。它表明:

A
AA
AAA 24.26636815071106
B
BB
BBB 37.17236865777522
当5秒过后,创建了一个新的数据集并将其传递给另一个对
updateD3()
的调用时,输出将更改为:

A-
B-
这不是我期望的结果。我没想到DOM的任何部分会被摧毁。基本上,我希望
AAA
BBB
的数字更新为新值

为什么会发生这种情况?如何仅使用更新的数据更新DOM?

我在互联网上到处寻找解决方案,但几乎每个“嵌套”数据的示例实际上只有两层深度,或者如果数据超过两层深度,则示例中没有显示更新数据的代码


非常感谢您的帮助,特别是在我为此用头撞墙6个小时后。

您需要在每个级别上选择一次,而不是多次,例如

var level1 = selection.data(...);
level1.enter()...
level1.exit()...
level1....

var level2 = level1.selectAll(...).data(...);
level2.enter()...
level2.exit()...
level2...

var level3 = level2.selectAll(...).data(...);
// etc

当您多次进行选择并绑定数据时,这些选择会相互影响,并且您会在选择中得到错误的元素。

每个
是什么。数据(…)
应该给出什么调用?我相信应该为
level1
调用提供原始数据,但是对
level2
level3
的调用是不是分别返回
d.valuesLevelOne
d.valuesLevelTwo
的函数?我现在有点进一步了。我没有意识到您必须绑定数据,然后
输入
,然后
退出
,然后
更新
。现在唯一的问题是,如果我更改数据并进行更新,
B
BB
BBB
部分将消失。有什么想法吗?这是我的代码目前的一个工作版本:您只选择了
div
s,所以实际上所有嵌套的
div
s都在顶级选择中。您可以使用在选择器中指定的类名来修复该问题。我也简化了你的代码谢谢你,拉尔斯。这很有帮助。我唯一的最后一个问题是:在您对JSFIDLE的编辑中,每次更新时,似乎都在为
AA
AAA
BB
BBB
部分销毁并重新创建DOM。D3就是这样工作的,还是有办法只更新DOM(而不是销毁它)?我不知道你说的“销毁DOM”是什么意思。如果这是您的意思,那么这些元素并不是全部删除然后重新读取的。