Here’s what I just tried. The result:
The complete sample code:
<!DOCTYPE html>
<html>
<head>
<title>Minimal GoJS Sample</title>
<!-- Copyright 1998-2025 by Northwoods Software Corporation. -->
</head>
<body>
<div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:400px"></div>
<script src="https://cdn.jsdelivr.net/npm/gojs/release/go-debug.js"></script>
<script id="code">
const myDiagram =
new go.Diagram("myDiagramDiv", {
"undoManager.isEnabled": true
});
myDiagram.nodeTemplate =
new go.Node("Spot", {
locationSpot: go.Spot.Center,
itemTemplate:
new go.Panel()
.bind("alignment", "spot", go.Spot.parse)
.add(
new go.Shape({ width: 16, height: 10, fill: "white" })
.bind("portId", "id")
.bind("fromSpot", "spot", s => {
const spot = go.Spot.parse(s);
return spot.x > 0.5 ? go.Spot.Right : go.Spot.Left;
})
.bind("toSpot", "spot", s => {
const spot = go.Spot.parse(s);
return spot.x > 0.5 ? go.Spot.Right : go.Spot.Left;
})
)
})
.bindTwoWay("location", "loc", go.Point.parse, go.Point.stringify)
.bind("itemArray", "ports")
.add(
new go.Panel("Auto", { width: 150, height: 75, portId: "" })
.add(
new go.Shape({ fill: "white" })
.bind("fill", "color"),
new go.TextBlock({ editable: true })
.bindTwoWay("text")
)
);
myDiagram.linkTemplate =
new go.Link({
routing: go.Link.Orthogonal, corner: 10,
relinkableFrom: true, relinkableTo: true,
reshapable: true, resegmentable: true
})
.add(
new go.Shape()
);
myDiagram.model = new go.GraphLinksModel(
{
linkFromPortIdProperty: "fid",
linkToPortIdProperty: "tid",
nodeDataArray:
[
{
key: 1, text: "Node A", loc: "0 0",
ports: [{ id: "a", spot: "1 0.15" }, { id: "b", spot: "1 0.85" }]
},
{
key: 2, text: "Node B", loc: "250 0"
}
],
linkDataArray:
[
{ from: 1, fid: "a", to: 2, tid: "" },
{ from: 1, fid: "b", to: 2, tid: "" },
]
});
</script>
</body>
</html>