Dynamic Grid (with subgrid)

Hi,

we want to change the grid of a diagram dynamically baed on a gridSize.
The idea is to have the default grid, which can be changed in size via a slider option.
Additionally, we have a pagination grid that is a sub grid that indicates page sizes like A4, A3 etc.
The page size and page orientation are dynamically changeable.

I tried a lot of stuff but couldnt get a nice and clean implementation working.
Before we had a solution in which we set grid properties (like gridCellSize) directly.
Ideally, we want a data driven approach, like with all other templates we create.

I now found out that the grid does not support bindings in this topic: How to dynamically change colour of grid
This is really unfortunate. Is there any reason as to why it doesnt support bindings?
How would one ideally implement what we want?
I attach the grid template I have so far.

export function createGridTemplate(): go.Panel {
const $ = go.GraphObject.make;

return $(
    go.Panel,
    go.Panel.Grid,
    {
        // Use 1x1 base cell so that intervals represent exact pixel distances for the default and pagination grid respectively.
        gridCellSize: new go.Size(1, 1),
        data: { gridSize: 25, paginationV: 1, paginationH: 1 },
    },
    // Default grid lines
    $(
        go.Shape,
        'LineH',
        {
            stroke: 'lightgrey',
            strokeWidth: 0.5,
            interval: 25,
            name: 'DefaultGridH',
        },
        new go.Binding('interval', 'gridSize'),
    ),
    $(
        go.Shape,
        'LineV',
        {
            stroke: 'lightgrey',
            strokeWidth: 0.5,
            interval: 25,
            name: 'DefaultGridV',
        },
        new go.Binding('interval', 'gridSize', (v: number) => {
            console.log(v);
            return v;
        }),
    ),
    // Pagination grid lines
    $(
        go.Shape,
        'LineH',
        {
            stroke: '#2d3842',
            strokeDashArray: [2, 2],
            strokeWidth: 0.5,
            interval: 1,
            name: 'PaginationGridH',
        },
        new go.Binding('interval', 'paginationH', (v: number) => {
            console.log(v);
            return v;
        }),
    ),
    $(
        go.Shape,
        'LineV',
        {
            stroke: '#2d3842',
            strokeDashArray: [2, 2],
            strokeWidth: 0.5,
            name: 'PaginationGridV',
        },
        new go.Binding('interval', 'paginationV'),
    ),
);

}

Example screenshot.

Cheers.

Well, it is possible, but it isn’t designed functionality in the GoJS library.

<!DOCTYPE html>
<html>
<head>
  <title>Hack for data binding in Diagram.grid</title>
  <!-- Copyright 1998-2026 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:400px"></div>
  <button id="myTestButton">Test</button>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>

  <script src="https://cdn.jsdelivr.net/npm/gojs"></script>
  <script id="code">
const myDiagram =
  new go.Diagram("myDiagramDiv", {
      grid: new go.Panel("Grid")
        .add(
          new go.Shape("BarH", { fill: "#FF000010", strokeWidth: 0, interval: 2 })
            .bind("fill", "color")
            .bind("interval"),
          new go.Shape("BarV", { fill: "#FF000010", strokeWidth: 0, interval: 2 })
            .bind("fill", "color")
            .bind("interval")
        ),
      "undoManager.isEnabled": true,
      "ModelChanged": e => {     // just for demonstration purposes,
        if (e.isTransactionFinished) {  // show the model data in the page's TextArea
          document.getElementById("mySavedModel").textContent = e.model.toJson();
        }
      }
    });

myDiagram.nodeTemplate =
  new go.Node("Auto")
    .add(
      new go.Shape({ fill: "white" })
        .bind("fill", "color"),
      new go.TextBlock({ margin: 8 })
        .bind("text")
    );

myDiagram.model = new go.GraphLinksModel(
  {
    modelData: { color: "#00FF0010" },
    nodeDataArray:
      [
        { key: 1, text: "Alpha", color: "lightblue" },
        { key: 2, text: "Beta", color: "orange" },
        { key: 3, text: "Gamma", color: "lightgreen" },
        { key: 4, text: "Delta", color: "pink" }
      ],
    linkDataArray:
      [
        { from: 1, to: 2 },
        { from: 1, to: 3 },
        { from: 2, to: 2 },
        { from: 3, to: 4 },
        { from: 4, to: 1 }
      ]
  });

// Change the Diagram's special grid Part to be data bound.
// Can't use a node data object, because it needs to work even if there are no Nodes or Links
// (i.e. Model.nodeDataArray could be empty).
// Try using the shared Model.modelData. However this could be inefficient
// Furthermore because the grid Part is in a Layer that is Layer.isTemporary,
// no changes in the grid Part will be recorded in the UndoManager.
myDiagram.grid.part.data = myDiagram.model.modelData;

document.getElementById("myTestButton").addEventListener("click", e => {
  myDiagram.model.commit(m => {
    m.set(m.modelData, "color", m.modelData.color === "#00FF0010" ? "#FF000010" : "#00FF0010");
    m.set(m.modelData, "interval", m.modelData.interval > 2 ? 2 : 3)
  }, null);  // don't want to record these Model.modelData changes
});
  </script>
</body>
</html>