UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

361 lines (314 loc) 15.1 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 tournament or bracket diagram, with automatic promotion as results are entered interactively." /> <meta itemprop="description" content="A tournament or bracket diagram, with automatic promotion as results are entered interactively." /> <meta property="og:description" content="A tournament or bracket diagram, with automatic promotion as results are entered interactively." /> <meta name="twitter:description" content="A tournament or bracket diagram, with automatic promotion as results are entered interactively." /> <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="Tournament Bracket Diagram with Automatic Computations" /> <meta property="og:title" content="Tournament Bracket Diagram with Automatic Computations" /> <meta name="twitter:title" content="Tournament Bracket Diagram with Automatic Computations" /> <meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/tournament.png" /> <meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/tournament.png" /> <meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/tournament.png" /> <meta property="og:url" content="https://gojs.net/latest/samples/tournament.html" /> <meta property="twitter:url" content="https://gojs.net/latest/samples/tournament.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> Tournament Bracket Diagram with Automatic Computations | 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 id="code"> function init() { myDiagram = new go.Diagram('myDiagramDiv', { 'textEditingTool.starting': go.TextEditingStarting.SingleClick, 'textEditingTool.textValidation': isValidScore, layout: new go.TreeLayout({ angle: 180 }), 'undoManager.isEnabled': true }); // validation function for editing text function isValidScore(textblock, oldstr, newstr) { if (newstr === '') return true; var num = parseInt(newstr, 10); return !isNaN(num) && num >= 0 && num < 1000; } // define a simple Node template myDiagram.nodeTemplate = new go.Node('Auto', { selectable: false }) .add( new go.Shape('Rectangle', { fill: '#8C8C8C', stroke: null }) // Shape.fill is bound to Node.data.color .bind('fill', 'color'), new go.Panel('Table') .addColumnDefinition(0, { separatorStroke: 'black' }) .addColumnDefinition(1, { separatorStroke: 'black', background: '#BABABA' }) .addRowDefinition(0, { separatorStroke: 'black' }) .addRowDefinition(1, { separatorStroke: 'black' }) .add( new go.TextBlock('', { row: 0, wrap: go.Wrap.None, margin: 5, width: 90, isMultiline: false, textAlign: 'left', font: '10pt Segoe UI,sans-serif', stroke: 'white' }) .bindTwoWay('text', 'player1'), new go.TextBlock('', { row: 1, wrap: go.Wrap.None, margin: 5, width: 90, isMultiline: false, textAlign: 'left', font: '10pt Segoe UI,sans-serif', stroke: 'white' }) .bindTwoWay('text', 'player2'), new go.TextBlock('', { column: 1, row: 0, wrap: go.Wrap.None, margin: 2, width: 25, isMultiline: false, editable: true, textAlign: 'center', font: '10pt Segoe UI,sans-serif', stroke: 'black' }) .bindTwoWay('text', 'score1'), new go.TextBlock('', { column: 1, row: 1, wrap: go.Wrap.None, margin: 2, width: 25, isMultiline: false, editable: true, textAlign: 'center', font: '10pt Segoe UI,sans-serif', stroke: 'black' }) .bindTwoWay('text', 'score2') ) ); // define the Link template myDiagram.linkTemplate = new go.Link({ routing: go.Routing.Orthogonal, selectable: false }) .add( new go.Shape({ strokeWidth: 2, stroke: 'white' }) ); // Generates the original graph from an array of player names function createPairs(players) { if (players.length % 2 !== 0) players.push('(empty)'); var startingGroups = players.length / 2; var currentLevel = Math.ceil(Math.log(startingGroups) / Math.log(2)); var levelGroups = []; var currentLevel = Math.ceil(Math.log(startingGroups) / Math.log(2)); for (var i = 0; i < startingGroups; i++) { levelGroups.push(currentLevel + '-' + i); } var totalGroups = []; makeLevel(levelGroups, currentLevel, totalGroups, players); return totalGroups; } function makeLevel(levelGroups, currentLevel, totalGroups, players) { currentLevel--; var len = levelGroups.length; var parentKeys = []; var parentNumber = 0; var p = ''; for (var i = 0; i < len; i++) { if (parentNumber === 0) { p = currentLevel + '-' + parentKeys.length; parentKeys.push(p); } if (players !== null) { var p1 = players[i * 2]; var p2 = players[i * 2 + 1]; totalGroups.push({ key: levelGroups[i], parent: p, player1: p1, player2: p2, parentNumber: parentNumber }); } else { totalGroups.push({ key: levelGroups[i], parent: p, parentNumber: parentNumber }); } parentNumber++; if (parentNumber > 1) parentNumber = 0; } // after the first created level there are no player names if (currentLevel >= 0) makeLevel(parentKeys, currentLevel, totalGroups, null); } function updateNode(data) { if (isNaN(data.score1) || isNaN(data.score2)) return; // TODO: What happens if score1 and score2 are the same number? // both score1 and score2 are numbers, // set the name of the higher-score'd player in the advancing (parent) node // if the data.parentNumber is 0, then we set player1 on the parent // if the data.parentNumber is 1, then we set player2 var parent = myDiagram.findNodeForKey(data.parent); if (parent === null) return; var playerName = parseInt(data.score1) > parseInt(data.score2) ? data.player1 : data.player2; if (parseInt(data.score1) === parseInt(data.score2)) playerName = ''; myDiagram.model.setDataProperty(parent.data, data.parentNumber === 0 ? 'player1' : 'player2', playerName); updateNode(parent.data); // go up the tree propagating changes } function makeModel(players) { var model = new go.TreeModel(createPairs(players)); model.addChangedListener(e => { if (e.propertyName !== 'score1' && e.propertyName !== 'score2') return; updateNode(e.object); }); myDiagram.model = model; // provide initial scores for at most three pairings for (var i = 0; i < Math.min(3, model.nodeDataArray.length); i++) { var d = model.nodeDataArray[i]; if (d.player1 && d.player2) { // TODO: doesn't prevent tie scores model.setDataProperty(d, 'score1', Math.floor(Math.random() * 100)); model.setDataProperty(d, 'score2', Math.floor(Math.random() * 100)); } } } makeModel(['Adler', 'Pollock', 'Montgomery', 'Lestrade', 'Wilson', 'Moran', 'Bardle', 'Edwards']); } // end init window.addEventListener('DOMContentLoaded', init); </script> <div id="sample"> <!-- The DIV for the Diagram needs an explicit size or else we won't see anything. Also add a border to help see the edges. --> <div id="myDiagramDiv" style="border: solid 1px black; background: #4d4d4d; width: 700px; height: 600px"></div> <p> Click on the empty score boxes next to names to fill in scores for each player. The scores must be non-negative numbers with at most 3 digits. Scores are validated using a <a>TextEditingTool.textValidation</a> function. When two players in a "game" have a score, one of them will automatically advance to the next round of the bracket. </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>Table Panels</h4> <p> The "Table" Panel, <a href="../api/symbols/Panel.html#static-Table" target="api">Panel.Table</a>, arranges objects in rows and columns. Each object in a Table Panel is put into the cell indexed by the value of <a href="../api/symbols/GraphObject.html#row" target="api">GraphObject.row</a> and <a href="../api/symbols/GraphObject.html#column" target="api">GraphObject.column</a>. The panel will look at the rows and columns for all of the objects in the panel to determine how many rows and columns the table should have. More information can be found in the <a href="../intro/tablePanels.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#tables">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Tree Layout</h4> <p> This predefined layout is used for placing Nodes of a tree-structured graph in layers (rows or columns). For discussion and examples of the most commonly used properties of the <a href="../api/symbols/TreeLayout.html">TreeLayout</a>, see the <a href="../intro/trees.html">Trees</a> page in the Introduction. More information can be found in the <a href="../intro/layouts.html#TreeLayout">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#treelayout">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>