Moving whole diagram to centering a node without changing layout

Hi,
I would like to check if the diagram’s scale is not 1, then when user click on a node, the whole diagram’s location will be changed to centering that node without changing current layout of nodes or current scale.
How can I do that?

In your node template:

  {
    click: function(e, node) {
      if (e.diagram.scale !== 1.0) e.diagram.centerRect(node.actualBounds);
    }
  }

@walter thank you for that.
More requirements: when user click on a node, there will be an Ajax request send to server to add new node data to current diagram. I wonder if I can check when the new node data is added then I can centerRect the clicked node.

Yes, but you’ll need to wait until any layouts have completed, because only then will the new node’s location be known. You can do that in a “LayoutCompleted” DiagramEvent listener.

Oh, sorry, I missed that you said on the clicked node, not on the new node. Still, the old node might have changed location on a layout. Unless you have disabled layout invalidation: GoJS Layouts -- Northwoods Software

I tried to do that but after I added a breakpoint at the “LayoutCompleted” event listener function, I see that when this function starts to run, the new nodes are still not displayed yet. And then the clicked node is not moved to center. What should I do?

Did you add new nodes and links within a transaction?

Yes, of course. I startTransaction first, send Ajax request, re-initialize the diagram with new nodeDataArray from Ajax response, then commitTransaction

Even when I see the sample for the function centerRect(r) on this page GoJS Initial Viewport -- Northwoods Software, when I continually refresh the page, there are some times the selected node is not centered as well.

I also tried using scrollToRect() instead of centerRect(), but if the clicked node is outside of the initial viewport, then the function does not work.

@walter What should I do ?

If the node is near the edge of the document bounds, the diagram cannot be scrolled far enough to actually center the node in the viewport. That can be accommodated by increasing the Diagram.padding or changing the Diagram.scrollMode.

How is your “LayoutCompleted” listener implemented? What Diagram properties have you set?

Please be patient – I’m responding to a lot of other people too. We normally get a lot more email than forum or StackOverflow messages.

Ok sorry for that.
Here is how my Diagram implemented

this.diagram = $(go.Diagram, "divId", { layout : $(go.LayeredDigraphLayout, { setsPortSpots : false, columnSpacing : 20, layerSpacing : 70 }), // scrollMode: go.Diagram.InfiniteScroll, // padding: new go.Margin(50), "animationManager.isEnabled" : false, "LayoutCompleted" : function(e){ calculateLabelSizeOfNode(); if(nodeToCenter){ // e.diagram.scrollToRect(nodeToCenter.actualBounds); e.diagram.centerRect(nodeToCenter.actualBounds); } } });
I tried to use scrollToRect® and Diagram.scrollMode = go.Diagram.InfiniteScroll together, the diagram is scrolled but the nodeToCenter is still outside of the viewport.

OK, I just tried adding this code to an existing simple sample:

  var nodeToCenter = null;

  function newNodes() {
    myDiagram.startTransaction();
    var stuff = [];
    var num = Math.ceil(Math.random() * 10);
    for (var i = 0; i < num; i++) {
      stuff.push({ text: i.toString(), color: go.Brush.randomColor() })
    }
    myDiagram.model.nodeDataArray = stuff;
    nodeToCenter = myDiagram.findNodeForData(stuff[num-1]);
    myDiagram.commitTransaction("new nodes");
  }

And this HTML Button:

<button onclick="newNodes()">New Nodes</button>

I also added this initialization of my Diagram:

          {
            . . .,
            layout: $(go.ForceDirectedLayout),
            scrollMode: go.Diagram.InfiniteScroll,
            "LayoutCompleted": function(e) {
              if (nodeToCenter) e.diagram.centerRect(nodeToCenter.actualBounds);
            },
           . . .

Everything worked exactly as I believe you are asking for.

@walter

I tried to change the diagram implemented as below but nothing changes:
$(go.Diagram, "graphContainer", { layout : $(go.LayeredDigraphLayout, { setsPortSpots : false, // Links already know their fromSpot and // toSpot columnSpacing : data.columnSpacing, layerSpacing : 70 }), // layout: $(go.ForceDirectedLayout), scrollMode: go.Diagram.InfiniteScroll, // padding: new go.Margin(50), "animationManager.isEnabled" : false, "LayoutCompleted" : function(e){ calculateLabelSizeOfNode(); if(nodeToCenter){ e.diagram.centerRect(nodeToCenter.actualBounds); } } })

This is the default displayed graph, there is only 1 node displayed


Click the button on the left, there will be an Ajax request sent to server to add 10 new nodes to json data and then re-initialize the diagram to display them. The old diagram will be removed by the method diagram.div = null. This is how it is going on, the node B1 is outside of the viewport so you cannot see it on this picture.

Scroll down to see the node B1, and click the button on the left, now the nodeToCenter will be B1, then the progress is like above: send Ajax request to server, remove old diagram, display new diagram. This is how it is going on, you can see I used centerRect(nodeToCenter) in my diagram, the nodeToCenter is currently B1 but it is still outside of the viewport.

Hope you can fix this.

I hope you are finding the Node again after re-creating the Diagram each time.

What you are doing seems terribly wasteful.

@walter No, I am currently creating a variable outside of the diagram to save the nodeToCenter so I do not need to find it again after re-creating the Diagram each time.
I know this is wasteful but there is no other way to do with our customer’s requirements.
Hope you can help.

@walter anyway, after trying to save the key instead of the node and find it again after re-creating diagram each time, seems like it worked. Thank you so much.
I will keep asking if there is any other problem.