create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
491 lines (443 loc) • 20.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="UML Class-like nodes showing two collapsible lists of items." />
<meta itemprop="description" content="UML Class-like nodes showing two collapsible lists of items." />
<meta property="og:description" content="UML Class-like nodes showing two collapsible lists of items." />
<meta name="twitter:description" content="UML Class-like nodes showing two collapsible lists of items." />
<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="UML Class Diagram Editor" />
<meta property="og:title" content="UML Class Diagram Editor" />
<meta name="twitter:title" content="UML Class Diagram Editor" />
<meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/umlclass.png" />
<meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/umlclass.png" />
<meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/umlclass.png" />
<meta property="og:url" content="https://gojs.net/latest/samples/umlClass.html" />
<meta property="twitter:url" content="https://gojs.net/latest/samples/umlClass.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
UML Class Diagram Editor | 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', {
'undoManager.isEnabled': true,
layout: new go.TreeLayout({
// this only lays out in trees nodes connected by "generalization" links
angle: 90,
path: go.TreePath.Source, // links go from child to parent
setsPortSpot: false, // keep Spot.AllSides for link connection spot
setsChildPortSpot: false, // keep Spot.AllSides
// nodes not connected by "generalization" links are laid out horizontally
arrangement: go.TreeArrangement.Horizontal
})
});
// show visibility or access as a single character at the beginning of each property or method
function convertVisibility(v) {
switch (v) {
case 'public': return '+';
case 'private': return '-';
case 'protected': return '#';
case 'package': return '~';
default: return v;
}
}
// the item template for properties
var propertyTemplate =
new go.Panel('Horizontal')
.add(
// property visibility/access
new go.TextBlock({ isMultiline: false, editable: false, width: 12 })
.bind('text', 'visibility', convertVisibility),
// property name, underlined if scope=="class" to indicate static property
new go.TextBlock({ isMultiline: false, editable: true })
.bindTwoWay('text', 'name')
.bind('isUnderline', 'scope', s => s[0] === 'c'),
// property type, if known
new go.TextBlock('')
.bind('text', 'type', t => t ? ': ' : ''),
new go.TextBlock({ isMultiline: false, editable: true })
.bindTwoWay('text', 'type'),
// property default value, if any
new go.TextBlock({ isMultiline: false, editable: false })
.bind('text', 'default', s => s ? ' = ' + s : '')
);
// the item template for methods
var methodTemplate =
new go.Panel('Horizontal')
.add(
// method visibility/access
new go.TextBlock({ isMultiline: false, editable: false, width: 12 })
.bind('text', 'visibility', convertVisibility),
// method name, underlined if scope=="class" to indicate static method
new go.TextBlock({ isMultiline: false, editable: true })
.bindTwoWay('text', 'name')
.bind('isUnderline', 'scope', s => s[0] === 'c'),
// method parameters
new go.TextBlock('()')
// this does not permit adding/editing/removing of parameters via inplace edits
.bind('text', 'parameters', parr => {
var s = '(';
for (var i = 0; i < parr.length; i++) {
var param = parr[i];
if (i > 0) s += ', ';
s += param.name + ': ' + param.type;
}
return s + ')';
}),
// method return type, if any
new go.TextBlock('')
.bind('text', 'type', t => t ? ': ' : ''),
new go.TextBlock({ isMultiline: false, editable: true })
.bindTwoWay('text', 'type')
);
// this simple template does not have any buttons to permit adding or
// removing properties or methods, but it could!
myDiagram.nodeTemplate =
new go.Node('Auto', {
locationSpot: go.Spot.Center,
fromSpot: go.Spot.AllSides,
toSpot: go.Spot.AllSides
})
.add(
new go.Shape({ fill: 'lightyellow' }),
new go.Panel('Table', { defaultRowSeparatorStroke: 'black' })
.add(
// header
new go.TextBlock({
row: 0, columnSpan: 2, margin: 3, alignment: go.Spot.Center,
font: 'bold 12pt sans-serif',
isMultiline: false, editable: true
})
.bindTwoWay('text', 'name'),
// properties
new go.TextBlock('Properties', { row: 1, font: 'italic 10pt sans-serif' })
.bindObject('visible', 'visible', v => !v, undefined, 'PROPERTIES'),
new go.Panel('Vertical', {
name: 'PROPERTIES',
row: 1,
margin: 3,
stretch: go.Stretch.Horizontal,
defaultAlignment: go.Spot.Left,
background: 'lightyellow',
itemTemplate: propertyTemplate
})
.bind('itemArray', 'properties'),
go.GraphObject.build("PanelExpanderButton", {
row: 1,
column: 1,
alignment: go.Spot.TopRight,
visible: false
}, "PROPERTIES")
.bind('visible', 'properties', arr => arr.length > 0),
// methods
new go.TextBlock('Methods', { row: 2, font: 'italic 10pt sans-serif' })
.bindObject('visible', 'visible', v => !v, undefined, 'METHODS'),
new go.Panel('Vertical', {
name: 'METHODS',
row: 2,
margin: 3,
stretch: go.Stretch.Horizontal,
defaultAlignment: go.Spot.Left,
background: 'lightyellow',
itemTemplate: methodTemplate
})
.bind('itemArray', 'methods'),
go.GraphObject.build("PanelExpanderButton", {
row: 2,
column: 1,
alignment: go.Spot.TopRight,
visible: false
}, "METHODS")
.bind('visible', 'methods', arr => arr.length > 0)
)
);
const LinkStyle = { isTreeLink: false, fromEndSegmentLength: 0, toEndSegmentLength: 0 };
myDiagram.linkTemplate =
new go.Link(LinkStyle) // by default, "Inheritance" or "Generalization"
.set({ isTreeLink: true })
.add(
new go.Shape(),
new go.Shape({ toArrow: 'Triangle', fill: 'white' })
);
myDiagram.linkTemplateMap.add('Association',
new go.Link(LinkStyle)
.add(
new go.Shape()
));
myDiagram.linkTemplateMap.add('Realization',
new go.Link(LinkStyle)
.add(
new go.Shape({ strokeDashArray: [3, 2] }),
new go.Shape({ toArrow: 'Triangle', fill: 'white' })
));
myDiagram.linkTemplateMap.add('Dependency',
new go.Link(LinkStyle)
.add(
new go.Shape({ strokeDashArray: [3, 2] }),
new go.Shape({ toArrow: 'OpenTriangle' })
));
myDiagram.linkTemplateMap.add('Composition',
new go.Link(LinkStyle)
.add(
new go.Shape(),
new go.Shape({ fromArrow: 'StretchedDiamond', scale: 1.3 }),
new go.Shape({ toArrow: 'OpenTriangle' })
));
myDiagram.linkTemplateMap.add('Aggregation',
new go.Link(LinkStyle)
.add(
new go.Shape(),
new go.Shape({ fromArrow: 'StretchedDiamond', fill: 'white', scale: 1.3 }),
new go.Shape({ toArrow: 'OpenTriangle' })
));
// setup a few example class nodes and relationships
var nodedata = [
{
key: 1,
name: 'BankAccount',
properties: [
{ name: 'owner', type: 'String', visibility: 'public' },
{ name: 'balance', type: 'Currency', visibility: 'public', default: '0' }
],
methods: [
{ name: 'deposit', parameters: [{ name: 'amount', type: 'Currency' }], visibility: 'public' },
{ name: 'withdraw', parameters: [{ name: 'amount', type: 'Currency' }], visibility: 'public' }
]
},
{
key: 11,
name: 'Person',
properties: [
{ name: 'name', type: 'String', visibility: 'public' },
{ name: 'birth', type: 'Date', visibility: 'protected' }
],
methods: [
{ name: 'getCurrentAge', type: 'int', visibility: 'public' }
]
},
{
key: 12,
name: 'Student',
properties: [
{ name: 'classes', type: 'List<Course>', visibility: 'public' }
],
methods: [
{ name: 'attend', parameters: [{ name: 'class', type: 'Course' }], visibility: 'private' },
{ name: 'sleep', visibility: 'private' }
]
},
{
key: 13,
name: 'Professor',
properties: [
{ name: 'classes', type: 'List<Course>', visibility: 'public' }
],
methods: [
{ name: 'teach', parameters: [{ name: 'class', type: 'Course' }], visibility: 'private' }
]
},
{
key: 14,
name: 'Course',
properties: [
{ name: 'name', type: 'String', visibility: 'public' },
{ name: 'description', type: 'String', visibility: 'public' },
{ name: 'professor', type: 'Professor', visibility: 'public' },
{ name: 'location', type: 'String', visibility: 'public' },
{ name: 'times', type: 'List<Time>', visibility: 'public' },
{ name: 'prerequisites', type: 'List<Course>', visibility: 'public' },
{ name: 'students', type: 'List<Student>', visibility: 'public' }
],
//should figure out a better way to fix this sometime
methods: []
}
];
var linkdata = [
{ from: 12, to: 11 },
{ from: 13, to: 11 },
{ from: 14, to: 13, relationship: 'Association' }
];
myDiagram.model = new go.GraphLinksModel({
copiesArrays: true,
copiesArrayObjects: true,
linkCategoryProperty: 'relationship',
nodeDataArray: nodedata,
linkDataArray: linkdata
});
}
window.addEventListener('DOMContentLoaded', init);
</script>
<div id="sample">
<div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
<p>
This sample demonstrates one way of defining a UML (Unified Modeling Language) Class Diagram.
Note the use of a separate Panel for the properties and one for the methods,
allowing for an item template for properties and a separate item template for methods. <a href="../intro/buttons.html#panelExpanderButton"
target="_blank">PanelExpanderButton</a>s are used to hide/show class properties and methods.
</p>
<p>
In this example, symbol prefixes indicate the visibility of methods and properties. The three possibilities are:
<ul>
<li>+ (Public)</li>
<li>- (Private)</li>
<li># (Protected)</li>
</ul>
Additionally, the ~ symbol is used to indicate an item is a package.
</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>Table Panels</h4>
<p>
The "Table" Panel, <a href="../api/symbols/Panel.html#static-Table" target="api">Panel.Table</a>, arranges objects in rows and columns.
Each object in a Table Panel is put into the cell indexed by the value of <a href="../api/symbols/GraphObject.html#row" target="api">GraphObject.row</a> and <a href="../api/symbols/GraphObject.html#column" target="api">GraphObject.column</a>.
The panel will look at the rows and columns for all of the objects in the panel to determine how many rows and columns the table should have.
More information can be found in the <a href="../intro/tablePanels.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#tables">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Item Arrays</h4>
<p>
It is sometimes useful to display a variable number of elements in a node by data binding to a JavaScript Array.
In GoJS, this is simply achieved by binding (or setting) <a href="../api/symbols/Panel.html#itemArray" target="api">Panel.itemArray</a>.
The <a href="../api/symbols/Panel.html" target="api">Panel</a> will create an element in the panel for each value in the Array.
More information can be found in the <a href="../intro/itemArrays.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#itemarrays">Related samples</a>
</p>
<hr>
<!-- 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>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>