在d3.js中更新layout.pack

时间:2013-02-10 02:40:49

标签: javascript data-binding d3.js transition circle-pack

我试图围绕d3的包布局(http://bl.ocks.org/4063530)。

我的基本布局有效,但我想用新数据更新它。即收集新数据,将其绑定到当前layout.pack并相应更新(更新/退出/输入)。

我的尝试在这里(http://jsfiddle.net/emepyc/n4xk8/14/):

var bPack = function(vis) {
    var pack = d3.layout.pack()
    .size([400,400])
    .value(function(d) {return d.time});

    var node = vis.data([data])
    .selectAll("g.node")
    .data(pack.nodes)
    .enter()
    .append("g")
    .attr("class", function(d) { return d.children ? "node" : "leaf node"; })
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

node.append("circle")
    .attr("r", function(d) { return d.r });

    node.filter(function(d) { return !d.children; }).append("text")
    .attr("text-anchor", "middle")
    .attr("dy", ".3em")
    .text(function(d) { return d.analysis_id });

    bPack.update = function(new_data) {
        console.log("UPDATE");

        node
        .data([new_data])
        .selectAll("g.node")
        .data(pack.nodes);

        node
        .transition()
        .duration(1000)
        .attr("class", function(d) { return d.children ? "node" : "leaf node" })
    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")" });

        node.selectAll("circle")
        .data(new_data)
        .transition()
    .duration(1000)
    .attr("r", function(d) { return d.r; });

    };

具体问题......

如何绑定数据? (因为数据不是复杂的结构而不是数据数组)

如何将新节点/叶子添加到布局中?旧的被删除了吗?

非常感谢对工作示例的指示。

3 个答案:

答案 0 :(得分:10)

工作示例是here

基本上,有初始加载的代码,其中所有圆圈,工具提示等都是在初始位置创建和定位的。同样,也会创建布局(包)。

然后,按下每个按钮,将新数据加载到包中,然后重新计算包。这个关键代码在这里:

在这里你将数据绑定(加载)到包布局:(在我的例子中它的随机数据,当然你将从json或代码或类似的数据获得你的数据):

pack.value(function(d) { return 1 +
             Math.floor(Math.random()*501); });

此处计算新布局:

pack.nodes(data);

之后,元素将转换为新位置,其属性会在您确定时更改。

我只想强调一点,我不使用输入/更新/退出模式或转换(您可能会在其他解决方案中看到),因为我认为这会为此类示例带来不必要的复杂性。

以下是一些有效过渡的照片:

开始:

start

过渡:

transition

结束:

end

答案 1 :(得分:4)

我最近遇到了同样的问题,并且也遇到了一般更新模式教程。这些不符合我的目的。我在图中有几百个DOM元素(ForceLayout),然后我收到了REST数据,其中包含每个节点的属性。通过重新绑定数据进行刷新导致重建整个图表,正如您在回应mg1075的建议时所说的那样。在我的案例中,花了几分钟才完成更新DOM。

我最终为需要更新的元素分配了唯一ID,我用JQuery选择了它们。我的整个图表设置使用D3,但我的更新没有。这感觉不好,但它运作得很好。而不是花费几分钟来销毁和重新创建我的大多数DOM,它需要花费3秒钟的时间(省略REST调用的时间)。我没有看到在D3中无法实现类似属性更新的原因。

也许如果Mike Bostock在enter()选择中添加了remove()或正确的子选择函数,我们可以按照纯D3模式进行更新。虽然搞清楚这一点,但我试图绑定一个数据子集,添加新属性的数据,然后进行子选择以获取需要更新的元素,但由于输入的有限和特定性质,它不起作用()选择。

答案 2 :(得分:3)

相关的,如果你还没有审查过:
http://bl.ocks.org/3808218 - 一般更新模式,I
http://bl.ocks.org/3808221 - 一般更新模式,II http://bl.ocks.org/3808234 - 一般更新模式,III

此示例小提琴没有转换,但这里至少有一种更新数据的方法。

http://jsfiddle.net/jmKH6/

//  VISUALIZATION
var svg = d3.select("#kk")
    .append("svg")
    .attr("width", 500)
    .attr("height", 600)
    .attr("class", "pack"); 

var g = svg.append("g")
    .attr("transform", "translate(2,2)");

var pack = d3.layout.pack()
        .size([400,400])
        .value(function(d) {return d.time});

function update(data) {

    var nodeStringLenth = d3.selectAll("g.node").toString().length; 
    if ( nodeStringLenth > 0) {
        d3.selectAll("g.node")
            .remove();
    }

    var node = g.data([data]).selectAll("g.node")
            .data(pack.nodes);

        node.enter()
          .append("g")
            .attr("class", function(d) { return d.children ? "node" : "leaf node"; })
            .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

        node.append("circle")
            .attr("r", function(d) { return d.r });

        node.filter(function(d) { return !d.children; }).append("text")
            .attr("text-anchor", "middle")
            .attr("dy", ".3em")
            .text(function(d) { return d.analysis_id });

       node
            .exit()
            .remove();
}


var myData = [data1, data2, data3];
update(data1); 
setInterval(function() {
    update( myData[Math.floor(Math.random() * myData.length)] );  // http://stackoverflow.com/questions/4550505/getting-random-value-from-an-array?lq=1
}, 1500);