Search code examples
javascriptgojs

Can I have go.js force-directed layout exclude groups?


I'm using go.js to make concept maps with nodes and in some cases nodes within a group - the links are always between nodes and not directly to a group container but there are links between nodes inside and outside of groups.

When there are no groups the force-directed layout works really well to properly space out the nodes. But if there are nodes in a group, the force-directed layout seems to layout the group as if it was a single node and this can be sub optimal for the node connections. Is there a way to have the layout just be concerned with nodes, even if that means that the groups could be overlapping, larger than need to be or otherwise jumbled? The groups for me are just background category clouds and its really the nodes I'd like optimally arranged.


Solution

  • To stop Groups from participating in layouts, in your groupTemplate you can set isLayoutPositioned: false on the Group.

    But if you want all nodes to be affected by the same layout, instead of just top-level nodes (nodes that are not in groups) then you will have to do something like this:

    var layout = $(go.ForceDirectedLayout);
    layout.doLayout(myDiagram.nodes);
    

    Instead of setting the Diagram's layout. That way the layout will use the entire set of nodes, not just the top-level nodes.

    Here's a simple example:

    function init() {
        if (window.goSamples) goSamples();  // init for these samples -- you don't need to call this
        var $ = go.GraphObject.make;  // for conciseness in defining templates
    
        myDiagram = $(go.Diagram, "myDiagram",  // create a Diagram for the DIV HTML element
                      {
                        initialContentAlignment: go.Spot.Center,  // center the content
                        "undoManager.isEnabled": true  // enable undo & redo
                      });
    
        // define a simple Node template
        myDiagram.nodeTemplate =
          $(go.Node, "Auto",  // the Shape will go around the TextBlock
            $(go.Shape, "RoundedRectangle",
              // Shape.fill is bound to Node.data.color
              new go.Binding("fill", "color")),
            $(go.TextBlock,
              { margin: 3 },  // some room around the text
              // TextBlock.text is bound to Node.data.key
              new go.Binding("text", "key"))
          );
    
    
        myDiagram.groupTemplate =
          $(go.Group, "Vertical",
            { isLayoutPositioned: false,
              selectionObjectName: "PANEL",  // selection handle goes around shape, not label
              ungroupable: true },  // enable Ctrl-Shift-G to ungroup a selected Group
            $(go.TextBlock,
              {
                font: "bold 19px sans-serif",
                isMultiline: false,  // don't allow newlines in text
                editable: true  // allow in-place editing by user
              },
              new go.Binding("text", "text").makeTwoWay(),
              new go.Binding("stroke", "color")),
            $(go.Panel, "Auto",
              { name: "PANEL" },
              $(go.Shape, "Rectangle",  // the rectangular shape around the members
                { fill: "rgba(128,128,128,0.2)", stroke: "gray", strokeWidth: 3 }),
              $(go.Placeholder, { padding: 10 })  // represents where the members are
            )
          );
    
        // create the model data that will be represented by Nodes and Links
        myDiagram.model = new go.GraphLinksModel(
        [
          { key: "Alpha", color: "lightblue" },
          { key: "Beta", color: "orange" },
          { key: "Gamma", group: "G", color: "lightgreen" },
          { key: "Delta", group: "G", color: "pink" },
          { key: "G", isGroup: true, color: "pink" },
          
        ],
        [
        ]);
        
        var layout = $(go.ForceDirectedLayout);
        layout.doLayout(myDiagram.nodes);
        
        
        
      }
    
    init();
    <script src="http://gojs.net/latest/release/go.js"></script>
    <body>
    
      <div id="myDiagram" style="border: solid 3px red; width:400px; height:400px"></div>
        
    </body>