UNPKG

12.4 kBHTMLView Raw
1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="utf-8"/>
5<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
6<meta name="description" content="TypeScript: Radial layout of an arbitrary graph given a start node; selecting a node re-lays out using it as a new root node."/>
7<link rel="stylesheet" href="../assets/css/style.css"/>
8<!-- Copyright 1998-2021 by Northwoods Software Corporation. -->
9<title>Radial Layout</title>
10</head>
11
12<body>
13 <!-- This top nav is not part of the sample code -->
14 <nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
15 <div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
16 <div class="md:pl-4">
17 <a class="text-white hover:text-white no-underline hover:no-underline
18 font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
19 <h1 class="mb-0 p-1 ">GoJS</h1>
20 </a>
21 </div>
22 <button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
23 <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
24 <path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
25 <path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
26 </svg>
27 </button>
28 <div id="topnavList" class="hidden sm:block items-center w-auto mt-0 text-white p-0 z-20">
29 <ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
30 <li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
31 <li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
32 <li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
33 <li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
34 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
35 <li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
36 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
37 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
38 target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
39 <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
40 target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
41 </ul>
42 </div>
43 </div>
44 <hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
45 </nav>
46 <div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
47 <div id="navSide" class="flex flex-col w-full md:w-48 text-gray-700 bg-white flex-shrink-0"></div>
48 <!-- * * * * * * * * * * * * * -->
49 <!-- Start of GoJS sample code -->
50
51
52 <div class="p-4 w-full">
53 <div id="sample">
54 <div id="myDiagramDiv" style="border: solid 1px black; background: white; width: 100%; height: 600px"></div>
55 <label for="maxLayersChanger">Max Layers: </label><input type="text" id="maxLayersChanger" name="maxLayers" style="width: 50px" value="2" />
56 <button id="setMaxLayersButton">Set Max Layers</button>
57 <p>
58 Click on a Node to center it and show its relationships. It is also easy to add more information to each node, including
59 pictures, or to put such information into <a href="../intro/toolTips.html" target="_blank">Tooltips</a>.
60 </p>
61 <p>
62 The <code>RadialLayout</code> class is an extension defined at <a href="../extensionsJSM/RadialLayout.ts">RadialLayout.ts</a>.
63 You can control how many layers to show, whether to draw the circles, and whether to rotate the text, by modifying
64 RadialLayout properties or changing overrides of <code>RadialLayout.rotateNode</code> and/or <code>RadialLayout.commitLayers</code>.
65 </p>
66 </div>
67
68 <script type="module" id="code">
69 import * as go from "../release/go-module.js";
70 import { RadialLayout } from './RadialLayout.js';
71
72 if (window.goSamples) goSamples(); // init for the samples -- you don't need to call this
73 const $ = go.GraphObject.make; // for conciseness in defining templates
74
75 class CustomRadialLayout extends RadialLayout {
76 rotateNode(node, angle, sweep, radius) {
77 // rotate the nodes and make sure the text is not upside-down
78 node.angle = angle;
79 const label = node.findObject('TEXTBLOCK');
80 if (label !== null) {
81 label.angle = ((angle > 90 && angle < 270 || angle < -90) ? 180 : 0);
82 }
83 }
84 commitLayers() {
85 // optional: add circles in the background
86 // need to remove any old ones first
87 const diagram = this.diagram;
88 if (diagram === null)
89 return;
90 const gridlayer = diagram.findLayer('Grid');
91 if (gridlayer === null)
92 return;
93 const root = this.root;
94 if (root === null)
95 return;
96 const circles = new go.Set();
97 gridlayer.parts.each(function(circle) {
98 if (circle.name === 'CIRCLE')
99 circles.add(circle);
100 });
101 circles.each(function(circle) {
102 diagram.remove(circle);
103 });
104 // add circles centered at the root
105 const $$ = go.GraphObject.make; // for conciseness in defining templates
106 for (let lay = 1; lay <= this.maxLayers; lay++) {
107 const radius = lay * this.layerThickness;
108 const circle = $$(go.Part, { name: 'CIRCLE', layerName: 'Grid' }, { locationSpot: go.Spot.Center, location: root.location }, $$(go.Shape, 'Circle', { width: radius * 2, height: radius * 2 }, { fill: 'rgba(200,200,200,0.2)', stroke: null }));
109 diagram.add(circle);
110 }
111 }
112 } // end CustomRadialLayout
113
114 const myDiagram =
115 $(go.Diagram, 'myDiagramDiv', // must be the ID or reference to div
116 {
117 initialAutoScale: go.Diagram.Uniform,
118 padding: 10,
119 isReadOnly: true,
120 layout: $(CustomRadialLayout, { maxLayers: 2 }),
121 'animationManager.isEnabled': false
122 });
123
124 // shows when hovering over a node
125 const commonToolTip = $('ToolTip', $(go.Panel, 'Vertical', { margin: 3 }, $(go.TextBlock, // bound to node data
126 { margin: 4, font: 'bold 12pt sans-serif' }, new go.Binding('text')), $(go.TextBlock, // bound to node data
127 new go.Binding('text', 'color', function(c) { return 'Color: ' + c; })), $(go.TextBlock, // bound to Adornment because of call to Binding.ofObject
128 new go.Binding('text', '', function(ad) { return 'Connections: ' + ad.adornedPart.linksConnected.count; }).ofObject())) // end Vertical Panel
129 ); // end Adornment
130
131 // define the Node template
132 myDiagram.nodeTemplate =
133 $(go.Node, 'Spot',
134 {
135 locationSpot: go.Spot.Center,
136 locationObjectName: 'SHAPE',
137 selectionAdorned: false,
138 click: nodeClicked,
139 toolTip: commonToolTip
140 }, $(go.Shape, 'Circle',
141 {
142 name: 'SHAPE',
143 fill: 'lightgray',
144 stroke: 'transparent',
145 strokeWidth: 2,
146 desiredSize: new go.Size(20, 20),
147 portId: '' // so links will go to the shape, not the whole node
148 }, new go.Binding('fill', 'color')), $(go.TextBlock,
149 {
150 name: 'TEXTBLOCK',
151 alignment: go.Spot.Right,
152 alignmentFocus: go.Spot.Left
153 }, new go.Binding('text')));
154 // this is the root node, at the center of the circular layers
155 myDiagram.nodeTemplateMap.add('Root',
156 $(go.Node, 'Auto',
157 {
158 locationSpot: go.Spot.Center,
159 selectionAdorned: false,
160 toolTip: commonToolTip
161 },
162 $(go.Shape, 'Circle', { fill: 'white' }),
163 $(go.TextBlock, { font: 'bold 12pt sans-serif', margin: 5 }, new go.Binding('text'))
164 ));
165
166 // define the Link template
167 myDiagram.linkTemplate =
168 $(go.Link,
169 {
170 routing: go.Link.Normal,
171 curve: go.Link.Bezier,
172 selectionAdorned: false,
173 layerName: 'Background'
174 },
175 $(go.Shape,
176 { stroke: 'black', strokeWidth: 1 },
177 new go.Binding('stroke', 'color')));
178
179 generateGraph();
180
181 function generateGraph() {
182 const names = [
183 'Joshua', 'Daniel', 'Robert', 'Noah', 'Anthony',
184 'Elizabeth', 'Addison', 'Alexis', 'Ella', 'Samantha',
185 'Joseph', 'Scott', 'James', 'Ryan', 'Benjamin',
186 'Walter', 'Gabriel', 'Christian', 'Nathan', 'Simon',
187 'Isabella', 'Emma', 'Olivia', 'Sophia', 'Ava',
188 'Emily', 'Madison', 'Tina', 'Elena', 'Mia',
189 'Jacob', 'Ethan', 'Michael', 'Alexander', 'William',
190 'Natalie', 'Grace', 'Lily', 'Alyssa', 'Ashley',
191 'Sarah', 'Taylor', 'Hannah', 'Brianna', 'Hailey',
192 'Christopher', 'Aiden', 'Matthew', 'David', 'Andrew',
193 'Kaylee', 'Juliana', 'Leah', 'Anna', 'Allison',
194 'John', 'Samuel', 'Tyler', 'Dylan', 'Jonathan'
195 ];
196 const nodeDataArray = [];
197 for (let i = 0; i < names.length; i++) {
198 nodeDataArray.push({ key: i, text: names[i], color: go.Brush.randomColor(128, 240) });
199 }
200 const linkDataArray = [];
201 const num = nodeDataArray.length;
202 for (let i = 0; i < num * 2; i++) {
203 const a = Math.floor(Math.random() * num);
204 const b = Math.floor(Math.random() * num / 4) + 1;
205 linkDataArray.push({ from: a, to: (a + b) % num, color: go.Brush.randomColor(0, 127) });
206 }
207 myDiagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
208 const someone = nodeDataArray[Math.floor(Math.random() * nodeDataArray.length)];
209 nodeClicked(null, myDiagram.findNodeForData(someone));
210 }
211
212 function nodeClicked(e, root) {
213 if (!(root instanceof go.Node))
214 return;
215 const diagram = root.diagram;
216 if (diagram === null)
217 return;
218 // all other nodes should be visible and use the default category
219 diagram.nodes.each(function(n) {
220 n.visible = true;
221 if (n !== root)
222 n.category = '';
223 });
224 // make this Node the root
225 root.category = 'Root';
226 // tell the RadialLayout what the root node should be
227 diagram.layout.root = root;
228 diagram.layoutDiagram(true);
229 }
230 // called when "Set Max Layers" button is clicked
231 function adjustMaxLayers() {
232 const newMaxLayers = parseInt(document.getElementById('maxLayersChanger').value);
233 function isInteger(val) {
234 return typeof val === 'number' &&
235 isFinite(val) &&
236 Math.floor(val) === val;
237 }
238 if (!isInteger(newMaxLayers) || newMaxLayers < 1 || newMaxLayers > 10) {
239 alert('Please enter an integer larger than zero and less than or equal to 10.');
240 }
241 else {
242 const lay = myDiagram.layout;
243 lay.maxLayers = Math.max(1, Math.min(newMaxLayers, 10));
244 nodeClicked(null, lay.root);
245 }
246 }
247 document.getElementById("setMaxLayersButton").onclick = adjustMaxLayers;
248
249 window.myDiagram = myDiagram; // Attach to the window for console debugging
250 </script>
251 </div>
252 <!-- * * * * * * * * * * * * * -->
253 <!-- End of GoJS sample code -->
254 </div>
255</body>
256<!-- This script is part of the gojs.net website, and is not needed to run the sample -->
257<script src="../assets/js/goSamples.js"></script>
258</html>