user1114
user1114

Reputation: 1169

D3 Zoomable Treemap changing the children accessor

I am trying to use Mike Bostock's zoomable treemap http://bost.ocks.org/mike/treemap/ with one modification. Instead of using nested JSON data, I have have a simple mapping from parents to a list of children. I built a function, getChildren(root), that simply returns root's children, or null if root does not have any children.

I have tried replacing all instances of d.children() with getChildren(d) in the treemap javascript file, but it seems that it is not working properly.

The resulting page shows the orange bar as normal up top, but nothing else displays correctly (i.e. there are no rectangles underneath the orange bar, just empty gray space). All the text from the children is mashed up in the top left corner of the empty gray space, so it might be that coordinates are not being assigned correctly.

Any ideas?? Thanks!

Upvotes: 2

Views: 1079

Answers (1)

nrabinowitz
nrabinowitz

Reputation: 55678

It looks like there were a few issues here:

  • Your data structure doesn't seem to be referencing the child nodes:

    var nMap = {};
    nMap.papa = {};
    nMap.papa["children"] = [];
    nMap.papa["children"].push({
        "name": "c1"
    });
    // snip
    nMap.c1 = {
        size: 5
    };
    

    Unless I'm missing something, your getChildren function gets the { name: "c1" } object but never looks up nMap.c1. I'm not exactly certain what your alternative data structure is trying to achieve, but it seems like the most obvious option is to use a flat map of nodes, with children referenced by id, like this:

    var nMap = {};
    nMap.c1 = {
        name: "c1",
        value: 5
    };
    nMap.c2 = {
        name: "c2",
        value: 5
    };
    nMap.c3 = {
        name: "c3",
        value: 5
    };
    nMap.papa = {
        name: "papa",
        children: ['c1', 'c2', 'c3']
    };
    

    With a structure like this, you can map to the real children in the getChildren function:

    function getChildren(par){
         var parName = par.name,
             childNames = parName in nMap && nMap[parName].children;
         if (childNames) {
             // look up real nodes
             return childNames.map(function(name) { return nMap[name]; });
         } 
    }
    
  • Your children were using size instead of value to indicate weight, and the rest of the code expected value (so they all had weight 0).

  • Because you're using the "zoomable" treemap approach, which uses a specialized version of the treemap layout, you don't need to specify the .children accessor of the treemap layout. Instead, use your custom accessor in the the custom layout helper:

    function layout(d) {
        // get the children with your accessor
        var children = getChildren(d);
        if (children && children.length > 0) {
            treemap.nodes({ children: children });
            children.forEach(function(c) {
                c.x = d.x + c.x * d.dx;
                c.y = d.y + c.y * d.dy;
                c.dx *= d.dx;
                c.dy *= d.dy;
                c.parent = d;
                layout(c);
            });
        }
    }
    

Working fiddle here: http://jsfiddle.net/nrabinowitz/WpQCy/

Upvotes: 2

Related Questions