UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

660 lines (621 loc) 26.8 kB
<!DOCTYPE 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="Highlighting" /> <meta property="og:title" content="Highlighting" /> <meta name="twitter:title" content="Highlighting" /> <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/highlighting.html" /> <meta property="twitter:url" content="https://gojs.net/latest/intro/highlighting.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> Highlighting | 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 &amp; 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>Highlighting</h1> <p> It is common to make a Node (or a part of a Node or a Link) stand out by "highlighting" it in some way. This happens with selection when a selection Adornment is shown. However one frequently wants to highlight Parts independently of selection. This can be done by changing the fill or stroke of a Shape, replacing a Picture source with another source, adding or removing a shadow, and so on. </p> <h2 id="HighlightingNodeUponMouseOver">Highlighting a Node upon Mouse Over</h2> <p> The most general kind of highlighting is to change appearance when an action occurs, such as mousing over a node. This can draw attention to interactive Nodes or Links or really any GraphObject, such as buttons. This is why the <a href="buttons.html">predefined buttons in GoJS</a> highlight on mouse-over. </p> <p> To achieve this effect you just need to define <a>GraphObject.mouseEnter</a> and <a>GraphObject.mouseLeave</a> event handlers. </p> <pre class="lang-js" id="highlighting1"><code> function mouseEnter(e, node) { const shape = node.findObject("SHAPE"); shape.fill = "green"; shape.stroke = "lightgreen"; const text = node.findObject("TEXT"); text.stroke = "white"; }; function mouseLeave(e, node) { const shape = node.findObject("SHAPE"); // Return the Shape's fill and stroke to the defaults shape.fill = node.data.color; shape.stroke = null; // Return the TextBlock's stroke to its default const text = node.findObject("TEXT"); text.stroke = "black"; }; diagram.nodeTemplate = new go.Node("Auto", { mouseEnter: mouseEnter, mouseLeave: mouseLeave }) .add( new go.Shape({ strokeWidth: 2, stroke: null, name: "SHAPE" }) .bind("fill", "color"), new go.TextBlock({ margin: 10, font: "bold 18px Verdana", name: "TEXT" }) .bind("text") ); diagram.model = new go.GraphLinksModel( [ { key: 1, text: "Alpha", color: "#96D6D9" }, { key: 2, text: "Beta", color: "#96D6D9" }, { key: 3, text: "Gamma", color: "#EFEBCA" }, { key: 4, text: "Delta", color: "#EFEBCA" } ], [ { from: 1, to: 2 }, { from: 1, to: 3 }, { from: 2, to: 2 }, { from: 3, to: 4 }, { from: 4, to: 1 } ]); </code></pre> <script> goCode('highlighting1', 600, 150); </script> <p>Mouse-over nodes to see them highlight.</p> <p> It is also commonplace to perform highlighting of stationary Parts during a drag, which is a different case of "mouse over". This can be implemented in a manner similar to the mouseEnter/mouseLeave events by implementing <a>GraphObject.mouseDragEnter</a> and <a>GraphObject.mouseDragLeave</a> event handlers. Several samples demonstrate this: <a href="../samples/orgChartEditor.html">Org Chart Editor</a>, <a href="../samples/planogram.html">Planogram</a>, <a href="../samples/regrouping.html">Regrouping</a>, and <a href="../samples/seatingChart.html">Seating Chart</a>. </p> <h2 id="HighlightingNodesAndLinks">Highlighting Nodes and Links</h2> <p> It is common to want to show Nodes or Links that are related to a particular Node. Unlike the mouse-over scenarios, one may want to maintain the highlighting for many Parts independent of any mouse state or selection state. </p> <p> Here is an example of highlighting all of the nodes and links that come out of a node that the user clicks. This example uses the <a>Part.isHighlighted</a> property and data binding of visual properties to that Part.isHighlighted property. Unlike the <a>Part.isSelected</a> property, there are no pre-defined appearance behaviors defined when a Part is highlighted or loses highlight. </p> <pre class="lang-js" id="highlighting2"><code> diagram.nodeTemplate = new go.Node("Auto", { // when the user clicks on a Node, highlight all Links coming out of the node // and all of the Nodes at the other ends of those Links. click: (e, node) => { // highlight all Links and Nodes coming out of a given Node const diagram = node.diagram; diagram.startTransaction("highlight"); // remove any previous highlighting diagram.clearHighlighteds(); // for each Link coming out of the Node, set Link.isHighlighted node.findLinksOutOf().each(l => l.isHighlighted = true); // for each Node destination for the Node, set Node.isHighlighted node.findNodesOutOf().each(n => n.isHighlighted = true); diagram.commitTransaction("highlight"); } }) .add( new go.Shape("Rectangle", { strokeWidth: 2, stroke: null }) .bind("fill", "color") // the Shape.stroke color depends on whether Node.isHighlighted is true .bindObject("stroke", "isHighlighted", h => h ? "red" : "black"), new go.TextBlock({ margin: 10, font: "bold 18px Verdana" }) .bind("text") ); // define the Link template diagram.linkTemplate = new go.Link({ toShortLength: 4 }) .add( new go.Shape() // the Shape.stroke color depends on whether Link.isHighlighted is true .bindObject("stroke", "isHighlighted", h => h ? "red" : "black") // the Shape.strokeWidth depends on whether Link.isHighlighted is true .bindObject("strokeWidth", "isHighlighted", h => h ? 3 : 1), new go.Shape({ toArrow: "Standard", strokeWidth: 0 }) // the Shape.fill color depends on whether Link.isHighlighted is true .bindObject("fill", "isHighlighted", h => h ? "red" : "black") ); // when the user clicks on the background of the Diagram, remove all highlighting diagram.click = e => { e.diagram.commit(d => d.clearHighlighteds(), "no highlighteds"); }; diagram.model = new go.GraphLinksModel( [ { key: 1, text: "Alpha", color: "#96D6D9" }, { key: 2, text: "Beta", color: "#96D6D9" }, { key: 3, text: "Gamma", color: "#EFEBCA" }, { key: 4, text: "Delta", color: "#EFEBCA" } ], [ { from: 1, to: 2 }, { from: 1, to: 3 }, { from: 2, to: 2 }, { from: 3, to: 4 }, { from: 4, to: 1 } ]); </code></pre> <script> goCode('highlighting2', 600, 200); </script> <p> Click on a node to highlight outbound connected links and nodes. Click in the diagram background to remove all highlights. Note that the highlighting is independent of selection. </p> <p> The use of data binding to modify the Shape properties allows you to avoid specifying names for each Shape and writing code to find the Shape and modify its properties. Note how the call to establish a Binding where the source object is the whole Node instead of the node data is to <a>GraphObject.bindObject</a> instead of the usual <a>GraphObject.bind</a>. </p> <p> However when the modifications you want to make are too complicated to implement using data binding, you can implement a <a>Part.highlightedChanged</a> event handler. Similar to the restrictions of the analogous <a>Part.selectionChanged</a> event handler, you must not change the highlighting of any other Parts, and we recommend against making any changes that would cause a layout to happen or any links to be rerouted. </p> <h3 id="ChangingNodeSizeWhenHighlighting">Changing Node Size When Highlighting</h3> <p> You may want to increase the size of a node or of an element in a node in order to highlight it. For example you could have a Binding on <a>GraphObject.scale</a> or <a>Shape.strokeWidth</a>: </p> <pre class="lang-js"><code> new go.Node(...) .add( new go.Shape(...) .bindObject("strokeWidth", "isHighlighted", h => h ? 5 : 1), ... ) </code></pre> <p> However, doing so will change the size of the object. That is likely to invalidate the route of any links that are connected with that node. That might not matter in many apps, but in some cases the routes of some links may have been reshaped by the user. Any recomputation of the route due to a connected node moving or changing size might lose that route. </p> <p> If that is a consideration in your app, you might consider instead having each node hold an additional Shape that would provide the highlighting when shown and that would be unseen otherwise. But do not toggle the <a>GraphObject.visible</a> property, because that would cause the node to change size. Instead toggle the <a>GraphObject.opacity</a> property between 0.0 and 1.0. </p> <pre class="lang-js" id="highlighting3"><code> diagram.nodeTemplate = new go.Node("Auto", { locationSpot: go.Spot.Center, // when the user clicks on a Node, highlight all Links coming out of the node // and all of the Nodes at the other ends of those Links. click: (e, node) => { const diagram = node.diagram; diagram.startTransaction("highlight"); diagram.clearHighlighteds(); node.findLinksOutOf().each(l => l.isHighlighted = true); node.findNodesOutOf().each(n => n.isHighlighted = true); diagram.commitTransaction("highlight"); } }) .add( new go.Panel("Auto") .add( new go.Shape("Ellipse", { strokeWidth: 2, portId: "" }) .bind("fill", "color"), new go.TextBlock({ margin: 5, font: "bold 18px Verdana" }) .bind("text") ), // the highlight shape, which is always a thick red ellipse new go.Shape("Ellipse", { // this shape is the "border" of the Auto Panel, but is drawn in front of the // regular Auto Panel holding the black-bordered ellipse and text isPanelMain: true, spot1: go.Spot.TopLeft, spot2: go.Spot.BottomRight, strokeWidth: 6, stroke: "red", fill: null }) // only show this ellipse when Part.isHighlighted is true .bindObject("opacity", "isHighlighted", h => h ? 1.0 : 0.0) ); // define the Link template diagram.linkTemplate = new go.Link({ toShortLength: 4, reshapable: true, resegmentable: true }) .add( new go.Shape() // when highlighted, draw as a thick red line .bindObject("stroke", "isHighlighted", h => h ? "red" : "black") .bindObject("strokeWidth", "isHighlighted", h => h ? 3 : 1), new go.Shape({ toArrow: "Standard", strokeWidth: 0 }) .bindObject("fill", "isHighlighted", h => h ? "red" : "black") ); // when the user clicks on the background of the Diagram, remove all highlighting diagram.click = e => { e.diagram.commit(d => d.clearHighlighteds(), "no highlighteds"); }; diagram.model = new go.GraphLinksModel( [ { key: 1, text: "Alpha", color: "#96D6D9" }, { key: 2, text: "Beta", color: "#96D6D9" }, { key: 3, text: "Gamma", color: "#EFEBCA" }, { key: 4, text: "Delta", color: "#EFEBCA" } ], [ { from: 1, to: 2 }, { from: 1, to: 3 }, { from: 2, to: 2 }, { from: 3, to: 4 }, { from: 4, to: 1 } ]); </code></pre> <script> goCode('highlighting3', 600, 200); </script> <p> The highlight Shape is the outer ellipse that always has a thick red stroke. It is normally hidden by having zero opacity, but the Binding will change its opacity to one when <a>Part.isHighlighted</a> is true. </p> <p> That highlight Shape is always shown in front of the panel of the colored ellipse and text by putting it afterwards in the list of the panel's child elements. However since the "Auto" Panel assumes the first element acts as the border, we need to set <a>GraphObject.isPanelMain</a> to true on the highlight Shape so that it is the border for the inner panel. </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>