Creating branches in treelayout

Hi GoJs Team,

We are evaluating the GoJS HTML5 library to implement a flow component within our product, but we are facing some issues while drawing.

Please find following scenarios.

Problem 1:

When Two nodes are having same parent, The links are not starting exactly from the split node. Please refer point 1 in below image.

We tried with other routing properties too in link template, but while using other properties(other than AvoidsNodes) links are getting intersected.

Problem 2:

When Two links are merging at joint node, the joining is not happening at node point. Refer point 2 in below image.

And Joint node is not vertically aligned with respect to split node.

Note:

We tried with LayeredDigraphLayout, but it’s totally changing the diagram shape by giving unnecessary elbows.

Layout Properties Used:

_diagram = $$(go.Diagram, "myDiagram-" + id, {

initialAutoScale : go.Diagram.UniformToFill,

layout : $$(go.TreeLayout,{nodeSpacing:35}),

"toolManager.mouseWheelBehavior" : go.ToolManager.WheelZoom,

initialContentAlignment : go.Spot.Center,

allowMove : false,

allowDelete : false

});

Link Properties Used:

var linkTemplate = $$(go.Link,

{

routing : go.Link.AvoidsNodes ,

curve : go.Link.JumpOver,

corner : 3,

toShortLength : 2,

adjusting : go.Link.Stretch,

smoothness : 1

},

Please let us know your response.

Thank You

Srinivas

Try not using AvoidsNodes routing.

If you are using TreeLayout, try setting TreeLayout.setsPortSpot and setsChildPortSpot both to false. For LayeredDigraphLayout, set LayeredDigraphLayout.setsPortSpots.

I have tried with the above properties, still its not drawing as desired.
we are using AvoidsNodes to avoid cross overs like I mentioned in
http://www.nwoods.com/forum/forum_posts.asp?TID=5511&title=how-to-create-a-loop-in-tree-layout

Our main problem is:
A SplitNode will have few branches and these branches will merges at JointNode.
This JointNode should be aligned with respect to SplitNode.
But in result its not joining at desired location, and this joining location is not consistent.

Is there any way to achieve this.

But here you are explicitly not wanting orthogonally routed links, yes?

As I said in the other topic, you want to position the Join node yourself. TreeLayout will naturally align it with its parent node, since it is ignoring other incoming links.

And as I also said, for such situations one normally uses LayeredDigraphLayout inside Groups.

Sorry for posting other query in that thread.
We tried all the possible cases of routing, in all the cases avoidsNodes is giving nearest desired output.
And moreover we are using TreeLayout not LayeredDigraph.
As we are drawing it dynamically we are not applying/calculating location on JointNode,
Our first preference is not to position it by our self.
Is there is any way that it will join all the branches as its splitting.
If it’s not possible how can we position JointNode.
Is there any way to calculate JointNode location ?

Actually We are trying to achieve like this (or atleast nearest to this),

Is there a reason you are not using LayeredDigraphLayout? That should handle your Join node and I believe routing will be good too. As I said, most customers that do what you want have used LayeredDigraphLayout within Groups.

If you insist on using TreeLayout, you’ll need to override commitNodes in order to position the Join node where you want it to be, after calling the base method.

If you insist on using AvoidsNodes routing, you are discarding the routing that would be done by the TreeLayout or LayeredDigraphLayout.

Now we are using LayeredDigraph and Orthogonal for routing.And we are able to position required nodes overriding commitLayout.
( took reference from here http://www.gojs.net/latest/samples/parseTree.html )

Same way we want to route our links, which are having more(unnecessary ) turns.
Using this.network.edges we are getting all edges/links from the diagram.
after that we dont have any clue to update routing.
Is there any way to Route the edges/links.

It would be great if you provide information about what things we can do
in commitLayout(),commitNodes() and commitLinks() to set required nodes positions and route specific links.

I’m glad to hear that you are making good progress. LayeredDigraphLayout does try to straighten chains of nodes. Could you provide examples of what you mean?

With Current implementation we are getting output as first diagram, which is having extra turns.
we want A–>C and B–>C should have only one turn each, as showed in second diagram.
What our doubt is,
Can we get A–>C and B–>C edge/links. (While debugging we got edges using this.network.edges in commitLinks and commitLayout methods. )
If we get , is there any way that we can remove unnecessary turns.
If so, where and how we need to apply.

If modifying a route is not possible, is there any other solution which will do our work.

OK, try the following custom LayeredDigraphLayout, which overrides commitLinks to modify the routes of those split links and join/merge links to line up vertically (or horizontally if the layout direction is 90 or 270).

[code] // This custom LayeredDigraphLayout routes all of the links from split nodes and into join nodes
// so that they all have middle segments that have the same X or Y value.
function CoincidentRoutingLayout() {
go.LayeredDigraphLayout.call(this);
}
go.Diagram.inherit(CoincidentRoutingLayout, go.LayeredDigraphLayout);

CoincidentRoutingLayout.prototype.commitLinks = function() {
go.LayeredDigraphLayout.prototype.commitLinks.call(this);
if (this.direction === 0 || this.direction === 180) {
var vit = this.network.vertexes.iterator;
while (vit.next()) {
var v = vit.value;
var n = v.node;
var x;
if (n) {
var lit = n.findLinksInto();
if (lit.count > 1) {
if (this.direction === 0) {
x = n.position.x - this.layerSpacing/2;
} else {
x = n.position.x + n.actualBounds.width + this.layerSpacing / 2;
}
while (lit.next()) {
var l = lit.value;
if (l.pointsCount === 0) l.updateRoute();
if (l.pointsCount >= 6) {
var pts = l.points.copy();
var p2 = pts.elt(pts.length-4);
pts.setElt(pts.length-4, new go.Point(x, p2.y));
var p3 = pts.elt(pts.length-3);
pts.setElt(pts.length-3, new go.Point(x, p3.y));
l.points = pts;
}
}
}
lit = n.findLinksOutOf();
if (lit.count > 1) {
if (this.direction === 0) {
x = n.position.x + n.actualBounds.width + this.layerSpacing / 2;
} else {
x = n.position.x - this.layerSpacing / 2;
}
while (lit.next()) {
var l = lit.value;
if (l.pointsCount === 0) l.updateRoute();
if (l.pointsCount >= 6) {
var pts = l.points.copy();
var p2 = pts.elt(2);
pts.setElt(2, new go.Point(x, p2.y));
var p3 = pts.elt(3);
pts.setElt(3, new go.Point(x, p3.y));
l.points = pts;
}
}
}
}
}
} else { // this.direction === 90 or 270
var vit = this.network.vertexes.iterator;
while (vit.next()) {
var v = vit.value;
var n = v.node;
var y;
if (n) {
var lit = n.findLinksInto();
if (lit.count > 1) {
if (this.direction === 90) {
y = n.position.y - this.layerSpacing / 2;
} else {
y = n.position.y + n.actualBounds.height + this.layerSpacing / 2;
}
while (lit.next()) {
var l = lit.value;
if (l.pointsCount === 0) l.updateRoute();
if (l.pointsCount >= 6) {
var pts = l.points.copy();
var p2 = pts.elt(pts.length - 4);
pts.setElt(pts.length - 4, new go.Point(p2.x, y));
var p3 = pts.elt(pts.length - 3);
pts.setElt(pts.length - 3, new go.Point(p3.x, y));
l.points = pts;
}
}
}
lit = n.findLinksOutOf();
if (lit.count > 1) {
if (this.direction === 90) {
y = n.position.y + n.actualBounds.height + this.layerSpacing / 2;
} else {
y = n.position.y - this.layerSpacing / 2;
}
while (lit.next()) {
var l = lit.value;
if (l.pointsCount === 0) l.updateRoute();
if (l.pointsCount >= 6) {
var pts = l.points.copy();
var p2 = pts.elt(2);
pts.setElt(2, new go.Point(p2.x, y));
var p3 = pts.elt(3);
pts.setElt(3, new go.Point(p3.x, y));
l.points = pts;
}
}
}
}
}
}
};
// end custom LayeredDigraphLayout[/code]
To use, just replace your reference to go.LayeredDigraphLayout with CoincidentRoutingLayout.

Also you could adapt the code above to do the non-orthogonal routing that you wanted originally, just by deleting the Point of the Link.points array at index length-3 or 2, depending on the direction.

Thanks for giving the example with full code, that’s quite helpful.
Now I am facing one problem.
I can change the position of nodes and links, but not able to change the position of the groups.

In commitlinks method I am trying in following way ,

var arr = this.network.vertexes.toArray();
for (var i=0; i < arr.length;i++ ) {
var node = arr.node;
if(node.data.isGroup) {
node.position = new go.Point(node.position.x+50, node.position.y+20); //Line# 5
break;
}
}

Its going to Line# 5, and Node’s position values also getting updated.
but it’s not changing the position of the group in the diagram.
Is there any problem with my current implementation??

That depends on the circumstances. Normally each node, including each Group, is positioned by the Layout that is responsible for it. So your Group.layout should position and route all of the group’s member parts, but it will not determine the position of the Group itself. That would be the responsibility of the Group’s container’s layout, which might be the Diagram.layout.

“this.network.vertexes” will produce the LayoutVertexes of all of the nodes being laid out. Any node for which “node.data.isGroup” is true will be a nested group, not the group holding the subgraph.

BTW, you could check “(node instanceof go.Group)”. LayoutVertex.node might be null, so “node.data” might fail.

In our current implementation, We are creating a CustomLayeredDigraph by overriding commitLinks() method.
We are having a group template, which is having same CustomLayeredDigraph as layout property.
Now we are facing following problems.
1. As addressed in previous query, We were able to change the position of the nodes, but not the groups. How can we achieve this, It would be great if you give a small example.


2. By overriding commitLinks(), we are changing the routing of links. but this functionality is not working on the links which are part of a group. (when we remove group property, then its working)
Is there any diff. implementation needed for links which are part of a group ??


3. Tried your sample code of commitLinks() in custom TreeLayout. We are able to get Links, but there is no link points.
(link.points.count is zero), so not able to customize it. Is there any different approach for TreeLayout ??.

  1. As I just replied, the position of a Group is determined by the Layout that is responsible for positioning that Group. In your case that might be the Diagram.layout. For example, the SwimLanes sample has a Diagram.layout that positions each Group (i.e. each “lane”) to be stacked vertically. The layout of the nodes within the group is independent of the diagram’s layout positioning of the group.

  2. I can look into this.

  3. My guess is that that particular invocation of TreeLayout did not explicitly route any links – it is depending on the standard link routing implemented by each link depending on the link’s properties. But you could certainly do the routing yourself by specifying the list of Points that you want.

  1. This appears to be a bug that we will fix in version 1.3.2. Thanks for reporting it!

I have updated my code above to deal with the case where the route had not yet been determined, causing the points count to be zero.

Hi,
Is there any update on issue.2 (Updating links, which are part of a group),
When version 1.3.2 is going to release.

1.3.2 has been released: http://www.gojs.net/latest/index.html