Custom link and nodes

In my application user can modify the link shape thanks to LinkShifthing and SnapLinkReshaping tools but I noticed that the specified points are considered only if the node isn’t layout positioned (have a specific location), like in this example.

If the node is layout positioned, the points are ignored and the link route is completely recalculated by goJS.
Would be possible to have link with custom shape between nodes automatically positioned? If so, how?

Whenever a node is moved, whether by a Layout or by the DraggingTool, the connected links’ routes are invalidated.

I suppose you could set Link.adjusting to go.Link.End, but that might be undesirable if the node is moved a lot.

Hi, I am already using go.Link.End for adjusting for all links with specific points… or better, I am using go.Link.Stretch but having Orthogonal routing, the specification says that adjusting is treated as it would go.Link.End.

Do the links get their routes via a Link.points Binding? I really do not see how it is possible for a link to have a predefined route unless the connected nodes also have predefined locations.

Either turn off any layout (Layout.isInitial false) or override Link.computeRoute to do what you want. What is your layout?

Yes, I have a bindings for points and I am using SideTreeLayout… My functional requirement is to make possible to the user to modify a link shape when/if he is not satisfied by the one computed by GoJS during his automatic nodes disposition.
My desire would be to have GoJS do all links calculation and, after, he should modify only the links that have specif points setted.
Do you think is this obtainable only overriding Link.computeRoute?

That should be the default behavior for loading a saved model containing node locations and link points. You can see that demonstrated by all of the sample apps that allow the user to reshape or resegment a link and have a TwoWay Binding on Link.points as well as a TwoWay Binding on Node.location.

So how is your situation different?

If you are modifying the model data while it is not being shown in a diagram, I can see how the link routes do not correctly connect with the nodes, either because the nodes changed size or moved or both.

Yes, I have two way binding in place for node Location and link Points. Until I saved and reloaded the whole JSON everything was fine and the whole aspect of my OrgChart (nodes and links) was preserved. But now, I have to load node data array and link data array separately… can be this to make the difference?

For example, the following is the link array for Node 6501 to 6902 and 6903:

{“from”:“6501”,“to”:“6903”,“text”:"",“category”:"",“structureId”:0,“routing”:“go.Link.Orthogonal”,“isTreeLink”:true,“points”:[291.5,172.0,291.5,182.0,291.5,283.0,340.0,283.0,340.0,320.0,371.75,320.0,371.75,283.0,452.0,283.0,452.0,273.0],“adjusting”:“go.Link.Stretch”,“fromSpot”:“0.5 1 0 0”,“toSpot”:“0.8314917127071824 1 0 0”},
{“from”:“6501”,“to”:“6902”,“text”:"",“category”:"",“structureId”:0,“routing”:“go.Link.Orthogonal”,“isTreeLink”:true,“adjusting”:“go.Link.None”},

the first link has lots of points but it is drawn exactly as the one for 6902 that has no points.

Yes, loading the links separately from the nodes is probably the problem. I recommend that you do them together, by waiting until you have both data Arrays before you construct and initialize a new GraphLinksModel and then assign it to your Diagram.

This is my initialization sequence… is it as you suggested?
I also pulled out the layout initialization from diagram creation and put it at the end, just to be sure but the problem is still there.

	myDiagram = $(go.Diagram, "nosOrganigrammaDiv",
	{
	   .....
        }

	var myModel=new go.GraphLinksModel(); 
	
        myModel.nodeDataArray=<%= chart.getNodeDataArray() %>;
	myModel.linkDataArray=<%= chart.getLinkDataArray() %>;
 	
        [some listeners]

 	myDiagram.model=myModel;

	myDiagram.layout=$(SideTreeLayout,  
        {
           isInitial:true,
           angle: 90,
            .......
        });
		
	myDiagram.toolManager.mouseDownTools.add($(LinkShiftingTool));
	myDiagram.toolManager.mouseDownTools.add($(SnapLinkReshapingTool));

I think it would be better to do all of the Diagram (and tool) initialization before setting Diagram.model. In this case, I suspect that setting the layout afterwards might be a problem.

In this case changing the tools almost certainly does not matter, but for consistency I think it would be best to make the Diagram completely ready to accept a new model.

I did what you suggested and also some other arrangements and now it is almost working!

but it seem it still doesn’t consider the toSpot value:

{“from”:“6501”, “to”:“6903”, “text”:"", “category”:"", “structureId”:0, “routing”:“go.Link.Orthogonal”, “isTreeLink”:true, “points”:[ 291.5,172,291.5,182,291.5,180,440,180,440,160,440,160,440,160,440,160,440,160,440,160,440,160,420,160,420,140,492.5,140,492.5,247,482.5,247 ], “adjusting”:“go.Link.Stretch”, “fromSpot”:“0.5 1 0 0”, “toSpot”:“1 0.647887323943662 0 0”},

those are my bindings for fromSpot and toSpot

new go.Binding ("fromSpot","fromSpot",go.Spot.parse).makeTwoWay(go.Spot.stringify),
new go.Binding ("toSpot","toSpot",go.Spot.parse).makeTwoWay(go.Spot.stringify),

that are working well for fixed positioned nodes (see Node 6801)

thanks
Marco

That behavior is correct – if you set or bind Link.points, that takes precedence over all of the other properties that normally guide how routing happens.

Ok.
Then let me try to recap, just to be sure:

  • if the node is not positioned by layout, link’s points and spots (and other properties) are considered and the link is drawn accordingly

  • conversely if the node is positioned by the layout the route is automatically calculated and, if present, also points are taken in account as much as is possible, but all other properties (like to/from spots) remain the ones calculated by layout algorithm, independently of what is specified in the link’s properties

Most apps do not save routes (i.e. Link.points), so the various Link and port properties are used to compute the route.

When routes are saved (normally through a TwoWay Binding on Link.points) then when they are loaded routes do not need to be computed, so all those other properties are ignored.

But those properties are used again when a route needs to be calculated again after a link route is invalidated. That might happen because the node is moved or because the node changed size or because one of those route-guiding properties changed value.

Note that the layouts that set Link.fromSpot and/or Link.toSpot have properties that disable such settings.

Setting these to false allows the spot properties on the Link or port to affect the routing.

Ok! Thanks a lot for this useful clarification and for your support.