Yes, you could add a “ViewportBoundsChanged” DiagramEvent listener that updated a property in the Model.modelData shared Object. Then your Adornments could have toModel Bindings on that property in order to control the scale or strokeWidth or whatever property your Shapes have in your Adornments. Perhaps something like:
myDiagram = new go.Diagram('myDiagramDiv', {
"ViewportBoundsChanged": e => {
if (e.subject.scale !== e.diagram.scale) {
const m = e.diagram.model;
m.commit(m => m.set(m.modelData, "scale", e.diagram.scale), null);
}
},
. . .
And then your node template could be something like:
myDiagram.nodeTemplate = new go.Node({
selectionAdornmentTemplate:
new go.Adornment("Auto")
.add(
new go.Shape({ fill: null, stroke: "dodgerblue", strokeWidth: 4 })
.bindModel("strokeWidth", "scale", s => 4/s),
new go.Placeholder({ padding: 2 })
),
resizable: true,
resizeObjectName: 'SHAPE',
resizeAdornmentTemplate:
new go.Adornment("Spot")
.add(
new go.Placeholder(),
new go.Shape({ alignment: go.Spot.Right, width: 6, height: 6, fill: "lightblue", stroke: "dodgerblue", cursor: "pointer" })
.bindModel("scale", "scale", s => 1/s),
new go.Shape({ alignment: go.Spot.Bottom, width: 6, height: 6, fill: "lightblue", stroke: "dodgerblue", cursor: "pointer" })
.bindModel("scale", "scale", s => 1/s),
new go.Shape({ alignment: go.Spot.BottomRight, width: 6, height: 6, fill: "lightblue", stroke: "dodgerblue", cursor: "pointer" })
.bindModel("scale", "scale", s => 1/s),
),
reshapable: true, // GeometryReshapingTool assumes nonexistent Part.reshapeObjectName would be "SHAPE"
rotatable: true,
rotationSpot: go.Spot.Center,
rotateAdornmentTemplate:
new go.Adornment({ locationSpot: go.Spot.Center })
.add(
new go.Shape("Circle", { width: 8, height: 8, fill: "lightblue", stroke: "dodgerblue" })
.bindModel("scale", "scale", s => 1/s)
),
. . .