UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

860 lines (760 loc) 49.4 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="Interactive demonstration of circular layout features by the CircularLayout class." /> <meta itemprop="description" content="Interactive demonstration of circular layout features by the CircularLayout class." /> <meta property="og:description" content="Interactive demonstration of circular layout features by the CircularLayout class." /> <meta name="twitter:description" content="Interactive demonstration of circular layout features by the CircularLayout class." /> <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="Circular Layout Demonstration of CircularLayout options" /> <meta property="og:title" content="Circular Layout Demonstration of CircularLayout options" /> <meta name="twitter:title" content="Circular Layout Demonstration of CircularLayout options" /> <meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/clayout.png" /> <meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/clayout.png" /> <meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/clayout.png" /> <meta property="og:url" content="https://gojs.net/latest/samples/cLayout.html" /> <meta property="twitter:url" content="https://gojs.net/latest/samples/cLayout.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> Circular Layout Demonstration of CircularLayout options | 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> <link rel="stylesheet" href="../assets/css/prism.css"/> <script src="../assets/js/prism.js"></script> <div id="allSampleContent" class="p-4 w-full"> <script id="code"> function init() { myDiagram = new go.Diagram('myDiagramDiv', { initialAutoScale: go.AutoScale.UniformToFill, layout: new go.CircularLayout() // other properties are set by the layout function, defined below }); // define the Node template myDiagram.nodeTemplate = new go.Node('Spot', { // make sure the Node.location is different from the Node.position locationSpot: go.Spot.Center }) .bind('text') // for sorting .add( new go.Shape('Ellipse', { // the default value for the Shape.figure property fill: 'lightgray', strokeWidth: 0, desiredSize: new go.Size(30, 30) }) .bind('figure') .bind('fill') .bind('desiredSize', 'size'), new go.TextBlock() .bind('text') ); // define the Link template myDiagram.linkTemplate = new go.Link({ selectable: false }) .add(new go.Shape({ strokeWidth: 3, stroke: '#333' })); // generate a circle using the default values buildSettingsMenu(); rebuildGraph(); } function rebuildGraph() { var numNodes = document.getElementById('numNodes').value; numNodes = parseInt(numNodes, 10); if (isNaN(numNodes)) numNodes = 16; var width = document.getElementById('width').value; width = parseFloat(width, 10); var height = document.getElementById('height').value; height = parseFloat(height, 10); var randSizes = document.getElementById('randSizes').checked; var circ = document.getElementById('circ').checked; var cyclic = document.getElementById('cyclic').checked; var minLinks = document.getElementById('minLinks').value; minLinks = parseInt(minLinks, 10); var maxLinks = document.getElementById('maxLinks').value; maxLinks = parseInt(maxLinks, 10); generateCircle(numNodes, width, height, minLinks, maxLinks, randSizes, circ, cyclic); myDiagram.zoomToFit(); } function generateCircle(numNodes, width, height, minLinks, maxLinks, randSizes, circ, cyclic) { myDiagram.startTransaction('generateCircle'); // replace the diagram's model's nodeDataArray generateNodes(numNodes, width, height, randSizes, circ); // replace the diagram's model's linkDataArray generateLinks(minLinks, maxLinks, cyclic); // force a diagram layout layout(); myDiagram.commitTransaction('generateCircle'); } function randomBlueColor() { // Creates shades of blue for nodes var red = Math.floor(Math.random() * 36 + 40); var green = Math.floor(Math.random() * 56) + 140; var blue = Math.floor(Math.random() * 46 + 210); return "rgb(" + red + "," + green + "," + blue + ")"; } function generateNodes(numNodes, width, height, randSizes, circ) { var nodeArray = []; for (var i = 0; i < numNodes; i++) { var size; // If sizes randomized sets them if (randSizes) { size = new go.Size(Math.floor(Math.random() * (41)) + 25, Math.floor(Math.random() * (41)) + 25); } else { size = new go.Size(width, height); } // If circular sets height to width if (circ) size.height = size.width; var figure = 'Rectangle'; if (circ) figure = 'Ellipse'; nodeArray.push({ key: i, text: i.toString(), figure: figure, fill: go.Brush.lightenBy(randomBlueColor(), .1), // Sets color to random shade of blue size: size }); } // randomize the data, to help demonstrate sorting for (i = 0; i < nodeArray.length; i++) { var swap = Math.floor(Math.random() * nodeArray.length); var temp = nodeArray[swap]; nodeArray[swap] = nodeArray[i]; nodeArray[i] = temp; } // set the nodeDataArray to this array of objects myDiagram.model.nodeDataArray = nodeArray; } function generateLinks(min, max, cyclic) { var linkArray = []; if (myDiagram.nodes.count < 2) myDiagram.model.linkDataArray = linkArray; var nit = myDiagram.nodes; var nodes = new go.List(/*go.Node*/); nodes.addAll(nit); var num = nodes.length; if (cyclic) { for (var i = 0; i < num; i++) { if (i >= num - 1) { linkArray.push({ from: i, to: 0 }); } else { linkArray.push({ from: i, to: i + 1 }); } } } else { if (isNaN(min) || min < 0) min = 0; if (isNaN(max) || max < min) max = min; for (var i = 0; i < num; i++) { var next = nodes.get(i); var children = Math.floor(Math.random() * (max - min + 1)) + min; for (var j = 1; j <= children; j++) { var to = nodes.get(Math.floor(Math.random() * num)); // get keys from the Node.text strings var nextKey = parseInt(next.text, 10); var toKey = parseInt(to.text, 10); if (nextKey !== toKey) { linkArray.push({ from: nextKey, to: toKey }); } } } } myDiagram.model.linkDataArray = linkArray; } function buildSettingsMenu() { // Builds the setting menu through calls to respective builder buildButtonRow('radius', 10, 6, 'Radius','table1', 0); buildButtonRow('aspectRatio', 0.05, 1.00, 'Aspect Ratio','table1', 0, 100, 2); buildButtonRow('startAngle', 5, 0, 'Starting Angle','table1', 0, 360); buildButtonRow('sweepAngle', 5, 360, 'Sweep Angle','table1', 0, 360); buildButtonRow('spacing', 5, 6, 'Spacing','table1'); buildDropdown('arrangement', 'Arrangement','table2', ['Constant Distance', 'Constant Angle', 'Constant Spacing', 'Packed']) buildDropdown('direction', 'Direction','table2', ['Clockwise', 'Counterclockwise', 'Bidirectional Left', 'Bidirectional Right']) buildDropdown('sorting', 'Sorting','table2', ['Forwards', 'Reverse', 'Ascending', 'Descending', 'Optimized']) buildDropdown('nodeDiameterFormula', 'Diameter', 'table2', ['Pythagorean', 'Circular']) document.querySelectorAll('.info').forEach(element => { element.addEventListener('mouseover', () => { iframe(element); }) element.addEventListener('mouseout', () => { document.getElementById('frame').style.display = 'none'; document.getElementById('description').innerHTML = '' }) }) } // Update the layout from the controls, and then perform the layout again function layout() { myDiagram.startTransaction('change Layout'); var lay = myDiagram.layout; var d = document; var code = 'new go.CircularLayout({' var radius = d.getElementById('radius').value; if (radius !== 0) radius = parseFloat(radius, 10); else radius = NaN; lay.radius = radius; if (radius != d.getElementById('radius').name) code += `\n radius: ${radius},`; // These update code block allowing for builder to display code var aspectRatio = d.getElementById('aspectRatio').value; aspectRatio = parseFloat(aspectRatio, 10); lay.aspectRatio = aspectRatio; if (aspectRatio != d.getElementById('aspectRatio').name) code += `\n aspectRatio: ${aspectRatio},`; var startAngle = d.getElementById('startAngle').value; startAngle = parseFloat(startAngle, 10); lay.startAngle = startAngle; if (startAngle != d.getElementById('startAngle').name) code += `\n startAngle: ${startAngle},` var sweepAngle = d.getElementById('sweepAngle').value; sweepAngle = parseFloat(sweepAngle, 10); lay.sweepAngle = sweepAngle; if (sweepAngle != d.getElementById('sweepAngle').name) code += `\n sweepAngle: ${sweepAngle},` var spacing = d.getElementById('spacing').value; spacing = parseFloat(spacing, 10); lay.spacing = spacing; if (spacing != d.getElementById('spacing').name) code += `\n spacing: ${spacing},` var arrangement = d.getElementById('arrangement').value.split(/\s+/).join(''); if (arrangement === 'ConstantDistance') lay.arrangement = go.CircularArrangement.ConstantDistance; else if (arrangement === 'ConstantAngle') lay.arrangement = go.CircularArrangement.ConstantAngle; else if (arrangement === 'ConstantSpacing') lay.arrangement = go.CircularArrangement.ConstantSpacing; else if (arrangement === 'Packed') lay.arrangement = go.CircularArrangement.Packed; if (arrangement != d.getElementById('arrangement').name.split(/\s+/).join('')) code += `\n arrangement: go.CircularArrangement.${arrangement},` var nodeDiameterFormula = d.getElementById('nodeDiameterFormula').value; if (nodeDiameterFormula === 'Pythagorean') lay.nodeDiameterFormula = go.CircularNodeDiameterFormula.Pythagorean; else if (nodeDiameterFormula === 'Circular') lay.nodeDiameterFormula = go.CircularNodeDiameterFormula.Circular; if (nodeDiameterFormula != d.getElementById('nodeDiameterFormula').name) code += `\n nodeDiameterFormula: go.CircularNodeDiameterFormula.${nodeDiameterFormula},` var direction = d.getElementById('direction').value.split(/\s+/).join(''); if (direction === 'Clockwise') lay.direction = go.CircularDirection.Clockwise; else if (direction === 'Counterclockwise') lay.direction = go.CircularDirection.Counterclockwise; else if (direction === 'BidirectionalLeft') lay.direction = go.CircularDirection.BidirectionalLeft; else if (direction === 'BidirectionalRight') lay.direction = go.CircularDirection.BidirectionalRight; if (direction != d.getElementById('direction').name.split(/\s+/).join('')) code += `\n direction: go.CircularDirection.${direction},` var sorting = d.getElementById('sorting').value; if (sorting === 'Forwards') lay.sorting = go.CircularSorting.Forwards; else if (sorting === 'Reverse') lay.sorting = go.CircularSorting.Reverse; else if (sorting === 'Ascending') lay.sorting = go.CircularSorting.Ascending; else if (sorting === 'Descending') lay.sorting = go.CircularSorting.Descending; else if (sorting === 'Optimized') lay.sorting = go.CircularSorting.Optimized; if (sorting != d.getElementById('sorting').name) code += `\n sorting: go.CircularSorting.${sorting},` if (code === 'new go.CircularLayout({') code = 'new go.CircularLayout()'; // If no changes made to layout else code = code.slice(0, -1) + '\n})'; // Removes last comma and adds closing bracket d.getElementById('layoutBuilder').textContent = code; if (window.Prism) window.Prism.highlightAll(); myDiagram.commitTransaction('change Layout'); myDiagram.zoomToFit(); } function changeLinks(max, value) { // Makes sure min links is less than max links and vice versa e = document; if (max) { e.getElementById('maxLinks').value = Math.max(e.getElementById('maxLinks').value - -value, 0); } else { e.getElementById('minLinks').value = Math.max(e.getElementById('minLinks').value - -value, 0); } if (parseInt(e.getElementById('minLinks').value) > parseInt(e.getElementById('maxLinks').value)) { (max)? e.getElementById('minLinks').value = e.getElementById('maxLinks').value : e.getElementById('maxLinks').value = e.getElementById('minLinks').value; } } function changeDropdown(element) { // Changes dropdowns and updates code block and reset button element.parentNode.querySelector('.button1').style = (element.value != element.name)? "background-color: lightcoral;" : "background-color: lightgray;"; layout(); } function resetButton(element) { // Resets the value of the input box and updates respective divs e = element.parentNode.querySelector('.input'); e.value = e.name; element.style = "background-color: lightgray;"; layout(); } function changeInput(element, change = true) { // Changes value and checks for default equality for the reset button e = element.parentNode.querySelector('.inputBox'); change? number = element.name: number = 0; const max = element.parentNode.querySelector('.maximum').name; const min = element.parentNode.querySelector('.minimum').name; const decimal = element.parentNode.querySelector('.decimal').name; var value = (e.value - -number); // Changes by recorded interval if (max !== null) value = Math.min(value, max); // Checks for max and min values if (min !== null) value = Math.max(value, min); e.value = (value).toFixed(((value - value.toFixed(0)) == 0)? 0 : decimal); // Rounds to assigned place element.parentNode.querySelector('.button1').style = (e.value != e.name)? "background-color: lightcoral;" : "background-color: lightgray;"; layout(); } function buildButtonRow(id, change, start, title, table, min = null, max = null, decimal = 0) { var template = document.getElementById('buttonRow'); var clone = template.content.cloneNode(true); clone.querySelector('.button3').name = change; clone.querySelector('.button2').name = -change; clone.querySelector('.inputBox').name = start; clone.querySelector('.inputBox').id = id; clone.querySelector('.inputBox').value = start; clone.querySelector('.maximum').name = max; clone.querySelector('.minimum').name = min; clone.querySelector('.decimal').name = decimal; clone.querySelector('.title').textContent = title; document.getElementById(table).appendChild(clone); } function buildDropdown(id, title, table, options) { var template = document.getElementById('dropdown'); var clone = template.content.cloneNode(true); dropdown = clone.querySelector('.input') dropdown.name = options[0]; dropdown.id = id; clone.querySelector('.title').textContent = title; options.forEach(element => { let option = document.createElement('option'); option.value = element; // Set the value to be the index + 1 option.text = element; // Set the text to be the element from the array dropdown.add(option); }); dropdown.options[0].selected = true; document.getElementById(table).appendChild(clone); } // Disables different inputs based on other properties function heightVisibility() { e = document; if (e.getElementById('circ').checked || e.getElementById('randSizes').checked) { e.getElementById('nodeHeightText').style.opacity = 0.5; e.getElementById('nodeHeightForm').style.opacity = 0.4; e.getElementById('nodeHeightForm').style.pointerEvents = 'none'; } else { e.getElementById('nodeHeightText').style.opacity = 1; e.getElementById('nodeHeightForm').style.opacity = 1; e.getElementById('nodeHeightForm').style.pointerEvents = 'auto'; } if (e.getElementById('randSizes').checked) { e.getElementById('nodeWidthText').style.opacity = 0.5; e.getElementById('nodeWidthForm').style.opacity = 0.4; e.getElementById('nodeWidthForm').style.pointerEvents = 'none'; } else { e.getElementById('nodeWidthText').style.opacity = 1; e.getElementById('nodeWidthForm').style.opacity = 1; e.getElementById('nodeWidthForm').style.pointerEvents = 'auto'; } } function linkVisibility() { e = document; if (e.getElementById('cyclic').checked) { e.getElementById('minLinkText').style.opacity = 0.5; e.getElementById('maxLinkText').style.opacity = 0.5; e.getElementById('minLinksForm').style.opacity = 0.4; e.getElementById('minLinksForm').style.pointerEvents = 'none'; e.getElementById('maxLinksForm').style.opacity = 0.4; e.getElementById('maxLinksForm').style.pointerEvents = 'none'; } else { e.getElementById('minLinkText').style.opacity = 1; e.getElementById('maxLinkText').style.opacity = 1; e.getElementById('minLinksForm').style.opacity = 1; e.getElementById('minLinksForm').style.pointerEvents = 'auto'; e.getElementById('maxLinksForm').style.opacity = 1; e.getElementById('maxLinksForm').style.pointerEvents = 'auto'; } } function copyCode() { navigator.clipboard.writeText(document.getElementById('layoutBuilder').textContent); document.getElementById('default').style.display = 'none' document.getElementById('clicked').style.display = 'inline-flex' document.getElementById('copyButton').style.pointerEvents = 'none' setTimeout(() => { document.getElementById('default').style.display = 'inline-flex' document.getElementById('clicked').style.display = 'none' document.getElementById('copyButton').style.pointerEvents = 'auto' }, 1500); } function iframe(element) { var iframe = document.getElementById('apiFrame'); var frame = document.getElementById('frame'); frame.style.display = 'block'; var id = element.parentElement.querySelector('.input').id; document.getElementById('description').innerHTML = (iframe.contentWindow.document.getElementById(id).parentElement.children[2].firstChild.firstChild.innerHTML); document.getElementById('name').textContent = id; frame.style.left = (element.getBoundingClientRect().left) + 'px'; frame.style.top = (element.getBoundingClientRect().top - 10 + window.pageYOffset) + 'px'; } window.addEventListener('DOMContentLoaded', init); </script> <style> .table { display: table; width: 100%; } .row { display: table-row; } .cell { display: table-cell; vertical-align: middle; } .celldif { display: table-cell; } .sampleWrapper { display: flex; flex-direction: column; @media (min-width: 800px) { flex-direction: row; } & > div:first-child { margin-bottom: 0.5rem; @media (min-width: 800px) { margin-right: 0; margin-bottom: 0; } } } .info { display: inline-block; cursor: pointer; } .copyButton:hover { background-color: #e9e9e9 !important; color: #000000 !important; } </style> <template id="buttonRow"> <div class="row tooltip" > <svg onclick="" class="cell info shrink-0 inline w-4 h-4 align-middle" style="margin-right: 2px; margin-bottom: 6px;" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"> <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"/> </svg> <div class="title cell whitespace-nowrap p-1 select-none" style="font-size: large;"></div> <div class="cell"> <div class="relative flex items-center"> <div class="maximum" ></div> <div class="minimum" ></div> <div class="decimal" ></div> <button type="button" onclick="resetButton(this)" class="button1 rounded-s-lg rounded-e-none h-7 m-0 pr-[2px] pl-[2px]" style="background-color: lightgray;"> <svg fill="#000000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12px" height="12px" viewBox="0 0 528.919 528.919" xml:space="preserve"> <path id="reset" stroke-width="2" d= "M70.846,324.059c3.21,3.926,8.409,3.926,11.619,0l69.162-84.621c3.21-3.926,1.698-7.108-3.372-7.108h-36.723 c-5.07,0-8.516-4.061-7.427-9.012c18.883-85.995,95.625-150.564,187.207-150.564c105.708,0,191.706,85.999,191.706,191.706 c0,105.709-85.998,191.707-191.706,191.707c-12.674,0-22.95,10.275-22.95,22.949s10.276,22.949,22.95,22.949 c131.018,0,237.606-106.588,237.606-237.605c0-131.017-106.589-237.605-237.606-237.605 c-116.961,0-214.395,84.967-233.961,196.409c-0.878,4.994-5.52,9.067-10.59,9.067H5.057c-5.071,0-6.579,3.182-3.373,7.108 L70.846,324.059z"/> </svg> </button> <button type="button" onclick="changeInput(this)" class="button2 bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-none h-7 m-0 pr-[11px] pl-[6px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/> </svg> </button> <input type="text" onchange="changeInput(this, false)" class="input inputBox bg-gray-50 border-x-1 border-gray-300 h-7 text-center outline-none text-gray-900 text-sm w-10 m-[-4.5px] z-10" required /> <button type="button" onclick="changeInput(this)" class="button3 bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg h-7 m-0 pr-[7px] pl-[12px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/> </svg> </button> </div> </div> </div> </template> <template id="dropdown"> <div class="row"> <svg onclick="" class="cell info shrink-0 inline w-4 h-4 align-middle" style="margin-top: 17px; margin-right: 2px; margin-left: 4px" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20"> <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"/> </svg> <div class="title cell whitespace-nowrap p-1 select-none pt-4"></div> <div class="cell pt-4"> <div class="relative flex"> <button type="button" onclick="resetButton(this)" class="button1 rounded-s-lg rounded-e-none h-8.1 m-0 pr-[2px] pl-[2px] align-middle" style="background-color: lightgray;"> <svg fill="#000000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12px" height="12px" viewBox="0 0 528.919 528.919" xml:space="preserve"> <path id="reset" stroke-width="2" d= "M70.846,324.059c3.21,3.926,8.409,3.926,11.619,0l69.162-84.621c3.21-3.926,1.698-7.108-3.372-7.108h-36.723 c-5.07,0-8.516-4.061-7.427-9.012c18.883-85.995,95.625-150.564,187.207-150.564c105.708,0,191.706,85.999,191.706,191.706 c0,105.709-85.998,191.707-191.706,191.707c-12.674,0-22.95,10.275-22.95,22.949s10.276,22.949,22.95,22.949 c131.018,0,237.606-106.588,237.606-237.605c0-131.017-106.589-237.605-237.606-237.605 c-116.961,0-214.395,84.967-233.961,196.409c-0.878,4.994-5.52,9.067-10.59,9.067H5.057c-5.071,0-6.579,3.182-3.373,7.108 L70.846,324.059z"/> </svg> </button> <select onchange="changeDropdown(this)" style="width: 160px;" class="input outline-none bg-gray-50 border rounded-s-none rounded-e-lg border-gray-300 text-gray-900 text-sm block p-1.5"></select> </div> </div> </div> </template> <div id="sample"> <iframe id="apiFrame" src="https://gojs.net/latest/api/symbols/CircularLayout.html" style="display: none;"></iframe> <div id="frame" style="z-index: 100; pointer-events: none; position: absolute; display: none; "> <div id="container" style="border: 1px solid #ddd; border-radius: 5px; padding: 15px; max-width: 600px;margin: 20px auto; font-family: Arial, sans-serif; background-color: #fff;"> <div id="name" class="name" style="font-weight: bold; font-size: 16px; display: flex; align-items: center;"></div> <div id="description" style=" margin-top: 10px; font-size: 14px; color: #000;"></div> </div> </div> <div class="sampleWrapper"> <div id="myDiagramDiv" style="flex-grow: 1; height: 550px; border: solid 1px black; margin-right: 10px;"></div> <div style="flex: 1;"> <section class="grid grid-cols-1 gap-y-3 divide-y"> <details open class="group py-1 text-lg"> <summary class="flex cursor-pointer flex-row items-center whitespace-nowrap justify-between py-1 font-semibold marker:[font-size:0px] select-none">Nodes and Links <svg class="h-6 w-6 rotate-0 transform text-gray-400 group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true"> <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path> </svg> </summary> <span class="sampleWrapper"> <div class="table"> <div class="row" > <div class="cell whitespace-nowrap p-1 select-none" style="font-size: large; padding-right: 0px;">Number of Nodes </div> <div class="cell"> <!--Number of Nodes--> <label for="numNodes" class="items-center cursor-pointer"> <div class="relative flex items-center max-w-[6.5rem] "> <button type="button" onclick="getElementById('numNodes').value = (getElementById('numNodes').value > 0)? getElementById('numNodes').value - 1 : 0" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[12px] pl-[7px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/> </svg> </button> <input type="text" id="numNodes" aria-describedby="helper-text-explanation" class="bg-gray-50 border-x-1 border-gray-300 h-7 text-center outline-none text-gray-900 text-sm w-11 m-[-4.5px] z-10" value="16" required /> <button type="button" onclick="getElementById('numNodes').value = getElementById('numNodes').value - -1" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[7px] pl-[12px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/> </svg> </button> </div> </label> </div> </div> <div class="row"> <div id= "nodeWidthText" class="cell whitespace-nowrap p-1 select-none" style="font-size: large">Node Width</div> <div class="cell max-w-xs" id="nodeWidthForm"> <!--node width--> <label for="minLinks" class="items-center cursor-pointer"> <div class="relative flex items-center max-w-[6.5rem]"> <button type="button" onclick="getElementById('width').value = Math.max(getElementById('width').value - 1, 0)" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[12px] pl-[7px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/> </svg> </button> <input type="text" id="width" aria-describedby="helper-text-explanation" onchange="" class="bg-gray-50 border-x-1 border-gray-300 h-7 text-center text-gray-900 text-sm outline-none w-11 m-[-4.5px] z-10" value="25" required /> <button type="button" onclick="getElementById('width').value = getElementById('width').value - -1" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[7px] pl-[12px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/> </svg> </button> </div> </label> </div> </div> <div class="row"> <div id= "nodeHeightText" class="cell whitespace-nowrap p-1 select-none" style="font-size: large">Node Height</div> <div class="cell max-w-xs" id="nodeHeightForm"> <!--node height--> <label for="minLinks" class="items-center cursor-pointer"> <div class="relative flex items-center max-w-[6.5rem]"> <button type="button" onclick="getElementById('height').value = Math.max(getElementById('height').value - 1, 0)" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[12px] pl-[7px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/> </svg> </button> <input type="text" id="height" aria-describedby="helper-text-explanation" onchange="" class="bg-gray-50 border-x-1 outline-none border-gray-300 h-7 text-center text-gray-900 text-sm block w-11 m-[-4.5px] z-10" value="25" required /> <button type="button" onclick="getElementById('height').value = getElementById('height').value - -1" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[7px] pl-[12px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/> </svg> </button> </div> </label> </div> </div> <div class="row"> <div id="minLinkText" class="cell whitespace-nowrap p-1 select-none" style="font-size: large; ">Minimum Links</div> <div class="cell max-w-xs" id="minLinksForm"> <!--Min Links from Node--> <label for="minLinks" class="items-center cursor-pointer"> <div class="relative flex items-center max-w-[6.5rem]"> <button type="button" onclick="changeLinks(false, -1)" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[12px] pl-[7px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/> </svg> </button> <input type="text" id="minLinks" aria-describedby="helper-text-explanation" onchange="changeLinks(false, 0)" class="bg-gray-50 border-x-1 outline-none border-gray-300 h-7 text-center text-gray-900 text-sm block w-11 m-[-4.5px] z-10" value="1" required /> <button type="button" onclick="changeLinks(false, 1)" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[7px] pl-[12px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/> </svg> </button> </div> </label> </div> </div> <div class="row"> <div id= "maxLinkText" class= "cell whitespace-nowrap p-1 select-none" style="font-size: large">Maximum Links</div> <div class="cell max-w-xs" id="maxLinksForm"> <!--Max Links from Node--> <label for="maxLinks" class="items-center cursor-pointer"> <div class="relative flex items-center max-w-[6.5rem]"> <button type="button" onclick="changeLinks(true, -1)" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-s-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[12px] pl-[7px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 2"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h16"/> </svg> </button> <input type="text" id="maxLinks" aria-describedby="helper-text-explanation" onchange="changeLinks(true, 0)" class="bg-gray-50 border-x-1 outline-none border-gray-300 h-7 text-center text-gray-900 text-sm block w-11 m-[-4.5px] z-10" value="2" required /> <button type="button" onclick="changeLinks(true, 1)" class="bg-gray-100 hover:bg-gray-200 border border-gray-300 rounded-e-lg h-7 focus:ring-gray-100 focus:ring-2 focus:outline-none m-0 pr-[7px] pl-[12px]"> <svg class="w-3 h-3 text-gray-900" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 18"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 1v16M1 9h16"/> </svg> </button> </div> </label> </div> </div> </div> <div> <div class="table pl-[35px] pr-[125px]" > <label class="row"> <div class="cell whitespace-nowrap select-none" style="padding-right: 15px;">Random Sizes</div> <div class="cell inline-flex items-center cursor-pointer"> <!--Random Sizes--> <input type="checkbox" value="" class="sr-only peer" id="randSizes" onchange="heightVisibility()"> <div height=5 class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-0 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div> </div> </label> <label class="row"> <div class="cell whitespace-nowrap select-none">Circular Nodes</div> <div class="cell inline-flex items-center cursor-pointer"> <!--Circular Nodes--> <input type="checkbox" value="" class="sr-only peer" id="circ" onchange="heightVisibility()"> <div height=5 class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-0 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div> </div> </label> <label class="row"> <div class="cell whitespace-nowrap select-none">Simple Ring</div> <div class="cell inline-flex items-center cursor-pointer"> <!--Graph is simple Ring--> <input type="checkbox" value="" class="sr-only peer" id="cyclic" onchange="linkVisibility()"> <div height=5 class="relative w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-0 peer-focus:ring-blue-300 dark:peer-focus:ring-blue-800 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600"></div> </div> </label> <label class="row"> <button type="button" class="mt-4 ml-2 whitespace-nowrap" onclick="rebuildGraph()">Generate Circle</button> </label> </div> </div> </span> </details> <details open class="group py-1 text-lg"> <summary class="flex cursor-pointer flex-row items-center justify-between py-1 font-semibold marker:[font-size:0px] select-none">Layout Properties <svg class="h-6 w-6 rotate-0 transform text-gray-400 group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path></svg> </summary> <span class="sampleWrapper"> <div class="table" id="table1"></div> <div class="table mt-[-15px]" id="table2"></div> </span> </details> <details open class="group py-1 text-lg" > <summary class="flex cursor-pointer flex-row items-center justify-between py-1 font-semibold marker:[font-size:0px] select-none">Circular Layout Builder <svg class="h-6 w-6 rotate-0 transform text-gray-400 group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path></svg> </summary> <div class="p-1" style="position: relative;"><!--Layout Output--> <pre style="overflow: auto;"> <code id="layoutBuilder" class="lang-js" style="font-size: large;"></code> </pre> <button onclick="copyCode()" style="position: absolute; top: 14px; right: 8px; width: 35px; height: 35px;" id="copyButton" class="copyButton text-gray-900 m-1 rounded-lg py-2 px-2.5 inline-flex items-center justify-center bg-white border-gray-200 border"> <svg id="default" class="w-4 h-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 18 20"> <path d="M16 1h-3.278A1.992 1.992 0 0 0 11 0H7a1.993 1.993 0 0 0-1.722 1H2a2 2 0 0 0-2 2v15a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2Zm-3 14H5a1 1 0 0 1 0-2h8a1 1 0 0 1 0 2Zm0-4H5a1 1 0 0 1 0-2h8a1 1 0 1 1 0 2Zm0-5H5a1 1 0 0 1 0-2h2V2h4v2h2a1 1 0 1 1 0 2Z"/> </svg> <svg id="clicked" class="w-4 h-4" style="display: none;" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 12"> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 5.917 5.724 10.5 15 1.5"/> </svg> </button> </div> </details> </section> </div> </div> <p style="flex-grow: 1;">For information on <b>CircularLayout</b> and its properties, see the <a>CircularLayout</a> documentation page.</p> </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>Circular Layout</h4> <p> This predefined layout is used for placing Nodes in a cirular or elliptical arrangement. More information can be found in the <a href="../intro/layouts.html#CircularLayout">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#circularlayout">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>HTML Interaction</h4> <p> GoJS Diagrams can be used alongside other HTML elements in a webapp. For custom Text Editors, Context Menus, and ToolTips, which are invoked and hidden via GoJS tool operations, it is best to use the <a href="../api/symbols/HTMLInfo.html" target="api">HTMLInfo</a> class. </p> <p> More information can be found in the <a href="../intro/HTMLinteraction.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#html">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>