224 lines
9.4 KiB
HTML
224 lines
9.4 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>GoJS SubGraphs -- Northwoods Software</title>
|
|
<!-- Copyright 1998-2017 by Northwoods Software Corporation. -->
|
|
<script src="../release/go.js"></script>
|
|
<script src="goIntro.js"></script>
|
|
</head>
|
|
<body onload="goIntro()">
|
|
<div id="container" class="container-fluid">
|
|
<div id="content">
|
|
|
|
<h1>Groups as SubGraphs</h1>
|
|
<p>
|
|
There are some common ways of treating the nodes and links that are the members of a group as if it were its own graph.
|
|
One way to declutter a diagram is to "collapse" a <a>Group</a> to hide the subgraph that it holds.
|
|
</p>
|
|
<p>
|
|
A <a>Group</a> has its own <a>Group.layout</a> that is responsible for the positioning of member <a>Node</a>s
|
|
and the routing of member <a>Link</a>s.
|
|
This is exactly like a <a>Diagram</a> having its own <a>Diagram.layout</a> that positions top-level Nodes and routes top-level Links.
|
|
</p>
|
|
<p>
|
|
Keep in mind that subgraphs are not separate Diagrams and that Groups are just one way of organizing Parts.
|
|
Because subgraphs are collections of Nodes and Links in the same Diagram as the Group itself,
|
|
it is possible to have Links that connect Nodes that are inside a Group with Nodes that are outside of the group.
|
|
It is also possible to have links that connect nodes with the group of which they are a member.
|
|
</p>
|
|
|
|
<h2 id="LayoutsOfSubgraphs">Layouts of SubGraphs</h2>
|
|
<p>
|
|
You can specify a <a>Layout</a> that applies to a group's subgraph by setting the <a>Group.layout</a> property.
|
|
This operates on the group's member nodes and links as if it were its own diagram.
|
|
A diagram layout of nodes that include groups with their own layout will treat those groups
|
|
as if they were simple nodes, albeit probably larger than normal nodes.
|
|
</p>
|
|
<p>
|
|
In this example the group has a different layout than the layout for the whole diagram.
|
|
In this case the only difference is the direction in which the layout works,
|
|
but you could use a completely different layout algorithm.
|
|
</p>
|
|
<p>
|
|
For simplicity these examples use the default templates for nodes and links.
|
|
</p>
|
|
|
|
<pre data-language="javascript" id="layouts">
|
|
diagram.groupTemplate =
|
|
$(go.Group, "Auto",
|
|
// declare the Group.layout:
|
|
{ layout: $(go.LayeredDigraphLayout,
|
|
{ direction: 0, columnSpacing: 10 }) },
|
|
$(go.Shape, "RoundedRectangle", // surrounds everything
|
|
{ parameter1: 10, fill: "rgba(128,128,128,0.33)" }),
|
|
$(go.Panel, "Vertical", // position header above the subgraph
|
|
$(go.TextBlock, // group title near top, next to button
|
|
{ font: "Bold 12pt Sans-Serif" },
|
|
new go.Binding("text", "key")),
|
|
$(go.Placeholder, // represents area for all member parts
|
|
{ padding: 5, background: "white" })
|
|
)
|
|
);
|
|
|
|
// declare the Diagram.layout:
|
|
diagram.layout = $(go.LayeredDigraphLayout,
|
|
{ direction: 90, layerSpacing: 10, isRealtime: false });
|
|
|
|
diagram.initialContentAlignment = go.Spot.Center;
|
|
|
|
var nodeDataArray = [
|
|
{ key: "Alpha" },
|
|
{ key: "Omega", isGroup: true },
|
|
{ key: "Beta", group: "Omega" },
|
|
{ key: "Gamma", group: "Omega" },
|
|
{ key: "Epsilon", group: "Omega" },
|
|
{ key: "Zeta", group: "Omega" },
|
|
{ key: "Delta" }
|
|
];
|
|
var linkDataArray = [
|
|
{ from: "Alpha", to: "Omega" }, // from a Node to the Group
|
|
{ from: "Beta", to: "Gamma" }, // this link is a member of the Group
|
|
{ from: "Beta", to: "Epsilon" }, // this link is a member of the Group
|
|
{ from: "Gamma", to: "Zeta" }, // this link is a member of the Group
|
|
{ from: "Epsilon", to: "Zeta" }, // this link is a member of the Group
|
|
{ from: "Omega", to: "Delta" } // from the Group to a Node
|
|
];
|
|
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
|
|
</pre>
|
|
<script>goCode("layouts", 600, 250)</script>
|
|
|
|
<p>
|
|
The default layout for a Group is an instance of <a>Layout</a>, just as it is for <a>Diagram</a>.
|
|
So if you do not specify a value for <a>Group.layout</a>, the default layout for the group will position
|
|
all member nodes that do not have a real <a>Part.location</a>.
|
|
</p>
|
|
|
|
<p>
|
|
If you explicitly set <a>Group.layout</a> to null, the Diagram will be responsible for laying out all of
|
|
Nodes and Links as if the Group did not exist.
|
|
This is possible because a subgraph is not another <a>Diagram</a>.
|
|
</p>
|
|
|
|
<h2 id="CollapsingAndExpandingGroups">Collapsing and Expanding Groups</h2>
|
|
<p>
|
|
One common technique to visually simplify a diagram is to hide parts of them by "collapsing" them.
|
|
In the case of <a>Group</a>s, it may make sense to be able to hide the subgraph.
|
|
</p>
|
|
<p>
|
|
To collapse a group, set <a>Group.isSubGraphExpanded</a> to false; to make sure it is expanded,
|
|
set that property to true.
|
|
</p>
|
|
<p>
|
|
It is commonplace to provide a button on a group to allow users to collapse and expand groups as they wish.
|
|
<b>GoJS</b> makes this easy to implement by providing a predefined kind of <a>Panel</a>, named "SubGraphExpanderButton",
|
|
that acts as a button to collapse and expand <a>Group</a>s.
|
|
This button changes the visibility of the member nodes and links but does not change
|
|
the visibility of the group itself.
|
|
When the group's visual tree includes a <a>Placeholder</a>, the placeholder will automatically
|
|
shrink when the member parts become invisible and will inflate when the member parts become visible again.
|
|
</p>
|
|
<p>
|
|
Click on the expander button to collapse or expand the group.
|
|
Changing the size of the group also invalidates the layout that is responsible for positioning the group as a single node.
|
|
Often the size of the group changes greatly, so a layout usually needs to be performed again.
|
|
</p>
|
|
<pre data-language="javascript" id="collapseExpand">
|
|
diagram.groupTemplate =
|
|
$(go.Group, "Auto",
|
|
{ layout: $(go.LayeredDigraphLayout,
|
|
{ direction: 0, columnSpacing: 10 }) },
|
|
$(go.Shape, "RoundedRectangle", // surrounds everything
|
|
{ parameter1: 10, fill: "rgba(128,128,128,0.33)" }),
|
|
$(go.Panel, "Vertical", // position header above the subgraph
|
|
{ defaultAlignment: go.Spot.Left },
|
|
$(go.Panel, "Horizontal", // the header
|
|
{ defaultAlignment: go.Spot.Top },
|
|
$("SubGraphExpanderButton"), // this Panel acts as a Button
|
|
$(go.TextBlock, // group title near top, next to button
|
|
{ font: "Bold 12pt Sans-Serif" },
|
|
new go.Binding("text", "key"))
|
|
),
|
|
$(go.Placeholder, // represents area for all member parts
|
|
{ padding: new go.Margin(0, 10), background: "white" })
|
|
)
|
|
);
|
|
|
|
diagram.layout = $(go.LayeredDigraphLayout,
|
|
{ direction: 90, layerSpacing: 10, isRealtime: false });
|
|
|
|
diagram.initialContentAlignment = go.Spot.Center;
|
|
|
|
var nodeDataArray = [
|
|
{ key: "Alpha" },
|
|
{ key: "Omega", isGroup: true },
|
|
{ key: "Beta", group: "Omega" },
|
|
{ key: "Gamma", group: "Omega" },
|
|
{ key: "Epsilon", group: "Omega" },
|
|
{ key: "Zeta", group: "Omega" },
|
|
{ key: "Delta" }
|
|
];
|
|
var linkDataArray = [
|
|
{ from: "Alpha", to: "Omega" }, // from a Node to the Group
|
|
{ from: "Beta", to: "Gamma" }, // this link is a member of the Group
|
|
{ from: "Beta", to: "Epsilon" }, // this link is a member of the Group
|
|
{ from: "Gamma", to: "Zeta" }, // this link is a member of the Group
|
|
{ from: "Epsilon", to: "Zeta" }, // this link is a member of the Group
|
|
{ from: "Omega", to: "Delta" } // from the Group to a Node
|
|
];
|
|
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
|
|
</pre>
|
|
<script>goCode("collapseExpand", 600, 250)</script>
|
|
|
|
<p>
|
|
If you do not want a layout to be performed again when the group changes size,
|
|
you can set the <a>Part.layoutConditions</a> property to control the circumstances under which
|
|
the layout will be invalidated.
|
|
</p>
|
|
|
|
<p>
|
|
<a>Placeholder</a>s can be part of complex panels.
|
|
The following example demonstrates a different way to have each Group have a header holding a button and some text.
|
|
</p>
|
|
<pre data-language="javascript" id="collapseExpand2">
|
|
diagram.groupTemplate =
|
|
$(go.Group, "Auto",
|
|
{ layout: $(go.TreeLayout) },
|
|
$(go.Shape, "Rectangle", { fill: "orange", stroke: "darkorange" }),
|
|
$(go.Panel, "Table",
|
|
{ margin: 0.5 }, // avoid overlapping border with table contents
|
|
$(go.RowColumnDefinition, { row: 0, background: "white" }), // header is white
|
|
$("SubGraphExpanderButton", { row: 0, column: 0, margin: 3 }),
|
|
$(go.TextBlock, // title is centered in header
|
|
{ row: 0, column: 1, font: "bold 14px Sans-Serif", stroke: "darkorange",
|
|
textAlign: "center", stretch: go.GraphObject.Horizontal },
|
|
new go.Binding("text")),
|
|
$(go.Placeholder, // becomes zero-sized when Group.isSubGraphExpanded is false
|
|
{ row: 1, columnSpan: 2, padding: 10, alignment: go.Spot.TopLeft },
|
|
new go.Binding("padding", "isSubGraphExpanded",
|
|
function(exp) { return exp ? 10 : 0; } ).ofObject())
|
|
)
|
|
);
|
|
|
|
diagram.layout = $(go.TreeLayout, { isRealtime: false });
|
|
|
|
diagram.model = new go.GraphLinksModel([
|
|
{ key: 1, text: "Alpha" },
|
|
{ key: 2, text: "GROUP", isGroup: true },
|
|
{ key: 3, text: "Beta", group: 2 },
|
|
{ key: 4, text: "Gamma", group: 2 },
|
|
{ key: 5, text: "Delta" }
|
|
], [
|
|
{ from: 1, to: 3 },
|
|
{ from: 3, to: 4 },
|
|
{ from: 1, to: 5 }
|
|
]);
|
|
</pre>
|
|
<script>goCode("collapseExpand2", 600, 200)</script>
|
|
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|