Is it possible for a node to have multiple parents?

Hi ,

I have a requirement where in the organization chart, a node has multiple parents, could please help me get a sample on how to configure a node with multiple parents.??

Regards,
Kshitij

Yes, you can have nodes have both “children” and “parents”. However that is no longer a tree structured graph, so you will not be able to use a TreeModel – you must use a GraphLinksModel. Whether or not you can use TreeLayout depends on the circumstances.

If there is just one node that has “descendants” and “ancestors”, you could do what the Double Tree sample does: Double Tree. That basically uses two TreeLayouts going in opposite directions.

If there are any number of nodes that have multiple “parents” but no further “grandparent”, and none of those have their own “children”, one could still use a TreeLayout by customizing the layout to pretend that the extra “parents” are part of the main “parent” node which is a lot bigger to make room for the other “parents”.

But more generally, you may need to use LayeredDigraphLayout. However that is vastly slower than TreeLayout, so the size of the graph that you can handle will be limited by your patience. Alas, JavaScript is several-to-many times slower than .NET or Java.

Examples of LayeredDigraphLayout include Beat Paths, Data Flow Diagram, Sankey Diagram, Page Flow, and Swim Lanes (vertical). You can play with the layout’s properties at Layered Digraph Layout.

The doubletree sample linked is so close to what I’m looking for, but seems to not care about the direction of the links. This first screen shot below is ultimately what I’m looking for, but required me to manually re-position Owner 1-4 nodes. The teal node is the root of this double tree. Basically it has 4 parents that, as you can see, have a percentage of ownership of the root node. That root node then has ownership of, in this case, two actual children 1 and 2 (not pictured). The tree primarily grows down, and at the moment the requirement is only that the root can have N parents. No grandparent or any other children of those parents, just the link to root.

What I actually get, prior to moving these nodes:

The code is below, and is adapted from the doubletree sample. I’m using a GraphLinksModel with arrays for both nodes and links. It currently generates the down tree as I’d expect, but yields the above graph with the Owner nodes clustered around, and in the case of Owner 1, behind the root. I assume this is partially related to the fact that I’m configuring multiple parents to root, but I think I have to do that to preserve the cardinality of the link/ownership. When configuring the diagram initially, I am not specifying a layout, per the doubletree sample and then I attempt to collect all nodes going up/down. You can see the commented out code where I attempt to manually collect the parts of the up graph. Like I said, the doubletree appears to not care about the cardinality and the nodes to the right and left are all children. In my case the sample code doesn’t pick up Owner 1-4 as up nodes because they aren’t actually children of the root per the linkData from/to.

I feel like the key to my answer lies in the following from walter, but I’m not clear on exactly what he means:

If there are any number of nodes that have multiple “parents” but no further “grandparent”, and none of those have their own “children”, one could still use a TreeLayout by customizing the layout to pretend that the extra “parents” are part of the main “parent” node which is a lot bigger to make room for the other “parents”.

He seems to indicate that there needs to be more room for the “parents” which I would agree with, but how? And how can I get them to layout with proper layer spacing/style as all children in the down graph?

Apologies for the length, and if more code is required, I’m happy to provide the entire file I’m using, but it would require a bit more blanking out of more sensitive data. Thanks!

function doubleTreeLayout(diagram)
{
	// Within this function override the definition of '$' from jQuery:
	var $ = go.GraphObject.make;  // for conciseness in defining templates
	diagram.startTransaction("Double Tree Layout");

	// split the nodes and links into two Sets, depending on direction
	var upParts = new go.Set(go.Part);
	var downParts = new go.Set(go.Part);
	separatePartsByLayout(diagram, upParts, downParts);

	// but the ROOT node will be in both collections

	// create and perform two TreeLayouts, one in each direction,
	// without moving the ROOT node, on the different subsets of nodes and links
	var layout1 =
	$(go.TreeLayout,
	{ 
		angle: 270,
		nodeSpacing: 0,
		layerSpacing: 0,
		layerStyle: go.TreeLayout.LayerSiblings, 
		arrangement: go.TreeLayout.ArrangementFixedRoots,
		childPortSpot: go.Spot.Bottom,
		portSpot: go.Spot.Top,
		setsPortSpot: false,
		setsChildPortSpot: false
	});

	var layout2 =
	$(go.TreeLayout,
	{
		angle: 90,
		nodeSpacing: 80,
		layerSpacing: 150,
		layerStyle: go.TreeLayout.LayerSiblings,
		arrangement: go.TreeLayout.ArrangementFixedRoots,
		//setsPortSpot: false,
		setsChildPortSpot: false
	});

	layout1.doLayout(upParts);
	layout2.doLayout(downParts);

	diagram.commitTransaction("Double Tree Layout");
}

function separatePartsByLayout(diagram, upParts, downParts)
{
	var root = diagram.findNodeForKey("0");
	if (root === null) return;

	// the ROOT node is shared by both subtrees!
	upParts.add(root);
	downParts.add(root);				

	// look at all of the immediate children of the ROOT node
	root.findTreeChildrenNodes().each(function(child)
	{
		// in what direction is this child growing?
		var dir = child.data.dir;
		
		var coll = (dir === "up") ? upParts : downParts;
		
		// add the whole subtree starting with this child node
		coll.addAll(child.findTreeParts());
		
		// and also add the link from the ROOT node to this child node
		coll.add(child.findTreeParentLink());
	});
	
	// todo: get the up parts dynamically
	//upParts.add(diagram.findNodeForKey("-1"));
	//upParts.add(diagram.findNodeForKey("-2"));
	//upParts.add(diagram.findNodeForKey("-3"));
	//upParts.add(diagram.findNodeForKey("-4"));
	
	//upParts.addAll(diagram.findNodeForKey("-1").findTreeParts());
	//upParts.addAll(diagram.findNodeForKey("-2").findTreeParts());
	//upParts.addAll(diagram.findNodeForKey("-3").findTreeParts());
	//upParts.addAll(diagram.findNodeForKey("-4").findTreeParts());
}


// set up the nodeDataArray, describing each entity
var nodeDataArray = [
	{ key: -1, longname: "Owner 1 [Technically Parent of Root]", shortname: "O1", category: "main2", dir: "up"},
	{ key: -2, longname: "Owner 2 [Technically Parent of Root]", shortname: "O2", category: "main2", dir: "up"},
	{ key: -3, longname: "Owner 3 [Technically Parent of Root]", shortname: "O3", category: "main2", dir: "up"},
	{ key: -4, longname: "Owner 4 [Technically Parent of Root]", shortname: "O4", category: "main2", dir: "up"},
	
	{ key: 0, longname: "Root", shortname: "Root", category: "main"},
	
	{ key: 1, longname: "Root Child 1", shortname: "RC 1", category: "entityExceptMain", dir: "down"},
	{ key: 2, longname: "Root Child 2", shortname: "RC 2", category: "entityExceptMain", dir: "down"},
	
	// snip (lots more children of 1 and 2
]

var linkDataArray = [
	{ from: -1, to: 0, text: "25%", category: "ownership"},
	{ from: -2, to: 0, text: "25%", category: "ownership"},
	{ from: -3, to: 0, text: "25%", category: "ownership"},
	{ from: -4, to: 0, text: "25%", category: "ownership"},
	
	{ from: 0, to: 1, text: "100%", category: "ownership"},
	{ from: 0, to: 2, text: "100%", category: "ownership"},
	
	{ from: 1, to: 3, text: "83.57%", category: "ownership"},
	{ from: 1, to: 4, text: "93.88%", category: "ownership"},
	
	// snip (lots more children linked below to 1 and 2
]

Why not use a LayeredDigraphLayout with { direction: 90 }.

That appears to be exactly what I want! I was incorrectly trying to force it to be a tree. I think we have some diagrams that get larger, but hopefully not too big to run into performance issues. Thanks!