Bindings are evaluated when the Part (i.e. Node or Link) is added to the Diagram. So if you annotation TextBlock has a Binding on its “text” property and you are using a binding conversion function to compute the text you want to show, the values pertaining to the node itself will be up-to-date, but values relating to the rest of the diagram will not be. In fact, depending on values such as diagram.nodes.count
will vary as each node is created and added to the diagram.
So it seems to me that if you want the annotation of each node to depend on the state of the whole diagram, you will have to update all of them when you want to. Data binding works for keeping property state up-to-date locally for each Part – it doesn’t work for global state. There is an exception: Binding.ofModel, depending on data properties of the shared object Model.modelData.
So I’m not sure when you want to update all of the nodes. It seems that you want to do so in a “ChangedSelection” DiagramEvent listener, and maybe after some nodes have been added or removed from the diagram/model.
Here’s an example app showing some of the issues:
<!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:400px"></div>
<textarea id="mySavedModel" style="width:100%;height:250px"></textarea>
<script src="https://unpkg.com/gojs"></script>
<script id="code">
const $ = go.GraphObject.make;
const myDiagram =
$(go.Diagram, "myDiagramDiv",
{
"InitialLayoutCompleted": e => updateAllAnnotations(),
"ChangedSelection": e => updateAllAnnotations(),
"ModelChanged": e => {
if (e.change === go.ChangedEvent.Insert || e.change === go.ChangedEvent) {
updateAllAnnotations();
}
if (e.isTransactionFinished) { // show the model data in the page's TextArea
document.getElementById("mySavedModel").textContent = e.model.toJson();
}
},
"undoManager.isEnabled": true
});
myDiagram.nodeTemplate =
$(go.Node, "Vertical",
// maybe you'll want this setting to prevent a new layout whenever an annotation
// change causes the node to change size?
//??? { layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized },
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle",
{ fill: "white" },
new go.Binding("fill", "color")),
$(go.TextBlock,
{ margin: 8 },
new go.Binding("text"))
),
$(go.TextBlock,
{ name: "ANNOT", textAlign: "center" },
new go.Binding("text", "", computeAnnotation)),
{
doubleClick: (e, node) => { // toggle the visibility of the annotation
e.diagram.commit(d => {
const annot = node.findObject("ANNOT");
if (annot) annot.visible = !annot.visible;
});
}
}
);
function computeAnnotation(data, textblock) {
const node = textblock.part;
return data.text + "\n" +
`isSelected: ${node.isSelected}\n` +
`# selected: ${node.diagram.selection.count} of ${node.diagram.nodes.count}`;
}
function updateAllAnnotations() {
myDiagram.commit(d => d.updateAllTargetBindings());
}
myDiagram.model = new go.GraphLinksModel(
[
{ key: 1, text: "Alpha", color: "lightblue" },
{ key: 2, text: "Beta", color: "orange" },
{ key: 3, text: "Gamma", color: "lightgreen" },
{ key: 4, text: "Delta", color: "pink" }
]);
</script>
</body>
</html>