2

I'm working with D3 to create a tree layout that user's can manipulate. I have an object that contains child arrays of other objects in an app that let's the user choose different paths.

I started with an object with no IDs and looped through them using D3 to add IDs:

    var source = {
    "name": "Top Condition",
    "state": "condition",
    "children": [{
            "name": "Open",
            "dest": "true",
            "state": "open"
    }, {
            "name": "Sub Condition 1",
            "dest": "false",
            "state": "condition",
            "children": [{
                    "name": "Open",
                    "dest": "true",
                    "state": "open"
            }, {
                    "name": "Open",
                    "dest": "false",
                    "state": "open"
            }, {
                    "name": "Open",
                    "dest": "unknown",
                    "state": "open",
                    "children": [{
                            "name": "Open",
                            "dest": "true",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "dest": "false",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "dest": "unknown",
                            "state": "open"
                    }]
            }]
    },{
            "name": "Sub Condition 2",
            "dest": "unknown",
            "state": "condition"
            ,"children": [{
                    "name": "Open",
                    "dest": "true",
                    "state": "open"
            }, {
                    "name": "Open",
                    "dest": "false",
                    "state": "open"
            }, {
                    "name": "Sub Condition 3",
                    "dest": "false",
                    "state": "condition",
                    "children": [{
                            "name": "Open",
                            "dest": "true",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "dest": "false",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "dest": "unknown",
                            "state": "open"
                    }]

            }]
    }]
}




// Compute the new tree layout.
var nodes = tree.nodes(source).reverse(),
        links = tree.links(nodes);

// Update the nodes with IDs
var node = svg.selectAll("g.node")
    .data(nodes, function (d) {
    return d.id || (d.id = ++i);
});

Here is the object I am working with after D3 does it's magic above (ID's added manually, not exactly what would be produced by D3):

source = {
    "name": "Top Condition",
    "id": 1,
    "state": "condition",
    "children": [{
            "name": "Open",
            "id": 2,
            "dest": "true",
            "state": "open"
    }, {
            "name": "Sub Condition 1",
            "id": 3,
            "dest": "false",
            "state": "condition",
            "children": [{
                    "name": "Open",
                    "id": 4,
                    "dest": "true",
                    "state": "open"
            }, {
                    "name": "Open",
                    "id": 5,
                    "dest": "false",
                    "state": "open"
            }, {
                    "name": "Open",
                    "id": 6,
                    "dest": "unknown",
                    "state": "open",
                    "children": [{
                            "name": "Open",
                            "id": 14,
                            "dest": "true",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "id": 15,
                            "dest": "false",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "id": 16,
                            "dest": "unknown",
                            "state": "open"
                    }]
            }]
    },{
            "name": "Sub Condition 2",
            "id": 7,
            "dest": "unknown",
            "state": "condition"
            ,"children": [{
                    "name": "Open",
                    "id": 8,
                    "dest": "true",
                    "state": "open"
            }, {
                    "name": "Open",
                    "id": 9,
                    "dest": "false",
                    "state": "open"
            }, {
                    "name": "Sub Condition 3",
                    "id": 10,
                    "dest": "false",
                    "state": "condition",
                    "children": [{
                            "name": "Open",
                            "id": 11,
                            "dest": "true",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "id": 12,
                            "dest": "false",
                            "state": "open"
                    }, {
                            "name": "Open",
                            "id": 13,
                            "dest": "unknown",
                            "state": "open"
                    }]

            }]
    }]
}

So what I want to be able to do is have a function that takes an object's ID and either adds a 'children' array to an object (or removes a children array) somewhere nested in source.

So for instance, for the object containing id: 13, I would like to add this to the object:

    var children = [{
        "name": "Open",
        "dest": "true",
        "state": "open"
}, {
        "name": "Open",
        "dest": "false",
        "state": "open"
}, {
        "name": "Open",
        "dest": "unknown",
        "state": "open"
}];

Also, I would need the ability to do the opposite and remove the children array from say ID 10.

I would then run it back through D3 to get IDs for any nodes that were entered and re-render the tree.

Is this possible and how could I accomplish it? I'm open to using underscore or another library but couldn't figure out how based on my understanding of the documentation.

2
  • Let try to clear this out you one to find one object based on ID and add an array of children. Is this correct? Commented Jan 22, 2014 at 21:14
  • That's correct. I also want to be able to find an object that already has the children array and remove it. Commented Jan 22, 2014 at 21:28

1 Answer 1

3

The easiest approach here is probably to walk the tree to create a separate map to reference objects by id:

// set up the map
var idMap = {};

// recursive collection function
function collect(item) {
    idMap[item.id] = item;
    // recurse through the children, if any
    (item.children || []).map(collect);
}

// kick off
collect(source);

Now you have a map like { 1: <Object>, 2: <Object>, ...}, and it's simple enough to add or remove children with a separate function, e.g.:

function updateChildren(id, children) {
    var o = idMap[id];
    o.children = children;
}

You might want to do other things here as well, e.g. updating the id map based on the new children (or on the removal of children), merging old and new children, etc.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.