create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
598 lines (547 loc) • 28.2 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="Drag a link to reconnect it. Nodes have custom Adornments for selection, resizing, and rotating. The Palette includes links." />
<meta itemprop="description" content="Drag a link to reconnect it. Nodes have custom Adornments for selection, resizing, and rotating. The Palette includes links." />
<meta property="og:description" content="Drag a link to reconnect it. Nodes have custom Adornments for selection, resizing, and rotating. The Palette includes links." />
<meta name="twitter:description" content="Drag a link to reconnect it. Nodes have custom Adornments for selection, resizing, and rotating. The Palette includes links." />
<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="Allow Users to Drag Links and Reconnect Them on Drop" />
<meta property="og:title" content="Allow Users to Drag Links and Reconnect Them on Drop" />
<meta name="twitter:title" content="Allow Users to Drag Links and Reconnect Them on Drop" />
<meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/draggablelink.png" />
<meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/draggablelink.png" />
<meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/draggablelink.png" />
<meta property="og:url" content="https://gojs.net/latest/samples/draggableLink.html" />
<meta property="twitter:url" content="https://gojs.net/latest/samples/draggableLink.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
Allow Users to Drag Links and Reconnect Them on Drop | 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 src="../extensions/Figures.js"></script>
<script id="code">
function init() {
myDiagram = new go.Diagram('myDiagramDiv', { // must name or refer to the DIV HTML element
grid:
new go.Panel('Grid')
.add(
new go.Shape('LineH', { stroke: 'lightgray', strokeWidth: 0.5 }),
new go.Shape('LineH', { stroke: 'gray', strokeWidth: 0.5, interval: 10 }),
new go.Shape('LineV', { stroke: 'lightgray', strokeWidth: 0.5 }),
new go.Shape('LineV', { stroke: 'gray', strokeWidth: 0.5, interval: 10 })
),
'draggingTool.dragsLink': true,
'draggingTool.isGridSnapEnabled': true,
'linkingTool.isUnconnectedLinkValid': true,
'linkingTool.portGravity': 20,
'relinkingTool.isUnconnectedLinkValid': true,
'relinkingTool.portGravity': 20,
'relinkingTool.fromHandleArchetype':
new go.Shape('Diamond', {
segmentIndex: 0,
cursor: 'pointer',
desiredSize: new go.Size(8, 8),
fill: 'tomato',
stroke: 'darkred'
}),
'relinkingTool.toHandleArchetype':
new go.Shape('Diamond', {
segmentIndex: -1,
cursor: 'pointer',
desiredSize: new go.Size(8, 8),
fill: 'darkred',
stroke: 'tomato'
}),
'linkReshapingTool.handleArchetype':
new go.Shape('Diamond', {
desiredSize: new go.Size(7, 7),
fill: 'lightblue',
stroke: 'deepskyblue'
}),
'rotatingTool.handleAngle': 270,
'rotatingTool.handleDistance': 30,
'rotatingTool.snapAngleMultiple': 15,
'rotatingTool.snapAngleEpsilon': 15,
'undoManager.isEnabled': true
});
// 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);
}
});
// Define a function for creating a "port" that is normally transparent.
// The "name" is used as the GraphObject.portId, the "spot" is used to control how links connect
// and where the port is positioned on the node, and the boolean "output" and "input" arguments
// control whether the user can draw links from or to the port.
function makePort(name, spot, output, input) {
// the port is basically just a small transparent circle
return new go.Shape('Circle', {
fill: null, // not seen, by default; set to a translucent gray by showSmallPorts, defined below
stroke: null,
desiredSize: new go.Size(7, 7),
alignment: spot, // align the port on the main Shape
alignmentFocus: spot, // just inside the Shape
portId: name, // declare this object to be a "port"
fromSpot: spot,
toSpot: spot, // declare where links may connect at this port
fromLinkable: output,
toLinkable: input, // declare whether the user may draw links to/from here
cursor: 'pointer' // show a different cursor to indicate potential link point
});
}
var nodeSelectionAdornmentTemplate =
new go.Adornment('Auto')
.add(
new go.Shape({ fill: null, stroke: 'deepskyblue', strokeWidth: 1.5, strokeDashArray: [4, 2] }),
new go.Placeholder()
);
var nodeResizeAdornmentTemplate =
new go.Adornment('Spot', { locationSpot: go.Spot.Right })
.add(
new go.Placeholder(),
new go.Shape({ alignment: go.Spot.TopLeft, cursor: 'nw-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ alignment: go.Spot.Top, cursor: 'n-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ alignment: go.Spot.TopRight, cursor: 'ne-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ alignment: go.Spot.Left, cursor: 'w-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ alignment: go.Spot.Right, cursor: 'e-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ alignment: go.Spot.BottomLeft, cursor: 'se-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ alignment: go.Spot.Bottom, cursor: 's-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ alignment: go.Spot.BottomRight, cursor: 'sw-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'deepskyblue' })
);
var nodeRotateAdornmentTemplate =
new go.Adornment({
locationSpot: go.Spot.Center,
locationObjectName: 'ELLIPSE'
})
.add(
new go.Shape('Ellipse', { name: 'ELLIPSE', cursor: 'pointer', desiredSize: new go.Size(7, 7), fill: 'lightblue', stroke: 'deepskyblue' }),
new go.Shape({ geometryString: 'M3.5 7 L3.5 30', isGeometryPositioned: true, stroke: 'deepskyblue', strokeWidth: 1.5, strokeDashArray: [4, 2] })
);
myDiagram.nodeTemplate =
new go.Node('Spot', {
locationSpot: go.Spot.Center,
selectable: true,
selectionAdornmentTemplate: nodeSelectionAdornmentTemplate,
resizable: true,
resizeObjectName: 'PANEL',
resizeAdornmentTemplate: nodeResizeAdornmentTemplate,
rotatable: true,
rotateAdornmentTemplate: nodeRotateAdornmentTemplate,
// handle mouse enter/leave events to show/hide the ports
mouseEnter: (e, node) => showSmallPorts(node, true),
mouseLeave: (e, node) => showSmallPorts(node, false)
})
.bindTwoWay('location', 'loc', go.Point.parse, go.Point.stringify)
.bindTwoWay('angle')
.add(
// the main object is a Panel that surrounds a TextBlock with a Shape
new go.Panel('Auto', { name: 'PANEL' })
.bindTwoWay('desiredSize', 'size', go.Size.parse, go.Size.stringify)
.add(
new go.Shape('Rectangle', { // default figure
portId: '', // the default port: if no spot on link data, use closest side
fromLinkable: true,
toLinkable: true,
cursor: 'pointer',
fill: 'white', // default color
strokeWidth: 2
})
.bind('figure')
.bind('fill'),
new go.TextBlock({
font: 'bold 10pt Helvetica, Arial, sans-serif',
margin: 8,
maxSize: new go.Size(160, NaN),
wrap: go.Wrap.Fit,
editable: true
})
.bindTwoWay('text')
),
// four small named ports, one on each side:
makePort('T', go.Spot.Top, false, true),
makePort('L', go.Spot.Left, true, true),
makePort('R', go.Spot.Right, true, true),
makePort('B', go.Spot.Bottom, true, false)
);
function showSmallPorts(node, show) {
node.ports.each(port => {
if (port.portId !== '') {
// don't change the default port, which is the big shape
port.fill = show ? 'rgba(0,0,0,.3)' : null;
}
});
}
var linkSelectionAdornmentTemplate =
new go.Adornment('Link')
.add(
new go.Shape({
isPanelMain: true, // isPanelMain declares that this Shape shares the Link.geometry
fill: null,
stroke: 'deepskyblue',
strokeWidth: 0 // use selection object's strokeWidth
})
);
myDiagram.linkTemplate =
new go.Link({ // the whole link panel
selectable: true,
selectionAdornmentTemplate: linkSelectionAdornmentTemplate,
relinkableFrom: true,
relinkableTo: true,
reshapable: true,
routing: go.Routing.AvoidsNodes,
curve: go.Curve.JumpOver,
corner: 5,
toShortLength: 4
})
.bindTwoWay('points')
.add(
new go.Shape({ // the link path shape
isPanelMain: true,
strokeWidth: 2
}),
new go.Shape({ // the arrowhead
toArrow: 'Standard',
stroke: null
}),
new go.Panel('Auto')
.bindObject('visible', 'isSelected')
.add(
new go.Shape('RoundedRectangle', { // the link shape
fill: '#F8F8F8',
stroke: null
}),
new go.TextBlock({
textAlign: 'center',
font: '10pt helvetica, arial, sans-serif',
stroke: '#919191',
margin: 2,
minSize: new go.Size(10, NaN),
editable: true
})
.bindTwoWay('text')
)
);
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', {
maxSelectionCount: 1,
nodeTemplateMap: myDiagram.nodeTemplateMap, // share the templates used by myDiagram
// simplify the link template, just in this Palette
linkTemplate:
new go.Link({
// because the GridLayout.alignment is Location and the nodes have locationSpot == Spot.Center,
// to line up the Link in the same manner we have to pretend the Link has the same location spot
locationSpot: go.Spot.Center,
selectionAdornmentTemplate:
new go.Adornment('Link', { locationSpot: go.Spot.Center })
.add(
new go.Shape({
isPanelMain: true,
fill: null,
stroke: 'deepskyblue',
strokeWidth: 0
}),
new go.Shape({ // the arrowhead
toArrow: 'Standard',
stroke: null
})
),
routing: go.Routing.AvoidsNodes,
curve: go.Curve.JumpOver,
corner: 5,
toShortLength: 4
})
.bind('points')
.add(
new go.Shape({ // the link path shape
isPanelMain: true,
strokeWidth: 2
}),
new go.Shape({ // the arrowhead
toArrow: 'Standard',
stroke: null
})
),
model: new go.GraphLinksModel(
[
// specify the contents of the Palette
{ text: 'Start', figure: 'Ellipse', size: '75 75', fill: '#00AD5F' },
{ text: 'Step' },
{ text: 'DB', figure: 'Database', fill: 'lightgray' },
{ text: '???', figure: 'Diamond', fill: 'lightskyblue' },
{ text: 'End', figure: 'Ellipse', size: '75 75', fill: '#CE0620' },
{ text: 'Comment', figure: 'RoundedRectangle', fill: 'lightyellow' }
],
[
// the Palette also has a disconnected Link, which the user can drag-and-drop
{ points: new go.List(/*go.Point*/).addAll([new go.Point(0, 0), new go.Point(30, 0), new go.Point(30, 40), new go.Point(60, 40)]) }
]
)
});
}
// Show the diagram's model in JSON format that the user may edit
function save() {
saveDiagramProperties(); // do this first, before writing to JSON
document.getElementById('mySavedModel').value = myDiagram.model.toJson();
myDiagram.isModified = false;
}
function load() {
myDiagram.model = go.Model.fromJson(document.getElementById('mySavedModel').value);
loadDiagramProperties(); // do this after the Model.modelData has been brought into memory
}
function saveDiagramProperties() {
myDiagram.model.modelData.position = go.Point.stringify(myDiagram.position);
}
function loadDiagramProperties(e) {
// set Diagram.initialPosition, not Diagram.position, to handle initialization side-effects
var pos = myDiagram.model.modelData.position;
if (pos) myDiagram.initialPosition = go.Point.parse(pos);
}
window.addEventListener('DOMContentLoaded', init);
</script>
<div id="sample">
<div style="width: 100%; display: flex; justify-content: space-between">
<div id="myPaletteDiv" style="width: 105px; margin-right: 2px; background-color: whitesmoke; border: solid 1px black"></div>
<div id="myDiagramDiv" style="flex-grow: 1; height: 620px; border: solid 1px black"></div>
</div>
<p>
This sample demonstrates the ability for the user to drag around a Link as if it were a Node. When either end of the link passes over a valid port, the port
is highlighted.
</p>
<p>
The link-dragging functionality is enabled by setting some or all of the following properties:
<a>DraggingTool.dragsLink</a>, <a>LinkingTool.isUnconnectedLinkValid</a>, and <a>RelinkingTool.isUnconnectedLinkValid</a>.
</p>
<p>
Note that a Link is present in the <a>Palette</a> so that it too can be dragged out and onto the main Diagram. Because links are not automatically routed
when either end is not connected with a Node, the route is provided explicitly when that Palette item is defined.
</p>
<p>
This also demonstrates several custom Adornments:
<a>Part.selectionAdornmentTemplate</a>, <a>Part.resizeAdornmentTemplate</a>, and <a>Part.rotateAdornmentTemplate</a>.
</p>
<p>
Finally this sample demonstrates saving and restoring the <a>Diagram.position</a> as a property on the <a>Model.modelData</a> object that is automatically
saved and restored when calling <a>Model.toJson</a> and <a>Model.fromJson</a>.
</p>
<div>
<div>
<button id="SaveButton" onclick="save()">Save</button>
<button onclick="load()">Load</button>
Diagram Model saved in JSON format:
</div>
<textarea id="mySavedModel" style="width: 100%; height: 300px">
{ "class": "go.GraphLinksModel",
"linkFromPortIdProperty": "fromPort",
"linkToPortIdProperty": "toPort",
"pointsDigits": 1,
"nodeDataArray": [
],
"linkDataArray": [
]}
</textarea>
</div>
</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>Collections</h4>
<p>
<b>GoJS</b> provides its own collection classes: <a href="../api/symbols/List.html" target="api">List</a>, <a href="../api/symbols/Set.html" target="api">Set</a>, and <a href="../api/symbols/Map.html" target="api">Map</a>.
You can iterate over a collection by using an <a href="../api/symbols/Iterator.html" target="api">Iterator</a>.
More information can be found in the <a href="../intro/collections.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#collections">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Links</h4>
<p>
The <a href="../api/symbols/Link.html" target="api">Link</a> class is used to implement a visual relationship between nodes.
Links are normally created by the presence of link data objects in the <a href="../api/symbols/GraphLinksModel.html#linkDataArray" target="api">GraphLinksModel.linkDataArray</a>
or by a parent key reference as the value of the <a href="../api/symbols/TreeModel.html#nodeParentKeyProperty" target="api">TreeModel.nodeParentKeyProperty</a> of a node data object
in a <a href="../api/symbols/TreeModel.html" target="api">TreeModel</a>.
More information can be found in the <a href="../intro/links.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#links">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Tools</h4>
<p>
<a href="../api/symbols/Tool.html" target="api">Tool</a>s handle all input events, such as mouse and keyboard interactions, in a Diagram.
There are many kinds of predefined Tool classes that implement all of the common operations that users do.
</p>
<p>
For flexibility and simplicity, all input events are canonicalized as <a href="../api/symbols/InputEvent.html" target="api">InputEvent</a>s and
redirected by the diagram to go to the <a href="../api/symbols/Diagram.html#currentTool" target="api">Diagram.currentTool</a>.
By default the Diagram.currentTool is an instance of <a href="../api/symbols/ToolManager.html" target="api">ToolManager</a> held as the <a href="../api/symbols/Diagram.html#toolManager" target="api">Diagram.toolManager</a>.
The ToolManager implements support for all mode-less tools.
The ToolManager is responsible for finding another tool that is ready to run and then making it the new current tool.
This causes the new tool to process all of the input events (mouse, keyboard, and touch) until the tool decides that it is finished,
at which time the diagram's current tool reverts back to the <a href="../api/symbols/Diagram.html#defaultTool" target="api">Diagram.defaultTool</a>, which is normally the ToolManager, again.
</p>
<p>
More information can be found in the <a href="../intro/tools.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#tools">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>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Geometry Path Strings</h4>
<p>
The <b>GoJS</b> <a href="../api/symbols/Geometry.html" target="api">Geometry</a> class controls the "shape" of a <a href="../api/symbols/Shape.html" target="api">Shape</a>,
whereas the <a href="../api/symbols/Shape.html#fill" target="api">Shape.fill</a> and <a href="../api/symbols/Shape.html#stroke" target="api">Shape.stroke</a> and other shape properties control the colors and appearance of the shape.
For common shape figures, there are predefined geometries that can be used by setting <a href="../api/symbols/Shape.html#figure" target="api">Shape.figure</a>.
However one can also define custom geometries.
</p>
<p>
One can construct any Geometry by allocating and initializing a <a href="../api/symbols/Geometry.html" target="api">Geometry</a> of at least one <a href="../api/symbols/PathFigure.html" target="api">PathFigure</a> holding some <a href="../api/symbols/PathSegment.html" target="api">PathSegment</a>s.
But you may find that using the string representation of a Geometry is easier to write and save in a database.
Use the static method <a href="../api/symbols/Geometry.html#parse" target="api">Geometry.parse</a> or the <a href="../api/symbols/Shape.html#geometryString" target="api">Shape.geometryString</a> property to transform a geometry path string into a <a href="../api/symbols/Geometry.html" target="api">Geometry</a> object.
</p>
<p>
More information can be found in the <a href="../intro/geometry.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#geometries">Related samples</a>
</p>
<hr>
<!-- blacklist tags that do not correspond to a specific GoJS feature -->
<h4>Grid Patterns</h4>
<p>
<b>GoJS</b> provides functionality to display a grid of lines drawn at regular intervals.
Grid Panels can also force dragged parts to be aligned on grid points, and resize parts to be multiples of the grid cell size.
</p>
<p>
Grids are implemented using a type of <a href="../api/symbols/Panel.html" target="api">Panel</a>, <a href="../api/symbols/PanelLayout.html#Grid" target="api">Panel.Grid</a>.
Grid Panels, like most other types of Panels, can be used within <a href="../api/symbols/Node.html" target="api">Node</a>s or any other kind of <a href="../api/symbols/Part.html" target="api">Part</a>.
However when they are used as the <a href="../api/symbols/Diagram.html#grid" target="api">Diagram.grid</a>, they are effectively infinite in extent.
</p>
<p>
More information can be found in the <a href="../intro/grids.html">GoJS Intro</a>.
</p>
<p>
<a href="../samples/index.html#grid">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>