create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
305 lines (268 loc) • 13.6 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="Automatically start editing dropped nodes and ungroup dropped groups to create subgraphs." />
<meta itemprop="description" content="Automatically start editing dropped nodes and ungroup dropped groups to create subgraphs." />
<meta property="og:description" content="Automatically start editing dropped nodes and ungroup dropped groups to create subgraphs." />
<meta name="twitter:description" content="Automatically start editing dropped nodes and ungroup dropped groups to create subgraphs." />
<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="Macros -- Automatic Ungrouping of Dropped Elements" />
<meta property="og:title" content="Macros -- Automatic Ungrouping of Dropped Elements" />
<meta name="twitter:title" content="Macros -- Automatic Ungrouping of Dropped Elements" />
<meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/macros.png" />
<meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/macros.png" />
<meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/macros.png" />
<meta property="og:url" content="https://gojs.net/latest/samples/macros.html" />
<meta property="twitter:url" content="https://gojs.net/latest/samples/macros.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
Macros -- Automatic Ungrouping of Dropped Elements | 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>
<link rel="stylesheet" href="../assets/css/prism.css"/>
<script src="../assets/js/prism.js"></script>
<div id="allSampleContent" class="p-4 w-full">
<script id="code">
function init() {
myDiagram = new go.Diagram('myDiagramDiv', {
// automatically show the state of the diagram's model on the page in a PRE element
ModelChanged: e => {
if (e.isTransactionFinished) {
document.getElementById('mySavedModel').innerHTML = myDiagram.model.toJson();
if (window.Prism) window.Prism.highlightAll();
}
},
'undoManager.isEnabled': true
});
// define the Node template for regular nodes
myDiagram.nodeTemplateMap.add('', // the default category
new go.Node('Auto')
// The Node.location comes from the "loc" property of the node data,
// converted by the Point.parse method.
// If the Node.location is changed, it updates the "loc" property of the node data,
// converting back using the Point.stringify method.
.bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify)
.add(
// the main object is a Panel that surrounds a TextBlock with a rectangular Shape
new go.Shape({
figure: 'Rectangle',
fill: 'white',
strokeWidth: 2,
portId: '',
fromLinkable: true,
toLinkable: true,
cursor: 'pointer'
})
.bind('stroke', 'color'),
new go.TextBlock({
maxSize: new go.Size(150, NaN),
textAlign: 'center',
margin: 6,
editable: true,
name: 'TEXT',
font: '16pt Helvetica, Arial, sans-serif'
})
.bindTwoWay('text')
)
);
myDiagram.groupTemplate =
new go.Group('Auto', {
isSubGraphExpanded: false, // only show the Group itself, not any of its members
ungroupable: true
}) // allow the ExternalObjectsDropped event handler to ungroup
.add(
// the members to be top-level parts, via a command
new go.Shape('Rectangle', { // the rectangular shape around the members
fill: 'rgba(128,128,128,0.2)', stroke: 'gray', strokeWidth: 3
}),
new go.Placeholder({ alignment: go.Spot.TopLeft }),
new go.TextBlock({ font: 'bold 16pt Helvetica, Arial, sans-serif', margin: 10 })
.bind('text')
);
myDiagram.linkTemplate =
new go.Link()
.add(
new go.Shape({ strokeWidth: 1.5 }),
new go.Shape({ toArrow: 'Standard', stroke: null })
);
// this DiagramEvent is raised when the user has drag-and-dropped something
// from another Diagram (a Palette in this case) into this Diagram
myDiagram.addDiagramListener('ExternalObjectsDropped', e => {
// stop any ongoing text editing
if (myDiagram.currentTool instanceof go.TextEditingTool) {
myDiagram.currentTool.acceptText(go.TextEditingAccept.LostFocus);
}
// expand any "macros"
myDiagram.commandHandler.ungroupSelection();
// start editing the first node that was dropped after ungrouping
var tb = myDiagram.selection.first().findObject('TEXT');
if (tb) myDiagram.commandHandler.editTextBlock(tb);
});
// initialize the Palette that is on the left side of the page
myPalette = new go.Palette('myPaletteDiv', {
nodeTemplateMap: myDiagram.nodeTemplateMap,
groupTemplateMap: myDiagram.groupTemplateMap
});
myPalette.model = new go.GraphLinksModel(
[
// a regular node
{ key: 'B', text: 'some block', color: 'blue' },
// a group node, plus three member nodes in that group
{ key: 'G', text: 'Macro', isGroup: true },
{ key: 'Ga', text: 'A block', color: 'green', group: 'G', loc: '0 0' },
{ key: 'Gb', text: 'B block', color: 'orange', group: 'G', loc: '150 25' },
{ key: 'Gc', text: 'C block', color: 'red', group: 'G', loc: '50 100' }
],
[
{ from: 'Ga', to: 'Gb' },
{ from: 'Ga', to: 'Gc' },
{ from: 'Gb', to: 'Gc' }
]
);
}
window.addEventListener('DOMContentLoaded', init);
</script>
<div id="sample">
<div style="width: 100%; display: flex; justify-content: space-between">
<div id="myPaletteDiv" style="width: 135px; margin-right: 2px; background-color: whitesmoke; border: solid 1px black"></div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 500px; border: solid 1px black"></div>
</div>
<p>
When one drags the "Macro" node (actually a <a>Group</a>) from the Palette into the main Diagram, the "ExternalObjectsDropped" <a>DiagramEvent</a> listener
automatically ungroups that group node to show all of its members nodes and links that were copied by the drag-and-drop.
</p>
<p>Note also that a drop causes the <a>TextEditingTool</a> to automatically start editing the text in the node.</p>
Diagram Model saved in JSON format:
<br />
<pre class="lang-js" style="max-height: 300px"><code id="mySavedModel"></code></pre>
</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>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>Palette</h4>
<p>
A <a href="../api/symbols/Palette.html" target="api">Palette</a> is a subclass of <a href="../api/symbols/Diagram.html" target="api">Diagram</a> that is used to display a number of <a href="../api/symbols/Part.html" target="api">Part</a>s that
can be dragged into the diagram that is being modified by the user.
The initialization of a <a href="../api/symbols/Palette.html" target="api">Palette</a> is just like the initialization of any <a href="../api/symbols/Diagram.html" target="api">Diagram</a>.
Like Diagrams, you can have more than one Palette on the page at the same time.
</p>
<p>
More information can be found in the <a href="../intro/palette.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#palette">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>