create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
493 lines (459 loc) • 22.1 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"/>
<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="Performance Considerations" />
<meta property="og:title" content="Performance Considerations" />
<meta name="twitter:title" content="Performance Considerations" />
<meta property="og:image" content="https://gojs.net/latest/assets/images/fp/defaultCard.png" />
<meta itemprop="image" content="https://gojs.net/latest/assets/images/fp/defaultCard.png" />
<meta name="twitter:image" content="https://gojs.net/latest/assets/images/fp/defaultCard.png" />
<meta property="og:url" content="https://gojs.net/latest/intro/performance.html" />
<meta property="twitter:url" content="https://gojs.net/latest/intro/performance.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
Performance Considerations | GoJS
</title>
<link rel="stylesheet" href="../assets/css/prism.css"/>
</head>
<script>
window.diagrams = [];
window.goCode = function (pre, w, h, parentid, animation) {
window
.diagrams
.push([pre, w, h, parentid, animation]);
}
</script>
<body>
<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="sticky top-0 left-0 z-10 px-2 w-full bg-white border-b border-b-gray-200 md:hidden">
<button id="sidenavButton" class="flex p-2 text-gray-900 bg-inherit shadow-none items-center text-sm font-semibold hover:!bg-inherit hover:!text-nwoods-accent hover:!shadow-none" aria-label="Navigation">
<svg class="h-7 w-7 block mr-2" 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>
<span>Menu</span>
</button>
</div>
<script>
window.addEventListener("DOMContentLoaded", function () {
// sidenav
var sideButton = document.getElementById("sidenavButton");
var sidenav = document.getElementById("sidenav");
if (sideButton && sidenav) {
sideButton.addEventListener("click", function (e) {
sidenav
.classList
.toggle("hidden");
e.stopPropagation();
});
document.addEventListener("click", function (e) {
// if the clicked element isn't the list, close the list
if (!sidenav.classList.contains("hidden") && !e.target.closest("#sidenavList")) {
sideButton.click();
}
});
}
});
</script>
<div class="flex flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
<aside id="sidenav"
class="hidden fixed top-0 left-0 z-10 w-full bg-black/10 min-h-screen max-h-screen overflow-x-hidden overflow-y-auto shrink-0
md:block md:sticky md:w-52 md:min-h-0 md:bg-inherit md:border-r md:border-r-gray-200 md:overscroll-auto">
<nav id="sidenavList" class="flex flex-col bg-white w-52 min-h-screen pl-2 pt-4 pb-24 md:w-full md:min-h-0">
<a href="index.html">Basics</a>
<a href="buildingObjects.html">Building Parts</a>
<a href="usingModels.html">Using Models</a>
<a href="dataBinding.html">Data Binding</a>
<a href="react.html">GoJS with React</a>
<a href="svelte.html">GoJS with Svelte</a>
<a href="angular.html">GoJS with Angular</a>
<a href="textBlocks.html">TextBlocks</a>
<a href="shapes.html">Shapes</a>
<a href="pictures.html">Pictures</a>
<a href="panels.html">Panels</a>
<a href="tablePanels.html">Table Panels</a>
<a href="brush.html">Brushes</a>
<a href="sizing.html">Sizing Objects</a>
<a href="itemArrays.html">Item Arrays</a>
<a href="changedEvents.html">Changed Events</a>
<a href="transactions.html">Transactions</a>
<a href="viewport.html">Coordinates</a>
<a href="initialView.html">Initial View</a>
<a href="collections.html">Collections</a>
<a href="links.html">Links</a>
<a href="linkLabels.html">Link Labels</a>
<a href="connectionPoints.html">Link Points</a>
<a href="ports.html">Ports</a>
<a href="nodes.html">Nodes</a>
<a href="typings.html">Typings</a>
<a href="debugging.html">Debugging</a>
<a href="layouts.html">Layouts</a>
<a href="routers.html">Routers</a>
<a href="trees.html">Trees</a>
<a href="subtrees.html">SubTrees</a>
<a href="groups.html">Groups</a>
<a href="subgraphs.html">SubGraphs</a>
<a href="sizedGroups.html">Sized Groups</a>
<a href="selection.html">Selection</a>
<a href="highlighting.html">Highlighting</a>
<a href="theming.html">Theming</a>
<a href="tooltips.html">ToolTips</a>
<a href="contextMenus.html">Context Menus</a>
<a href="events.html">Diagram Events</a>
<a href="tools.html">Tools</a>
<a href="commands.html">Commands</a>
<a href="accessibility.html">Accessibility</a>
<a href="buttons.html">Buttons</a>
<a href="permissions.html">Permissions</a>
<a href="validation.html">Validation</a>
<a href="animation.html">Animation</a>
<a href="HTMLInteraction.html">HTML Interaction</a>
<a href="layers.html">Layers & Z-ordering</a>
<a href="palette.html">Palette</a>
<a href="overview.html">Overview</a>
<a href="replacingDeleting.html">Replacing and Deleting</a>
<a href="templateMaps.html">Template Maps</a>
<a href="legends.html">Legends and Titles</a>
<a href="extensions.html">Extensions</a>
<a href="geometry.html">Geometry Strings</a>
<a href="grids.html">Grid Patterns</a>
<a href="graduatedPanels.html">Graduated Panels</a>
<a href="SVGContext.html">Rendering to SVG</a>
<a href="makingSVG.html">Snapshot to SVG</a>
<a href="makingImages.html">Diagram Images</a>
<a href="printing.html">Printing</a>
<a href="serverSideImages.html">Server-side Images</a>
<a href="nodeScript.html">GoJS in Node.js</a>
<a href="testing.html">Testing</a>
<a href="performance.html">Performance</a>
<a href="platforms.html">Platforms</a>
<a href="deployment.html">Deployment</a>
</nav>
</aside>
<script>
var navList = document.getElementById('sidenavList');
if (navList !== null) {
var url = window.location.href;
var lindex = url.lastIndexOf('/');
url = url
.slice(lindex + 1)
.toLowerCase();
var aTags = navList.getElementsByTagName('a');
var currentindex = -1;
for (var i = 0; i < aTags.length; i++) {
var lowerhref = aTags[i]
.href
.toLowerCase();
if (lowerhref.indexOf('/' + url) !== -1) {
currentindex = i;
aTags[i]
.classList
.add('active');
break;
}
}
}
</script>
<div class="px-4 pb-16 w-full overflow-hidden prose">
<h1>Performance Considerations</h1>
<p>
Getting good performance for your diagrams does not require any effort on your part when the diagrams are limited to a few hundreds of nodes and links,
especially on the desktop. However when your app might deal with thousands or tens of thousands of nodes and links, you may need to adapt your implementation
to avoid expensive features.
</p>
<p>The perceived performance of your diagram depends on many different factors.</p>
<ul>
<li>JavaScript code is normally several to many times slower than Java or .NET code on the same hardware platform.</li>
<li>JavaScript code performance varies between different browsers and versions of browsers.</li>
<li>Memory limitations, particularly on mobile devices, affect performance.</li>
<li>There can be a wide variation of drawing performance on different platforms.</li>
<li>Drawing and animation effects take resources.</li>
<li>Complicated nodes or links are slower to build and update and draw than simple ones.</li>
<li>Some layouts are inherently slower than others.</li>
</ul>
<h2 id="EffectsAndAppearances">Effects and Appearances</h2>
<p>
Shadows are relatively expensive to draw, so consider not setting <a>Part.isShadowed</a> to true. Gradient <a>Brush</a>es are slower to draw than solid
colors. Complex <a>Shape</a> <a>Geometry</a>s are slower to draw than simpler ones, and they require more computation when computing intersections.
</p>
<p>Animation takes up resources; consider setting <a>AnimationManager.isEnabled</a> to false.</p>
<h2 id="ConstructingAndSizingNodes">Constructing and Sizing Nodes</h2>
<p>
Keep your Nodes and Links as simple as you can make it. Limit how many GraphObjects that you use in your templates. Use simpler Panel types when feasible --
the "Table" Panel is the most featureful, but maybe you can just use a "Horizontal" or a "Vertical" or a "Spot" or an "Auto" Panel. A Panel should have two or
more elements in them (although there can be exceptions). If you have no elements in a Panel, delete the panel. If you have only one element in a Panel,
consider removing the panel and merging the element into the panel's containing panel.
</p>
<p>
Do not include objects that are not visible. Limit how much data binding that you use, and avoid <a>Binding</a>s with no source property name or that are
<a>Binding.ofObject</a>.
</p>
<p>
If you have a <a>Picture</a> and you know its intended size beforehand, it's best to set its <a>GraphObject.desiredSize</a> (or <a>GraphObject.width</a> and
<a>GraphObject.height</a>) so that it does not have to re-measured once the image loads. When nodes change size a <a>Layout</a> might need to be performed
again, so having fixed size nodes helps reduce diagram layouts. In general, setting <a>GraphObject.desiredSize</a> on the elements of your nodes, especially
<a>Picture</a>s, will speed up how quickly <b>GoJS</b> can measure and arrange the <a>Panel</a>s that form your Nodes or Links.
</p>
<h2 id="Shapes">Shapes</h2>
<p>
Shapes can decrease memory usage by sharing Geometries. Shapes that are given a set size with either <code>desiredSize</code> or <code>width</code> and
<code>height</code>, and that are also using a <a>Shape.figure</a> of "Rectangle", "Circle", or "RoundedRectangle", will have their geometries potentially
shared automatically.
</p>
<p>In other words, a single shape in a Node template defined like this:</p>
<code> new go.Shape("RoundedRectangle", { width: 50, height: 50 }) </code>
<p>Will create a single geometry that is shared among all copies of the Node.</p>
<h2 id="Links">Links</h2>
<p>
The <a>Link.routing</a> property value <a>Routing.AvoidsNodes</a> can be slow in very large graphs. Consider not using it in performance-minded large graphs,
or setting it only after the initial layout is completed (use "InitialLayoutCompleted" <a href="events.html">Diagram event listener</a>), or ideally setting
it at that time only on select Links.
</p>
<p>
Using a <a>Link.curve</a> value of either <a>Curve.JumpOver</a> or <a>Curve.JumpGap</a> is a lot slower than not having to compute all the points where such
links cross and drawing the small arc or drawing a gap.
</p>
<h2 id="Layouts">Layouts</h2>
<p><a>GridLayout</a> and <a>TreeLayout</a> and most other layouts are fast.</p>
<p>
<a>LayeredDigraphLayout</a> is slow -- it cannot handle thousands of nodes and links. The documentation of <a>LayeredDigraphLayout</a> suggests some
properties that you can set in order to improve performance. Contact us if you continue to have any problems.
</p>
<h2 id="Overviews">Overviews</h2>
<p>
Overviews generally require drawing a Diagram a second time, so there may be some performance impact on large graphs. Consider setting
<a>Overview.drawsGrid</a> to <code>false</code> or and <a>Overview.updateDelay</a> to a non-negative number.
</p>
<h2 id="Virtualization">Virtualization</h2>
<p>
For diagrams with many nodes and links that only display a fraction of them at a time, you could implement some form of virtualization to optimize your
diagram. The <a href="../samples/virtualizedTree.html">Virtualized Tree sample</a> contains 123,456 total nodes, yet is fairly quick to load and render,
because it only constructs nodes and links that intersect with the viewport.
</p>
<p>
But this does complicate the implementation of the diagram, because you need to use a separate model from the <a>Diagram.model</a> and manage adding and
removing Nodes and Links when the viewport changes. Furthermore layout is more complicated because it needs to work on <a>LayoutVertex</a>es and
<a>LayoutEdge</a>s, not on <a>Node</a>s and <a>Link</a>s.
</p>
<p>Other virtualization samples are listed in the <a href="../samples/index.html#performance">samples index</a>.</p>
<h2 id="OtherConsiderations">Other considerations</h2>
<p>
If you want to disassociate the Diagram from the HTML Div element, set <a>Diagram.div</a> to null. If you remove a part of the HTML DOM containing a Div with
a Diagram, you will need to set <a>Diagram.div</a> to null in order for the page to garbage collect the memory.
</p>
<p>
Depending on your app, it may be worthwhile to selectively toggle off some features (like shadows and animation) or to use simpler templates altogether, when
slower environments are present, such as on mobile devices.
</p>
<p>
You can use multiple templates depending on your zoom level. If you are zoomed out far enough (and therefore have a lot of nodes on the screen) you can switch
to a simplified template so that rendering (when panning, dragging, etc) is faster. The process of switching templates has a performance cost, though, since
Parts have to rebuild themselves.
</p>
<p>
If you think you have a unique or high node count Diagramming situation that may benefit from other drawing optimizations,
<a href="https://nwoods.com/contact.html">contact support</a>.
</p>
</div>
</div>
<footer class="bg-white text-gray-900 border-t border-t-gray-200">
<div class="w-full max-w-screen-lg mx-auto px-4 py-6">
<p id="version" class="text-xs text-gray-900 m-0"></p>
<div class="text-sm px-0 mb-4 grid grid-cols-2 sm:grid-cols-3 gap-y-10">
<div>
<h2 class="text-base font-semibold text-nwoods-primary">GoJS</h2>
<ul class="list-none space-y-4 md:space-y-1 px-0">
<li>
<a href="../samples/index.html">Samples</a>
</li>
<li>
<a href="../learn/index.html">Learn</a>
</li>
<li>
<a href="../intro/index.html">Intro</a>
</li>
<li>
<a href="../api/index.html">API</a>
</li>
<li>
<a href="../changelog.html">Changelog</a>
</li>
<li>
<a href="https://github.com/NorthwoodsSoftware/GoJS" target="_blank" rel="noopener">GitHub</a>
</li>
</ul>
</div>
<div>
<h2 class="text-base font-semibold text-nwoods-primary">Support</h2>
<ul class="list-none space-y-4 md:space-y-1 px-0">
<li>
<a href="https://nwoods.com/contact.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/contact.html', 'contact');">Contact</a>
</li>
<li>
<a href="https://forum.nwoods.com/c/gojs" target="_blank" rel="noopener">Forum</a>
</li>
<li>
<a href="https://nwoods.com/app/activate.aspx?sku=gojs" target="_blank" rel="noopener">Activate</a>
</li>
<li>
<a href="https://nwoods.com/sales/index.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/sales/index.html', 'buy');">Buy</a>
</li>
<li>
<a href="https://nwoods.com/register.html" target="_blank" rel="noopener">Register</a>
</li>
</ul>
</div>
<div>
<h2 class="text-base font-semibold text-nwoods-primary">Company</h2>
<ul class="list-none space-y-4 md:space-y-1 px-0">
<li>
<a target="_blank" href="https://nwoods.com" target="_blank" rel="noopener">Northwoods</a>
</li>
<li>
<a target="_blank" href="https://nwoods.com/about.html" target="_blank" rel="noopener">About Us</a>
</li>
<li>
<a target="_blank" href="https://nwoods.com/contact.html" target="_blank" rel="noopener">Contact Us</a>
</li>
<li>
<a target="_blank" href="https://nwoods.com/consulting.html" target="_blank" rel="noopener">Consulting</a>
</li>
<li>
<a target="_blank" href="https://twitter.com/northwoodsgo" target="_blank" rel="noopener">Twitter</a>
</li>
</ul>
</div>
</div>
<p class="text-sm text-gray-900 md:mb-6">
Copyright 1998-2025 <a href="https://nwoods.com">Northwoods Software</a>
</p>
</div>
</footer>
</body>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-S5QK8VSK84"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-S5QK8VSK84');
var getOutboundLink = function (url, label) {
gtag('event', 'click', {
'event_category': 'outbound',
'event_label': label,
'transport_type': 'beacon'
});
}
const params = new URL(document.location).searchParams
let a = params.get('a');
if (a) localStorage.setItem('a', a);
a = localStorage.getItem('a');
if (a) {
const links = [...document.body.getElementsByTagName("a")].filter((l) => l.href.includes('nwoods.com'));
for (const l of links) {
const url = new URL(l.href);
url.searchParams.set('a', a);
l.href = url;
}
}
</script>
<script src="../assets/js/prism.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gojs@3.1.0"></script>
<script src="../assets/js/goDoc.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
if (window.go)
document
.getElementById('version')
.textContent = "GoJS version " + go.version;
if (window.goDoc)
window.goDoc();
var d = window.diagrams;
for (var i = 0; i < d.length; i++) {
var dargs = d[i];
goCodeExecute(dargs[0], dargs[1], dargs[2], dargs[3], dargs[4]);
}
if (window.extra)
window.extra();
}
);
</script>
</html>