Simple Link Template

Hello Walter, I spent many hours navigating through lots of examples and I can’t find what I’m looking for because the solutions are too complex and I know that in our team we need a simple solution out of the box.

Basically, we like the go.GridLayout and the default flow left-to-right, top-to-bottom and how the Diagram re-draws on window resize, that’s perfect.

The issue is that the Link shape from the last Node on the row to the first Node on the next row down crosses over other Nodes etc etc, it doesn’t look right (Serpentine Layout Links looks great). I won’t write more explanation to save you reading time, you’ll know what I mean.

Thank you so much! we should be purchasing a license soon, we’re still configuring our domain environment etc, it’s a brand new internal React/TS app.

import * as go from 'gojs';

/**
 * GoJs Diagram initialization method, which is passed to the ReactDiagram component.
 */
export default (props: any) => {
    return () => {
        const { externalObjectsDropped, selectionChanged } = props;

        const $ = go.GraphObject.make;
        // set your license key here before creating the diagram: go.Diagram.licenseKey = "...";
        const diagram = $(go.Diagram, {
            isTreePathToChildren: false, // links go from child to parent
            layout: $(go.GridLayout),
            'undoManager.isEnabled': true, // must be set to allow for model change listening
            // 'undoManager.maxHistoryLength': 0,  // uncomment disable undo/redo functionality
            'clickCreatingTool.archetypeNodeData': {
                text: 'new node',
                color: 'lightblue',
            },
            model: new go.GraphLinksModel({
                linkKeyProperty: 'key', // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
            }),
            allowDrop: true,
            maxSelectionCount: 1,
        });

        const docletTitle = $(go.TextBlock, new go.Binding('text', 'title'));
        const docletTags = $(go.TextBlock, new go.Binding('text', 'tags'));
        const docletSummary = $(
            go.TextBlock,
            new go.Binding('text', 'summary')
        );
        const docletMetadata = $(
            go.TextBlock,
            new go.Binding('text', 'metadata')
        );

        const nodeTemplate = $(
            go.Node,
            new go.Binding('visible', 'visible'),
            new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(
                go.Point.stringify
            ),
            'Auto',
            { selectionChanged },
            $(
                go.Shape,
                new go.Binding('figure', 'fig'),
                new go.Binding('fill', 'color')
            ),
            $(go.Panel, 'Vertical', [
                docletTitle,
                docletTags,
                docletSummary,
                docletMetadata,
            ])
        );

        const linkTemplate = $(
            go.Link,
            {
                routing: go.Link.AvoidsNodes,
                selectable: false,
            },
            $(go.Shape, { strokeWidth: 2, stroke: 'black' })
        );

        function handleDrop() {
            externalObjectsDropped(diagram);
        }

        diagram.linkTemplateMap.add('', linkTemplate);
        diagram.nodeTemplateMap.add('', nodeTemplate);
        diagram.addDiagramListener('ExternalObjectsDropped', handleDrop);
        return diagram;
    };
};

Could you please show us some screenshots showing what you have now and what you want instead?

This is what we have from the code I shared in my initial post

Hello, we’d like to have something very similar to the Serpentine Layout without having to implement it as an extension and the link arrows going from last Node in the row to first Node in the next row down…

Try this:

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2022 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  $(go.Diagram, "myDiagramDiv",
    {
      layout: $(go.GridLayout,
        { cellSize: new go.Size(1, 1), spacing: new go.Size(20, 20) })
    });

myDiagram.nodeTemplate =
  $(go.Node, "Auto",
    { width: 80, height: 40 },
    $(go.Shape,
      { fill: "white", portId: "", fromSpot: go.Spot.BottomRightSides, toSpot: go.Spot.TopLeftSides },
      new go.Binding("fill", "color")),
    $(go.TextBlock,
      new go.Binding("text", "key"))
  );

myDiagram.linkTemplate =
  $(go.Link,
    { routing: go.Link.AvoidsNodes },
    $(go.Shape),
    $(go.Shape, { toArrow: "Standard" })
  )

var nda = [
  { key: "Alpha", color: "coral" },
  { key: "Beta", color: "tomato" },
  { key: "Gamma", color: "goldenrod" },
  { key: "Delta", color: "orange" },
  { key: "Epsilon", color: "coral" },
  { key: "Zeta", color: "tomato" },
  { key: "Eta", color: "goldenrod" },
  { key: "Theta", color: "orange" },
  { key: "Iota", color: "coral" },
  { key: "Kappa", color: "tomato" },
  { key: "Lambda", color: "goldenrod" },
  { key: "Mu", color: "orange" },
  { key: "Nu", color: "coral" },
  { key: "Xi", color: "tomato" },
  { key: "Omicron", color: "goldenrod" },
  { key: "Pi", color: "orange" },
  { key: "Rho", color: "coral" },
  { key: "Sigma", color: "tomato" },
  { key: "Tau", color: "goldenrod" },
  { key: "Upsilon", color: "orange" },
  { key: "Phi", color: "coral" },
  { key: "Chi", color: "tomato" },
  { key: "Psi", color: "goldenrod" },
  { key: "Omega", color: "orange" }
];
var lda = [];
for (var i = 0; i < nda.length-1; i++) {
  lda.push({ from: nda[i].key, to: nda[i+1].key });
}
myDiagram.model = new go.GraphLinksModel(nda, lda);
  </script>
</body>
</html>

Note how the fromSpot and toSpot are set so that links always come out of a node on either the right or bottom side and go into a node on the left or top side.

If you want to have the nodes go right-to-left, you’ll want to update the spots too – set GridLayout.arrangement to go.GridLayout.RightToLeft and change the spots to be fromSpot: go.Spot.BottomLeftSides, toSpot: go.Spot.TopRightSides,

Note also that this example doesn’t use Link.routing of AvoidsNodes. If you do need that, make sure there’s enough room around each node for links to be routed without having to go through any other nodes. Your example doesn’t seem to do that. In this case even though it’s not needing AvoidsNodes routing, I set the GridLayout.spacing to leave some extra space between the nodes.

That worked spectacularly <3 thank you!