Bezier link doesn't route correctly

Hi! I came across problem, that link looks incorrect (as I think). How can I tune it? Nodes have immutable coordinates and I expect that Diagram draw correct link by portIds. Maybe I skip something into configs? Or can I indicate intermediate points?

Currently behavior: Monosnap
Example: Monosnap
red line - how line are going
yellow line - example of expected behavior

I have that configs:

Link:

export const linkTemplate = $(
    go.Link,
    {
        curve: go.Link.Bezier,
        fromEndSegmentLength: 50,
        toEndSegmentLength: 50,
        fromShortLength: 5,
        toShortLength: 10,
        selectable: false,
        fromSpot: go.Spot.Right,
        toSpot: go.Spot.Left,
    },
    $(
        go.Shape,
        { stroke: referenceColors.inactive },
        new go.Binding('stroke', 'isSelected', (isSelected) =>
            isSelected ? referenceColors.highlighted : referenceColors.inactive,
        ),
    ),
    $(
        go.Shape,
        {
            toArrow: 'Standard',
            stroke: referenceColors.inactive,
            fill: referenceColors.inactive,
            alignmentFocus: new go.Spot(1, 0.5, 5, 0),
        },
        new go.Binding('stroke', 'isSelected', (isSelected) =>
            isSelected ? referenceColors.highlighted : referenceColors.inactive,
        ),
        new go.Binding('fill', 'isSelected', (isSelected) =>
            isSelected ? referenceColors.highlighted : referenceColors.inactive,
        ),
    ),
);

Diagram:

$(go.Diagram, {
    isReadOnly: true,
    model: $(go.GraphLinksModel, {
        linkFromPortIdProperty: 'fromPort',
        linkToPortIdProperty: 'toPort',
        nodeKeyProperty: 'id',
        linkKeyProperty: 'id',
    }),
    layout: $(go.TreeLayout, {
        arrangementOrigin: new go.Point(0, 0),
        angle: 0,
        treeStyle: go.TreeLayout.StyleLayered,
        layerStyle: go.TreeLayout.LayerSiblings,
        alignment: go.TreeLayout.AlignmentCenterChildren,
        nodeSpacing: 50,
        layerSpacing: 50,
        arrangement: go.TreeLayout.ArrangementVertical,
        path: go.TreeLayout.PathDestination,
        isInitial: false,
        isOngoing: false,
    }),
});

TreeLayout is typically used for tree-structured graphs. It appears you have a link going backwards.

LayeredDigraphLayout may give you better linking results.

I tried every layout type, but result dosn’t change ( I tried one more time with use LayeredDigraphLayout, but nothing changed Monosnap

Maybe Im missing smth

Config:

$(go.Diagram, {
    isReadOnly: true,
    model: $(go.GraphLinksModel, {
        linkFromPortIdProperty: 'fromPort',
        linkToPortIdProperty: 'toPort',
        nodeKeyProperty: 'id',
        linkKeyProperty: 'id',
    }),
    layout: $(go.LayeredDigraphLayout, {
        isInitial: false,
        isOngoing: false,
    }),
});

You have isInitial and isOngoing set to false. That means you probably should call Diagram.layoutDiagram.

If I use layoutDiagram(true) or set isInitial and isOngoing to true, I will get incorrect behavior, because nodes changed positio, like this. I want to use my coordinates for nodes

If I use layoutDiagram(false), I will see nothing changes.

I’ve seen on routing: go.Link.AvoidsNodes yet, but I get near result which I expect, but links looks like one line Monosnap

How is what you want to do fundamentally different from Data Flow Diagram ?

Yep, it looks like my expected result. I added routing: go.Link.Orthogonal and it looks better. I can add that parameter for that links. Can I added margin between that links, bcs now it looks line one line? Monosnap

Don’t set fromEndSegmentLength or toEndSegmentLength to such a large value, or greatly increase the spacing between the layers.

If you still have Link.curve set to Bezier, I suppose you could decrease the Link.smoothing property. Try a value such as 0.25 or some other values.

Unfortenately, nothing changes

I set that config for links:

{
        curve: go.Link.Bezier,
        selectable: false,
        fromSpot: go.Spot.Right,
        toSpot: go.Spot.Left,
        routing: go.Link.Orthogonal,
        smoothness: 0.75, // and I tried 0.25
    }

I made a copy of the samples/dataFlow.html page. I changed the link template but made no other code changes:

      myDiagram.linkTemplate =
        $(go.Link,
          {
            routing: go.Link.Orthogonal, curve: go.Link.Bezier, smoothness: 0.25,
            relinkableFrom: true, relinkableTo: true
          },
          $(go.Shape, { stroke: "gray", strokeWidth: 2 }),
          $(go.Shape, { stroke: "gray", fill: "gray", toArrow: "Standard" })
        );

I deleted a “Table” Node at the left and then drew a new Link from a “Filter” Node to the first “Join” Node. Here’s the result:

Furthermore, if I go back to what I think you had for the link template – no orthogonal routing:

      myDiagram.linkTemplate =
        $(go.Link,
          {
            curve: go.Link.Bezier,
            fromEndSegmentLength: 50, toEndSegmentLength: 50,
            relinkableFrom: true, relinkableTo: true
          },
          $(go.Shape, { stroke: "gray", strokeWidth: 2 }),
          $(go.Shape, { stroke: "gray", fill: "gray", toArrow: "Standard" })
        );

I get:

Which I think is what you want. So I cannot explain why you aren’t getting those results.

Hm, I think it’s because I use is isInitial and isOngoing as false. I reproduce my behavior in DataFlowDiagram example. Monosnap

  1. I added isInitial: false and isOngoing: false
  2. Than config for link
{
  curve: go.Link.Bezier,
  fromEndSegmentLength: 50,
  toEndSegmentLength: 50,
  fromShortLength: 5,
  toShortLength: 10,
  selectable: false,
  fromSpot: go.Spot.Right,
  toSpot: go.Spot.Left,
}
  1. I updated template for nodes and added new go.Binding('location', 'loc', go.Point.parse),
  2. I added location for nodes. See data:
myDiagram.model = go.Model.fromJson({
  "class": "go.GraphLinksModel",
  "nodeCategoryProperty": "type",
  "linkFromPortIdProperty": "frompid",
  "linkToPortIdProperty": "topid",
  "nodeDataArray": [
    {"key":1, "type":"Table", "name":"Product", loc: "0 0"},
    {"key":2, "type":"Table", "name":"Sales", loc: "0 200"},
    {"key":3, "type":"Table", "name":"Period", loc: "150 200"},
    {"key":4, "type":"Table", "name":"Store", loc: "300 200"},
    {"key":11, "type":"Join", "name":"Product, Class", loc: "150 0"},
    {"key":12, "type":"Join", "name":"Period", loc: "300 0"},
    {"key":13, "type":"Join", "name":"Store", loc: "450 100"},
    {"key":21, "type":"Project", "name":"Product, Class", loc: "600 100"},
    {"key":31, "type":"Filter", "name":"Boston, Jan2014", loc: "750 0"},
    {"key":32, "type":"Filter", "name":"Boston, 2014", loc: "750 200"},
    {"key":41, "type":"Group", "name":"Sales", loc: "900 0"},
    {"key":42, "type":"Group", "name":"Total Sales", loc: "900 200"},
    {"key":51, "type":"Join", "name":"Product Name", loc: "1050 100"},
    {"key":61, "type":"Sort", "name":"Product Name", loc: "1200 100"},
    {"key":71, "type":"Export", "name":"File", loc: "1350 100"}
  ],
  "linkDataArray": [
    {"from":1, "frompid":"OUT", "to":11, "topid":"L"},
    {"from":2, "frompid":"OUT", "to":11, "topid":"R"},
    {"from":3, "frompid":"OUT", "to":12, "topid":"R"},
    {"from":4, "frompid":"OUT", "to":13, "topid":"R"},
    {"from":11, "frompid":"M", "to":12, "topid":"L"},
    {"from":12, "frompid":"M", "to":13, "topid":"L"},
    {"from":13, "frompid":"M", "to":21},
    {"from":13, "frompid":"M", "to":11},
    {"from":21, "frompid":"OUT", "to":31},
    {"from":21, "frompid":"OUT", "to":32},
    {"from":31, "frompid":"OUT", "to":41},
    {"from":32, "frompid":"OUT", "to":42},
    {"from":41, "frompid":"OUT", "to":51, "topid":"L"},
    {"from":42, "frompid":"OUT", "to":51, "topid":"R"},
    {"from":51, "frompid":"OUT", "to":61},
    {"from":61, "frompid":"OUT", "to":71}
  ]
});

Or if I use routing: go.Link.Orthogonal, Monosnap

Data with one more link:

myDiagram.model = go.Model.fromJson({
  "class": "go.GraphLinksModel",
  "nodeCategoryProperty": "type",
  "linkFromPortIdProperty": "frompid",
  "linkToPortIdProperty": "topid",
  "nodeDataArray": [
    {"key":1, "type":"Table", "name":"Product", loc: "0 0"},
    {"key":2, "type":"Table", "name":"Sales", loc: "0 200"},
    {"key":3, "type":"Table", "name":"Period", loc: "150 200"},
    {"key":4, "type":"Table", "name":"Store", loc: "300 200"},
    {"key":11, "type":"Join", "name":"Product, Class", loc: "150 0"},
    {"key":12, "type":"Join", "name":"Period", loc: "300 0"},
    {"key":13, "type":"Join", "name":"Store", loc: "450 100"},
    {"key":21, "type":"Project", "name":"Product, Class", loc: "600 100"},
    {"key":31, "type":"Filter", "name":"Boston, Jan2014", loc: "750 0"},
    {"key":32, "type":"Filter", "name":"Boston, 2014", loc: "750 200"},
    {"key":41, "type":"Group", "name":"Sales", loc: "900 0"},
    {"key":42, "type":"Group", "name":"Total Sales", loc: "900 200"},
    {"key":51, "type":"Join", "name":"Product Name", loc: "1050 100"},
    {"key":61, "type":"Sort", "name":"Product Name", loc: "1200 100"},
    {"key":71, "type":"Export", "name":"File", loc: "1350 100"}
  ],
  "linkDataArray": [
    {"from":1, "frompid":"OUT", "to":11, "topid":"L"},
    {"from":2, "frompid":"OUT", "to":11, "topid":"R"},
    {"from":3, "frompid":"OUT", "to":12, "topid":"R"},
    {"from":4, "frompid":"OUT", "to":13, "topid":"R"},
    {"from":11, "frompid":"M", "to":12, "topid":"L"},
    {"from":12, "frompid":"M", "to":13, "topid":"L"},
    {"from":13, "frompid":"M", "to":21},
    {"from":13, "frompid":"M", "to":11},
    {"from":13, "frompid":"MR", "to":11},
    {"from":21, "frompid":"OUT", "to":31},
    {"from":21, "frompid":"OUT", "to":32},
    {"from":31, "frompid":"OUT", "to":41},
    {"from":32, "frompid":"OUT", "to":42},
    {"from":41, "frompid":"OUT", "to":51, "topid":"L"},
    {"from":42, "frompid":"OUT", "to":51, "topid":"R"},
    {"from":51, "frompid":"OUT", "to":61},
    {"from":61, "frompid":"OUT", "to":71}
  ]
});

Ah, yes, you need to let the layout do the routing.

Or else, if you don’t want nodes to be moved by a layout, you could try setting Link.routing to go.Link.AvoidsNodes. But my other suggestions about Link properties would still apply.

Yep, go.Link.Orthogonal works for me, but some links connect in one line. As I understood I cannot change that behavior Monosnap ?

Only LayeredDigraphLayout will do the routing to keep the link paths separated.