I want to generate this:
With this data structure (ids are random, btw not sequential):
var tree = [
{ "id": 1, "name": "Me", "dob": "1988", "children": [4], "partners" : [2,3], root:true, level: 0, "parents": [5,6] },
{ "id": 2, "name": "Mistress 1", "dob": "1987", "children": [4], "partners" : [1], level: 0, "parents": [] },
{ "id": 3, "name": "Wife 1", "dob": "1988", "children": [5], "partners" : [1], level: 0, "parents": [] },
{ "id": 4, "name": "son 1", "dob": "", "children": [], "partners" : [], level: -1, "parents": [1,2] },
{ "id": 5, "name": "daughter 1", "dob": "", "children": [7], "partners" : [6], level: -1, "parents": [1,3] },
{ "id": 6, "name": "daughter 1s boyfriend", "dob": "", "children": [7], "partners" : [5], level: -1, "parents": [] },
{ "id": 7, "name": "son (bottom most)", "dob": "", "children": [], "partners" : [], level: -2, "parents": [5,6] },
{ "id": 8, "name": "jeff", "dob": "", "children": [1], "partners" : [9], level: 1, "parents": [10,11] },
{ "id": 9, "name": "maggie", "dob": "", "children": [1], "partners" : [8], level: 1, "parents": [] },
{ "id": 10, "name": "bob", "dob": "", "children": [8], "partners" : [11], level: 2, "parents": [12] },
{ "id": 11, "name": "mary", "dob": "", "children": [], "partners" : [10], level: 2, "parents": [] },
{ "id": 12, "name": "john", "dob": "", "children": [10], "partners" : [], level: 3, "parents": [] },
{ "id": 13, "name": "robert", "dob": "", "children": [9], "partners" : [], level: 2, "parents": [] },
{ "id": 14, "name": "jessie", "dob": "", "children": [9], "partners" : [], level: 2, "parents": [15,16] },
{ "id": 15, "name": "raymond", "dob": "", "children": [14], "partners" : [], level: 3, "parents": [] },
{ "id": 16, "name": "betty", "dob": "", "children": [14], "partners" : [], level: 3, "parents": [] },
];
To give a description of the data structure, the root/starting node (me) is defined. Any partner (wife,ex) is on the same level. Anything below becomes level -1, -2. Anything above is level 1, 2, etc. There are properties for parents, siblings, children and partners which define the ids for that particular field.
In my previous question, eh9 described how he would solve this. I am attempting to do this, but as I've found out, it isn't an easy task.
My first attempt is rendering this by levels from the top down. In this more simplistic attempt, I basically nest all of the people by levels and render this from the top down.
My second attempt is rendering this with one of the ancestor nodes using a depth-first search.
My main question is: How can I actually apply that answer to what I currently have? In my second attempt I'm trying to do a depth first traversal but how can I even begin to account for calculating the distances necessary to offset the grids to make it consistent with how I want to generate this?
Also, is my understanding/implementation of depth-first ideal, or can I traverse this differently?
The nodes obviously overlap in my second example since I have no offsetting/distance calculation code, but I'm lost as to actually figuring out how I can begin that.
Here is a description of the walk function I made, where I am attempting a depth first traversal:
// this is used to map nodes to what they have "traversed". So on the first call of "john", dict would internally store this:
// dict.getItems() = [{ '12': [10] }]
// this means john (id=10) has traversed bob (id=10) and the code makes it not traverse if its already been traversed.
var dict = new Dictionary;
walk( nested[0]['values'][0] ); // this calls walk on the first element in the "highest" level. in this case it's "john"
function walk( person, fromPersonId, callback ) {
// if a person hasn't been defined in the dict map, define them
if ( dict.get(person.id) == null ) {
dict.set(person.id, []);
if ( fromPersonId !== undefined || first ) {
var div = generateBlock ( person, {
// this offset code needs to be replaced
top: first ? 0 : parseInt( $(getNodeById( fromPersonId ).element).css('top'), 10 )+50,
left: first ? 0 : parseInt( $(getNodeById( fromPersonId ).element).css('left'), 10 )+50
});
//append this to the canvas
$(canvas).append(div);
person.element = div;
}
}
// if this is not the first instance, so if we're calling walk on another node, and if the parent node hasn't been defined, define it
if ( fromPersonId !== undefined ) {
if ( dict.get(fromPersonId) == null ) {
dict.set(fromPersonId, []);
}
// if the "caller" person hasn't been defined as traversing the current node, define them
// so on the first call of walk, fromPersonId is null
// it calls walk on the children and passes fromPersonId which is 12
// so this defines {12:[10]} since fromPersonId is 12 and person.id would be 10 (bob)
if ( dict.get(fromPersonId).indexOf(person.id) == -1 )
dict.get(fromPersonId).push( person.id );
}
console.log( person.name );
// list of properties which house ids of relationships
var iterable = ['partners', 'siblings', 'children', 'parents'];
iterable.forEach(function(property) {
if ( person[property] ) {
person[property].forEach(function(nodeId) {
// if this person hasnt been "traversed", walk through them
if ( dict.get(person.id).indexOf(nodeId) == -1 )
walk( getNodeById( nodeId ), person.id, function() {
dict.get(person.id).push( nodeId );
});
});
}
});
}
}
Requirements/restrictions:
- This is for an editor and would be similar to familyecho.com. Pretty much any business rules not defined can be assumed through that.
- In-family breeding isn't supported as it would make this way too complex. Don't worry about this.
- Multiple partners are supported so this isn't as easy as a traditional "family tree" with just 2 parents and 1 child.
- There is only one "root" node, which is just the starting node.
Notes: familyecho.com seems to "hide" a branch if there's lots of leaf nodes and there's a collision. May need to implement this.
id
ordering matches the level ordering? And you always get the person's level in the data? So to understand better, you just need to figure out how to render the branches and the x offsets of each person? – Teddytedeschiid
is just an increment/GUID which has nothing to do withlevel
. This "tree" data assumes this data is stored and loaded, and I'll just re-render the family graph in a permalink page basically. – Cathrineid
(which matches your rendering). Is this just for ease of explanation of what you want? i.e. if you added robert and jessie before bob and mary their ids would not be in layer rendering order? – Teddytedeschi