create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
616 lines (557 loc) • 24.4 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="Interactive flowchart diagram implemented by GoJS in JavaScript for HTML." />
<meta itemprop="description" content="Interactive flowchart diagram implemented by GoJS in JavaScript for HTML." />
<meta property="og:description" content="Interactive flowchart diagram implemented by GoJS in JavaScript for HTML." />
<meta name="twitter:description" content="Interactive flowchart diagram implemented by GoJS in JavaScript for HTML." />
<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="Interactive Diagram for Building Flowcharts" />
<meta property="og:title" content="Interactive Diagram for Building Flowcharts" />
<meta name="twitter:title" content="Interactive Diagram for Building Flowcharts" />
<meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/flowchart.png" />
<meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/flowchart.png" />
<meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/flowchart.png" />
<meta property="og:url" content="https://gojs.net/latest/samples/flowchart.html" />
<meta property="twitter:url" content="https://gojs.net/latest/samples/flowchart.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
Interactive Diagram for Building Flowcharts | 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">
<link href="https://fonts.googleapis.com/css?family=Figtree:400,600&subset=latin,latin-ext" rel="stylesheet" type="text/css" />
<style>
#hidden {
font: 600 18px Figtree;
opacity: 0;
}
</style>
<script id="code">
function init() {
myDiagram = new go.Diagram('myDiagramDiv', {
'undoManager.isEnabled': true, // enable undo & redo
'themeManager.changesDivBackground': true,
'themeManager.currentTheme': document.getElementById('theme').value
});
// when the document is modified, add a "*" to the title and enable the "Save" button
myDiagram.addDiagramListener('Modified', e => {
const button = document.getElementById('SaveButton');
if (button) button.disabled = !myDiagram.isModified;
const idx = document.title.indexOf('*');
if (myDiagram.isModified) {
if (idx < 0) document.title += '*';
} else {
if (idx >= 0) document.title = document.title.slice(0, idx);
}
});
// set up some colors/fonts for the default ('light') and dark Themes
myDiagram.themeManager.set('light', {
colors: {
text: '#fff',
start: '#064e3b',
step: '#49939e',
conditional: '#6a9a8a',
end: '#7f1d1d',
comment: '#a691cc',
bgText: '#000',
link: '#dcb263',
linkOver: '#cbd5e1',
div: '#ede9e0'
}
});
myDiagram.themeManager.set('dark', {
colors: {
text: '#fff',
step: '#414a8d',
conditional: '#88afa2',
comment: '#bfb674',
bgText: '#fff',
link: '#fdb71c',
linkOver: '#475569',
div: '#141e37'
}
});
defineFigures();
// helper definitions for node templates
function nodeStyle(node) {
node
// the Node.location is at the center of each node
.set({ locationSpot: go.Spot.Center })
// The Node.location comes from the "loc" property of the node data,
// converted by the Point.parse static method.
// If the Node.location is changed, it updates the "loc" property of the node data,
// converting back using the Point.stringify static method.
.bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify);
}
function shapeStyle(shape) {
// make the whole node shape a port
shape.set({ strokeWidth: 0, portId: '', cursor: 'pointer' });
}
function textStyle(textblock) {
textblock
.set({ font: 'bold 11pt Figtree, sans-serif' })
.theme('stroke', 'text');
}
// define the Node templates for regular nodes
myDiagram.nodeTemplateMap.add('', // the default category
new go.Node('Auto')
.apply(nodeStyle)
.add(
new go.Shape('Rectangle', {
fromLinkable: true,
toLinkable: true,
fromSpot: go.Spot.AllSides,
toSpot: go.Spot.AllSides
})
.apply(shapeStyle)
.theme('fill', 'step'),
new go.TextBlock({
margin: 12,
maxSize: new go.Size(160, NaN),
wrap: go.Wrap.Fit,
editable: true
})
.apply(textStyle)
.bindTwoWay('text')
)
);
myDiagram.nodeTemplateMap.add('Conditional',
new go.Node('Auto')
.apply(nodeStyle)
.add(
new go.Shape('Conditional', { fromLinkable: true, toLinkable: true })
.apply(shapeStyle)
.theme('fill', 'conditional'),
new go.TextBlock({
margin: 8,
maxSize: new go.Size(160, NaN),
wrap: go.Wrap.Fit,
textAlign: 'center',
editable: true
})
.apply(textStyle)
.bindTwoWay('text')
)
);
myDiagram.nodeTemplateMap.add('Start',
new go.Node('Auto')
.apply(nodeStyle)
.add(
new go.Shape('Capsule', { fromLinkable: true })
.apply(shapeStyle)
.theme('fill', 'start'),
new go.TextBlock('Start', { margin: new go.Margin(5, 6) })
.apply(textStyle)
.bind('text')
)
);
myDiagram.nodeTemplateMap.add('End',
new go.Node('Auto')
.apply(nodeStyle)
.add(
new go.Shape('Capsule', { toLinkable: true })
.apply(shapeStyle)
.theme('fill', 'end'),
new go.TextBlock('End', { margin: new go.Margin(5, 6) })
.apply(textStyle)
.bind('text')
)
);
myDiagram.nodeTemplateMap.add('Comment',
new go.Node('Auto')
.apply(nodeStyle)
.add(
new go.Shape('File', { strokeWidth: 3 })
.theme('fill', 'div')
.theme('stroke', 'comment'),
new go.TextBlock({
font: '9pt Figtree, sans-serif',
margin: 8,
maxSize: new go.Size(200, NaN),
wrap: go.Wrap.Fit,
textAlign: 'center',
editable: true
})
.theme('stroke', 'bgText')
.bindTwoWay('text')
// no ports, because no links are allowed to connect with a comment
)
);
// replace the default Link template in the linkTemplateMap
myDiagram.linkTemplate =
new go.Link({
routing: go.Routing.AvoidsNodes,
curve: go.Curve.JumpOver,
corner: 5,
toShortLength: 4,
relinkableFrom: true,
relinkableTo: true,
reshapable: true,
resegmentable: true,
// mouse-overs subtly highlight links:
mouseEnter: (e, link) => (link.findObject('HIGHLIGHT').stroke = link.diagram.themeManager.findValue('linkOver', 'colors')),
mouseLeave: (e, link) => (link.findObject('HIGHLIGHT').stroke = 'transparent'),
// context-click creates an editable link label
contextClick: (e, link) => {
e.diagram.model.commit(m => {
m.set(link.data, 'text', 'Label');
});
}
})
.bindTwoWay('points')
.add(
// the highlight shape, normally transparent
new go.Shape({
isPanelMain: true,
strokeWidth: 8,
stroke: 'transparent',
name: 'HIGHLIGHT'
}),
// the link path shape
new go.Shape({ isPanelMain: true, strokeWidth: 2 })
.theme('stroke', 'link'),
// the arrowhead
new go.Shape({ toArrow: 'standard', strokeWidth: 0, scale: 1.5 })
.theme('fill', 'link'),
// the link label
new go.Panel('Auto', { visible: false })
.bind('visible', 'text', t => typeof t === 'string' && t.length > 0) // only shown if there is text
.add(
// a gradient that fades into the background
new go.Shape('Ellipse', { strokeWidth: 0 })
.theme('fill', 'div', null, null, c => new go.Brush("Radial", { 0: c, 0.5: `${c}00` })),
new go.TextBlock({
name: 'LABEL',
font: '9pt Figtree, sans-serif',
margin: 3,
editable: true
})
.theme('stroke', 'bgText')
.bindTwoWay('text')
)
);
// temporary links used by LinkingTool and RelinkingTool are also orthogonal:
myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Routing.Orthogonal;
myDiagram.toolManager.relinkingTool.temporaryLink.routing = go.Routing.Orthogonal;
load(); // load an initial diagram from some JSON text
// initialize the Palette that is on the left side of the page
myPalette = new go.Palette('myPaletteDiv', {
nodeTemplateMap: myDiagram.nodeTemplateMap, // share the templates used by myDiagram
themeManager: myDiagram.themeManager, // share the ThemeManager used by myDiagram
model: new go.GraphLinksModel([
// specify the contents of the Palette
{ category: 'Start', text: 'Start' },
{ text: 'Step' },
{ category: 'Conditional', text: '???' },
{ category: 'End', text: 'End' },
{ category: 'Comment', text: 'Comment' }
])
});
} // end init
// define some custom shapes for node templates
function defineFigures() {
go.Shape.defineFigureGenerator('Conditional', (shape, w, h) => {
const geo = new go.Geometry();
const fig = new go.PathFigure(w * 0.15, 0, true);
geo.add(fig);
fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.85, 0));
fig.add(new go.PathSegment(go.SegmentType.Line, w, 0.5 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.85, h));
fig.add(new go.PathSegment(go.SegmentType.Line, w * 0.15, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, 0.5 * h).close());
geo.spot1 = new go.Spot(0.15, 0);
geo.spot2 = new go.Spot(0.85, 1);
return geo;
});
// taken from ../extensions/Figures.js:
go.Shape.defineFigureGenerator('File', (shape, w, h) => {
const geo = new go.Geometry();
const fig = new go.PathFigure(0, 0, true); // starting point
geo.add(fig);
fig.add(new go.PathSegment(go.SegmentType.Line, 0.75 * w, 0));
fig.add(new go.PathSegment(go.SegmentType.Line, w, 0.25 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, w, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, h).close());
const fig2 = new go.PathFigure(0.75 * w, 0, false);
geo.add(fig2);
// The Fold
fig2.add(new go.PathSegment(go.SegmentType.Line, 0.75 * w, 0.25 * h));
fig2.add(new go.PathSegment(go.SegmentType.Line, w, 0.25 * h));
geo.spot1 = new go.Spot(0, 0.25);
geo.spot2 = go.Spot.BottomRight;
return geo;
});
}
// Show the diagram's model in JSON format that the user may edit
function save() {
document.getElementById('mySavedModel').value = myDiagram.model.toJson();
myDiagram.isModified = false;
}
function load() {
myDiagram.model = go.Model.fromJson(document.getElementById('mySavedModel').value);
}
// print the diagram by opening a new window holding SVG images of the diagram contents for each page
function printDiagram() {
const svgWindow = window.open();
if (!svgWindow) return; // failure to open a new Window
svgWindow.document.title = "GoJS Flowchart";
svgWindow.document.body.style.margin = "0px";
const printSize = new go.Size(700, 960);
const bnds = myDiagram.documentBounds;
let x = bnds.x;
let y = bnds.y;
while (y < bnds.bottom) {
while (x < bnds.right) {
const svg = myDiagram.makeSvg({
scale: 1.0,
position: new go.Point(x, y),
size: printSize,
background: myDiagram.themeManager.findValue('div', 'colors')
});
svgWindow.document.body.appendChild(svg);
x += printSize.width;
}
x = bnds.x;
y += printSize.height;
}
setTimeout(() => { svgWindow.print(); svgWindow.close(); }, 1);
}
function changeTheme() {
const myDiagram = go.Diagram.fromDiv('myDiagramDiv');
if (myDiagram) {
myDiagram.themeManager.currentTheme = document.getElementById('theme').value;
}
}
window.addEventListener('DOMContentLoaded', () => {
// setTimeout only to ensure font is loaded before loading diagram
// you may want to use an asset loading library for this
// to keep this sample simple, it does not
setTimeout(() => {
init();
}, 300);
});
</script>
<div id="sample">
<div class="sampleWrapper">
<div style="width: 100%; height: fit-content; display: flex; flex: 2">
<div id="myPaletteDiv" style="width: 100px; margin-right: 2px"></div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 810px"></div>
</div>
<div style="flex: 1; min-width: 425px">
Theme:
<select id="theme" onchange="changeTheme()">
<option value="system">System</option>
<option value="light">Light</option>
<option value="dark" selected>Dark</option>
</select>
<p>
The Flowchart sample demonstrates several key features of GoJS, namely
<a href="../intro/palette.html">Palette</a>s, <a href="../intro/links.html">Linkable nodes</a>, Drag/Drop behavior,
<a href="../intro/textBlocks.html">Text Editing</a>, and the use of <a href="../intro/templateMaps.html">Node Template Maps</a> in Diagrams.
</p>
<p>
Drag from the edges of a Node to create new Links. Selecting Links allows you to re-shape and re-link them. Selecting a Node and then clicking its
TextBlock will allow you to edit text (except on the Start and End Nodes). Context clicking a Link creates an editable link label.
</p>
<p>The dark and light themes are controlled using the <a>ThemeManager</a>.</p>
<button onclick="printDiagram()">Print Diagram Using SVG</button>
<br />
<button id="SaveButton" onclick="save()">Save</button>
<button onclick="load()">Load</button>
Diagram Model saved in JSON format:
<textarea id="mySavedModel" style="width: 100%; height: 375px">
{ "class": "GraphLinksModel",
"pointsDigits": 0,
"nodeDataArray": [
{"key":-1,"category":"Start","loc":"-237 41","text":"Start"},
{"key":-2,"category":"End","loc":"277 696","text":"End"},
{"category":"Conditional","text":"Is data\ntree-like?","key":-14,"loc":"40 165"},
{"text":"Use a TreeModel","key":-5,"loc":"-100 230"},
{"text":"Use a GraphLinksModel","key":-6,"loc":"180 230"},
{"category":"Comment","text":"GraphLinksModel\nalso allows Groups","key":-7,"loc":"362 230"},
{"text":"Create DIV for Diagram","key":-8,"loc":"-64 41"},
{"text":"Create new Diagram associated with DIV","key":-9,"loc":"164 41"},
{"text":"Style node templates","key":-10,"loc":"40 617"},
{"text":"Add data to node/linkDataArray","key":-12,"loc":"180 320"},
{"text":"Add data to nodeDataArray, including parent","key":-13,"loc":"-100 320"},
{"text":"Style link templates","key":-15,"loc":"277 617"},
{"category":"Conditional","text":"Should nodes be auto-positioned?","key":-16,"loc":"40 460"},
{"text":"Choose a layout","key":-18,"loc":"-100 525"},
{"text":"Set location in node data and bind","key":-17,"loc":"180 525"}
],
"linkDataArray": [
{"from":-1,"to":-8},
{"from":-8,"to":-9},
{"from":-5,"to":-13},
{"from":-6,"to":-12},
{"from":-15,"to":-2},
{"from":-14,"to":-5,"text":"Yes"},
{"from":-14,"to":-6,"text":"No"},
{"from":-9,"to":-14},
{"from":-13,"to":-16},
{"from":-12,"to":-16},
{"from":-16,"to":-18,"text":"Yes"},
{"from":-16,"to":-17,"text":"No"},
{"from":-18,"to":-10},
{"from":-17,"to":-10},
{"from":-10,"to":-15}
]}
</textarea>
<p id="hidden" style="padding: 0; height: 0px">this forces the font to load in Chromium browsers</p>
</div>
</div>
</div>
<style>
.sampleWrapper {
display: flex;
flex-direction: column;
@media (min-width: 1280px) {
flex-direction: row;
}
& > div:first-child {
margin-bottom: 0.5rem;
@media (min-width: 1280px) {
margin-right: 0.5rem;
margin-bottom: 0;
}
}
}
</style>
</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>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>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Exporting SVGs</h4>
<p>
<b>GoJS</b> has one function for creating SVG: <a href="../api/symbols/Diagram.html#makeSVG" target="api">Diagram.makeSVG</a>, which returns a new SVGElement with a representation of a GoJS Diagram. The method has a single argument, a JavaScript Object that contains several definable properties, enumerated in the documentation.
More information can be found in the <a href="../intro/makingSVG.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#svg">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Theming</h4>
<p>
<b>GoJS</b> allows diagrams to be themed. This is commonly used to provide a light and dark mode for diagrams.
</p>
<p>
The <a href="../api/symbols/Diagram.html#themeManager" target="api">Diagram.themeManager</a> handles themes within a <a href="../api/symbols/Diagram.html" target="api">Diagram</a>.
The <a href="../api/symbols/ThemeManager.html" target="api">ThemeManager</a> can by shared by multiple diagrams,
and is responsible to managing the current theme and default theme, along with any theme updates.
More information can be found in the <a href="../intro/theming.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#theme">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>