@davidsouther/agathon 0.0.0-stage → 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/package.json +19 -4
  2. package/src/assert.ts +67 -0
  3. package/src/geometry/box.ts +76 -0
  4. package/src/geometry/circle.ts +296 -0
  5. package/src/geometry/geometry.ts +318 -0
  6. package/src/geometry/path.ts +315 -0
  7. package/src/geometry/quadtree.ts +321 -0
  8. package/src/geometry/rectangle.ts +129 -0
  9. package/src/geometry/rngon.ts +132 -0
  10. package/src/geometry/types.ts +102 -0
  11. package/src/geometry.ts +61 -0
  12. package/src/highlight/highlight.ts +85 -0
  13. package/src/index.ts +5 -0
  14. package/src/layout/grid/manager.ts +55 -0
  15. package/src/layout/grid.ts +1 -0
  16. package/src/layout/hierarchic/README.md +21 -0
  17. package/src/layout/hierarchic/acyclic.ts +249 -0
  18. package/src/layout/hierarchic/children.ts +169 -0
  19. package/src/layout/hierarchic/debug.ts +186 -0
  20. package/src/layout/hierarchic/layout.ts +266 -0
  21. package/src/layout/hierarchic/manager.ts +65 -0
  22. package/src/layout/hierarchic/normalize.ts +177 -0
  23. package/src/layout/hierarchic/order.ts +321 -0
  24. package/src/layout/hierarchic/position.ts +514 -0
  25. package/src/layout/hierarchic/rank.ts +629 -0
  26. package/src/layout/hierarchic.ts +2 -0
  27. package/src/layout/hulls/arrange.ts +94 -0
  28. package/src/layout/hulls/hulls.ts +243 -0
  29. package/src/layout/hulls/segments.ts +174 -0
  30. package/src/layout/hulls.ts +3 -0
  31. package/src/layout/manager/child_manager.ts +42 -0
  32. package/src/layout/manager/drag_manager.ts +112 -0
  33. package/src/layout/manager/manager.ts +425 -0
  34. package/src/layout/manager/pan_manager.ts +146 -0
  35. package/src/layout/manager/visibility_manager.ts +84 -0
  36. package/src/layout/manager/zoom_manager.ts +263 -0
  37. package/src/layout/manager.ts +6 -0
  38. package/src/layout/properties/defaults.ts +99 -0
  39. package/src/layout/properties/symbol.ts +99 -0
  40. package/src/layout/properties/weak_map.ts +73 -0
  41. package/src/layout/properties.ts +111 -0
  42. package/src/layout/types.ts +470 -0
  43. package/src/layout/util.ts +444 -0
  44. package/src/layout.ts +6 -0
  45. package/src/samples/diff_graph.ts +15 -0
  46. package/src/samples/edge_cases.ts +168 -0
  47. package/src/samples/gansner_with_states.ts +67 -0
  48. package/src/samples/load_generator.ts +213 -0
  49. package/src/samples/search_graph.ts +35 -0
  50. package/src/tsabre/algo.ts +126 -0
  51. package/src/tsabre/builder.ts +97 -0
  52. package/src/tsabre/compress.ts +15 -0
  53. package/src/tsabre/dijkstra/dijkstra.ts +76 -0
  54. package/src/tsabre/dijkstra/heap.ts +83 -0
  55. package/src/tsabre/graph.ts +808 -0
  56. package/src/tsabre/parse.ts +634 -0
  57. package/src/tsabre/print.ts +188 -0
  58. package/src/tsabre/sourcebuilder/code_content_buffer.ts +275 -0
  59. package/src/tsabre/sourcebuilder/printable.ts +33 -0
  60. package/src/tsabre.ts +6 -0
  61. package/src/types.ts +424 -0
  62. package/README.md +0 -3
@@ -0,0 +1,444 @@
1
+ /**
2
+ * @fileoverview
3
+ *
4
+ * Topological layout has a number of internal properties used throughout the
5
+ * computation. Some are configurable by the user. To consistently get this
6
+ * data, instances of SmartGraph, Edge, and Node used for layout can have an
7
+ * optional `layout` property, with an object matching the exposed `Config`
8
+ * interfaces. These are merged into the default objects, in this file, before
9
+ * being stored in the [Symbol.Layout] property of each object. This ensures
10
+ * it's initialized a single time, and then always reused on future property
11
+ * lookups.
12
+ *
13
+ * This file also has utilities for adding virtual nodes and edges to a graph,
14
+ * an operation used in several places.
15
+ */
16
+
17
+ import { assertFinite, checkExhaustive } from "../assert.ts";
18
+ import type { Geometry } from "../geometry/types.ts";
19
+ import { RNGon } from "../geometry.ts";
20
+ import type { Edge, FullGraph, Node, NodeId, Point, Segment, SmartGraph } from "../types.ts";
21
+
22
+ import {
23
+ clearEdgeProps,
24
+ clearGraphProps,
25
+ clearNodeProps,
26
+ clearSegmentProps,
27
+ getEdgeProps,
28
+ getGraphProps,
29
+ getNodeProps,
30
+ getSegmentProps,
31
+ } from "./properties.ts";
32
+ import type {
33
+ EdgeProperties,
34
+ LayoutEdge,
35
+ LayoutGraph,
36
+ LayoutNode,
37
+ NodeProperties,
38
+ } from "./types.ts";
39
+
40
+ // Reexport properties fns, for backwards compatibility.
41
+ export {
42
+ clearEdgeProps,
43
+ clearGraphProps,
44
+ clearNodeProps,
45
+ clearSegmentProps,
46
+ getEdgeProps,
47
+ getGraphProps,
48
+ getNodeProps,
49
+ getSegmentProps,
50
+ };
51
+
52
+ const CacheAction = {
53
+ WRITE: "WRITE",
54
+ READ: "READ",
55
+ } as const;
56
+ type CacheAction = (typeof CacheAction)[keyof typeof CacheAction];
57
+
58
+ /** Memoize virtual nodes' ranks and orders. */
59
+ export function writeVirtualNodeLayoutCache(g: FullGraph): void {
60
+ virtualNodeLayoutCache(g, CacheAction.WRITE);
61
+ }
62
+
63
+ /** Read virtual nodes' ranks and orders from cache */
64
+ export function readVirtualNodeLayoutCache(g: FullGraph): void {
65
+ virtualNodeLayoutCache(g, CacheAction.READ);
66
+ }
67
+
68
+ function virtualNodeLayoutCache(g: FullGraph, action: CacheAction): void {
69
+ const graphProps = getGraphProps(g);
70
+ const { virtualNodeLayout } = graphProps;
71
+
72
+ for (const node of g.allNodes) {
73
+ const nodeProps = getNodeProps(node);
74
+
75
+ if (nodeProps.virtual) {
76
+ switch (action) {
77
+ case CacheAction.WRITE:
78
+ virtualNodeLayout!.set(node.id, {
79
+ rank: nodeProps.rank,
80
+ order: nodeProps.order,
81
+ });
82
+ break;
83
+ case CacheAction.READ:
84
+ {
85
+ const vNodeLayoutCache = virtualNodeLayout!.get(node.id);
86
+ nodeProps.rank = vNodeLayoutCache!.rank;
87
+ nodeProps.order = vNodeLayoutCache!.order;
88
+ }
89
+ break;
90
+ default:
91
+ checkExhaustive(action);
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ /** Pull nodes into a 2d matrix of [rank, order] with a node id. */
98
+ export function buildLayerMatrix(g: SmartGraph<Node, {}>): NodeId[][] {
99
+ const layers: NodeId[][] = range(maxRank(g) + 1).map(() => []);
100
+ for (const node of g.allNodes) {
101
+ const id = node.id;
102
+ const { rank, order } = getNodeProps(node);
103
+ // Position in the matrix row is associated with a node's order. If we have
104
+ // one node with {id: '1st', rank: 0, order: 0} and another with {id: '2nd',
105
+ // rank: 0, order: 3}, this would create a layer ['1st', empty x 2, '2nd'].
106
+ // These undefined elements in the layer matrix row can lead to
107
+ // ReferenceErrors further in the code...[CONT.]
108
+ layers[rank][order] = id;
109
+ }
110
+
111
+ //[CONT.]...to prevent that, holes in each layer are filtered out.
112
+ return layers.map((layer) => layer.filter(Boolean));
113
+ }
114
+
115
+ /** Return an edge with layout set. */
116
+ export function makeEdge(
117
+ source: string,
118
+ target: string,
119
+ layout?: Partial<EdgeProperties>,
120
+ name?: string,
121
+ ): Edge<{ layout: Partial<EdgeProperties> | undefined }> {
122
+ return { source, target, name, layout };
123
+ }
124
+
125
+ /**
126
+ * Find the highest rank value in a graph.
127
+ */
128
+ export function maxRank(g: SmartGraph<Node, {}>): number {
129
+ const ranks = Array.from(g.allNodes).map((node) =>
130
+ assertFinite(getNodeProps(node).rank, `Invalid rank ${getNodeProps(node).rank} for ${node.id}`),
131
+ );
132
+ // Include 0, so that no nodes still returns a valid max rank.
133
+ return Math.max(0, ...ranks);
134
+ }
135
+
136
+ /** Generate an array with n undefined values. */
137
+ export function range(n: number): undefined[] {
138
+ return new Array(n).fill(undefined);
139
+ }
140
+
141
+ /** Virtual nodes have a type corresponding to their usage. */
142
+ export const Virtual = {
143
+ EDGE: "edge",
144
+ BORDER: "border",
145
+ ROOT: "root",
146
+ } as const;
147
+ export type Virtual = (typeof Virtual)[keyof typeof Virtual];
148
+
149
+ let vnodeIdx = 0;
150
+ /**
151
+ * Create a virtual node.
152
+ */
153
+ export function addVirtualNode(
154
+ g: FullGraph,
155
+ virtual: Virtual,
156
+ layout: Partial<NodeProperties>,
157
+ id?: NodeId,
158
+ prefix = "",
159
+ ): NodeId {
160
+ layout.virtual = virtual;
161
+
162
+ if (!id) {
163
+ do {
164
+ id = `(϶${prefix}${vnodeIdx++})`;
165
+ } while (g.hasNode(id));
166
+ }
167
+
168
+ const node: LayoutNode = { id, layout };
169
+ g.setNode(id, node);
170
+
171
+ return id;
172
+ }
173
+
174
+ /** Valid border directions */
175
+ export const Border = {
176
+ TOP: "_bt_",
177
+ BOTTOM: "_bb_",
178
+ } as const;
179
+ export type Border = (typeof Border)[keyof typeof Border];
180
+
181
+ /** Add a virtual border node */
182
+ export function addBorderNode(g: FullGraph, prefix: Border, rank?: number, order?: number): NodeId {
183
+ const layout: Partial<NodeProperties> = {
184
+ geometry: RNGon.point(),
185
+ rank,
186
+ order,
187
+ };
188
+ return addVirtualNode(g, Virtual.BORDER, layout, undefined, prefix);
189
+ }
190
+
191
+ /**
192
+ * Create an initial layout matrix, with no ordering constraints. While this is
193
+ * a terrible order in practice, it's a convenient first step for further
194
+ * ordering calculations. When used for debugging, will use the order as set on
195
+ * the node if called after ordering has taken place.
196
+ */
197
+ export function initOrder(g: FullGraph): NodeId[][] {
198
+ const visited = new Set<NodeId>();
199
+ // Working from the topmost rank down, assign initial ranks to subgraph leaf
200
+ // nodes.
201
+ const simpleNodes = Array.from(g.nodes)
202
+ .filter((id) => g.children(id).size === 0)
203
+ .sort((a, b) => {
204
+ const rankA = getNodeProps(g.node(a)!).rank;
205
+ const rankB = getNodeProps(g.node(b)!).rank;
206
+ return rankA - rankB;
207
+ });
208
+ const layers: NodeId[][] = [];
209
+ for (const id of simpleNodes) {
210
+ iterate(id);
211
+ }
212
+
213
+ // Ensure all layers are initialized
214
+ for (let i = 0; i < layers.length; i++) {
215
+ layers[i] = layers[i] || [];
216
+ }
217
+
218
+ return layers;
219
+
220
+ // Just push each node onto layers in whatever order it happens to be found.
221
+ function iterate(id: NodeId) {
222
+ if (visited.has(id)) return;
223
+ visited.add(id);
224
+
225
+ const { rank } = getNodeProps(g.node(id)!);
226
+ if (layers[rank] === undefined) {
227
+ layers[rank] = [];
228
+ }
229
+ layers[rank].push(id);
230
+
231
+ for (const cid of g.successors(id)) iterate(cid);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Get the correct coordinates for a node, taking fixed values over updated
237
+ * values.
238
+ */
239
+ export function position(node: Node): Point {
240
+ const {
241
+ geometry: { x, y },
242
+ fx,
243
+ fy,
244
+ } = getNodeProps(node);
245
+ // Use "fixed" fx, fy if provided, otherwise
246
+ return {
247
+ x: fx ?? x,
248
+ y: fy ?? y,
249
+ };
250
+ }
251
+
252
+ /**
253
+ * Returns a line segment with ends on borders of given nodes and lying on the
254
+ * line defined by nodes center points.
255
+ */
256
+ export function getLineSegmentBetweenNodes(
257
+ nodeA: Geometry,
258
+ nodeB: Geometry,
259
+ ): { source: Point; target: Point } {
260
+ const s = nodeA.clip([nodeB, nodeA]);
261
+ const t = nodeB.clip([nodeA, nodeB]);
262
+
263
+ return { source: s, target: t };
264
+ }
265
+
266
+ /**
267
+ * Given two points, P0 & P1, and a Y value, find the point P1' along P0->P1
268
+ * such that P1'.Y = Y. Update P1 to be P1'. This modifies the referenced point.
269
+ */
270
+ export function projectPointAlongLineToYValue(p0: Readonly<Point>, p1: Point, endY: number): void {
271
+ const { x: x0, y: y0 } = p0;
272
+ const { x: x1, y: y1 } = p1;
273
+ const dx = x1 - x0;
274
+ const dy = y1 - y0;
275
+ const t = (endY - y0) / dy;
276
+ const endX = x0 + t * dx;
277
+ p1.x = endX;
278
+ p1.y = endY;
279
+ }
280
+
281
+ /**
282
+ * Given a graph and a node, find all segments that could be affected by
283
+ * moving that node. Those segments are the segment neighborhood of the root
284
+ * ancestor of the given node. Segments below collapsed nodes are not included.
285
+ * The iterable will iterate nodes from top to bottom.
286
+ */
287
+ export function findSegmentNeighborhood(
288
+ graph: LayoutGraph,
289
+ id?: NodeId,
290
+ ): Iterable<Segment<LayoutEdge>> {
291
+ const neighborhood = new Set<Segment<LayoutEdge>>();
292
+
293
+ const findSegmentSegments = (segment: Segment<LayoutEdge>): void => {
294
+ for (const previous of segment.previous) {
295
+ if (!graph.node(previous.target)!.expanded) continue;
296
+ neighborhood.add(previous);
297
+ findNodeSegments(previous.source);
298
+ findSegmentSegments(previous);
299
+ }
300
+ };
301
+
302
+ const findNodeSegments = (id?: NodeId): void => {
303
+ if (graph.hasNode(id) && !graph.node(id)!.expanded) return;
304
+ for (const segment of graph.childSegments(id)) {
305
+ neighborhood.add(segment);
306
+ findSegmentSegments(segment);
307
+ }
308
+ for (const child of graph.children(id)) {
309
+ findNodeSegments(child);
310
+ }
311
+ };
312
+
313
+ // Include segments below this node
314
+ findNodeSegments(id);
315
+
316
+ // Include segments into and out from this node, if present
317
+ if (id) {
318
+ for (const segment of graph.nodeSegments(id)) {
319
+ neighborhood.add(segment);
320
+ findSegmentSegments(segment);
321
+ }
322
+ }
323
+
324
+ return neighborhood;
325
+ }
326
+
327
+ /**
328
+ * Given an item, determine at runtime whether it's a Node or a Segment.
329
+ */
330
+ export function isSegment(entity: NodeId | Segment<LayoutEdge>): entity is Segment<LayoutEdge> {
331
+ return (entity as Segment<LayoutEdge>).source !== undefined;
332
+ }
333
+
334
+ /**
335
+ * Returns a bottom-up breadth-first traversal of topNode's children tree. If no
336
+ * topNode given, returns the entire tree's traversal. Nodes that have an
337
+ * unexpanded ancestor do not get into the traversal, as they do not need to be
338
+ * recalculated. Based on code taken from: https://stackoverflow.com/a/23981550
339
+ */
340
+ export function bottomUpBFTraversal(graph: LayoutGraph, topNode?: NodeId): NodeId[] {
341
+ let neighborhood: NodeId[];
342
+ let hulls: Array<Set<NodeId>>;
343
+
344
+ if (topNode) {
345
+ hulls = [graph.children(topNode)];
346
+ neighborhood = [topNode];
347
+ } else {
348
+ hulls = [graph.children()];
349
+ neighborhood = [];
350
+ }
351
+
352
+ while (hulls.length > 0) {
353
+ const hull: Set<NodeId> = hulls.shift()!;
354
+ neighborhood.unshift(...hull);
355
+
356
+ for (const id of hull) {
357
+ if (graph.node(id)!.expanded && graph.hasChildren(id)) {
358
+ hulls.push(graph.children(id));
359
+ }
360
+ }
361
+ }
362
+
363
+ return neighborhood;
364
+ }
365
+
366
+ /**
367
+ * staggerRow will take a single rank and "stagger" adjacent items. This
368
+ * reduces visual density along long single ranks, and improves visibility
369
+ * of such ranks. It works by creating "rows" for every few items, as
370
+ * specified by staggerRows.
371
+ *
372
+ * For instance, with staggerRows = 3 and with 8 items, it would turn this
373
+ * rank
374
+ *
375
+ * 0 0 0 0 0 0 0 0
376
+ *
377
+ * into
378
+ *
379
+ * 0 0 0
380
+ * 0 0 0
381
+ * 0 0
382
+ *
383
+ * For further ranks, this rank's height is the sum of the height of the rows.
384
+ * rankSep does not apply between rows within ranks, it only applies between
385
+ * ranks. All nodes in a row have the same Y center position. A row's height
386
+ * is the height of the largest single node within the rank.
387
+ *
388
+ * The default staggerRows is set to 10.
389
+ */
390
+ export function staggerRow(
391
+ g: LayoutGraph,
392
+ layer: NodeId[],
393
+ coordinates: Record<NodeId, number>,
394
+ staggerRows: number = Math.sqrt(layer.length),
395
+ ): number {
396
+ if (layer.length === 0) return 40;
397
+
398
+ const rowSpread = Math.ceil(layer.length / staggerRows);
399
+
400
+ const rowMaxHeights: number[] = [];
401
+ // Determine the max height for every staggered row.
402
+ for (let i = 0; i < layer.length; i++) {
403
+ const j = i % rowSpread;
404
+ const node = g.node(layer[i])!;
405
+ rowMaxHeights[j] = Math.max(
406
+ rowMaxHeights[j] || 0,
407
+ node ? getNodeProps(node).geometry.height : 0,
408
+ );
409
+ }
410
+
411
+ const rowHeights: number[] = [rowMaxHeights[0] / 2];
412
+ for (let i = 1; i < rowMaxHeights.length; i++) {
413
+ rowHeights[i] = rowHeights[i - 1] + rowMaxHeights[i] / 2;
414
+ }
415
+
416
+ for (let i = 0; i < layer.length; i++) {
417
+ const j = i % rowSpread;
418
+ const id = layer[i];
419
+ coordinates[id] = rowHeights[j];
420
+ }
421
+
422
+ return rowHeights[rowSpread - 1] + rowMaxHeights[rowMaxHeights.length - 1] / 2;
423
+ }
424
+
425
+ /**
426
+ * Given a layer of nodes, distribute them evenly along the horizontal axis.
427
+ */
428
+ export function distributeHorizontalLayer(
429
+ g: LayoutGraph,
430
+ layer: NodeId[],
431
+ coordinates: Record<NodeId, number>,
432
+ ): number {
433
+ let width = 0;
434
+ const padding = getGraphProps(g).nodeSep;
435
+ for (const id of layer) {
436
+ const { geometry } = getNodeProps(g.node(id)!);
437
+ coordinates[id] = width + geometry.width / 2;
438
+ width += geometry.width;
439
+ width += padding;
440
+ }
441
+ width -= padding;
442
+
443
+ return width;
444
+ }
package/src/layout.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * as grid from "./layout/grid.ts";
2
+ export * from "./layout/hierarchic.ts";
3
+ export * as manager from "./layout/manager.ts";
4
+ export * as properties from "./layout/properties.ts";
5
+ export * as types from "./layout/types.ts";
6
+ export * as util from "./layout/util.ts";
@@ -0,0 +1,15 @@
1
+ /** Basic diff test graph. */
2
+ export const DIFF_GRAPH_TEST = `digraph {
3
+ a [presence=both];
4
+ b [presence="left"];
5
+ c [presence=both];
6
+ d [presence="right"];
7
+
8
+ a -> b [presence="left"];
9
+ b -> c [presence="left"];
10
+ c -> a [presence="left"];
11
+
12
+ a -> c [presence="right"];
13
+ c -> d [presence="right"];
14
+ d -> a [presence="right"];
15
+ }`;
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Gansner graph from Gansner paper
3
+ *
4
+ * a
5
+ * /|\
6
+ * bef
7
+ * |||
8
+ * c\|
9
+ * | g
10
+ * \ /
11
+ * h
12
+ */
13
+ export const GANSNER_GRAPH = `digraph {
14
+ a -> b;
15
+ b -> c;
16
+ c -> d;
17
+ d -> h;
18
+ a -> e;
19
+ e -> g;
20
+ g -> h;
21
+ a -> f;
22
+ f -> g;
23
+ }`;
24
+
25
+ /** Fixed rank diamond */
26
+ export const FIXED_DIAMOND = `digraph {
27
+ a [rank=1; fixedRank=true];
28
+ b [rank=2; fixedRank=true];
29
+ c [rank=3; fixedRank=true];
30
+ d [rank=4; fixedRank=true];
31
+
32
+ a -> b;
33
+ a -> c;
34
+ b -> d;
35
+ c -> d;
36
+ }`;
37
+
38
+ /** A simple 2-hulled example showing traffic between cousins. */
39
+ export const TWO_HULLS = `digraph {
40
+ A [status = good] {
41
+ AA { AAA {AAAA;} AAB; }
42
+ }
43
+ B [status = bad] {
44
+ BB;
45
+ }
46
+ AAA -> BB;
47
+ AAB -> BB;
48
+ AAAA -> BB;
49
+ }`;
50
+
51
+ /** Very deep hulls, to test child positioning. */
52
+ export const DEEP_HULLS = `digraph {
53
+ A {
54
+ AA {
55
+ AAA { AAAA; AAAB; }
56
+ AAB { AABA; AABB; }
57
+ }
58
+ AB {
59
+ ABA { ABAA; ABAB; }
60
+ ABB { ABBA; ABBB; }
61
+ }
62
+ }
63
+ B {
64
+ BA {
65
+ BAA { BAAA; BAAB; }
66
+ BAB { BABA; BABB; }
67
+ }
68
+ BB {
69
+ BBA { BBAA; BBAB; }
70
+ BBB { BBBA; BBBB; }
71
+ }
72
+ }
73
+ }`;
74
+
75
+ /**
76
+ * A small cyclic graph who's edge c -> a should be reversed, as it's the
77
+ * lightest.
78
+ */
79
+ export const SMALL_REVERSED = `digraph {
80
+ a -> b[weight=2;];
81
+ b -> c[weight=2;];
82
+ c -> a[weight=1;];
83
+ c -> d[weight=2;];
84
+ c -> e[weight=2;];
85
+ d -> e[weight=2;];
86
+ }`;
87
+
88
+ /**
89
+ * A large acyclic graph, loosely modeled after the GraphViz 0.11 Unices
90
+ * sample.
91
+ */
92
+ export const LARGE_GRAPH = `digraph {
93
+ [printDebug=true]
94
+ Tiger -> Lion;
95
+ Tiger -> Alligator;
96
+ Lion -> Bison;
97
+ Lion -> Shark;
98
+ Lion -> Ant;
99
+ Lion -> Wollongong;
100
+ Lion -> Zebra;
101
+ Zebra -> Deer;
102
+ Zebra -> Hippo;
103
+ Zebra -> Pig;
104
+ Pig -> Giraffe;
105
+ Pig -> Crab;
106
+ Pig -> Cow;
107
+ Pig -> Oyster;
108
+ Pig -> Lemur;
109
+ Pig -> Jaguar;
110
+ Cow -> Oyster;
111
+ Giraffe -> Kangaroo;
112
+ Shark -> Otter;
113
+ Otter -> Goat;
114
+ Goat -> Oyster;
115
+ Goat -> Lynx;
116
+ Crab -> Koala;
117
+ Koala -> Kiwi;
118
+ Kiwi -> Horse;
119
+ Horse -> Frog;
120
+ Horse -> Goat;
121
+ Horse -> Giraffe;
122
+ Frog -> Newt;
123
+ Frog -> Magpie;
124
+ Alligator -> Duck;
125
+ Alligator -> Snake;
126
+ Duck -> Hippo;
127
+ Snake -> Chicken;
128
+ Snake -> Eagle;
129
+ Chicken -> Butterfly;
130
+ Butterfly -> Turtle;
131
+ Turtle -> Rabbit;
132
+ Turtle -> Parrot;
133
+ Eagle -> Owl;
134
+ Owl -> Deer;
135
+ Hippo -> Deer;
136
+ Sheep -> Deer;
137
+ Deer -> Monkey;
138
+ Rabbit -> Monkey;
139
+ Turtle -> Monkey;
140
+ Monkey -> Bird;
141
+ Bird -> Fish;
142
+ Fish -> Mole;
143
+ }`;
144
+
145
+ /** A graph with a search and a focus. */
146
+ export const SEARCH_MATCH = `digraph {
147
+ [search="weasley"; match="fred";]
148
+ gryffindor;
149
+ ron_weasley;
150
+ fred_weasley;
151
+ george_weasley;
152
+ }`;
153
+
154
+ /** Small node-pool example for developing the expanded view */
155
+ export const NODE_POOL = `digraph {
156
+ A; B; C;
157
+ N [expanded=true; type="parent";] { NA; NB; NC; }
158
+ A -> NA; B -> NB; C -> NC;
159
+ }`;
160
+
161
+ /** Graph that has multiple geometries */
162
+ export const GEOMETRIES = `digraph {
163
+ A [geometry='{"type": "rngon", "n": 3, "radius": 12}'];
164
+ B [radius='35'];
165
+ C [geometry='{"type": "square", "side": 12}'];
166
+ A -> C;
167
+ B -> C;
168
+ }`;
@@ -0,0 +1,67 @@
1
+ /** Good bounds for snapshot tests. */
2
+ export const GANSNER_WITH_STATES_BOUNDS = {
3
+ width: 800,
4
+ height: 1000,
5
+ };
6
+
7
+ /** The Marquee "Put everything in" graph. */
8
+ export const GANSNER_WITH_STATES = `digraph {
9
+ [search="a"; match="aa"; icon="icons:workload"]
10
+
11
+ a -> b;
12
+ b -> c;
13
+ c -> d;
14
+ d -> h;
15
+ a -> e;
16
+ e -> g [presence = left];
17
+ g -> h [presence = left];
18
+ a -> f;
19
+ f -> g [presence = left];
20
+
21
+ b [chip="status-warning"];
22
+
23
+ a [expanded=true; chip="status-success"] {
24
+ aa [expanded=true; chip="status-success"] {
25
+ aaa [chip="status-success"];
26
+ aab [chip="status-success"];
27
+ }
28
+ ab [chip="status-success"] {
29
+ aba [chip="status-success"];
30
+ abb [chip="status-success"];
31
+ }
32
+ }
33
+
34
+ c [expanded = true; chip="status-error"; filtered=true] {
35
+ ca [chip="status-error"; presence=left; filtered=true]{
36
+ caa [chip="status-error"; presence=left; filtered=true];
37
+ cab [chip="status-error"; presence=left; filtered=true];
38
+ }
39
+ cb [chip="status-error"; presence = right; filtered=true];
40
+ }
41
+
42
+ f [matched = true];
43
+
44
+ g [expanded=true; selected=true; presence=left] {
45
+ ga [presence = left];
46
+ gb [presence = left];
47
+ gc [selected = true; presence=left];
48
+ }
49
+
50
+ ab -> b [presence = left];
51
+ ab -> f [presence = right];
52
+ aab -> e;
53
+ aab -> f;
54
+ aaa -> e;
55
+ aaa -> f;
56
+ aba -> e;
57
+ b -> ca [presence=left];
58
+ b -> cb [presence=right];
59
+ ca -> d [presence=left];
60
+ e -> gc [presence=left];
61
+ e -> gb [presence=left];
62
+ e -> ga [presence=left];
63
+ f -> gc [presence=left];
64
+ e -> h [presence=right];
65
+ f -> h [presence=right];
66
+ }
67
+ `;