Dynamically changing layout types

I have some code that lays out an initial diagram using a digraph layout and it works fine. I then allow a user to change the diagraph layout to a force directed layout using this code:

diagram.layout = new go.ForceDirectedLayout();

And this code works fine and the diagram changes to a force directed layout. But I also let the user change it back to a digraph layout using this code:

diagram.layout = new go.LayeredDigraphLayout();

This code does not work - the diagram never turns back into a digraph layout. Any idea why it would work one direction but not the other?

Thanks.

I just tried modifying an existing sample to do what you are talking
about, Concept
Map
.

I added this function:

function toggleLayout() { var $ = go.GraphObject.make; if (myDiagram.layout instanceof go.ForceDirectedLayout) { myDiagram.layout = $(go.LayeredDigraphLayout, { direction: 90 }); } else { myDiagram.layout = $(go.ForceDirectedLayout, { defaultSpringLength: 30, defaultElectricalCharge: 100 }); } }
and then I added a Button:

<button onclick="toggleLayout()">Toggle Layout</button>

And everything seems to work just the way you are expecting. So I’m wondering what else is different in your app.

At this point I’ve got nothing. I made some changes based on what you had here and my results went downhill. When starting from a LayeredDigraphLayout, when I make this call:
workItemDiagram.layout = new go.ForceDirectedLayout();
the diagram does change to a force directed. However, I changed it to match the code posted:
function setForceDiagram() {
var $ = go.GraphObject.make;
workItemDiagram.Layout = $(go.ForceDirectedLayout,
{
defaultSpringLength: 30,
defaultElectricalCharge: 100
});
};
And now it doesn’t change to a force directed at all. It still doesn’t switch back and the code is being hit and called.

Any other thoughts on where I can look?

Thanks!

You capitalized “Layout”, but all properties (other than constants) in GoJS start with a lower case letter.

Using go.GraphObject.make to initialize properties helps catch typos because it checks for correctly spelled property names. But you cannot use go.GraphObject.make to modify existing objects.

Sigh. It was just that simple. Thanks Walter - I completely missed that somehow.

In the next release if you use go-debug.js we’ll throw an Error if you try setting Diagram.Layout instead of setting Diagram.layout. (But if you use go.js, we won’t detect that.)

Hey there,
My requirement is also almost same. I have a diagram which is displayed as circular layout and on click of a button, it has to change to LayeredDigraphLayout. This is the code I used.

function toggleLayout() {
var $ = go.GraphObject.make;
if (diagram.layout instanceof go.CircularLayout) {
diagram.layout = $(go.LayeredDigraphLayout,
{
  direction: 90,
  layerSpacing: 90,
  layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource,
  setsPortSpots: false,
  columnSpacing: 90
  }
  );
}
else {
diagram.layout = $(go.CircularLayout,
                                    {
                                        radius: 10,
                                        aspectRatio: 1,
                                        startAngle : 0,
                                        sweepAngle : 360,
                                        spacing : 6,
                                        arrangement: go.CircularLayout.ConstantSpacing,
                                        direction: go.CircularLayout.Counterclockwise
                                    }
                                );
}
}

and I added a button on the page like

<input type="button" onclick="toggleLayout()"  value="change Layout">

but I can only see the diagram moving up and down on click of this button.
Do you have any suggestion for this?

Normally when you make any changes you should perform them all within a single transaction. See for example what this sample does: Fishbone Layout

Hey Walter, I tried something similar for switching between circular layout to a layered diagraph layout. but I have question, what is the equivalent of layered diagraph for “FishboneLink”? I mean this is how it is mentioned in the sample code.

myDiagram.linkTemplateMap.add('fishbone',
      $(**FishboneLink**, // defined above
        $(go.Shape)
      ));
function layoutFishbone() {
        myDiagram.startTransaction('fishbone layout');
        myDiagram.linkTemplate = myDiagram.linkTemplateMap.getValue('fishbone');
        myDiagram.layout = go.GraphObject.make(FishboneLayout, {
            angle: 180,
            layerSpacing: 10,
            nodeSpacing: 20,
            rowSpacing: 10
        });
        myDiagram.commitTransaction('fishbone layout');
    }

Taking this sample code as reference, I have written a code like this.

diagram.linkTemplateMap.add("layered",
        $(**LayeredDigraphLayout**,
          $(go.Shape)
        ));

and

function layoutLayeredDiagraph() {
    diagram.startTransaction("LayeredDigraph Layout");
    diagram.linkTemplate = myDiagram.linkTemplateMap.get("layered");
    diagram.layout = go.GraphObject.make(LayeredDigraphLayout,
    {  // defined above
            direction: 90,
            layerSpacing: 90,
            layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource,
            setsPortSpots: false,
            columnSpacing: 90
    });
    diagram.commitTransaction("LayeredDigraph Layout);
  }

my doubt is… what is the replacement of “FishboneLink” here. also this code doesn’t seems like working for me. is it because of the above mentioned one or do you see anything else wrong in my code?

Only FishboneLayout uses a custom FishboneLink class. Just use the regular Link class: $(go.Link, ...)

Assuming you have declared: const $ = go.GraphObject.make;

Hello Walter,

Thanks for responding, I have made couple of changes and here is how it went

function diagram_init() {
    console.log("Diagram initialized");
    var $ = go.GraphObject.make; 
    
    var diagram =
        $(go.Diagram, "hierarchyDiagram",
            {hoverDelay: 0, holdDelay:0, toolTipDuration: 3600000, padding:1000},            

  diagram.linkTemplateMap.add("layered",
          $(go.Link,
          { selectable: false },
          $(go.Shape,
            { strokeWidth: 1, stroke: "#333" })));


    // Node Design
    diagram.nodeTemplate =
        $(go.Node, "Auto",
            {
                desiredSize: new go.Size(150, 50),
                deletable: false,
                mouseOver: (e, node) => {diagram.toolManager.showToolTip(node.toolTip, node);} // Needed to fix flickering while moving mouse over the node
            },

            // defining the shape of the node based on whether the it is a cloud or not
            $(go.Shape,
            new go.Binding("figure", "is_cloud", is_cloud =>
            {
                switch(is_cloud)
                {
                case "true" : return "Cloud";
                default : return "RoundedRectangle";
                }
                }),
                new go.Binding("fill", "is_searched", is_searched => {
                    switch (is_searched) {
                        case "client" : return "grey";
                        case "cloud"  : return "#D3D3D3";
                        default : return "white";
                    }}
                )
            ),

            $(go.Panel, "Vertical",
                $(go.TextBlock, {alignment: go.Spot.Center, margin: 3},
                new go.Binding("text","header")),
                $(go.Panel, "Horizontal",
                    $(go.Panel, "Vertical", {margin: 3},
                        $(go.TextBlock, {alignment: go.Spot.Left},
                        new go.Binding("text","is_cloud", is_cloud =>{
                        switch(is_cloud){
                        case "true" : return "";
                        default: return ""
                        }
                        }
                        )),

                    ),
                    $(go.Panel, "Vertical", {margin: 3},
                        $(go.TextBlock, {alignment: go.Spot.Left},
                        new go.Binding("text"," ")),

                    )

                )
            )
        );


    // Selection design
    diagram.nodeSelectionAdornmentTemplate = diagram.linkSelectionAdornmentTemplate =
        $(go.Adornment, "Spot",
            $(go.Panel, "Auto",
                $(go.Shape, { fill: null, stroke: "transparent", strokeWidth: 10 }),
                $(go.Placeholder)
            )
        );

    // Group design
    diagram.groupTemplate =
        $(go.Group, "Auto",
            $(go.Placeholder, {padding: 30})  // with some extra padding around them
        );

    //Link design
    diagram.linkTemplate =
        $(go.Link,
            {curve: go.Link.Bezier, deletable: false, layerName: 'Background'},
            $(go.Shape), // Shape for the line
            $(go.Shape, {toArrow: "Standard"}), // Arrowhead at the end of the line
            $(go.TextBlock, // Label on the link
                {segmentOffset: new go.Point(0,10), segmentOrientation: go.Link.OrientUpright, margin: 15},
                new go.Binding("text", " "))
        );

 diagram.groupTemplate.layout = $(go.LayeredDigraphLayout,
        {
            direction: 0,
            layerSpacing: 90,
            layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource,
            setsPortSpots: false,
            columnSpacing: 30
        }
    );

    diagram.addDiagramListener("InitialLayoutCompleted", (e) => zoomToNodeByData(diagram, {key: 'group1'}, false));

    return diagram;
}

and the function to change the layout to Layered Digraph is

function layoutLayeredDiagraph() {
    diagram.startTransaction("Layered Digraph Layout");
    diagram.linkTemplate = diagram.linkTemplateMap.get("layered");
    diagram.groupTemplate.layout = $(go.LayeredDigraphLayout,
            {
                direction: 0,
                layerSpacing: 90,
                layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource,
                setsPortSpots: false,
                columnSpacing: 90
            }
        );

    diagram.commitTransaction("Layered Digraph Layout");
 

so, initially the diagram would be like this

after clicking the button, what is expcted is the below image

but instead I am getting the below image which simply changing the arrows link

is it like the layout part of the function is not having any affect on the diagram. where it went wrong?

Changing the group template’s Group.layout, or any other property on the Group template, will not affect anything in the Diagram. Every Part (Node, Link, Group, most Adornments) that is automatically added to the diagram is copied from a template. (Exceptions include tooltips and context menus that are Adornments, because there can be at most one of those showing at a time.)

So if the nodes that you are showing in your screenshot are members of a Group, you’ll need to change the Group.layout property (or any other properties) of that Group instance, not of the template. Or maybe you actually want to change the layout for all Groups.