Here I have replaced your implementation of each Node’s “Adornment” using a subclass of Node. Note how there is no odd Binding on the node template.
<!DOCTYPE html>
<html lang="en">
<body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/release/go-debug.js"></script>
<div id="sample" style="display: flex">
<div
id="diagramDiv"
style="border: solid 1px black; width: 600px; height: 600px"
></div>
</div>
<script id="code">
class AdornedNode extends go.Node {
static AdName = "Adornment";
static AdTemplate =
new go.Adornment("Spot")
.add(
new go.Panel("Vertical")
.add(
new go.Placeholder(),
new go.TextBlock({ text: "Adornment" })
)
).copyTemplate(true);
constructor(paneltype, init) {
if (typeof paneltype === "object") { init = paneltype; paneltype = undefined; }
super(paneltype);
if (init) Object.assign(this, init);
}
// this design assumes the "Adornment" should only be shown when Node.isHighlighted is true
maybeShowAdornment() {
let ad = this.findAdornment(AdornedNode.AdName);
if (this.isHighlighted && this.isVisible()) {
if (ad === null) {
ad = AdornedNode.AdTemplate.copy();
ad.adornedObject = this;
this.addAdornment(AdornedNode.AdName, ad);
}
} else {
if (ad !== null) {
this.removeAdornment(AdornedNode.AdName);
}
}
}
}
const diagram = new go.Diagram("diagramDiv", {
"animationManager.isEnabled": false,
"LayoutCompleted": e => {
e.diagram.links.each(l => l.invalidateRoute());
e.diagram.nodes.each(n => {
if (n instanceof AdornedNode) n.maybeShowAdornment();
})
},
"undoManager.isEnabled": true
});
const nodeTemplate = new AdornedNode /*go.Node*/("Auto", {
// when Node.isHighlighted changes value, call AdornedNode.maybeShowAdornment
highlightedChanged: node => node.maybeShowAdornment(),
// user can control which nodes have "Adornment" by double-clicking
doubleClick: (e, node) => {
e.diagram.commit(d => node.isHighlighted = !node.isHighlighted)
}
})
.bindTwoWay("isHighlighted", "isAdorned")
.bindTwoWay("location", "location", go.Point.parse, go.Point.stringify)
.add(
new go.Shape("RoundedRectangle", {
strokeWidth: 0,
fill: "white",
fromSpot: go.Spot.AllSides,
toSpot: go.Spot.AllSides,
portId: '',
})
.bind("fill", "color")
.bindTwoWay("fromSpot", "fromSpot", go.Spot.parse, go.Spot.stringify)
.bindTwoWay("toSpot", "toSpot", go.Spot.parse, go.Spot.stringify),
new go.TextBlock({
margin: 8,
font: "bold 14px sans-serif",
stroke: "#333",
})
.bind("text")
);
const poolTemplate = new go.Group("Auto", {
layout: new go.GridLayout({
alignment: go.GridAlignment.Position,
comparer: (a, b) => a.position.x - b.position.x,
spacing: new go.Size(0, 0),
cellSize: new go.Size(0, 0),
wrappingColumn: Infinity,
wrappingWidth: Infinity,
isRealtime: true,
})
})
.bindTwoWay("location", "location", go.Point.parse, go.Point.stringify)
.add(
new go.Shape("RoundedRectangle", {
strokeWidth: 1,
fill: "white",
width: 400,
height: 400,
})
);
const laneTemplate = new go.Group("Vertical", {
isSubGraphExpanded: true,
fromSpot: go.Spot.LeftRightSides, toSpot: go.Spot.LeftRightSides
})
.bindTwoWay("location", "location", go.Point.parse, go.Point.stringify)
.bindTwoWay("isSubGraphExpanded")
.add(
go.GraphObject.make("SubGraphExpanderButton", {
click: (event, thisObj) => {
thisObj.part.diagram.startTransaction("Toggle");
if (thisObj.part.isSubGraphExpanded) {
thisObj.part.collapseSubGraph();
} else {
thisObj.part.expandSubGraph();
}
thisObj.part.diagram.commitTransaction("Toggle");
},
}),
new go.Shape("RoundedRectangle", {
strokeWidth: 1,
fill: "white",
width: 150,
height: 350,
}).bindObject("desiredSize", "isSubGraphExpanded",
(isSubGraphExpanded) =>
isSubGraphExpanded ? new go.Size(150, 350) : new go.Size(30, 350))
);
const linkTemplate = new go.Link({
reshapable: true,
resegmentable: true,
routing: go.Routing.Orthogonal,
adjusting: go.LinkAdjusting.End
})
.bindTwoWay("points")
.add(new go.Shape({ strokeWidth: 1.5, stroke: "red" }))
.add(
new go.Shape({
strokeWidth: 0,
fill: "red",
scale: 0.7,
fromArrow: "circle",
})
)
.add(
new go.Shape({
strokeWidth: 0,
fill: "red",
scale: 0.7,
toArrow: "circle",
})
);
diagram.nodeTemplate = nodeTemplate;
diagram.groupTemplateMap.add("Pool", poolTemplate);
diagram.groupTemplateMap.add("Lane", laneTemplate);
diagram.linkTemplate = linkTemplate;
const nodes = [
{
key: "P",
isGroup: true,
category: "Pool",
location: "31.24609375 -0.3515625",
},
{
key: "L1",
group: "P",
isGroup: true,
category: "Lane",
location: "31.24609375 -0.3515625",
isSubGraphExpanded: true,
},
{
key: "L2",
group: "P",
isGroup: true,
category: "Lane",
location: "62.24609375 -0.3515625",
isSubGraphExpanded: true,
},
{
key: "L3",
group: "P",
isGroup: true,
category: "Lane",
location: "62.24609375 -0.3515625",
isSubGraphExpanded: true,
},
{
key: "N1",
group: "L1",
text: "Alpha",
color: "lightblue",
location: "74.30859375 157.82421875",
},
{
key: "N2",
group: "L2",
text: "Beta",
color: "orange",
location: "150.8359375 88.375",
},
{
key: "N3",
group: "L3",
text: "Gamma",
color: "lightgreen",
location: "100.37538656080795 203.03515625",
isAdorned: true
},
];
const links = [
{
from: "N1",
to: "N3",
},
{
from: "N1",
to: "N2",
},
];
diagram.model = new go.GraphLinksModel(nodes, links);
</script>
</body>
</html>