467 lines
18 KiB
HTML
467 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>GoJS Layouts -- 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>Diagram Layouts</h1>
|
|
<p>
|
|
In general terms, a "layout" is a way of sizing and positioning a collection of objects.
|
|
HTML has its own layouts for its HTML elements.
|
|
In <b>GoJS</b> you have already seen many examples of Panel layout, such as Auto or Table,
|
|
which sizes and positions <a>GraphObject</a>s within a <a>Panel</a>.
|
|
<b>GoJS</b> also provides Diagram layouts, which position <a>Node</a>s and route <a>Link</a>s
|
|
within a <a>Diagram</a> or a <a>Group</a>.
|
|
</p>
|
|
|
|
<p>
|
|
Naturally the principal purpose of each diagram <a>Layout</a> is to position nodes, typically by calling <a>Part.move</a>.
|
|
But layouts also may also result in custom routing of the links, by setting properties on each <a>Link</a>.
|
|
For example <a>TreeLayout</a> also ensures that links are routed in the expected direction by setting
|
|
<a>Link.fromSpot</a> and <a>Link.toSpot</a> depending on the <a>TreeLayout.angle</a>.
|
|
(However, that behavior can be disabled by setting <a>TreeLayout.setsPortSpot</a> and <a>TreeLayout.setsChildPortSpot</a>.
|
|
The same is true for some other layouts.)
|
|
</p>
|
|
|
|
<p>
|
|
Diagram layouts can be accomplished in several manners.
|
|
Manual layouts occur because the user moves nodes, thereby establishing new positions for those nodes.
|
|
Such layouts might be saved in some persistent data format and later loaded using data binding or assignments in code.
|
|
Programmatic layouts happen when some code executes to set the <a>Part</a> position or location.
|
|
Automatic layouts are programmatic layouts that are implemented by the <a>Layout</a> class or its subclasses.
|
|
</p>
|
|
|
|
<h2 id="DefaultLayout">Default Layout</h2>
|
|
<p>
|
|
The value of <a>Diagram.layout</a> defaults to an instance of <a>Layout</a>.
|
|
This kind of layout is unlike all of the other layout subclasses, in that it only sets the position of nodes
|
|
that do not already have a position -- i.e. where the X or Y of the <a>GraphObject.actualBounds</a> is NaN.
|
|
It leaves unmodified all nodes that do have a defined position, and it ignores all links.
|
|
</p>
|
|
|
|
<p>
|
|
Many of the examples you have seen so far do not set <a>Diagram.layout</a> and thus use the default layout.
|
|
Some of the examples data bind the <a>Part.location</a> or <a>GraphObject.position</a> to a data property.
|
|
Those examples are basically using manual layout, but with the node positions coming from the node data rather than from
|
|
arrangement by the user.
|
|
</p>
|
|
|
|
<p>
|
|
However many of the examples just allow the standard behavior of the <a>Layout</a> class to assign positions to the nodes
|
|
in the order in which they are seen by the layout.
|
|
Those examples are exhibiting automatic layout behavior.
|
|
</p>
|
|
|
|
<h2 id="AutomaticLayouts">Automatic Layouts</h2>
|
|
<p>
|
|
<b>GoJS</b> offers several kinds of automatic layouts, including:
|
|
</p>
|
|
<ul>
|
|
<li><a>GridLayout</a></li>
|
|
<li><a>TreeLayout</a></li>
|
|
<li><a>ForceDirectedLayout</a></li>
|
|
<li><a>LayeredDigraphLayout</a></li>
|
|
<li><a>CircularLayout</a></li>
|
|
</ul>
|
|
|
|
<p>
|
|
There are samples for each of these layouts, demonstrating the effects of setting various detailed layout properties:
|
|
</p>
|
|
<ul>
|
|
<li><a href="../samples/gLayout.html" target="samples">GridLayout Sample</a></li>
|
|
<li><a href="../samples/tLayout.html" target="samples">TreeLayout Sample</a></li>
|
|
<li><a href="../samples/fdLayout.html" target="samples">ForceDirectedLayout Sample</a></li>
|
|
<li><a href="../samples/ldLayout.html" target="samples">LayeredDigraphLayout Sample</a></li>
|
|
<li><a href="../samples/cLayout.html" target="samples">CircularLayout Sample</a></li>
|
|
</ul>
|
|
|
|
<p>
|
|
In the introduction pages and samples you will see many examples that make use of automatic layout by setting the <a>Diagram.layout</a> property. <a href="https://github.com/NorthwoodsSoftware/GoJS/search?utf8=%E2%9C%93&q=%22layout%3A+%26%28go%22&type=Code">Search the sources of the samples for many more examples.</a>
|
|
</p>
|
|
|
|
<h2 id="LayoutUsage">Layout Usage</h2>
|
|
|
|
<p>
|
|
You can set <a>Diagram.layout</a> in a JavaScript statement:
|
|
</p>
|
|
<pre>diagram.layout = new go.ForceDirectedLayout();</pre>
|
|
<p>
|
|
Or you can initialize that property using <a>GraphObject.make</a>:
|
|
</p>
|
|
<pre>
|
|
var diagram = $(go.Diagram, "myDiagramDiv",
|
|
{
|
|
initialContentAlignment: go.Spot.Center,
|
|
layout: $(go.TreeLayout,
|
|
{ angle: 90, nodeSpacing: 10, layerSpacing: 30 })
|
|
});
|
|
</pre>
|
|
<p>
|
|
We recommend using <b>GraphObject.make</b> whenever you can because of the error checking that it does for property names.
|
|
</p>
|
|
|
|
<h2 id="GridLayout">Grid Layout</h2>
|
|
|
|
<p>A simple layout for placing Nodes in a grid-like arrangement.</p>
|
|
|
|
<pre data-language="javascript" id="gridlayout" style="display: none;">
|
|
diagram.layout = $(go.GridLayout);
|
|
diagram.contentAlignment = go.Spot.Center;
|
|
|
|
// define a simple Node template
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Spot", // the Shape will go around the TextBlock
|
|
$(go.Shape, "Ellipse",
|
|
{ fill: 'palegreen', stroke: '#333', strokeWidth: 3, width: 40, height: 40 }
|
|
),
|
|
$(go.TextBlock,
|
|
{ margin: 3, font: 'bold 14px sans-serif', stroke: '#333' }, // some room around the text
|
|
// TextBlock.text is bound to Node.data.key
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
// Default routing is go.Link.Normal
|
|
// Default corner is 0
|
|
{ corner: 5 },
|
|
$(go.Shape, { strokeWidth: 3, stroke: "#333" })
|
|
);
|
|
|
|
// create the model data that will be represented by Nodes and Links
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: "1" },
|
|
{ key: "2" },
|
|
{ key: "3" },
|
|
{ key: "4" },
|
|
{ key: "5" },
|
|
{ key: "6" },
|
|
{ key: "7" },
|
|
{ key: "8" },
|
|
{ key: "9" },
|
|
{ key: "10" },
|
|
{ key: "11" },
|
|
],
|
|
[
|
|
]);
|
|
</pre>
|
|
<script>goCode("gridlayout", 400, 120)</script>
|
|
|
|
<p>
|
|
See the <a href="../samples/gLayout.html" target="samples">GridLayout Sample</a> for a demonstration of layout options.
|
|
The <a href="../samples/swimlanes.html" target="samples">Swim Lanes</a> sample demonstrates a customization of <a>GridLayout</a>.
|
|
See more samples that make use of <a>GridLayout</a> in the <a href="../samples/index.html#gridlayout">samples index</a>.
|
|
</p>
|
|
|
|
<h2 id="TreeLayout">Tree Layout</h2>
|
|
|
|
<p>This layout positions nodes of a tree-structured graph in layers (rows or columns).</p>
|
|
|
|
<pre data-language="javascript" id="treelayout" style="display: none;">
|
|
diagram.layout = $(go.TreeLayout);
|
|
diagram.contentAlignment = go.Spot.Center;
|
|
|
|
// define a simple Node template
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Spot", // the Shape will go around the TextBlock
|
|
$(go.Shape, "Ellipse",
|
|
{ fill: 'palegreen', stroke: '#333', strokeWidth: 3, width: 40, height: 40 }
|
|
),
|
|
$(go.TextBlock,
|
|
{ margin: 3, font: 'bold 14px sans-serif', stroke: '#333' }, // some room around the text
|
|
// TextBlock.text is bound to Node.data.key
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
// Default routing is go.Link.Normal
|
|
// Default corner is 0
|
|
{ corner: 5 },
|
|
$(go.Shape, { strokeWidth: 3, stroke: "#333" })
|
|
);
|
|
|
|
// create the model data that will be represented by Nodes and Links
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: "1" },
|
|
{ key: "2" },
|
|
{ key: "3" },
|
|
{ key: "4" },
|
|
{ key: "5" },
|
|
{ key: "6" }
|
|
],
|
|
[
|
|
{ from: "1", to: "2" },
|
|
{ from: "1", to: "3" },
|
|
{ from: "3", to: "4" },
|
|
{ from: "3", to: "5" },
|
|
{ from: "3", to: "6" }
|
|
]);
|
|
</pre>
|
|
<script>goCode("treelayout", 400, 200)</script>
|
|
|
|
<p>
|
|
See the <a href="../samples/tLayout.html" target="samples">TreeLayout sample</a> for a demonstration of layout options.
|
|
The <a href="../samples/orgChartEditor.html" target="samples">Org Chart Editor</a>,
|
|
<a href="../samples/parseTree.html" target="samples">Parse Tree</a>,
|
|
<a href="../samples/swimBands.html" target="samples">Layer Bands</a>, and
|
|
<a href="../samples/virtualizedTreeLayout.html" target="samples">Virtualized Tree</a>
|
|
samples demonstrate customization of <a>TreeLayout</a>.
|
|
See more samples that make use of <a>TreeLayout</a> in the <a href="../samples/index.html#treelayout">samples index</a>.
|
|
</p>
|
|
|
|
<h2 id="ForceDirectedLayout">Force-Directed Layout</h2>
|
|
|
|
<p>Force-directed layout treats the graph as if it were a system of physical bodies with forces acting on them and between them.</p>
|
|
|
|
<pre data-language="javascript" id="fdlayout" style="display: none;">
|
|
diagram.layout = $(go.ForceDirectedLayout);
|
|
diagram.initialAutoScale = go.Diagram.Uniform;
|
|
diagram.contentAlignment = go.Spot.Center;
|
|
|
|
// define a simple Node template
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Spot", // the Shape will go around the TextBlock
|
|
$(go.Shape, "Ellipse",
|
|
{ fill: 'palegreen', stroke: '#333', strokeWidth: 3, width: 40, height: 40 }
|
|
),
|
|
$(go.TextBlock,
|
|
{ margin: 3, font: 'bold 14px sans-serif', stroke: '#333' }, // some room around the text
|
|
// TextBlock.text is bound to Node.data.key
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
// Default routing is go.Link.Normal
|
|
// Default corner is 0
|
|
{ corner: 5 },
|
|
$(go.Shape, { strokeWidth: 3, stroke: "#333" })
|
|
);
|
|
|
|
// create the model data that will be represented by Nodes and Links
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: "1" },
|
|
{ key: "2" },
|
|
{ key: "3" },
|
|
{ key: "4" },
|
|
{ key: "5" },
|
|
{ key: "6" },
|
|
{ key: "7" },
|
|
{ key: "8" },
|
|
{ key: "9" },
|
|
{ key: "10" },
|
|
{ key: "11" },
|
|
],
|
|
[
|
|
{ from: "6", to: "2" },
|
|
{ from: "3", to: "4" },
|
|
{ from: "3", to: "5" },
|
|
{ from: "3", to: "6" },
|
|
{ from: "6", to: "1" },
|
|
{ from: "6", to: "7" },
|
|
{ from: "4", to: "8" },
|
|
{ from: "4", to: "9" },
|
|
{ from: "4", to: "10" },
|
|
{ from: "4", to: "11" },
|
|
]);
|
|
</pre>
|
|
<script>goCode("fdlayout", 400, 200)</script>
|
|
|
|
<p>
|
|
See the <a href="../samples/fdLayout.html" target="samples">ForceDirectedLayout sample</a> for a demonstration of layout options.
|
|
That sample also demonstrates a simple customization of <a>ForceDirectedLayout</a>.
|
|
The <a href="../samples/virtualizedForceLayout.html" target="samples">Virtualized Force Directed</a> sample
|
|
demonstrates a more complicated customization of <a>ForceDirectedLayout</a>.
|
|
See more samples that make use of <a>ForceDirectedLayout</a> in the <a href="../samples/index.html#forcedirectedlayout">samples index</a>.
|
|
</p>
|
|
|
|
<h2 id="LayeredDigraphLayout">Layered Digraph Layout</h2>
|
|
|
|
<p>This arranges nodes of directed graphs into layers (rows or columns).</p>
|
|
|
|
<pre data-language="javascript" id="ldllayout" style="display: none;">
|
|
diagram.layout = $(go.LayeredDigraphLayout);
|
|
diagram.contentAlignment = go.Spot.Center;
|
|
|
|
// define a simple Node template
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Spot", // the Shape will go around the TextBlock
|
|
$(go.Shape, "Ellipse",
|
|
{ fill: 'palegreen', stroke: '#333', strokeWidth: 3, width: 40, height: 40 }
|
|
),
|
|
$(go.TextBlock,
|
|
{ margin: 3, font: 'bold 14px sans-serif', stroke: '#333' }, // some room around the text
|
|
// TextBlock.text is bound to Node.data.key
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
// Default routing is go.Link.Normal
|
|
// Default corner is 0
|
|
{ corner: 5 },
|
|
$(go.Shape, { strokeWidth: 3, stroke: "#333" })
|
|
);
|
|
|
|
// create the model data that will be represented by Nodes and Links
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: "1" },
|
|
{ key: "2" },
|
|
{ key: "3" },
|
|
{ key: "4" },
|
|
{ key: "5" },
|
|
{ key: "6" },
|
|
{ key: "7" },
|
|
],
|
|
[
|
|
{ from: "1", to: "2" },
|
|
{ from: "1", to: "3" },
|
|
{ from: "3", to: "4" },
|
|
{ from: "3", to: "5" },
|
|
{ from: "3", to: "6" },
|
|
{ from: "2", to: "5" },
|
|
{ from: "1", to: "5" },
|
|
{ from: "1", to: "7" },
|
|
{ from: "6", to: "7" },
|
|
]);
|
|
</pre>
|
|
<script>goCode("ldllayout", 400, 300)</script>
|
|
|
|
<p>
|
|
See the <a href="../samples/ldLayout.html" target="samples">LayeredDigraphLayout sample</a> for a demonstration of layout options.
|
|
The <a href="../samples/genogram.html" target="samples">Genogram</a> sample demonstrates a complex customization of <a>LayeredDigraphLayout</a>.
|
|
See more samples that make use of <a>LayeredDigraphLayout</a> in the <a href="../samples/index.html#layereddigraphlayout">samples index</a>.
|
|
</p>
|
|
|
|
<h2 id="CircularLayout">Circular Layout</h2>
|
|
|
|
<p>This layout positions nodes in a circular or elliptical arrangement.</p>
|
|
|
|
<pre data-language="javascript" id="circularLayout" style="display: none;">
|
|
diagram.layout = $(go.CircularLayout);
|
|
diagram.contentAlignment = go.Spot.Center;
|
|
|
|
// define a simple Node template
|
|
diagram.nodeTemplate =
|
|
$(go.Node, "Spot", // the Shape will go around the TextBlock
|
|
$(go.Shape, "Ellipse",
|
|
{ fill: 'palegreen', stroke: '#333', strokeWidth: 3, width: 40, height: 40 }
|
|
),
|
|
$(go.TextBlock,
|
|
{ margin: 3, font: 'bold 14px sans-serif', stroke: '#333' }, // some room around the text
|
|
// TextBlock.text is bound to Node.data.key
|
|
new go.Binding("text", "key"))
|
|
);
|
|
|
|
diagram.linkTemplate =
|
|
$(go.Link,
|
|
// Default routing is go.Link.Normal
|
|
// Default corner is 0
|
|
{ corner: 5 },
|
|
$(go.Shape, { strokeWidth: 3, stroke: "#333" })
|
|
);
|
|
|
|
// create the model data that will be represented by Nodes and Links
|
|
diagram.model = new go.GraphLinksModel(
|
|
[
|
|
{ key: "1" },
|
|
{ key: "2" },
|
|
{ key: "3" },
|
|
{ key: "4" },
|
|
{ key: "5" },
|
|
{ key: "6" },
|
|
{ key: "7" },
|
|
],
|
|
[
|
|
{ from: "1", to: "2" },
|
|
{ from: "1", to: "3" },
|
|
{ from: "3", to: "4" },
|
|
{ from: "3", to: "5" },
|
|
{ from: "3", to: "6" },
|
|
{ from: "2", to: "5" },
|
|
{ from: "1", to: "5" },
|
|
{ from: "1", to: "7" },
|
|
{ from: "6", to: "7" },
|
|
]);
|
|
</pre>
|
|
<script>goCode("circularLayout", 400, 200)</script>
|
|
|
|
<p>
|
|
See the <a href="../samples/cLayout.html" target="samples">CircularLayout sample</a> for a demonstration of layout options.
|
|
The <a href="../samples/friendWheel.html" target="samples">Friend Wheel</a> sample demonstrates a simple customization of <a>CircularLayout</a>.
|
|
See more samples that make use of <a>CircularLayout</a> in the <a href="../samples/index.html#circularlayout">samples index</a>.
|
|
</p>
|
|
|
|
|
|
<h2 id="CustomLayouts">Custom Layouts</h2>
|
|
|
|
<p>
|
|
GoJS allows for the creation of custom layouts.
|
|
The intro page on <a href="extensions.html">GoJS extensions</a> gives a simple example of a custom layout.
|
|
The <a href="../extensions/Serpentine.html">Serpentine</a> and
|
|
<a href="../extensions/Fishbone.html">Fishbone</a> extension samples illustrate more complex custom layouts.
|
|
See more samples that make use of custom layouts in the <a href="../samples/index.html#customlayout">samples index</a>.
|
|
</p>
|
|
|
|
|
|
<h2 id="LayoutInvalidation">Layout Invalidation</h2>
|
|
<p>
|
|
A layout is considered "valid" when it has performed its positioning of its nodes and perhaps routed its links.
|
|
However some kinds of changes cause a layout to become "invalid", thereby causing it to be performed again in the near future.
|
|
Because layouts can be computationally expensive, automatic layouts are not performed as soon as a layout is invalidated.
|
|
Instead they are typically performed at the end of a transaction.
|
|
</p>
|
|
<p>
|
|
The most common reasons for a layout to be invalidated are because a node or a link has been added or removed from the collection
|
|
of nodes and links that a layout is responsible for, or because a node or a link has changed visibility, or because a node has changed size.
|
|
If you do not want an automatic layout to happen when such a change occurs, it may be easiest to set <a>Layout.isOngoing</a> to false.
|
|
</p>
|
|
<p>
|
|
Another common situation is where you have set <a>Diagram.layout</a> to some kind of layout but you want to load a diagram (model)
|
|
that contains manually positioned or adjusted node locations. The <a>Binding</a> of <a>Part.location</a> to the model data is effective,
|
|
but the locations are lost when a layout is performed immediately after loading. This situation can be avoided by setting
|
|
<a>Layout.isInitial</a> to false. After the initial layout the layout might still be invalidated by adding or removing or changing
|
|
the visibility of a node or a link or by a change in node size, unless you have also set <a>Layout.isOngoing</a> to false.
|
|
When both <a>Layout.isInitial</a> and <a>Layout.isOngoing</a> are false, you can still explicitly cause a layout to happen by either
|
|
calling <a>Layout.invalidateLayout</a> or by calling <a>Diagram.layoutDiagram</a> with a <code>true</code> argument.
|
|
</p>
|
|
<p>
|
|
But if you do not want a change to a particular Node or Link to cause an automatic layout, yet you do want that invalidation for other Nodes or Links,
|
|
you can set the <a>Part.layoutConditions</a> property to the combination of <a>Part</a> "Layout..." flags that suits your needs.
|
|
It is most common to not want a layout for the <a>Part.LayoutNodeSized</a> condition:
|
|
</p>
|
|
<pre>
|
|
$(go.Node, . . .,
|
|
{ layoutConditions: go.Part.LayoutStandard & ~go.Part.LayoutNodeSized },
|
|
. . .
|
|
)
|
|
</pre>
|
|
<p>
|
|
Parts that remain not visible or that are in layers that are <a>Layer.isTemporary</a> also never invalidate any Layout.
|
|
</p>
|
|
<p>
|
|
Finally, you can set <a>Part.isLayoutPositioned</a> to false in order for the Layout to completely ignore that Part.
|
|
But you will have to make sure that that Part does have a real <a>Part.location</a>, since no layout will set it for you.
|
|
Without a real location the part will not be visible anywhere in the diagram.
|
|
Furthermore if a node has isLayoutPositioned set to false, Layouts will not only ignore that node but also all links connecting with that node.
|
|
Because the node will not be moved by the layout, it might overlap with the laid-out nodes and links.
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|