create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
843 lines (792 loc) • 34.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="Template Maps" />
<meta property="og:title" content="Template Maps" />
<meta name="twitter:title" content="Template Maps" />
<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/templateMaps.html" />
<meta property="twitter:url" content="https://gojs.net/latest/intro/templateMaps.html" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="og:type" content="website" />
<meta property="twitter:domain" content="gojs.net" />
<title>
Template Maps | 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>Template Maps</h1>
<p>
Many of the previous examples have provided custom templates for nodes, groups, or links.
Those examples have shown how to make simple adaptations of the templates for particular data instances via data binding.
But what if you want to have nodes with drastically different appearances or behaviors in a single diagram at the same time?
</p>
<p>
It is possible to define a node template that includes all possible configurations for all of the kinds of nodes that you want to display.
There would need to be a lot of data binding and/or code to make the needed changes.
Often you will want to make not-<a>GraphObject.visible</a> large parts of the template in order to make visible the one panel
that you want to show.
But this technique is difficult to use -- templates get way too complicated too quickly.
</p>
<p>
Instead <b>GoJS</b> supports as many templates as you want -- you choose dynamically which one you want to use
to represent a particular node data.
This does mean potentially a lot of templates, but each one will be much simpler, easier to write, and easier to maintain.
</p>
<p>
Each <a>Diagram</a> actually holds a <a>Map</a> of templates for each type of <a>Part</a>: <a>Node</a>, <a>Group</a>, and <a>Link</a>.
Each Map associates a "category" name with a template.
For example, when the diagram wants to create a <a>Node</a> for a particular node data object, the diagram uses that node
data's category to look up the node template in the <a>Diagram.nodeTemplateMap</a>.
Similar lookups are done using the <a>Diagram.groupTemplateMap</a> and the <a>Diagram.linkTemplateMap</a>.
</p>
<p>
Each <a>Diagram</a> initially has its own template maps stocked with predefined categories.
The default category for any data object is the empty string, "".
The <a>Diagram.nodeTemplateMap</a> initially contains for the empty string a very simple <a>Node</a> template holding
a <a>TextBlock</a> whose <a>TextBlock.text</a> property is data bound to the data converted to a string.
You can see the default templates for nodes, groups, and links in a number of the previous examples,
such as the <a href="groups.html#GroupsLinks">Groups and Links</a> example.
</p>
<p>
The value of <a>Diagram.nodeTemplate</a> is just the value of <code>thatDiagram.nodeTemplateMap.get("")</code>.
Setting <a>Diagram.nodeTemplate</a> just replaces the template in <a>Diagram.nodeTemplateMap</a> named with the empty string.
</p>
<p>
The implementations of all predefined templates are provided in <a href="../extensions/Templates.js">Templates.js</a>
in the Extensions directory.
You may wish to copy and adapt these definitions when creating your own templates.
</p>
<h2 id="ExampleOfNodeTemplates">Example of Node templates</h2>
<pre class="lang-js" id="templates"><code>
// the "simple" template just shows the key string and the color in the background,
// but it also includes a tooltip that shows the description
const simpletemplate =
new go.Node("Auto", {
toolTip:
go.GraphObject.build("ToolTip")
.add(
new go.TextBlock({ margin: 4 })
.bind("text", "desc")
)
})
.add(
new go.Shape("Ellipse")
.bind("fill", "color"),
new go.TextBlock()
.bind("text", "key")
);
// the "detailed" template shows all of the information in a Table Panel
const detailtemplate =
new go.Node("Auto")
.add(
new go.Shape("RoundedRectangle")
.bind("fill", "color"),
new go.Panel("Table", { defaultAlignment: go.Spot.Left })
.add(
new go.TextBlock({ row: 0, column: 0, columnSpan: 2, font: "bold 12pt sans-serif" })
.bind("text", "key"),
new go.TextBlock("Description:", { row: 1, column: 0 }),
new go.TextBlock({ row: 1, column: 1 })
.bind("text", "desc"),
new go.TextBlock("Color:", { row: 2, column: 0 }),
new go.TextBlock({ row: 2, column: 1 })
.bind("text", "color")
)
);
// create the nodeTemplateMap, holding three node templates:
const templmap = new go.Map(); // In TypeScript you could write: new go.Map<string, go.Node>();
// for each of the node categories, specify which template to use
templmap.add("simple", simpletemplate);
templmap.add("detailed", detailtemplate);
// for the default category, "", use the same template that Diagrams use by default;
// this just shows the key value as a simple TextBlock
templmap.add("", diagram.nodeTemplate);
diagram.nodeTemplateMap = templmap;
diagram.model.nodeDataArray = [
{ key: "Alpha", desc: "first letter", color: "green" }, // uses default category: ""
{ key: "Beta", desc: "second letter", color: "lightblue", category: "simple" },
{ key: "Gamma", desc: "third letter", color: "pink", category: "detailed" },
{ key: "Delta", desc: "fourth letter", color: "cyan", category: "detailed" }
];
</code></pre>
<script>
goCode('templates', 600, 150);
</script>
<p>
If you hover the mouse over the "Beta" node, you will see the tooltip showing the description string.
The detailed template does not bother using tooltips to show extra information because everything is already shown.
</p>
<p>
By default the way that the model and diagram know about the category of a node data or a link data is by looking at its category property.
If you want to use a different property on the data, for example because you want to use the category property to mean something different,
set <a>Model.nodeCategoryProperty</a> to be the name of the property that results in the actual category string value.
Or set <a>Model.nodeCategoryProperty</a> to be the empty string to cause all nodes to use the default node template.
</p>
<h2 id="ExampleOfItemTemplates">Example of Item Templates</h2>
<p>
For Panels with a value for <a>Panel.itemArray</a>, there is also the <a>Panel.itemTemplateMap</a>.
As with Nodes and Groups and Links, the <a>Panel.itemTemplate</a> is just a reference to the template named with
the empty string in the <a>Panel.itemTemplateMap</a>.
Similarly, the <a>Panel.itemCategoryProperty</a> names the property on the item data that identifies the template
to use from the itemTemplateMap.
</p>
<pre class="lang-js" id="itemTemplates"><code>
// create a template map for items
const itemtemplates = new go.Map(); // In TypeScript you could write: new go.Map<string, go.Panel>();
// the template when type == "text"
itemtemplates.add("text",
new go.Panel()
.add(
new go.TextBlock()
.bind("text")
));
// the template when type == "button"
itemtemplates.add("button",
go.GraphObject.build("Button")
// convert a function name into a function value,
// because functions cannot be represented in JSON format
.bind("click", "handler",
name => {
if (name === "alert") return raiseAlert; // defined below
return null;
})
.add(
new go.TextBlock()
.bind("text")
));
diagram.nodeTemplate =
new go.Node("Vertical")
.add(
new go.TextBlock()
.bind("text", "key"),
new go.Panel("Auto")
.add(
new go.Shape({ fill: "white" }),
new go.Panel("Vertical", {
margin: 3,
defaultAlignment: go.Spot.Left,
itemCategoryProperty: "type", // this property controls the template used
itemTemplateMap: itemtemplates // map was defined above
})
.bind("itemArray", "info")
)
);
function raiseAlert(e, obj) { // here OBJ will be the item Panel
const node = obj.part;
alert(node.data.key + ": " + obj.data.text);
}
// The model data includes item arrays in the node data.
diagram.model = new go.GraphLinksModel( [
{ key: "Alpha",
info: [
{ type: "text", text: "some text" },
{ type: "button", text: "Click me!", handler: "alert"}
]
},
{ key: "Beta",
info: [
{ type: "text", text: "first line" },
{ type: "button", text: "First Button", handler: "alert"},
{ type: "text", text: "second line" },
{ type: "button", text: "Second Button", handler: "alert" }
]
}
],[
{ from: "Alpha", to: "Beta" }
]);
</code></pre>
<script>
goCode('itemTemplates', 600, 150);
</script>
<h2 id="ExampleOfTableHeaderShowingItemData">Example of Table Header Showing Item Data</h2>
<p>
The natural way to have a distinct header for a Table Panel is to have the first row (i.e. the first item)
hold the data for the header, but have it be styled differently.
In this example we define a "Header" item template in the <a>Panel.itemTemplateMap</a>.
</p>
<pre class="lang-js" id="header"><code>
const itemTemplateMap = new go.Map();
itemTemplateMap.add("",
new go.Panel("TableRow")
.add(
new go.TextBlock({ column: 0, margin: 2, font: "bold 10pt sans-serif" })
.bind("text", "name"),
new go.TextBlock({ column: 1, margin: 2 })
.bind("text", "phone"),
new go.TextBlock({ column: 2, margin: 2 })
.bind("text", "loc")
));
itemTemplateMap.add("Header",
new go.Panel("TableRow")
.add(
new go.TextBlock({ column: 0, margin: 2, font: "bold 10pt sans-serif" })
.bind("text", "name"),
new go.TextBlock({ column: 1, margin: 2, font: "bold 10pt sans-serif" })
.bind("text", "phone"),
new go.TextBlock({ column: 2, margin: 2, font: "bold 10pt sans-serif" })
.bind("text", "loc")
));
diagram.nodeTemplate =
new go.Node("Auto")
.add(
new go.Shape({ fill: "white" }),
new go.Panel("Table", {
defaultAlignment: go.Spot.Left,
defaultColumnSeparatorStroke: "black",
itemTemplateMap: itemTemplateMap
})
.bind("itemArray", "people")
.addRowDefinition(0, { background: "lightgray" })
.addRowDefinition(1, { separatorStroke: "black" })
);
diagram.model =
new go.GraphLinksModel(
{
nodeDataArray: [
{ key: "group1",
people: [
{ name: "Person", phone: "Phone", loc: "Location", category: "Header" },
{ name: "Alice", phone: "2345", loc: "C4-E18" },
{ name: "Bob", phone: "9876", loc: "E1-B34" },
{ name: "Carol", phone: "1111", loc: "C4-E23" },
{ name: "Ted", phone: "2222", loc: "C4-E197" },
{ name: "Robert", phone: "5656", loc: "B1-A27" },
{ name: "Natalie", phone: "5698", loc: "B1-B6" }
] }
],
linkDataArray: [
]
}
);
</code></pre>
<script>
goCode('header', 600, 200);
</script>
<p>
If you do not want to have the header data in the itemArray, and you want to define the header in the
node template rather than as an item template, see the example in <a href="itemArrays.html">Item Arrays</a>.
</p>
<h2 id="ChangingCategoryOfPart">Changing category of a Part</h2>
<p>
To change the representation of a data object, call <a>Model.setCategoryForNodeData</a> or <a>GraphLinksModel.setCategoryForLinkData</a>.
(If you set the <a>Part.category</a> of a data bound <a>Part</a>, it will call the Model method for you.)
This causes the diagram to discard any existing Part for the data and re-create it using the new template
that is associated with the new category value.
</p>
<pre class="lang-js" id="changingCategory"><code>
// this function changes the category of the node data to cause the Node to be replaced
function changeCategory(e, obj) {
const node = obj.part;
if (node) {
const diagram = node.diagram;
diagram.startTransaction("changeCategory");
let cat = diagram.model.getCategoryForNodeData(node.data);
if (cat === "simple")
cat = "detailed";
else
cat = "simple";
diagram.model.setCategoryForNodeData(node.data, cat);
diagram.commitTransaction("changeCategory");
}
}
// The "simple" template just shows the key string and the color in the background.
// There is a Button to invoke the changeCategory function.
const simpletemplate =
new go.Node("Spot")
.add(
new go.Panel("Auto")
.add(
new go.Shape("Ellipse")
.bind("fill", "color"),
new go.TextBlock()
.bind("text")
),
go.GraphObject.build("Button", {
alignment: go.Spot.TopRight,
click: changeCategory
})
.add(
new go.Shape("AsteriskLine", { width: 8, height: 8 })
)
);
// The "detailed" template shows all of the information in a Table Panel.
// There is a Button to invoke the changeCategory function.
const detailtemplate =
new go.Node("Spot")
.add(
new go.Panel("Auto")
.add(
new go.Shape("RoundedRectangle")
.bind("fill", "color"),
new go.Panel("Table", { defaultAlignment: go.Spot.Left })
.add(
new go.TextBlock({ row: 0, column: 0, columnSpan: 2, font: "bold 12pt sans-serif" })
.bind("text"),
new go.TextBlock("Description:", { row: 1, column: 0 }),
new go.TextBlock({ row: 1, column: 1 })
.bind("text", "desc"),
new go.TextBlock("Color:", { row: 2, column: 0 }),
new go.TextBlock({ row: 2, column: 1 })
.bind("text", "color")
)
),
go.GraphObject.build("Button", {
alignment: go.Spot.TopRight,
click: changeCategory
})
.add(
new go.Shape("AsteriskLine", { width: 8, height: 8 })
)
);
const templmap = new go.Map(); // In TypeScript you could write: new go.Map<string, go.Node>();
templmap.add("simple", simpletemplate);
templmap.add("detailed", detailtemplate);
diagram.nodeTemplateMap = templmap;
diagram.layout = new go.TreeLayout();
diagram.model.nodeDataArray = [
{ key: 2, text: "Beta", desc: "second letter", color: "lightblue", category: "simple" },
{ key: 3, text: "Gamma", desc: "third letter", color: "pink", category: "detailed" },
{ key: 4, text: "Delta", desc: "fourth letter", color: "cyan", category: "detailed" }
];
diagram.model.linkDataArray = [
{ from: 2, to: 3 },
{ from: 3, to: 4 }
];
</code></pre>
<script>
goCode('changingCategory', 600, 150);
</script>
<p>
Click on the "asterisk" button on any node to toggle dynamically between the "simple" and the "detailed" category for each node.
</p>
<h2 id="ChangingTemplateMaps">Changing template maps</h2>
<p>
You can also replace one or all of the diagram's template maps (e.g. <a>Diagram.nodeTemplateMap</a>)
in order to discard and re-create all of the nodes in the diagram.
If you are only using the default template for nodes, you would only need to replace the <a>Diagram.nodeTemplate</a>.
</p>
<p>
One common circumstance for doing this is as the <a>Diagram.scale</a> changes.
When the user zooms out far enough, there is no point in having too much detail about each of the nodes.
</p>
<p>
If you zoom out in this example, the <a>DiagramEvent</a> listener will detect when the <a>Diagram.scale</a>
becomes small enough to use the simpler template for all of the nodes.
Zoom in again and suddenly it uses the more detailed template.
</p>
<pre class="lang-js" id="changingMap"><code>
// The "simple" template just shows the key string and the color in the background.
const simpletemplate =
new go.Node("Spot")
.add(
new go.Panel("Auto")
.add(
new go.Shape("Ellipse")
.bind("fill", "color"),
new go.TextBlock()
.bind("text", "key")
)
);
// The "detailed" template shows all of the information in a Table Panel.
const detailtemplate =
new go.Node("Spot")
.add(
new go.Panel("Auto")
.add(
new go.Shape("RoundedRectangle")
.bind("fill", "color"),
new go.Panel("Table", { defaultAlignment: go.Spot.Left })
.add(
new go.TextBlock({ row: 0, column: 0, columnSpan: 2, font: "bold 12pt sans-serif" })
.bind("text"),
new go.TextBlock("Description:", { row: 1, column: 0 }),
new go.TextBlock({ row: 1, column: 1 })
.bind("text", "desc"),
new go.TextBlock("Color:", { row: 2, column: 0 }),
new go.TextBlock({ row: 2, column: 1 })
.bind("text", "color")
)
)
);
diagram.layout = new go.TreeLayout();
diagram.model.nodeDataArray = [
{ key: 2, text: "Beta", desc: "second letter", color: "lightblue" },
{ key: 3, text: "Gamma", desc: "third letter", color: "pink" },
{ key: 4, text: "Delta", desc: "fourth letter", color: "cyan" }
];
diagram.model.linkDataArray = [
{ from: 2, to: 3 },
{ from: 3, to: 4 }
];
// initially use the detailed templates
diagram.nodeTemplate = detailtemplate;
diagram.addDiagramListener("ViewportBoundsChanged",
e => {
if (diagram.scale < 0.9) {
diagram.nodeTemplate = simpletemplate;
} else {
diagram.nodeTemplate = detailtemplate;
}
});
// make accessible to the HTML buttons
myDiagram = diagram;
</code></pre>
<script>
goCode('changingMap', 600, 150);
</script>
<input id="ZoomOut" type="button" onclick="myDiagram.commandHandler.decreaseZoom()" value="Zoom Out" />
<input id="ZoomIn" type="button" onclick="myDiagram.commandHandler.increaseZoom()" value="Zoom In" />
<p>
Caution: if you modify a template <a>Map</a>, there is no notification that the map has changed.
You will need to call <a>Diagram.rebuildParts</a> explicitly.
If you are replacing the <a>Diagram.nodeTemplate</a> or the <a>Diagram.nodeTemplateMap</a> or the
corresponding properties for Groups or Links, the Diagram property setters will automatically call <a>Diagram.rebuildParts</a>.
</p>
<p>
When one or more templates are replaced in a diagram, layouts are automatically performed again.
</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="../extensions/Figures.js"></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>