javascriptdata-bindingd3.jstransitioncircle-pack

Updating a layout.pack in d3.js


I am trying to wrap my mind around d3's pack layout (http://bl.ocks.org/4063530).

I have the basic layout working but I would like to update it with new data. i.e. collect new data, bind it to the current layout.pack and update accordingly (update/exit/enter).

My attempts are here (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; });

    };

Specific questions...

How do I bind the data? (since the data is not complex structure and not an array of data)

How can new nodes/leafs be added to the layout? And old ones removed?

Pointers to a working example would be greatly appreciated.


Solution

  • Working example is here.

    Basically, there is code for initial load, where all circles, tooltips, etc. are created and positioned in initial places. As well, the layout (pack) is created.

    Than, on each button press, new data is loaded into pack, and the pack is recalculated. That crucial code is here:

    Here you bind (load) now data into pack layout: (in my example its random data, of course you'll have your data from json or code or similar):

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

    Here the new layout is calculated:

    pack.nodes(data);
    

    After that, elements are transitioned to new positions, and its attributes are changed as you determine.

    I just want to stress that I don't use enter/update/exit pattern or transformations (that you might see in others solutions), since I believe this introduces unnecessary complexity for examples like this.

    Here are some pics with transition in action:

    Start:

    start

    Transition:

    transition

    End:

    end