UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

474 lines (423 loc) 19.6 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"/> <meta name="description" content="A simple network configuration editor." /> <meta itemprop="description" content="A simple network configuration editor." /> <meta property="og:description" content="A simple network configuration editor." /> <meta name="twitter:description" content="A simple network configuration editor." /> <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="Network Configuration Diagram Editor With Bars" /> <meta property="og:title" content="Network Configuration Diagram Editor With Bars" /> <meta name="twitter:title" content="Network Configuration Diagram Editor With Bars" /> <meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/network.png" /> <meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/network.png" /> <meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/network.png" /> <meta property="og:url" content="https://gojs.net/latest/samples/network.html" /> <meta property="twitter:url" content="https://gojs.net/latest/samples/network.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> Network Configuration Diagram Editor With Bars | 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"> // A custom Link class that routes directly to the closest horizontal point of an "HBar" node. // If the regular node is too far to the left or right of the "HBar" node, the link connects // with the closest end of the "HBar" node. class BarLink extends go.Link { constructor(init) { super(); if (init) Object.assign(this, init); } computeSpot(from, port) { if (from && this.toNode && this.toNode.category === 'HBar') return go.Spot.TopBottomSides; if (!from && this.fromNode && this.fromNode.category === 'HBar') return go.Spot.TopBottomSides; return super.computeSpot(from, port); } getLinkPoint(node, port, spot, from, ortho, othernode, otherport) { if (!from && node.category === 'HBar') { var op = super.getLinkPoint(othernode, otherport, this.computeSpot(!from), !from, ortho, node, port); var r = port.getDocumentBounds(); var y = op.y > r.centerY ? r.bottom : r.top; if (op.x < r.left) return new go.Point(r.left, y); if (op.x > r.right) return new go.Point(r.right, y); return new go.Point(op.x, y); } else { return super.getLinkPoint(node, port, spot, from, ortho, othernode, otherport); } } getLinkDirection(node, port, linkpoint, spot, from, ortho, othernode, otherport) { if (node.category === 'HBar' || othernode.category === 'HBar') { var p = port.getDocumentPoint(go.Spot.Center); var op = otherport.getDocumentPoint(go.Spot.Center); var below = op.y > p.y; return below ? 90 : 270; } else { return super.getLinkDirection(node, port, linkpoint, spot, from, ortho, othernode, otherport); } } } // end BarLink class function init() { myDiagram = new go.Diagram('myDiagramDiv', { 'linkingTool.direction': go.LinkingDirection.ForwardsOnly, '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('saveModel'); 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); } }); myDiagram.nodeTemplateMap.add('Generator', new go.Node('Spot', { locationSpot: go.Spot.Center, selectionObjectName: 'BODY' }) .bindTwoWay('location', 'location', go.Point.parse, go.Point.stringify) .add( new go.Shape('ACVoltageSource', { name: 'BODY', stroke: 'white', strokeWidth: 3, fill: 'transparent', background: 'darkblue', width: 40, height: 40, margin: 5, portId: '', fromLinkable: true, cursor: 'pointer', fromSpot: go.Spot.TopBottomSides, toSpot: go.Spot.TopBottomSides }), new go.TextBlock({ alignment: go.Spot.Right, alignmentFocus: go.Spot.Left, editable: true }) .bindTwoWay('text') )); myDiagram.nodeTemplateMap.add('Connector', new go.Node('Spot', { locationSpot: go.Spot.Center, selectionObjectName: 'BODY' }) .bindTwoWay('location', 'location', go.Point.parse, go.Point.stringify) .add( new go.Shape('Circle', { name: 'BODY', stroke: null, fill: new go.Brush('Linear', { 0: 'lightgray', 1: 'gray' }), background: 'gray', width: 20, height: 20, margin: 2, portId: '', fromLinkable: true, cursor: 'pointer', fromSpot: go.Spot.TopBottomSides, toSpot: go.Spot.TopBottomSides }), new go.TextBlock({ alignment: go.Spot.Right, alignmentFocus: go.Spot.Left, editable: true }) .bindTwoWay('text') )); myDiagram.nodeTemplateMap.add('Consumer', new go.Node('Spot', { locationSpot: go.Spot.Center, locationObjectName: 'BODY', selectionObjectName: 'BODY' }) .bindTwoWay('location', 'location', go.Point.parse, go.Point.stringify) .add( new go.Picture('images/pc.jpg', { name: 'BODY', width: 50, height: 40, margin: 2, portId: '', fromLinkable: true, cursor: 'pointer', fromSpot: go.Spot.TopBottomSides, toSpot: go.Spot.TopBottomSides }), new go.TextBlock({ alignment: go.Spot.Right, alignmentFocus: go.Spot.Left, editable: true }) .bindTwoWay('text') )); myDiagram.nodeTemplateMap.add('HBar', new go.Node('Spot', { layerName: 'Background', // special resizing: just at the ends resizable: true, resizeObjectName: 'SHAPE', resizeAdornmentTemplate: new go.Adornment('Spot') .add( new go.Placeholder(), new go.Shape({ // left resize handle alignment: go.Spot.Left, cursor: 'col-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'dodgerblue' }), new go.Shape({ // right resize handle alignment: go.Spot.Right, cursor: 'col-resize', desiredSize: new go.Size(6, 6), fill: 'lightblue', stroke: 'dodgerblue' }) ) }) .bindTwoWay('location', 'location', go.Point.parse, go.Point.stringify) .add( new go.Shape('Rectangle', { name: 'SHAPE', fill: 'black', stroke: null, strokeWidth: 0, width: 1000, height: 4, minSize: new go.Size(100, 4), maxSize: new go.Size(Infinity, 4), portId: '', toLinkable: true }) .bindTwoWay('desiredSize', 'size', go.Size.parse, go.Size.stringify) .bind('fill'), new go.TextBlock({ alignment: go.Spot.Right, alignmentFocus: go.Spot.Left, editable: true }) .bindTwoWay('text') )); myDiagram.linkTemplate = new BarLink({ // subclass defined above routing: go.Routing.Orthogonal, relinkableFrom: true, relinkableTo: true, toPortChanged: (link, oldport, newport) => { if (newport instanceof go.Shape) link.path.stroke = newport.fill; } }) .add( new go.Shape({ strokeWidth: 2 }) ); // start off with a simple diagram load(); // initialize Palette myPalette = new go.Palette('myPaletteDiv', { nodeTemplateMap: myDiagram.nodeTemplateMap, layout: new go.GridLayout({ cellSize: new go.Size(2, 2), isViewportSized: true }) }); myPalette.model.nodeDataArray = [ { text: 'Generator', category: 'Generator' }, { text: 'Consumer', category: 'Consumer' }, { text: 'Connector', category: 'Connector' }, { text: 'Bar', category: 'HBar', size: '100 4' } ]; // remove cursors on all ports in the Palette // make TextBlocks invisible, to reduce size of Nodes myPalette.nodes.each(node => { node.ports.each(port => (port.cursor = '')); node.elements.each(tb => { if (tb instanceof go.TextBlock) tb.visible = false; }); }); // initialize Overview myOverview = new go.Overview('myOverviewDiv', { observed: myDiagram, contentAlignment: go.Spot.Center }); } // save a model to and load a model from JSON text, displayed below the Diagram function save() { document.getElementById('mySavedModel').value = myDiagram.model.toJson(); myDiagram.isModified = false; } function load() { myDiagram.model = go.Model.fromJson(document.getElementById('mySavedModel').value); } window.addEventListener('DOMContentLoaded', init); </script> <div id="sample"> <div style="width: 100%; display: flex; justify-content: space-between"> <div style="display: flex; flex-direction: column; margin-right: 2px"> <div id="myPaletteDiv" style="flex-grow: 1; width: 100px; background-color: whitesmoke; border: solid 1px black"></div> <div id="myOverviewDiv" style="margin-top: 2px; width: 100px; height: 100px; background-color: lightgray; border: solid 1px black"></div> </div> <div id="myDiagramDiv" style="flex-grow: 1; height: 400px; border: solid 1px black"></div> </div> <p> This sample creates and uses a custom <a>Link</a> class <code>BarLink</code>. It draws the perpendicular line between the <a>Node</a> and the HBar <a>Node</a>. When the <a>Node</a> doesn't line up horizontally with the HBAR it will draw an Orthogonal <a>Link</a> at close between them as possible. </p> <div id="buttons"> <button id="loadModel" onclick="load()">Load</button> <button id="saveModel" onclick="save()">Save</button> </div> <textarea id="mySavedModel" style="width: 100%; height: 300px"> { "class": "go.GraphLinksModel", "nodeDataArray": [ {"key":0, "text":"Gen1", "category":"Generator", "location":"300 0"}, {"key":1, "text":"Bar1", "category":"HBar", "location":"100 100", "size":"500 4", "fill":"green"}, {"key":3, "text":"Cons1", "category":"Consumer", "location":"53 234"}, {"key":2, "text":"Bar2", "category":"HBar", "location":"0 300", "size":"600 4", "fill":"orange"}, {"key":4, "text":"Conn1", "category":"Connector", "location":"232.5 207.75"}, {"key":5, "text":"Cons3", "category":"Consumer", "location":"357.5 230.75"}, {"key":6, "text":"Cons2", "category":"Consumer", "location":"484.5 164.75"} ], "linkDataArray": [ {"from":0, "to":1}, {"from":0, "to":2}, {"from":3, "to":2}, {"from":4, "to":1}, {"from":4, "to":2}, {"from":5, "to":2}, {"from":6, "to":1} ]} </textarea> </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>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>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>Overview Diagrams</h4> <p> An <a href="../api/symbols/Overview.html" target="api">Overview</a> is a subclass of <a href="../api/symbols/Diagram.html" target="api">Diagram</a> that is used to display all of the <a href="../api/symbols/Part.html" target="api">Part</a>s of another diagram and to show where that diagram's viewport is relative to all of those parts. The user can also scroll the overviewed diagram by clicking or dragging within the overview. </p> <p> The initialization of an <a href="../api/symbols/Overview.html" target="api">Overview</a> is just a matter of setting <a href="../api/symbols/Overview.html#observed" target="api">Overview.observed</a> to refer to the <a href="../api/symbols/Diagram.html" target="api">Diagram</a> that you want it to show. So there needs to be a DIV for your main diagram, for which you create a Diagram in the normal manner, and a separate DIV for your overview, for which you create the Overview in a very simple manner. </p> <p> More information can be found in the <a href="../intro/overview.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#overview">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>