create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
321 lines (284 loc) • 14.9 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
<meta name="description" content="A diagram holding groups that incrementally grow the diagram as groups are expanded." />
<meta itemprop="description" content="A diagram holding groups that incrementally grow the diagram as groups are expanded." />
<meta property="og:description" content="A diagram holding groups that incrementally grow the diagram as groups are expanded." />
<meta name="twitter:description" content="A diagram holding groups that incrementally grow the diagram as groups are expanded." />
<link rel="preconnect" href="https://rsms.me/">
<link rel="stylesheet" href="../assets/css/style.css">
<!-- Copyright 1998-2025 by Northwoods Software Corporation. -->
<meta itemprop="name" content="Creating SubGraphs only when Expanding a Group the First Time" />
<meta property="og:title" content="Creating SubGraphs only when Expanding a Group the First Time" />
<meta name="twitter:title" content="Creating SubGraphs only when Expanding a Group the First Time" />
<meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/grouping.png" />
<meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/grouping.png" />
<meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/grouping.png" />
<meta property="og:url" content="https://gojs.net/latest/samples/grouping.html" />
<meta property="twitter:url" content="https://gojs.net/latest/samples/grouping.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
Creating SubGraphs only when Expanding a Group the First Time | GoJS Diagramming Library
</title>
</head>
<body>
<!-- This top nav is not part of the sample code -->
<nav id="navTop" class=" w-full h-[var(--topnav-h)] z-30 bg-white border-b border-b-gray-200">
<div class="max-w-screen-xl mx-auto flex flex-wrap items-start justify-between px-4">
<a class="text-white bg-nwoods-primary font-bold !leading-[calc(var(--topnav-h)_-_1px)] my-0 px-2 text-4xl lg:text-5xl logo"
href="../">
GoJS
</a>
<div class="relative">
<button id="topnavButton" class="h-[calc(var(--topnav-h)_-_1px)] px-2 m-0 text-gray-900 bg-inherit shadow-none md:hidden hover:!bg-inherit hover:!text-nwoods-accent hover:!shadow-none" aria-label="Navigation">
<svg class="h-7 w-7 block" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div id="topnavList" class="hidden md:block">
<div class="absolute right-0 z-30 flex flex-col items-end rounded border border-gray-200 p-4 pl-12 shadow bg-white text-gray-900 font-semibold
md:flex-row md:space-x-4 md:items-start md:border-0 md:p-0 md:shadow-none md:bg-inherit">
<a href="../learn/">Learn</a>
<a href="../samples/">Samples</a>
<a href="../intro/">Intro</a>
<a href="../api/">API</a>
<a href="../download.html">Download</a>
<a href="https://forum.nwoods.com/c/gojs/11" target="_blank" rel="noopener">Forum</a>
<a id="tc" href="https://nwoods.com/contact.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/contact.html', 'contact');">Contact</a>
<a id="tb" href="https://nwoods.com/sales/index.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/sales/index.html', 'buy');">Buy</a>
</div>
</div>
</div>
</div>
</nav>
<script>
window.addEventListener("DOMContentLoaded", function () {
// topnav
var topButton = document.getElementById("topnavButton");
var topnavList = document.getElementById("topnavList");
if (topButton && topnavList) {
topButton.addEventListener("click", function (e) {
topnavList
.classList
.toggle("hidden");
e.stopPropagation();
});
document.addEventListener("click", function (e) {
// if the clicked element isn't the list, close the list
if (!topnavList.classList.contains("hidden") && !e.target.closest("#topnavList")) {
topButton.click();
}
});
// set active <a> element
var url = window
.location
.href
.toLowerCase();
var aTags = topnavList.getElementsByTagName('a');
for (var i = 0; i < aTags.length; i++) {
var lowerhref = aTags[i]
.href
.toLowerCase();
if (lowerhref.endsWith('.html'))
lowerhref = lowerhref.slice(0, -5);
if (url.startsWith(lowerhref)) {
aTags[i]
.classList
.add('active');
break;
}
}
}
});
</script>
<div class="flex flex-col prose">
<div class="w-full max-w-screen-xl mx-auto">
<!-- * * * * * * * * * * * * * -->
<!-- Start of GoJS sample code -->
<script src="https://cdn.jsdelivr.net/npm/gojs@3.1.0"></script>
<div id="allSampleContent" class="p-4 w-full">
<script id="code">
function init() {
myDiagram = new go.Diagram('myDiagramDiv', {
layout: new go.TreeLayout({ // the layout for the entire diagram
angle: 90,
arrangement: go.TreeArrangement.Horizontal,
isRealtime: false
})
});
// define the node template for non-groups
myDiagram.nodeTemplate =
new go.Node('Auto')
.add(
new go.Shape('Rectangle', { stroke: null, strokeWidth: 0 })
.bind('fill', 'key'),
new go.TextBlock({ margin: 7, font: 'Bold 14px Sans-Serif' })
//the text, color, and key are all bound to the same property in the node data
.bind('text', 'key')
);
myDiagram.linkTemplate =
new go.Link({ routing: go.Routing.Orthogonal, corner: 10 })
.add(
new go.Shape({ strokeWidth: 2 }),
new go.Shape({ toArrow: 'OpenTriangle' })
);
// define the group template
myDiagram.groupTemplate =
new go.Group('Auto', {
// define the group's internal layout
layout: new go.TreeLayout({ angle: 90, arrangement: go.TreeArrangement.Horizontal, isRealtime: false }),
// the group begins unexpanded;
// upon expansion, a Diagram Listener will generate contents for the group
isSubGraphExpanded: false,
// when a group is expanded, if it contains no parts, generate a subGraph inside of it
subGraphExpandedChanged: group => {
if (group.memberParts.count === 0) {
randomGroup(group.data.key);
}
}
})
.add(
new go.Shape('Rectangle', { fill: null, stroke: 'gray', strokeWidth: 2 }),
new go.Panel('Vertical', { defaultAlignment: go.Spot.Left, margin: 4 })
.add(
new go.Panel('Horizontal', { defaultAlignment: go.Spot.Top })
.add(
// the SubGraphExpanderButton is a panel that functions as a button to expand or collapse the subGraph
go.GraphObject.build('SubGraphExpanderButton'),
new go.TextBlock({ font: 'Bold 18px Sans-Serif', margin: 4 })
.bind('text', 'key')
),
// create a placeholder to represent the area where the contents of the group are
new go.Placeholder({ padding: new go.Margin(0, 10) })
) // end Vertical Panel
); // end Group
// generate the initial model
randomGroup();
}
// Generate a random number of nodes, including groups.
// If a group's key is given as a parameter, put these nodes inside it
function randomGroup(group) {
// all modification to the diagram is within this transaction
myDiagram.startTransaction('addGroupContents');
var addedKeys = []; // this will contain the keys of all nodes created
var groupCount = 0; // the number of groups in the diagram, to determine the numbers in the keys of new groups
myDiagram.nodes.each(node => {
if (node instanceof go.Group) groupCount++;
});
// create a random number of groups
// ensure there are at least 10 groups in the diagram
var groups = Math.floor(Math.random() * 2);
if (groupCount < 10) groups += 1;
for (var i = 0; i < groups; i++) {
var name = 'group' + (i + groupCount);
myDiagram.model.addNodeData({ key: name, isGroup: true, group: group });
addedKeys.push(name);
}
var nodes = Math.floor(Math.random() * 3) + 2;
// create a random number of non-group nodes
for (var i = 0; i < nodes; i++) {
var color = go.Brush.randomColor();
// make sure the color, which will be the node's key, is unique in the diagram before adding the new node
if (myDiagram.findPartForKey(color) === null) {
myDiagram.model.addNodeData({ key: color, group: group });
addedKeys.push(color);
}
}
// add at least one link from each node to another
// this could result in clusters of nodes unreachable from each other, but no lone nodes
var arr = [];
for (var x in addedKeys) arr.push(addedKeys[x]);
arr.sort((x, y) => Math.random(2) - 1);
for (var i = 0; i < arr.length; i++) {
var from = Math.floor(Math.random() * (arr.length - i)) + i;
if (from !== i) {
myDiagram.model.addLinkData({ from: arr[from], to: arr[i] });
}
}
myDiagram.commitTransaction('addGroupContents');
}
window.addEventListener('DOMContentLoaded', init);
</script>
<div id="sample">
<div id="myDiagramDiv" style="height: 600px; width: 100%; border: 1px solid black"></div>
<p>This sample demonstrates subgraphs that are created only as groups are expanded.</p>
<p>
The model is initially a random number of nodes, including some groups, in a tree layout. When a group is expanded, the
<a>Group.subGraphExpandedChanged</a> event handler calls a function to generate a random number of nodes in a tree layout inside the group if it did not
contain none any. Each non-group node added has a unique random color, and links are added by giving each node one link to another node.
</p>
<p>
The addition of nodes and links is performed within a transaction to ensure that the diagram updates itself properly. The diagram's tree layout and the tree
layouts within each group are performed again when a sub-graph is expanded or collapsed.
</p>
</div>
</div>
<!-- * * * * * * * * * * * * * -->
<!-- End of GoJS sample code -->
</div>
<div id="allTagDescriptions" class="p-4 w-full max-w-screen-xl mx-auto">
<hr/>
<h3 class="text-xl">GoJS Features in this sample</h3>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Tree Layout</h4>
<p>
This predefined layout is used for placing Nodes of a tree-structured graph in layers (rows or columns).
For discussion and examples of the most commonly used properties of the <a href="../api/symbols/TreeLayout.html">TreeLayout</a>,
see the <a href="../intro/trees.html">Trees</a> page in the Introduction.
More information can be found in the <a href="../intro/layouts.html#TreeLayout">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#treelayout">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Groups</h4>
<p>
The <a href="../api/symbols/Group.html" target="api">Group</a> class is used to treat a collection of <a href="../api/symbols/Node.html" target="api">Node</a>s and <a href="../api/symbols/Link.html" target="api">Link</a>s as if they were a single <a href="../api/symbols/Node.html" target="api">Node</a>.
Those nodes and links are members of the group; together they constitute a subgraph.
</p>
<p>
A subgraph is <em>not</em> another <a href="../api/symbols/Diagram.html" target="api">Diagram</a>, so there is no separate HTML Div element for the subgraph of a group.
All of the <a href="../api/symbols/Part.html" target="api">Part</a>s that are members of a <a href="../api/symbols/Group.html" target="api">Group</a> belong to the same Diagram as the Group.
There can be links between member nodes and nodes outside of the group as well as links between the group itself and other nodes.
There can even be links between member nodes and the containing group itself.
</p>
<p>
More information can be found in the <a href="../intro/groups.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#groups">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Buttons</h4>
<p>
GoJS defines several <a href="../api/symbols/Panel.html" target="api">Panel</a>s for common uses.
These include "Button", "TreeExpanderButton", "SubGraphExpanderButton", "PanelExpanderButton", "ContextMenuButton", and "CheckBoxButton".
"ContextMenuButton"s are typically used inside of "ContextMenu" Panels;
"CheckBoxButton"s are used in the implementation of "CheckBox" Panels.
</p>
<p>
These predefined panels can be used as if they were <a href="../api/symbols/Panel.html" target="api">Panel</a>-derived classes in calls to <a href="../api/symbols/GraphObject.html#build" target="api">GraphObject.build</a>.
They are implemented as simple visual trees of <a href="../api/symbols/GraphObject.html" target="api">GraphObject</a>s in <a href="../api/symbols/Panel.html" target="api">Panel</a>s,
with pre-set properties and event handlers.
</p>
<p>
More information can be found in the <a href="../intro/buttons.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#buttons">Related samples</a>
</p>
<hr>
</div>
</div>
</body>
<!-- This script is part of the gojs.net website, and is not needed to run the sample -->
<script src="../assets/js/goSamples.js"></script>
</html>