Reputation: 2363
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.
Upvotes: 2
Views: 1096
Reputation: 55688
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.
Upvotes: 3