create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
828 lines (775 loc) • 33.7 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="GoJS and React" />
<meta property="og:title" content="GoJS and React" />
<meta name="twitter:title" content="GoJS and React" />
<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/react.html" />
<meta property="twitter:url" content="https://gojs.net/latest/intro/react.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
GoJS and React | 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>Using GoJS with React</h1>
<p class="box" style="background-color: lightgoldenrodyellow;">
Examples of most of the topics discussed on this page can be found in the <a href="https://github.com/NorthwoodsSoftware/gojs-react-basic" target="_blank">gojs-react-basic</a> project,
which serves as a simple starter project.
</p>
<p>
If you are new to GoJS, it may be helpful to first visit the <a href="../learn/index.html" target="_blank">Getting Started Tutorial</a>.
</p>
<p>
The easiest way to get a component set up for a GoJS Diagram is to use the <a href="https://github.com/NorthwoodsSoftware/gojs-react" target="_blank">gojs-react</a> package,
which exports React Components for GoJS Diagrams, Palettes, and Overviews.
The <a href="https://github.com/NorthwoodsSoftware/gojs-react-basic" target="_blank">gojs-react-basic</a> project demonstrates how to use these components.
More information about the package, including the various props it takes, can be found on the <a href="https://github.com/NorthwoodsSoftware/gojs-react" target="_blank">Github</a> or
<a href="https://npmjs.com/gojs-react" target="_blank">NPM</a> pages. Our examples will be using a <a>GraphLinksModel</a>, but any model can be used.
</p>
<h2 id="quickstart">Quick start with an existing React application</h2>
<h4 id="Installation">Installation</h4>
<p>
Start by installing GoJS and gojs-react: <code>npm install gojs gojs-react</code>.
</p>
<h4 id="DiagramStyling">Diagram styling</h4>
Next, set up a CSS class for the GoJS diagram's div:
</p>
<pre class="lang-css"><code>
/* App.css */
.diagram-component {
width: 400px;
height: 400px;
border: solid 1px black;
background-color: white;
}
</code></pre>
<h4 id="RenderingComponent">Rendering the component</h4>
<p>
Finally, add an initDiagram function and a model change handler function, and add the ReactDiagram component inside your render method.
Note that the UndoManager should always be enabled to allow for transactions to take place,
but the <a>UndoManager.maxHistoryLength</a> can be set to 0 to prevent undo and redo.
</p>
<pre class="lang-js"><code>
// App.js
import React from 'react';
import * as go from 'gojs';
import { ReactDiagram } from 'gojs-react';
import './App.css'; // contains .diagram-component CSS
// ...
/**
* Diagram initialization method, which is passed to the ReactDiagram component.
* This method is responsible for making the diagram and initializing the model and any templates.
* The model's data should not be set here, as the ReactDiagram component handles that via the other props.
*/
function initDiagram() {
// set your license key here before creating the diagram: go.Diagram.licenseKey = "...";
const diagram =
new go.Diagram(
{
'undoManager.isEnabled': true, // must be set to allow for model change listening
// 'undoManager.maxHistoryLength': 0, // uncomment disable undo/redo functionality
'clickCreatingTool.archetypeNodeData': { text: 'new node', color: 'lightblue' },
model: new go.GraphLinksModel(
{
linkKeyProperty: 'key' // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
})
});
// define a simple Node template
diagram.nodeTemplate =
new go.Node('Auto') // the Shape will go around the TextBlock
.bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify)
.add(
new go.Shape('RoundedRectangle',
{ name: 'SHAPE', fill: 'white', strokeWidth: 0 })
// Shape.fill is bound to Node.data.color
.bind('fill', 'color'),
new go.TextBlock({ margin: 8, editable: true }) // some room around the text
.bindTwoWay('text')
);
return diagram;
}
/**
* This function handles any changes to the GoJS model.
* It is here that you would make any updates to your React state, which is discussed below.
*/
function handleModelChange(changes) {
alert('GoJS model changed!');
}
// render function...
function App() {
return (
<div>
...
<ReactDiagram
initDiagram={initDiagram}
divClassName='diagram-component'
nodeDataArray={[
{ key: 0, text: 'Alpha', color: 'lightblue', loc: '0 0' },
{ key: 1, text: 'Beta', color: 'orange', loc: '150 0' },
{ key: 2, text: 'Gamma', color: 'lightgreen', loc: '0 150' },
{ key: 3, text: 'Delta', color: 'pink', loc: '150 150' }
]}
linkDataArray={[
{ key: -1, from: 0, to: 1 },
{ key: -2, from: 0, to: 2 },
{ key: -3, from: 1, to: 1 },
{ key: -4, from: 2, to: 3 },
{ key: -5, from: 3, to: 0 }
]}
onModelChange={handleModelChange}
/>
...
</div>
);
}
</code></pre>
<p>
That's it! You should now have a GoJS diagram rendering within your React application.
Try editing the text of a node or deleting a node, and you'll see an alert on the page.
</p>
<h2 id="stateful">Usage in a stateful React app</h2>
<p>
Typically the data being passed to the ReactDiagram component will be used elsewhere in your app and will exist in React state.
For example, you may have some kind of inspector that can be used to modify node properties, and therefore the state should be lifted up and held by a parent component
of both the diagram and the inspector.
</p>
<p>
A basic setup can be seen in the <a href="https://github.com/NorthwoodsSoftware/gojs-react-basic" target="_blank">gojs-react-basic</a> project,
but we'll describe some of the methodology here.
</p>
<h4 id="CreatingWrapperComponent">Creating a wrapper component</h4>
<p>
When handling state, it is often useful to write a wrapper component around the gojs-react components to pass the necessary props along and keep GoJS initialization out of the main app.
There are a few things that should be set up in the wrapper component:
<ul>
<li>a set of props coming in from the parent component which holds state and handlers</li>
<li>a ref to the ReactDiagram component so getDiagram() and clear() can be used</li>
<li>a useEffect to add/remove app-specific diagram listeners</li>
<li>an initDiagram function to be passed to the ReactDiagram component</li>
</ul>
Node and link data are <i>merged</i> into the GoJS model, thus properties should not be removed from node or link data,
but rather set to undefined if they are no longer needed; GoJS avoids destructive merging.
</p>
<p>
Below, we'll pass linkDataArray and modelData as props to the ReactDiagram, but note that they are not always needed in gojs-react components,
so your app may not need to include them. For proper initial loading of data, one should have the data ready before the ReactDiagram component mounts.
This allows layouts and linking to occur properly with the initial data set.
</p>
<pre class="lang-js"><code>
import * as go from 'gojs';
import { ReactDiagram } from 'gojs-react';
import { useEffect, useRef } from 'react';
// props passed in from a parent component holding state, some of which will be passed to ReactDiagram
interface DiagramProps {
nodeDataArray: Array<go.ObjectData>;
linkDataArray: Array<go.ObjectData>;
modelData: go.ObjectData;
skipsDiagramUpdate: boolean;
onDiagramEvent: (e: go.DiagramEvent) => void;
onModelChange: (e: go.IncrementalData) => void;
}
export const DiagramWrapper = (props: DiagramProps) => {
// Ref to keep a reference to the component, which provides access to the GoJS diagram via getDiagram().
const diagramRef = useRef<ReactDiagram>(null);
// add/remove listeners
// only done on mount, not any time there's a change to props.onDiagramEvent
useEffect(() => {
if (diagramRef.current === null) return;
const diagram = diagramRef.current.getDiagram();
if (diagram instanceof go.Diagram) {
diagram.addDiagramListener('ChangedSelection', props.onDiagramEvent);
}
return () => {
if (diagram instanceof go.Diagram) {
diagram.removeDiagramListener('ChangedSelection', props.onDiagramEvent);
}
};
}, []);
/**
* Diagram initialization function, which is passed to the ReactDiagram component.
* This is responsible for making the diagram and initializing the model, any templates,
* and maybe doing other initialization tasks like customizing tools.
* The model's data should not be set here, as the ReactDiagram component handles that via the other props.
*/
const initDiagram = (): go.Diagram => {
// set your license key here before creating the diagram: go.Diagram.licenseKey = '...';
const diagram =
new go.Diagram(
{
'undoManager.isEnabled': true, // must be set to allow for model change listening
// 'undoManager.maxHistoryLength': 0, // uncomment disable undo/redo functionality
'clickCreatingTool.archetypeNodeData': { text: 'new node', color: 'lightblue' },
model: new go.GraphLinksModel(
{
linkKeyProperty: 'key', // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
// positive keys for nodes
makeUniqueKeyFunction: (m: go.Model, data: any) => {
let k = data.key || 1;
while (m.findNodeDataForKey(k)) k++;
data.key = k;
return k;
},
// negative keys for links
makeUniqueLinkKeyFunction: (m: go.GraphLinksModel, data: any) => {
let k = data.key || -1;
while (m.findLinkDataForKey(k)) k--;
data.key = k;
return k;
}
})
});
// define a simple Node template
diagram.nodeTemplate =
new go.Node('Auto') // the Shape will go around the TextBlock
.bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify)
.add(
new go.Shape('RoundedRectangle',
{
name: 'SHAPE', fill: 'white', strokeWidth: 0,
// set the port properties:
portId: '', fromLinkable: true, toLinkable: true, cursor: 'pointer'
})
// Shape.fill is bound to Node.data.color
.bind('fill', 'color'),
new go.TextBlock(
{ margin: 8, editable: true, font: '400 .875rem Roboto, sans-serif' }) // some room around the text
.bindTwoWay('text')
);
// relinking depends on modelData
diagram.linkTemplate =
new go.Link()
.bindModel('relinkableFrom', 'canRelink')
.bindModel('relinkableTo', 'canRelink')
.add(
new go.Shape(),
new go.Shape({ toArrow: 'Standard' })
);
return diagram;
};
return (
<ReactDiagram
ref={diagramRef}
divClassName='diagram-component'
initDiagram={initDiagram}
nodeDataArray={props.nodeDataArray}
linkDataArray={props.linkDataArray}
modelData={props.modelData}
onModelChange={props.onModelChange}
skipsDiagramUpdate={props.skipsDiagramUpdate}
/>
);
};
</code></pre>
<h4 id="UsingWrapperComponentWithinApp">Using the wrapper component within the app</h4>
<p>
The application should set up a few things to be passed to the wrapper described above:
<ul>
<li>state containing a nodeDataArray, linkDataArray, modelData object, and skipsDiagramUpdate flag</li>
<li>a handleDiagramEvent function for any app-specific DiagramEvents, such as 'ChangedSelection'</li>
<li>a handleModelChange function for updating state based on updates from the GoJS model</li>
</ul>
</p>
<pre class="lang-js"><code>
import * as go from 'gojs';
import { useEffect } from 'react';
import { useImmer } from 'use-immer'; // we use Immer here for simple immutable updates
import { DiagramWrapper } from './components/Diagram';
interface AppState {
// ...
nodeDataArray: Array<go.ObjectData>;
linkDataArray: Array<go.ObjectData>;
modelData: go.ObjectData;
selectedKey: number | null;
skipsDiagramUpdate: boolean;
}
export const App = () => {
// Diagram state
const [diagramData, updateDiagramData] = useImmer<AppState>({
nodeDataArray: [
{ key: 0, text: 'Alpha', color: 'lightblue', loc: '0 0' },
{ key: 1, text: 'Beta', color: 'orange', loc: '150 0' },
{ key: 2, text: 'Gamma', color: 'lightgreen', loc: '0 150' },
{ key: 3, text: 'Delta', color: 'pink', loc: '150 150' }
],
linkDataArray: [
{ key: -1, from: 0, to: 1 },
{ key: -2, from: 0, to: 2 },
{ key: -3, from: 1, to: 1 },
{ key: -4, from: 2, to: 3 },
{ key: -5, from: 3, to: 0 }
],
modelData: { canRelink: true },
selectedKey: null,
skipsDiagramUpdate: false
});
/**
* Handle any app-specific DiagramEvents, in this case just selection changes.
* On ChangedSelection, find the corresponding data and set the selectedKey state.
*
* This is not required, and is only needed when handling DiagramEvents from the GoJS diagram.
* @param e a GoJS DiagramEvent
*/
const handleDiagramEvent = (e: go.DiagramEvent) => {
const name = e.name;
switch (name) {
case 'ChangedSelection': {
const sel = e.subject.first();
updateDiagramData(draft => {
if (sel) {
draft.selectedKey = sel.key;
} else {
draft.selectedKey = null;
}
});
break;
}
default: break;
}
};
/**
* Handle GoJS model changes, which output an object of data changes via Model.toIncrementalData.
* This method should iterate over those changes and update state to keep in sync with the GoJS model.
* This can be done via setState in React or another preferred state management method,
* such as updateDiagramData in a case like this.
* @param obj a JSON-formatted string
*/
const handleModelChange = (obj: go.IncrementalData) => {
// const insertedNodeKeys = obj.insertedNodeKeys;
// const modifiedNodeData = obj.modifiedNodeData;
// const removedNodeKeys = obj.removedNodeKeys;
// const insertedLinkKeys = obj.insertedLinkKeys;
// const modifiedLinkData = obj.modifiedLinkData;
// const removedLinkKeys = obj.removedLinkKeys;
// const modifiedModelData = obj.modelData;
// see gojs-react-basic for an example model change handler
// when setting state, be sure to set skipsDiagramUpdate: true since GoJS already has this update
};
/**
* Handle changes to the checkbox on whether to allow relinking.
* @param e a change event from the checkbox
*/
const handleRelinkChange = (e: any) => {
const target = e.target;
const value = target.checked;
updateDiagramData(draft => {
draft.modelData = { canRelink: value };
draft.skipsDiagramUpdate = false;
});
};
let selKey;
if (diagramData.selectedKey !== null) {
selKey = <p>Selected key: {diagramData.selectedKey}</p>;
}
return (
<div>
<DiagramWrapper
nodeDataArray={diagramData.nodeDataArray}
linkDataArray={diagramData.linkDataArray}
modelData={diagramData.modelData}
skipsDiagramUpdate={diagramData.skipsDiagramUpdate}
onDiagramEvent={handleDiagramEvent}
onModelChange={handleModelChange}
/>
<label>
Allow Relinking?
<input
type='checkbox'
id='relink'
checked={diagramData.modelData.canRelink}
onChange={handleRelinkChange} />
</label>
{selKey}
</div>
);
}
</code></pre>
<h4>A Note on Diagram Reinitialization</h4>
<p>
Occasionally you may want to treat a model update as if you were loading a completely new model.
But initialization is done via the initDiagram function, when the ReactDiagram mounts, and only once.
A regular model update is not treated as an initialization, so none of the <b>initial...</b> properties
of your Diagram will apply.
</p>
<p>
To address this problem, ReactDiagram exposes a clear() method.
When called, it clears its diagram of all nodes, links, and model data, and
prepares the next state update to be treated as a diagram initialization.
That will result in an initial layout and perform initial diagram content alignment and scaling.
Note that the initDiagram function is not called again.
</p>
<p>
Here is a small sample of how one might trigger diagram reinitilization using the clear() method.
</p>
<pre class="lang-js"><code>
const reinitModel = () => {
diagramRef.current.clear();
updateDiagramData(draft => {
draft.nodeDataArray = [
{ key: 0, text: 'Epsilon', color: 'lightblue' },
{ key: 1, text: 'Zeta', color: 'orange' },
{ key: 2, text: 'Eta', color: 'lightgreen' },
{ key: 3, text: 'Theta', color: 'pink' }
];
draft.linkDataArray = [
{ key: -1, from: 0, to: 1 },
{ key: -2, from: 0, to: 2 },
{ key: -3, from: 1, to: 1 },
{ key: -4, from: 2, to: 3 },
{ key: -5, from: 3, to: 0 }
];
draft.skipsDiagramUpdate = false;
});
}
</code></pre>
<p>
These are the basics for setting up GoJS within a React application. See <a href="https://github.com/NorthwoodsSoftware/gojs-react-basic" target="_blank">gojs-react-basic</a>
for a working example and the <a href="https://github.com/NorthwoodsSoftware/gojs-react" target="_blank">gojs-react</a> Github page for further explanation of various props
passed to the components.
</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>