Rescaling Diagram

Hello,

Our company is using GoJs in Angular. Our application allows users to click various elements which will result in an API call and then populating a diagram of nodes based on the response. The issue we are facing is that if a user clicks an element and zooms, and then clicks a new element rendering a new set of nodes, the zoom state of the prior diagram is preserved. We want the scaling to be reset.

I spent the better part of the day looking through documentation and playing with code and no luck so far… I’ve tried to call zoomToFit, zoomToRect(diagram.documentBounds), setting the scale and playing with various properties. Some of these address the scaling issue and the new diagram is scaled accordingly. However, this results in not being able to zoom in and out, which is a requirement for our users.

I have also considered sending in a new initDiagram function as input when the user requests new data, but I’m thinking this may not be performant.

Here is the code for our diagram that is returned from the initDigram function
image

Any help would be greatly appreciated!

TJ

Wow, you’ve really set all of those Diagram.allow… properties.
If you read GoJS User Permissions -- Northwoods Software you’ll see that you can get most of those effects by setting Diagram.isReadOnly to true. But maybe you don’t want to bother now.

Back to your question. You have set Diagram.initialAutoScale which, when the model is loaded (or Diagram.delayInitialization has been called) will cause the Diagram to be zoomed automatically so that the documentBounds fits within the viewport.

However, after that there shouldn’t be any problem with zooming or scrolling or whatever. Do make sure you haven’t set Diagram.autoScale, because that would indeed prevent zooming. When it’s set it automatically rescales at each transaction.

Another possibility is that perhaps in your use of the gojs-angular component you are accidentally re-initializing everything with each change that you are making. That could happen if you call clear. But I think it’s unlikely you would be doing that.

Hi Walter,

Thank you for your prompt response and good call on the read only property! I think our team has the list for testing purposes, but this property might be helpful in the future.

Allow me to share some pictures to further illustrate our issue.

As you can see in the most recent image, the picture is scaled to the same zoom level as the previous diagram. Is there a way to reset the scaling property each and every time new data is requested for the diagram?

I might add that I have added a number of event listener functions that attempt to rescale, but I lose the zoom functionality at that point.
For example:
image

Here’s the gojs component:
image

Here’s a complete sample that creates a tree and has Diagram.initialAutoScale set to Uniform. It has a doubleClick event handler on each Node that adds some children to that node, perform a layout just on that subtree, and then call CommandHandler.zoomToFit.

There’s no problem with the user zooming or scrolling thereafter.

Note that zoomToFit limits scaling to the value of Diagram.defaultScale, so it won’t blow up a tiny Node to fill up the whole viewport.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2024 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <button id="myTestButton">Layout Whole Diagram</button>
  Double click a node to add some children to it without re-laying out the whole diagram.

  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
const $ = go.GraphObject.make;

const myDiagram =
  new go.Diagram("myDiagramDiv",
    {
      layout: new go.TreeLayout({ isOngoing: false }),
      initialAutoScale: go.Diagram.Uniform,
      "draggingTool.dragsTree": true,
      "undoManager.isEnabled": true
    });

myDiagram.nodeTemplate =
  $(go.Node, "Spot",
    { width: 70, height: 20 },
    $(go.Shape, "Rectangle",
      new go.Binding("fill", "color")),
    $(go.TextBlock,
      { margin: 2 },
      new go.Binding("text", "color")),
    {
      doubleClick: (e, node) => {
        e.diagram.commit(diag => {
          const numchildren = Math.random() * 5;
          for (let i = 0; i < numchildren; i++) {
            const d = { parent: node.key, color: "red" };
            diag.model.addNodeData(d);
          }
          const lay = new go.TreeLayout({ arrangement: go.TreeLayout.ArrangementFixedRoots });
          lay.doLayout(node.findTreeParts());
          myDiagram.commandHandler.zoomToFit();
        });
      }
    }
  );

// create some tree data
const total = 33;
const treedata = [];
for (let i = 0; i < total; i++) {
  // these property names are also specified when creating the TreeModel
  treedata.push({
    key: i,  // this node data's key
    parent: (i > 0 ? Math.floor(Math.random() * i / 2) : undefined),  // the random parent's key
    color: go.Brush.randomColor()  // the node's color (optional)
  });
}
// give the Diagram's model all the data
myDiagram.model = new go.TreeModel(treedata);

document.getElementById("myTestButton").addEventListener("click", e => {
  myDiagram.layoutDiagram(true);
});
  </script>
</body>
</html>

So I was able to get zoomToFit and zoomToRect to both work. It seems that calling these functions inside certain event handlers prevents them from working as intended. For anyone who may be running into this issue, try a different handler.

Thanks for your help Walter!

There are times when you need to execute commands “later”, so in a setTimeout function.