Overview render on request

When rendering approx 10K nodes in my diagram; rendering the overview is quite computationally expensive. Would it be possible to update the overview state on request, e.g. on a model changed event? So the desired behavior for the overview:

  • Render the overview on load
  • Render the viewport rect when the viewport moves
  • Do not update the overview when we drag items in the diagram
  • Update the overview when we release an item, e.g. model change event

Note: I am aware of the hidden updateDelay property but this still makes the diagram “hang” every update delay while interacting for a large number of nodes. So doing an update on mouse release after a drag action has finished would be better here.

The quick answer is no. I can look into it when I get some free time.

Thanks for your response, we will stick with the hidden updateDelay property for now then; let us know if there are any updates regarding this topic.

In v2.1.47 and later you’ll be able to call redraw, another undocumented method.

It’s undocumented because we don’t want people calling it when they are desperate to get some change that they’ve made showing in their viewport, so they’re trying whatever they can find. But usually the problem is that they forgot to notify the model or diagram about a change (i.e. not in a transaction), or their change is supposed to be unseen (offscreen or collapsed or transparent or occluded by something else). When they figure it out, they often leave the calls to the “bad” methods in, causing problems.

Thank! So you would suggest setting the updateDelay to inf and calling the redraw manually?

You’ll have to try it to make sure that will work for your app.

I tried settings the updatedelay to a large number and call redraw manually after a diagram model change. However, the overview is not redrawn. Anything that I might overlook?

OK, the problem is due to a declaration error in our source code. That will be fixed for the next release, 2.1.50, which should come out either later this week or earlier next week.

1 Like
<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Editor</title>
  <!-- Copyright 1998-2021 by Northwoods Software Corporation. -->
  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
    function init() {
      var $ = go.GraphObject.make;

      // initialize main Diagram
      myDiagram =
        $(go.Diagram, "myDiagramDiv",
          {
            "undoManager.isEnabled": true,
            // make sure the Overview is up-to-date initially
            "InitialLayoutCompleted": function(e) { myOverview.redraw(); },
            // and update the Overview after each transaction or undo or redo
            "ModelChanged": function(e) {
              if (e.isTransactionFinished) myOverview.redraw();
            }
          });

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

      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" }
      ],
      [
        { from: 1, to: 2 },
        { from: 1, to: 3 },
        { from: 2, to: 2 },
        { from: 3, to: 4 },
        { from: 4, to: 1 }
      ]);

      // initialize Palette
      myPalette =
        $(go.Palette, "myPaletteDiv",
          {
            nodeTemplateMap: myDiagram.nodeTemplateMap,
            model: new go.GraphLinksModel([
              { text: "red node", color: "red" },
              { text: "green node", color: "green" },
              { text: "blue node", color: "skyblue" },
              { text: "orange node", color: "orange" }
            ])
          });

      // initialize Overview
      myOverview =
        $(go.Overview, "myOverviewDiv",
          {
            updateDelay: 9999999,
            observed: myDiagram,
            contentAlignment: go.Spot.Center
          });
    }
    </script>
</head>
<body onload="init()">
  <div style="width: 100%; display: flex; justify-content: space-between">
    <div style="display: flex; flex-direction: column; margin: 0 2px 0 0">
      <div id="myPaletteDiv" style="flex-grow: 1; width: 100px; background-color: floralwhite; border: solid 1px black"></div>
      <div id="myOverviewDiv" style="margin: 2px 0 0 0; width: 100px; height: 100px; background-color: whitesmoke; border: solid 1px black"></div>
    </div>
    <div id="myDiagramDiv" style="flex-grow: 1; height: 400px; border: solid 1px black"></div>
  </div>
</body>
</html>

Thanks for the update and the example. For some reason it is not working in our code base but I will look further into it. Your example works nicely though!

Hi again,

At first sight, your solution seemed to work properly. However, when I zoom in, the rendered overview rect does not seem to match with the diagram view:

Could you confirm this? And could you thinks of a solution for this?

You asked for updating the Overview on a model changed event. Zooming and scrolling/panning do not cause model changes, so the “ModelChanged” listener isn’t invoked.

The obvious solution is to declare a “ViewportBoundsChanged” listener that blindly calls myOverview.redraw(), but you wouldn’t like the results because it would redraw on each scroll event. So you’ll need to decide exactly when to call it.

I understand what you are saying but I am still looking for a solution here. When I load an initial model and navigate using the overview rect, it works fine. However, when expanding the model, the overview rect does not correspond with the view frustum of the diagram. So still the question remains, what would be an approach for us to have a functioning overview when rendering 10K nodes?

Implement a “ViewportBoundsChanged” DiagramEvent listener.
https://gojs.net/latest/intro/events.html#ViewportBoundsChanged

But you’ll need to be smart about “debouncing” calls to Overview.redraw.

Thanks Walter. This will work in combination with some assumptions I can do for my application.